Workaround crashes in MAME's zlib decompression code (#3639)

* Workaround crashes in MAME's zlib decompression code (see https://github.com/TASEmulators/BizHawk/issues/3615)

* Use using block, only catch InvalidDataException (what will be thrown if the zip entry has an unsupported (likely lzma) compression method)
This commit is contained in:
CasualPokePlayer 2023-04-20 09:29:03 -07:00 committed by GitHub
parent efa6505826
commit a8aced4474
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 41 additions and 2 deletions

View File

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text.RegularExpressions;
using System.Runtime.InteropServices;
@ -9,6 +10,7 @@ using System.Text;
using BizHawk.BizInvoke;
using BizHawk.Common;
using BizHawk.Common.IOExtensions;
using BizHawk.Common.StringExtensions;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.Waterbox;
@ -129,15 +131,52 @@ namespace BizHawk.Emulation.Cores.Arcades.MAME
var gameName = _gameFileName.Split('.')[0];
static byte[] MakeRomData(IRomAsset rom)
{
if (rom.Extension.ToLowerInvariant() is ".zip")
{
// if this is deflate, unzip the zip, and rezip it without compression
// this is to get around some zlib bug?
using var ret = new MemoryStream();
ret.Write(rom.FileData, 0, rom.FileData.Length);
using (var zip = new ZipArchive(ret, ZipArchiveMode.Update, leaveOpen: true))
{
foreach (var entryName in zip.Entries.Select(e => e.FullName).ToList())
{
try // TODO: this is a bad way to detect deflate (although it works I guess)
{
var oldEntry = zip.GetEntry(entryName)!;
using var oldEntryStream = oldEntry.Open(); // if this isn't deflate, this throws InvalidDataException
var contents = oldEntryStream.ReadAllBytes();
oldEntryStream.Dispose();
oldEntry.Delete();
var newEntry = zip.CreateEntry(entryName, CompressionLevel.NoCompression);
using var newEntryStream = newEntry.Open();
newEntryStream.Write(contents, 0, contents.Length);
}
catch (InvalidDataException)
{
// ignored
}
}
}
// ZipArchive's Dispose() is what actually modifies the backing stream
return ret.ToArray();
}
return rom.FileData;
}
// mame expects chd files in a folder of the game name
string MakeFileName(IRomAsset rom)
=> rom.Extension.ToLowerInvariant() == ".chd"
=> rom.Extension.ToLowerInvariant() is ".chd"
? gameName + '/' + Path.GetFileNameWithoutExtension(rom.RomPath).ToLowerInvariant() + rom.Extension.ToLowerInvariant()
: Path.GetFileNameWithoutExtension(rom.RomPath).ToLowerInvariant() + rom.Extension.ToLowerInvariant();
foreach (var rom in roms)
{
_exe.AddReadonlyFile(rom.FileData, MakeFileName(rom));
_exe.AddReadonlyFile(MakeRomData(rom), MakeFileName(rom));
}
// https://docs.mamedev.org/commandline/commandline-index.html