From a8aced4474945a7a6b974f5a1947582134f008f3 Mon Sep 17 00:00:00 2001 From: CasualPokePlayer <50538166+CasualPokePlayer@users.noreply.github.com> Date: Thu, 20 Apr 2023 09:29:03 -0700 Subject: [PATCH] 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) --- .../Arcades/MAME/MAME.cs | 43 ++++++++++++++++++- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/src/BizHawk.Emulation.Cores/Arcades/MAME/MAME.cs b/src/BizHawk.Emulation.Cores/Arcades/MAME/MAME.cs index b6dd2fab01..99954da76a 100644 --- a/src/BizHawk.Emulation.Cores/Arcades/MAME/MAME.cs +++ b/src/BizHawk.Emulation.Cores/Arcades/MAME/MAME.cs @@ -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