From 21b6bd331b1617b0a8dbfd4471787bb43b95814c Mon Sep 17 00:00:00 2001 From: CasualPokePlayer <50538166+CasualPokePlayer@users.noreply.github.com> Date: Mon, 29 Apr 2024 22:20:24 -0700 Subject: [PATCH] Add CHD CD support --- .gitmodules | 3 + Assets/dll/chdr.dll | Bin 0 -> 225792 bytes ExternalProjects/libchdr/.gitignore | 1 + ExternalProjects/libchdr/build_release.bat | 10 + ExternalProjects/libchdr/build_release.sh | 12 + ExternalProjects/libchdr/libchdr | 1 + src/BizHawk.Client.Common/RomLoader.cs | 18 +- .../MainDiscoForm.Designer.cs | 2 +- src/BizHawk.Emulation.DiscSystem/Disc.cs | 2 +- .../DiscFormats/Blobs/Blob_CHD.cs | 64 ++ .../DiscFormats/CHD_format.cs | 793 ++++++++++++++++++ .../DiscFormats/CUE/CUE_SynthExtras.cs | 6 +- .../DiscMountJob.cs | 3 + src/BizHawk.Emulation.DiscSystem/LibChdr.cs | 266 ++++++ 14 files changed, 1174 insertions(+), 7 deletions(-) create mode 100644 Assets/dll/chdr.dll create mode 100644 ExternalProjects/libchdr/.gitignore create mode 100644 ExternalProjects/libchdr/build_release.bat create mode 100755 ExternalProjects/libchdr/build_release.sh create mode 160000 ExternalProjects/libchdr/libchdr create mode 100644 src/BizHawk.Emulation.DiscSystem/DiscFormats/Blobs/Blob_CHD.cs create mode 100644 src/BizHawk.Emulation.DiscSystem/DiscFormats/CHD_format.cs create mode 100644 src/BizHawk.Emulation.DiscSystem/LibChdr.cs diff --git a/.gitmodules b/.gitmodules index 6687ec1553..44d82333b5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -77,3 +77,6 @@ path = waterbox/gpgx/Genesis-Plus-GX url = https://github.com/TASEmulators/Genesis-Plus-GX.git branch = tasvideos-2.1 +[submodule "ExternalProjects/libchdr/libchdr"] + path = ExternalProjects/libchdr/libchdr + url = https://github.com/rtissera/libchdr.git diff --git a/Assets/dll/chdr.dll b/Assets/dll/chdr.dll new file mode 100644 index 0000000000000000000000000000000000000000..88b1449b686e792f68e47157bcaa5d6a006c6b87 GIT binary patch literal 225792 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 literal 0 HcmV?d00001 diff --git a/ExternalProjects/libchdr/.gitignore b/ExternalProjects/libchdr/.gitignore new file mode 100644 index 0000000000..3722ac63ca --- /dev/null +++ b/ExternalProjects/libchdr/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/ExternalProjects/libchdr/build_release.bat b/ExternalProjects/libchdr/build_release.bat new file mode 100644 index 0000000000..06625b160a --- /dev/null +++ b/ExternalProjects/libchdr/build_release.bat @@ -0,0 +1,10 @@ +rmdir /s /q build +mkdir build +cd build +:: cl must be used as clang fails to compile :( +cmake ..\libchdr -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=cl -G Ninja ^ + -DBUILD_LTO=ON -DBUILD_SHARED_LIBS=ON -DINSTALL_STATIC_LIBS=OFF -DWITH_SYSTEM_ZLIB=OFF +ninja +xcopy .\chdr.dll ..\..\..\Assets\dll\ /Y +xcopy .\chdr.dll ..\..\..\output\dll\ /Y +cd .. diff --git a/ExternalProjects/libchdr/build_release.sh b/ExternalProjects/libchdr/build_release.sh new file mode 100755 index 0000000000..a10465fe4c --- /dev/null +++ b/ExternalProjects/libchdr/build_release.sh @@ -0,0 +1,12 @@ +#!/bin/sh +set -e +if [ -z "$CC" ]; then export CC="clang"; fi + +rm -rf build +mkdir build +cd build +cmake ../libchdr -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=$CC -G Ninja \ + -DBUILD_LTO=ON -DBUILD_SHARED_LIBS=ON -DINSTALL_STATIC_LIBS=OFF -DWITH_SYSTEM_ZLIB=OFF +ninja +cp -t ../../../Assets/dll/ ./libchdr.so +cp -t ../../../output/dll/ ./libchdr.so diff --git a/ExternalProjects/libchdr/libchdr b/ExternalProjects/libchdr/libchdr new file mode 160000 index 0000000000..5c598c2df3 --- /dev/null +++ b/ExternalProjects/libchdr/libchdr @@ -0,0 +1 @@ +Subproject commit 5c598c2df3a7717552a76410d79f5af01ff51b1d diff --git a/src/BizHawk.Client.Common/RomLoader.cs b/src/BizHawk.Client.Common/RomLoader.cs index d4411bc1bf..009f11ceb1 100644 --- a/src/BizHawk.Client.Common/RomLoader.cs +++ b/src/BizHawk.Client.Common/RomLoader.cs @@ -557,6 +557,20 @@ namespace BizHawk.Client.Common game = rom.GameInfo; } + // HACK due to MAME wanting CHDs as hard drives / handling it on its own (bad design, I know!) + // only matters for XML, as CHDs are never the "main" rom for MAME + // (in general, this is kind of bad as CHD hard drives might be useful for other future cores?) + private static bool IsDiscForXML(string system, string path) + { + var ext = Path.GetExtension(path); + if (system == VSystemID.Raw.Arcade && ext.ToLowerInvariant() == ".chd") + { + return false; + } + + return Disc.IsValidExtension(ext); + } + private bool LoadXML(string path, CoreComm nextComm, HawkFile file, string forcedCoreName, out IEmulator nextEmulator, out RomGame rom, out GameInfo game) { nextEmulator = null; @@ -573,7 +587,7 @@ namespace BizHawk.Client.Common Comm = nextComm, Game = game, Roms = xmlGame.Assets - .Where(kvp => !Disc.IsValidExtension(Path.GetExtension(kvp.Key))) + .Where(kvp => !IsDiscForXML(system, kvp.Key)) .Select(kvp => (IRomAsset)new RomAsset { RomData = kvp.Value, @@ -584,7 +598,7 @@ namespace BizHawk.Client.Common }) .ToList(), Discs = xmlGame.AssetFullPaths - .Where(p => Disc.IsValidExtension(Path.GetExtension(p))) + .Where(p => IsDiscForXML(system, p)) .Select(discPath => (p: discPath, d: DiscExtensions.CreateAnyType(discPath, str => DoLoadErrorCallback(str, system, LoadErrorType.DiscError)))) .Where(a => a.d != null) .Select(a => (IDiscAsset)new DiscAsset diff --git a/src/BizHawk.Client.DiscoHawk/MainDiscoForm.Designer.cs b/src/BizHawk.Client.DiscoHawk/MainDiscoForm.Designer.cs index 66f924c1fe..02a5c8e994 100644 --- a/src/BizHawk.Client.DiscoHawk/MainDiscoForm.Designer.cs +++ b/src/BizHawk.Client.DiscoHawk/MainDiscoForm.Designer.cs @@ -154,7 +154,7 @@ this.label3.Name = "label3"; this.label3.Size = new System.Drawing.Size(235, 33); this.label3.TabIndex = 7; - this.label3.Text = "- Uses FFMPEG for audio decoding\r\n- Loads ISO, CUE, CCD, CDI, MDS, and NRG"; + this.label3.Text = "- Uses FFMPEG for audio decoding\r\n- Loads ISO, CUE, CCD, CDI, CHD, MDS, and NRG"; // // radioButton2 // diff --git a/src/BizHawk.Emulation.DiscSystem/Disc.cs b/src/BizHawk.Emulation.DiscSystem/Disc.cs index 1fbd3b9b30..5ce69c5e7f 100644 --- a/src/BizHawk.Emulation.DiscSystem/Disc.cs +++ b/src/BizHawk.Emulation.DiscSystem/Disc.cs @@ -122,6 +122,6 @@ namespace BizHawk.Emulation.DiscSystem {} public static bool IsValidExtension(string extension) - => extension.ToLowerInvariant() is ".ccd" or ".cdi" or ".cue" or ".iso" or ".toc" or ".mds" or ".nrg"; + => extension.ToLowerInvariant() is ".ccd" or ".cdi" or ".chd" or ".cue" or ".iso" or ".toc" or ".mds" or ".nrg"; } } \ No newline at end of file diff --git a/src/BizHawk.Emulation.DiscSystem/DiscFormats/Blobs/Blob_CHD.cs b/src/BizHawk.Emulation.DiscSystem/DiscFormats/Blobs/Blob_CHD.cs new file mode 100644 index 0000000000..70232deb68 --- /dev/null +++ b/src/BizHawk.Emulation.DiscSystem/DiscFormats/Blobs/Blob_CHD.cs @@ -0,0 +1,64 @@ +using System; +using System.IO; + +namespace BizHawk.Emulation.DiscSystem +{ + internal class Blob_CHD : IBlob + { + private LibChdr.CoreFileStreamWrapper _coreFile; + private IntPtr _chdFile; + + private readonly uint _hunkSize; + private readonly byte[] _hunkCache; + private int _currentHunk; + + public Blob_CHD(LibChdr.CoreFileStreamWrapper coreFile, IntPtr chdFile, uint hunkSize) + { + _coreFile = coreFile; + _chdFile = chdFile; + _hunkSize = hunkSize; + _hunkCache = new byte[hunkSize]; + _currentHunk = -1; + } + + public void Dispose() + { + if (_chdFile != IntPtr.Zero) + { + LibChdr.chd_close(_chdFile); + _chdFile = IntPtr.Zero; + } + + _coreFile?.Dispose(); + _coreFile = null; + } + + public int Read(long byte_pos, byte[] buffer, int offset, int count) + { + var ret = count; + while (count > 0) + { + var targetHunk = (uint)(byte_pos / _hunkSize); + if (targetHunk != _currentHunk) + { + var err = LibChdr.chd_read(_chdFile, targetHunk, _hunkCache); + if (err != LibChdr.chd_error.CHDERR_NONE) + { + // shouldn't ever happen in practice, unless something has gone terribly wrong + throw new IOException($"CHD read failed with error {err}"); + } + + _currentHunk = (int)targetHunk; + } + + var hunkOffset = (uint)(byte_pos - targetHunk * _hunkSize); + var bytesToCopy = Math.Min((int)(_hunkSize - hunkOffset), count); + Buffer.BlockCopy(_hunkCache, (int)hunkOffset, buffer, offset, bytesToCopy); + offset += bytesToCopy; + count -= bytesToCopy; + } + + return ret; + } + } +} diff --git a/src/BizHawk.Emulation.DiscSystem/DiscFormats/CHD_format.cs b/src/BizHawk.Emulation.DiscSystem/DiscFormats/CHD_format.cs new file mode 100644 index 0000000000..4bb2daab4a --- /dev/null +++ b/src/BizHawk.Emulation.DiscSystem/DiscFormats/CHD_format.cs @@ -0,0 +1,793 @@ +using System; +using System.Buffers.Binary; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using BizHawk.Common; +using BizHawk.Emulation.DiscSystem.CUE; + +#pragma warning disable BHI1005 + +//MAME CHD images, using the standard libchdr for reading + +namespace BizHawk.Emulation.DiscSystem +{ + public static class CHD_Format + { + /// + /// Represents a CHD file. + /// This isn't particularly faithful to the format, but rather it just wraps libchdr's chd_file + /// + public class CHDFile + { + /// + /// Wrapper of a C# stream to a chd_core_file + /// + public LibChdr.CoreFileStreamWrapper CoreFile; + + /// + /// chd_file* to be used for libchdr functions + /// + public IntPtr ChdFile; + + /// + /// CHD header, interpreted by libchdr + /// + public LibChdr.chd_header Header; + + /// + /// CHD CD metadata for each track + /// + public readonly IList CdMetadatas = new List(); + } + + /// + /// Results of chd_get_metadata with cdrom track metadata tags + /// + public class CHDCdMetadata + { + /// + /// Track number (1..99) + /// + public uint Track; + + /// + /// Indicates this is a CDI format + /// chd_track_type doesn't have an explicit enum for this + /// However, this is still important info for discerning the session format + /// + public bool IsCDI; + + /// + /// Track type + /// + public LibChdr.chd_track_type TrackType; + + /// + /// Subcode type + /// + public LibChdr.chd_sub_type SubType; + + /// + /// Size of each sector + /// + public uint SectorSize; + + /// + /// Subchannel size + /// + public uint SubSize; + + /// + /// Number of frames in this track + /// This might include pregap, if that is stored in the chd + /// + public uint Frames; + + /// + /// Number of "padding" frames in this track + /// This is done in order to maintain a multiple of 4 frames for each track + /// These padding frames aren't representative of the actual disc anyways + /// They're only useful to know the offset of the next track within the chd + /// + public uint Padding; + + /// + /// Number of pregap sectors + /// + public uint Pregap; + + /// + /// Pregap track type + /// + public LibChdr.chd_track_type PregapTrackType; + + /// + /// Pregap subcode type + /// + public LibChdr.chd_sub_type PregapSubType; + + /// + /// Indicates whether pregap is in the CHD + /// If pregap isn't in the CHD, it needs to be generated where appropriate + /// + public bool PregapInChd; + + /// + /// Number of postgap sectors + /// + public uint PostGap; + } + + public class CHDParseException : Exception + { + public CHDParseException(string message) : base(message) { } + public CHDParseException(string message, Exception ex) : base(message, ex) { } + } + + private static LibChdr.chd_track_type GetTrackType(string type) + { + return type switch + { + "MODE1" => LibChdr.chd_track_type.CD_TRACK_MODE1, + "MODE1/2048" => LibChdr.chd_track_type.CD_TRACK_MODE1, + "MODE1_RAW" => LibChdr.chd_track_type.CD_TRACK_MODE1_RAW, + "MODE1/2352" => LibChdr.chd_track_type.CD_TRACK_MODE1_RAW, + "MODE2" => LibChdr.chd_track_type.CD_TRACK_MODE2, + "MODE2/2336" => LibChdr.chd_track_type.CD_TRACK_MODE2, + "MODE2_FORM1" => LibChdr.chd_track_type.CD_TRACK_MODE2_FORM1, + "MODE2/2048" => LibChdr.chd_track_type.CD_TRACK_MODE2_FORM1, + "MODE2_FORM2" => LibChdr.chd_track_type.CD_TRACK_MODE2_FORM2, + "MODE2/2324" => LibChdr.chd_track_type.CD_TRACK_MODE2_FORM2, + "MODE2_FORM_MIX" => LibChdr.chd_track_type.CD_TRACK_MODE2_FORM_MIX, + "MODE2_RAW" => LibChdr.chd_track_type.CD_TRACK_MODE2_RAW, + "MODE2/2352" => LibChdr.chd_track_type.CD_TRACK_MODE2_RAW, + "CDI/2352" => LibChdr.chd_track_type.CD_TRACK_MODE2_RAW, + "AUDIO" => LibChdr.chd_track_type.CD_TRACK_AUDIO, + _ => throw new CHDParseException("Malformed CHD format: Invalid track type!"), + }; + } + + private static (LibChdr.chd_track_type TrackType, bool ChdContainsPregap) GetTrackTypeForPregap(string type) + { + if (type.Length > 0 && type[0] == 'V') + { + return (GetTrackType(type[1..]), true); + } + + return (GetTrackType(type), false); + } + + private static uint GetSectorSize(LibChdr.chd_track_type type) + { + return type switch + { + LibChdr.chd_track_type.CD_TRACK_MODE1 => 2048, + LibChdr.chd_track_type.CD_TRACK_MODE1_RAW => 2352, + LibChdr.chd_track_type.CD_TRACK_MODE2 => 2336, + LibChdr.chd_track_type.CD_TRACK_MODE2_FORM1 => 2048, + LibChdr.chd_track_type.CD_TRACK_MODE2_FORM2 => 2324, + LibChdr.chd_track_type.CD_TRACK_MODE2_FORM_MIX => 2336, + LibChdr.chd_track_type.CD_TRACK_MODE2_RAW => 2352, + LibChdr.chd_track_type.CD_TRACK_AUDIO => 2352, + _ => throw new CHDParseException("Malformed CHD format: Invalid track type!"), + }; + } + + private static LibChdr.chd_sub_type GetSubType(string type) + { + return type switch + { + "RW" => LibChdr.chd_sub_type.CD_SUB_NORMAL, + "RW_RAW" => LibChdr.chd_sub_type.CD_SUB_RAW, + "NONE" => LibChdr.chd_sub_type.CD_SUB_NONE, + _ => throw new CHDParseException("Malformed CHD format: Invalid sub type!"), + }; + } + + private static uint GetSubSize(LibChdr.chd_sub_type type) + { + return type switch + { + LibChdr.chd_sub_type.CD_SUB_NORMAL => 96, + LibChdr.chd_sub_type.CD_SUB_RAW => 96, + LibChdr.chd_sub_type.CD_SUB_NONE => 0, + _ => throw new CHDParseException("Malformed CHD format: Invalid sub type!"), + }; + } + + private static readonly string[] _metadataTags = { "TRACK", "TYPE", "SUBTYPE", "FRAMES", "PREGAP", "PGTYPE", "PGSUB", "POSTGAP" }; + + private static CHDCdMetadata ParseMetadata2(string metadata) + { + var strs = metadata.Split(' '); + if (strs.Length != 8) + { + throw new CHDParseException("Malformed CHD format: Incorrect number of metadata tags"); + } + + for (var i = 0; i < 8; i++) + { + var spl = strs[i].Split(':'); + if (spl.Length != 2 || _metadataTags[i] != spl[0]) + { + throw new CHDParseException("Malformed CHD format: Invalid metadata tag"); + } + + strs[i] = spl[1]; + } + + var ret = new CHDCdMetadata(); + try + { + ret.Track = uint.Parse(strs[0]); + ret.TrackType = GetTrackType(strs[1]); + ret.SubType = GetSubType(strs[2]); + ret.Frames = uint.Parse(strs[3]); + ret.Pregap = uint.Parse(strs[4]); + (ret.PregapTrackType, ret.PregapInChd) = GetTrackTypeForPregap(strs[5]); + ret.PregapSubType = GetSubType(strs[6]); + ret.PostGap = uint.Parse(strs[7]); + } + catch (Exception ex) + { + throw ex as CHDParseException ?? new("Malformed CHD format: Metadata parsing threw an exception", ex); + } + + if (ret.PregapInChd && ret.Pregap == 0) + { + throw new CHDParseException("Malformed CHD format: CHD track type indicate it contained pregap data, but no pregap data is present"); + } + + ret.IsCDI = strs[1] == "CDI/2352"; + ret.SectorSize = GetSectorSize(ret.TrackType); + ret.SubSize = GetSubSize(ret.SubType); + ret.Padding = (0 - ret.Frames) & 3; + return ret; + } + + private static CHDCdMetadata ParseMetadata(string metadata) + { + var strs = metadata.Split(' '); + if (strs.Length != 4) + { + throw new CHDParseException("Malformed CHD format: Incorrect number of metadata tags"); + } + + for (var i = 0; i < 4; i++) + { + var spl = strs[i].Split(':'); + if (spl.Length != 2 || _metadataTags[i] != spl[0]) + { + throw new CHDParseException("Malformed CHD format: Invalid metadata tag"); + } + + strs[i] = spl[1]; + } + + var ret = new CHDCdMetadata(); + try + { + ret.Track = uint.Parse(strs[0]); + ret.TrackType = GetTrackType(strs[1]); + ret.SubType = GetSubType(strs[2]); + ret.Frames = uint.Parse(strs[3]); + } + catch (Exception ex) + { + throw ex as CHDParseException ?? new("Malformed CHD format: Metadata parsing threw an exception", ex); + } + + ret.IsCDI = strs[1] == "CDI/2352"; + ret.SectorSize = GetSectorSize(ret.TrackType); + ret.SubSize = GetSubSize(ret.SubType); + ret.Padding = (0 - ret.Frames) & 3; + return ret; + } + + private static void ParseMetadataOld(ICollection cdMetadatas, Span metadata) + { + var numTracks = BinaryPrimitives.ReadUInt32LittleEndian(metadata); + var bigEndian = numTracks > 99; // apparently old metadata can appear as either little endian or big endian + if (bigEndian) + { + numTracks = BinaryPrimitives.ReverseEndianness(numTracks); + } + + if (numTracks > 99) + { + throw new CHDParseException("Malformed CHD format: Invalid number of tracks"); + } + + for (var i = 0; i < numTracks; i++) + { + var track = metadata[(4 + i * 24)..]; + var cdMetadata = new CHDCdMetadata + { + Track = (uint)i + 1 + }; + if (bigEndian) + { + cdMetadata.TrackType = (LibChdr.chd_track_type)BinaryPrimitives.ReadUInt32BigEndian(track); + cdMetadata.SubType = (LibChdr.chd_sub_type)BinaryPrimitives.ReadUInt32BigEndian(track[..4]); + cdMetadata.SectorSize = BinaryPrimitives.ReadUInt32BigEndian(track[..8]); + cdMetadata.SubSize = BinaryPrimitives.ReadUInt32BigEndian(track[..12]); + cdMetadata.Frames = BinaryPrimitives.ReadUInt32BigEndian(track[..16]); + cdMetadata.Padding = BinaryPrimitives.ReadUInt32BigEndian(track[..20]); + } + else + { + cdMetadata.TrackType = (LibChdr.chd_track_type)BinaryPrimitives.ReadUInt32LittleEndian(track); + cdMetadata.SubType = (LibChdr.chd_sub_type)BinaryPrimitives.ReadUInt32LittleEndian(track[..4]); + cdMetadata.SectorSize = BinaryPrimitives.ReadUInt32LittleEndian(track[..8]); + cdMetadata.SubSize = BinaryPrimitives.ReadUInt32LittleEndian(track[..12]); + cdMetadata.Frames = BinaryPrimitives.ReadUInt32LittleEndian(track[..16]); + cdMetadata.Padding = BinaryPrimitives.ReadUInt32LittleEndian(track[..20]); + } + + if (cdMetadata.SectorSize != GetSectorSize(cdMetadata.TrackType)) + { + throw new CHDParseException("Malformed CHD format: Invalid sector size"); + } + + if (cdMetadata.SubSize != GetSubSize(cdMetadata.SubType)) + { + throw new CHDParseException("Malformed CHD format: Invalid sub size"); + } + + var expectedPadding = (0 - cdMetadata.Frames) & 3; + if (cdMetadata.Padding != expectedPadding) + { + throw new CHDParseException("Malformed CHD format: Invalid padding value"); + } + + cdMetadatas.Add(cdMetadata); + } + } + + /// malformed chd format + public static CHDFile ParseFrom(Stream stream) + { + var chdf = new CHDFile(); + try + { + chdf.CoreFile = new(stream); + var err = LibChdr.chd_open_core_file(chdf.CoreFile.CoreFile, LibChdr.CHD_OPEN_READ, IntPtr.Zero, out chdf.ChdFile); + if (err != LibChdr.chd_error.CHDERR_NONE) + { + throw new CHDParseException($"Malformed CHD format: Failed to open chd, got error {err}"); + } + + unsafe + { + var header = (LibChdr.chd_header*)LibChdr.chd_get_header(chdf.ChdFile); + chdf.Header = *header; + } + + if (chdf.Header.hunkbytes == 0 || chdf.Header.hunkbytes % LibChdr.CD_FRAME_SIZE != 0) + { + throw new CHDParseException("Malformed CHD format: Invalid hunk size"); + } + + // libchdr puts the correct value here for older versions of chds which don't have this + // for newer chds, it is left as is, which might be invalid + if (chdf.Header.unitbytes != LibChdr.CD_FRAME_SIZE) + { + throw new CHDParseException("Malformed CHD format: Invalid unit size"); + } + + var metadataOutput = new byte[256]; + for (uint i = 0; i < 99; i++) + { + err = LibChdr.chd_get_metadata(chdf.ChdFile, LibChdr.CDROM_TRACK_METADATA2_TAG, + i, metadataOutput, (uint)metadataOutput.Length, out var resultLen, out _, out _); + if (err == LibChdr.chd_error.CHDERR_NONE) + { + var metadata = Encoding.ASCII.GetString(metadataOutput, 0, (int)resultLen); + chdf.CdMetadatas.Add(ParseMetadata2(metadata)); + continue; + } + + err = LibChdr.chd_get_metadata(chdf.ChdFile, LibChdr.CDROM_TRACK_METADATA_TAG, + i, metadataOutput, (uint)metadataOutput.Length, out resultLen, out _, out _); + if (err == LibChdr.chd_error.CHDERR_NONE) + { + var metadata = Encoding.ASCII.GetString(metadataOutput, 0, (int)resultLen); + chdf.CdMetadatas.Add(ParseMetadata(metadata)); + continue; + } + + // if no more metadata, we're out of tracks + break; + } + + // validate track numbers + if (chdf.CdMetadatas.Where((t, i) => t.Track != i + 1).Any()) + { + throw new CHDParseException("Malformed CHD format: Invalid track number"); + } + + if (chdf.CdMetadatas.Count == 0) + { + // if no metadata was present, we might have "old" metadata instead (which has all track info stored in one entry) + metadataOutput = new byte[4 + 24 * 99]; + err = LibChdr.chd_get_metadata(chdf.ChdFile, LibChdr.CDROM_OLD_METADATA_TAG, + 0, metadataOutput, (uint)metadataOutput.Length, out var resultLen, out _, out _); + if (err == LibChdr.chd_error.CHDERR_NONE) + { + if (resultLen != metadataOutput.Length) + { + throw new CHDParseException("Malformed CHD format: Incorrect length for old metadata"); + } + + ParseMetadataOld(chdf.CdMetadatas, metadataOutput); + } + } + + if (chdf.CdMetadatas.Count == 0) + { + throw new CHDParseException("Malformed CHD format: No tracks present in chd"); + } + + // validation checks + var chdExpectedNumSectors = 0L; + foreach (var cdMetadata in chdf.CdMetadatas) + { + // if pregap is in the chd, then the reported frame count includes both pregap and track data + if (cdMetadata.PregapInChd && cdMetadata.Pregap > cdMetadata.Frames) + { + throw new CHDParseException("Malformed CHD format: Pregap in chd is larger than total sectors in chd track"); + } + + chdExpectedNumSectors += cdMetadata.Frames + cdMetadata.Padding; + } + + var chdActualNumSectors = chdf.Header.hunkcount * (chdf.Header.hunkbytes / LibChdr.CD_FRAME_SIZE); + //if (chdExpectedNumSectors != chdActualNumSectors) // i see some chds with 4 extra sectors of padding in the end? + if (chdExpectedNumSectors > chdActualNumSectors) + { + throw new CHDParseException("Malformed CHD format: Mismatch in expected and actual number of sectors present"); + } + + return chdf; + } + catch (Exception ex) + { + if (chdf.ChdFile != IntPtr.Zero) + { + LibChdr.chd_close(chdf.ChdFile); + } + + if (chdf.CoreFile == null) + { + stream.Dispose(); + } + + chdf.CoreFile?.Dispose(); + throw ex as CHDParseException ?? new("Malformed CHD format: An unknown exception was thrown while parsing", ex); + } + } + + public class LoadResults + { + public CHDFile ParsedCHDFile; + public bool Valid; + public CHDParseException FailureException; + public string ChdPath; + } + + public static LoadResults LoadCHDPath(string path) + { + var ret = new LoadResults + { + ChdPath = path + }; + try + { + if (!File.Exists(path)) throw new CHDParseException("Malformed CHD format: Nonexistent CHD file!"); + + var infCHD = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read); + ret.ParsedCHDFile = ParseFrom(infCHD); + ret.Valid = true; + } + catch (CHDParseException ex) + { + ret.FailureException = ex; + } + + return ret; + } + + /// + /// CHD is dumb and byteswaps audio samples for some reason + /// + private class SS_CHD_Audio : SS_Base + { + public override void Synth(SectorSynthJob job) + { + // read the sector user data + if ((job.Parts & ESectorSynthPart.User2352) != 0) + { + Blob.Read(BlobOffset, job.DestBuffer2448, job.DestOffset, 2352); + EndiannessUtils.MutatingByteSwap16(job.DestBuffer2448.AsSpan().Slice(job.DestOffset, 2352)); + } + + // if subcode is needed, synthesize it + SynthSubchannelAsNeed(job); + } + } + + private class SS_CHD_Sub : ISectorSynthJob2448 + { + private readonly SS_Base _baseSynth; + private readonly bool _isInterleaved; + + public SS_CHD_Sub(SS_Base baseSynth, bool isInterleaved) + { + _baseSynth = baseSynth; + _isInterleaved = isInterleaved; + } + + public void Synth(SectorSynthJob job) + { + if ((job.Parts & ESectorSynthPart.SubcodeAny) != 0) + { + _baseSynth.Blob.Read(_baseSynth.BlobOffset + 2352, job.DestBuffer2448, job.DestOffset + 2352, 96); + + if ((job.Parts & ESectorSynthPart.SubcodeDeinterleave) != 0 && _isInterleaved) + { + SynthUtils.DeinterleaveSubcodeInplace(job.DestBuffer2448, job.DestOffset + 2352); + } + + if ((job.Parts & ESectorSynthPart.SubcodeDeinterleave) == 0 && !_isInterleaved) + { + SynthUtils.InterleaveSubcodeInplace(job.DestBuffer2448, job.DestOffset + 2352); + } + + job.Parts &= ~ESectorSynthPart.SubcodeAny; + } + + _baseSynth.Synth(job); + } + } + + /// file not found + public static Disc LoadCHDToDisc(string chdPath, DiscMountPolicy IN_DiscMountPolicy) + { + var loadResults = LoadCHDPath(chdPath); + if (!loadResults.Valid) + { + throw loadResults.FailureException; + } + + var disc = new Disc(); + try + { + var chdf = loadResults.ParsedCHDFile; + IBlob chdBlob = new Blob_CHD(chdf.CoreFile, chdf.ChdFile, chdf.Header.hunkbytes); + disc.DisposableResources.Add(chdBlob); + + // chds only support 1 session + var session = new DiscSession { Number = 1 }; + var chdOffset = 0L; + foreach (var cdMetadata in chdf.CdMetadatas) + { + RawTOCEntry EmitRawTOCEntry() + { + var q = default(SubchannelQ); + //absent some kind of policy for how to set it, this is a safe assumption + const byte kADR = 1; + var control = cdMetadata.TrackType != LibChdr.chd_track_type.CD_TRACK_AUDIO + ? EControlQ.DATA + : EControlQ.None; + q.SetStatus(kADR, control); + q.q_tno = BCD2.FromDecimal(0); + q.q_index = BCD2.FromDecimal((int)cdMetadata.Track); + q.Timestamp = 0; + q.zero = 0; + q.AP_Timestamp = disc._Sectors.Count; + q.q_crc = 0; + return new() { QData = q }; + } + + static SS_Base CreateSynth(LibChdr.chd_track_type trackType) + { + return trackType switch + { + LibChdr.chd_track_type.CD_TRACK_MODE1 => new SS_Mode1_2048(), + LibChdr.chd_track_type.CD_TRACK_MODE1_RAW => new SS_2352(), + LibChdr.chd_track_type.CD_TRACK_MODE2 => new SS_Mode2_2336(), + LibChdr.chd_track_type.CD_TRACK_MODE2_FORM1 => new SS_Mode2_Form1_2048(), + LibChdr.chd_track_type.CD_TRACK_MODE2_FORM2 => new SS_Mode2_Form2_2324(), + LibChdr.chd_track_type.CD_TRACK_MODE2_FORM_MIX => new SS_Mode2_2336(), + LibChdr.chd_track_type.CD_TRACK_MODE2_RAW => new SS_2352(), + LibChdr.chd_track_type.CD_TRACK_AUDIO => new SS_CHD_Audio(), + _ => throw new InvalidOperationException(), + }; + } + + static CueTrackType ToCueTrackType(LibChdr.chd_track_type chdTrackType, bool isCdi) + { + // rough matches, not too important if these are somewhat wrong (they're just used for generated gaps) + return chdTrackType switch + { + LibChdr.chd_track_type.CD_TRACK_MODE1 => CueTrackType.Mode1_2048, + LibChdr.chd_track_type.CD_TRACK_MODE1_RAW => CueTrackType.Mode1_2352, + LibChdr.chd_track_type.CD_TRACK_MODE2 => CueTrackType.Mode2_2336, + LibChdr.chd_track_type.CD_TRACK_MODE2_FORM1 => CueTrackType.Mode2_2336, + LibChdr.chd_track_type.CD_TRACK_MODE2_FORM2 => CueTrackType.Mode2_2336, + LibChdr.chd_track_type.CD_TRACK_MODE2_FORM_MIX => CueTrackType.Mode2_2336, + LibChdr.chd_track_type.CD_TRACK_MODE2_RAW when isCdi => CueTrackType.CDI_2352, + LibChdr.chd_track_type.CD_TRACK_MODE2_RAW => CueTrackType.Mode2_2352, + LibChdr.chd_track_type.CD_TRACK_AUDIO => CueTrackType.Audio, + _ => throw new InvalidOperationException(), + }; + } + + var pregapLength = cdMetadata.Pregap; + // force 150 sector pregap for the first track if not present in the chd + if (!cdMetadata.PregapInChd && cdMetadata.Track == 1) + { + cdMetadata.PregapTrackType = cdMetadata.TrackType; + cdMetadata.PregapSubType = cdMetadata.SubType; + pregapLength = 150; + } + + var relMSF = -pregapLength; + for (var i = 0; i < pregapLength; i++) + { + SS_Base synth; + if (cdMetadata.PregapInChd) + { + synth = CreateSynth(cdMetadata.PregapTrackType); + synth.Blob = chdBlob; + synth.BlobOffset = chdOffset; + } + else + { + synth = new SS_Gap { TrackType = ToCueTrackType(cdMetadata.PregapTrackType, cdMetadata.IsCDI) }; + } + + synth.Policy = IN_DiscMountPolicy; + const byte kADR = 1; + var control = cdMetadata.PregapTrackType != LibChdr.chd_track_type.CD_TRACK_AUDIO + ? EControlQ.DATA + : EControlQ.None; + synth.sq.SetStatus(kADR, control); + synth.sq.q_tno = BCD2.FromDecimal((int)cdMetadata.Track); + synth.sq.q_index = BCD2.FromDecimal(0); + synth.sq.Timestamp = !IN_DiscMountPolicy.CUE_PregapContradictionModeA + ? (int)relMSF + 1 + : (int)relMSF; + synth.sq.zero = 0; + synth.sq.AP_Timestamp = disc._Sectors.Count; + synth.sq.q_crc = 0; + synth.Pause = true; + + if (cdMetadata.PregapInChd) + { + // wrap the base synth with our special synth if we have subcode in the chd + ISectorSynthJob2448 chdSynth = cdMetadata.PregapSubType switch + { + LibChdr.chd_sub_type.CD_SUB_NORMAL => new SS_CHD_Sub(synth, isInterleaved: true), + LibChdr.chd_sub_type.CD_SUB_RAW => new SS_CHD_Sub(synth, isInterleaved: false), + LibChdr.chd_sub_type.CD_SUB_NONE => synth, + _ => throw new InvalidOperationException(), + }; + + disc._Sectors.Add(chdSynth); + chdOffset += LibChdr.CD_FRAME_SIZE; + } + else + { + disc._Sectors.Add(synth); + } + + relMSF++; + } + + session.RawTOCEntries.Add(EmitRawTOCEntry()); + + var trackLength = cdMetadata.Frames; + if (cdMetadata.PregapInChd) + { + trackLength -= pregapLength; + } + + for (var i = 0; i < trackLength; i++) + { + var synth = CreateSynth(cdMetadata.TrackType); + synth.Blob = chdBlob; + synth.BlobOffset = chdOffset; + synth.Policy = IN_DiscMountPolicy; + const byte kADR = 1; + var control = cdMetadata.TrackType != LibChdr.chd_track_type.CD_TRACK_AUDIO + ? EControlQ.DATA + : EControlQ.None; + synth.sq.SetStatus(kADR, control); + synth.sq.q_tno = BCD2.FromDecimal((int)cdMetadata.Track); + synth.sq.q_index = BCD2.FromDecimal(1); + synth.sq.Timestamp = (int)relMSF; + synth.sq.zero = 0; + synth.sq.AP_Timestamp = disc._Sectors.Count; + synth.sq.q_crc = 0; + synth.Pause = false; + ISectorSynthJob2448 chdSynth = cdMetadata.SubType switch + { + LibChdr.chd_sub_type.CD_SUB_NORMAL => new SS_CHD_Sub(synth, isInterleaved: true), + LibChdr.chd_sub_type.CD_SUB_RAW => new SS_CHD_Sub(synth, isInterleaved: false), + LibChdr.chd_sub_type.CD_SUB_NONE => synth, + _ => throw new InvalidOperationException(), + }; + disc._Sectors.Add(chdSynth); + chdOffset += LibChdr.CD_FRAME_SIZE; + relMSF++; + } + + chdOffset += cdMetadata.Padding * LibChdr.CD_FRAME_SIZE; + + for (var i = 0; i < cdMetadata.PostGap; i++) + { + var synth = new SS_Gap + { + TrackType = ToCueTrackType(cdMetadata.TrackType, cdMetadata.IsCDI), + Policy = IN_DiscMountPolicy + }; + const byte kADR = 1; + var control = cdMetadata.TrackType != LibChdr.chd_track_type.CD_TRACK_AUDIO + ? EControlQ.DATA + : EControlQ.None; + synth.sq.SetStatus(kADR, control); + synth.sq.q_tno = BCD2.FromDecimal((int)cdMetadata.Track); + synth.sq.q_index = BCD2.FromDecimal(2); + synth.sq.Timestamp = (int)relMSF; + synth.sq.zero = 0; + synth.sq.AP_Timestamp = disc._Sectors.Count; + synth.sq.q_crc = 0; + synth.Pause = true; + disc._Sectors.Add(synth); + relMSF++; + } + } + + SessionFormat GuessSessionFormat() + { + foreach (var cdMetadata in chdf.CdMetadatas) + { + if (cdMetadata.IsCDI) + { + return SessionFormat.Type10_CDI; + } + + if (cdMetadata.TrackType is LibChdr.chd_track_type.CD_TRACK_MODE2 + or LibChdr.chd_track_type.CD_TRACK_MODE2_FORM1 + or LibChdr.chd_track_type.CD_TRACK_MODE2_FORM2 + or LibChdr.chd_track_type.CD_TRACK_MODE2_FORM_MIX + or LibChdr.chd_track_type.CD_TRACK_MODE2_RAW) + { + return SessionFormat.Type20_CDXA; + } + } + + return SessionFormat.Type00_CDROM_CDDA; + } + + var TOCMiscInfo = new Synthesize_A0A1A2_Job( + firstRecordedTrackNumber: 1, + lastRecordedTrackNumber: chdf.CdMetadatas.Count, + sessionFormat: GuessSessionFormat(), + leadoutTimestamp: disc._Sectors.Count); + TOCMiscInfo.Run(session.RawTOCEntries); + + disc.Sessions.Add(session); + return disc; + } + catch + { + disc.Dispose(); + throw; + } + } + } +} \ No newline at end of file diff --git a/src/BizHawk.Emulation.DiscSystem/DiscFormats/CUE/CUE_SynthExtras.cs b/src/BizHawk.Emulation.DiscSystem/DiscFormats/CUE/CUE_SynthExtras.cs index b42e494af0..151e3fcf85 100644 --- a/src/BizHawk.Emulation.DiscSystem/DiscFormats/CUE/CUE_SynthExtras.cs +++ b/src/BizHawk.Emulation.DiscSystem/DiscFormats/CUE/CUE_SynthExtras.cs @@ -6,7 +6,7 @@ namespace BizHawk.Emulation.DiscSystem.CUE /// /// Represents a Mode2 Form1 2048-byte sector - /// Only used by MDS + /// Only used by NRG, MDS, and CHD /// internal class SS_Mode2_Form1_2048 : SS_Base { @@ -36,7 +36,7 @@ namespace BizHawk.Emulation.DiscSystem.CUE /// /// Represents a Mode2 Form1 2324-byte sector - /// Only used by MDS + /// Only used by MDS and CHD /// internal class SS_Mode2_Form2_2324 : SS_Base { @@ -82,7 +82,7 @@ namespace BizHawk.Emulation.DiscSystem.CUE /// /// Represents a full 2448-byte sector with interleaved subcode - /// Only used by MDS and CDI + /// Only used by MDS, NRG, and CDI /// internal class SS_2448_Interleaved : SS_Base { diff --git a/src/BizHawk.Emulation.DiscSystem/DiscMountJob.cs b/src/BizHawk.Emulation.DiscSystem/DiscMountJob.cs index 08ef0781c1..e3c053de40 100644 --- a/src/BizHawk.Emulation.DiscSystem/DiscMountJob.cs +++ b/src/BizHawk.Emulation.DiscSystem/DiscMountJob.cs @@ -195,6 +195,9 @@ namespace BizHawk.Emulation.DiscSystem case ".cdi": OUT_Disc = CDI_Format.LoadCDIToDisc(IN_FromPath, IN_DiscMountPolicy); break; + case ".chd": + OUT_Disc = CHD_Format.LoadCHDToDisc(IN_FromPath, IN_DiscMountPolicy); + break; case ".cue": LoadCue(dir, File.ReadAllText(IN_FromPath)); break; diff --git a/src/BizHawk.Emulation.DiscSystem/LibChdr.cs b/src/BizHawk.Emulation.DiscSystem/LibChdr.cs new file mode 100644 index 0000000000..23b3aa5dba --- /dev/null +++ b/src/BizHawk.Emulation.DiscSystem/LibChdr.cs @@ -0,0 +1,266 @@ +using System; +using System.IO; +using System.Runtime.InteropServices; + +#pragma warning disable IDE1006 + +// ReSharper disable UnusedMember.Global +// ReSharper disable UnusedType.Global + +namespace BizHawk.Emulation.DiscSystem +{ + /// + /// libchdr bindings + /// TODO: should this be common-ized? chd isn't limited to discs, it could be used for hard disk images (e.g. for MAME) + /// + public static class LibChdr + { + public enum chd_error : int + { + CHDERR_NONE, + CHDERR_NO_INTERFACE, + CHDERR_OUT_OF_MEMORY, + CHDERR_INVALID_FILE, + CHDERR_INVALID_PARAMETER, + CHDERR_INVALID_DATA, + CHDERR_FILE_NOT_FOUND, + CHDERR_REQUIRES_PARENT, + CHDERR_FILE_NOT_WRITEABLE, + CHDERR_READ_ERROR, + CHDERR_WRITE_ERROR, + CHDERR_CODEC_ERROR, + CHDERR_INVALID_PARENT, + CHDERR_HUNK_OUT_OF_RANGE, + CHDERR_DECOMPRESSION_ERROR, + CHDERR_COMPRESSION_ERROR, + CHDERR_CANT_CREATE_FILE, + CHDERR_CANT_VERIFY, + CHDERR_NOT_SUPPORTED, + CHDERR_METADATA_NOT_FOUND, + CHDERR_INVALID_METADATA_SIZE, + CHDERR_UNSUPPORTED_VERSION, + CHDERR_VERIFY_INCOMPLETE, + CHDERR_INVALID_METADATA, + CHDERR_INVALID_STATE, + CHDERR_OPERATION_PENDING, + CHDERR_NO_ASYNC_OPERATION, + CHDERR_UNSUPPORTED_FORMAT + } + + public const int CHD_OPEN_READ = 1; + public const int CHD_OPEN_READWRITE = 2; + + [StructLayout(LayoutKind.Sequential)] + public struct chd_core_file + { + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate ulong FSizeDelegate(IntPtr file); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate nuint FReadDelegate(IntPtr buffer, nuint size, nuint count, IntPtr file); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate int FCloseDelegate(IntPtr file); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate int FSeekDelegate(IntPtr file, long offset, SeekOrigin origin); + + public IntPtr argp; + [MarshalAs(UnmanagedType.FunctionPtr)] + public FSizeDelegate fsize; + [MarshalAs(UnmanagedType.FunctionPtr)] + public FReadDelegate fread; + [MarshalAs(UnmanagedType.FunctionPtr)] + public FCloseDelegate fclose; + [MarshalAs(UnmanagedType.FunctionPtr)] + public FSeekDelegate fseek; + } + + /// + /// Convenience chd_core_file wrapper against a generic Stream + /// + public class CoreFileStreamWrapper : IDisposable + { + private const uint READ_BUFFER_LEN = 8 * CD_FRAME_SIZE; // 8 frames, usual uncompressed hunk size + private readonly byte[] _readBuffer = new byte[READ_BUFFER_LEN]; + + private Stream _s; + + // ReSharper disable once MemberCanBePrivate.Global + private readonly chd_core_file _coreFile; + public readonly IntPtr CoreFile; + + private ulong FSize(IntPtr file) + { + try + { + return (ulong)_s.Length; + } + catch (Exception e) + { + Console.Error.WriteLine(e); + return unchecked((ulong)-1); + } + } + + private nuint FRead(IntPtr buffer, nuint size, nuint count, IntPtr file) + { + nuint ret = 0; + try + { + // note: size will always be 1, so this should never overflow + var numBytesToRead = (uint)Math.Min(size * (ulong)count, uint.MaxValue); + while (numBytesToRead > 0) + { + var numRead = _s.Read(_readBuffer, 0, (int)Math.Min(READ_BUFFER_LEN, numBytesToRead)); + if (numRead == 0) + { + return ret; + } + + Marshal.Copy(_readBuffer, 0, buffer, numRead); + buffer += numRead; + ret += (uint)numRead; + numBytesToRead -= (uint)numRead; + } + + return ret; + } + catch (Exception e) + { + Console.Error.WriteLine(e); + return ret; + } + } + + private int FClose(IntPtr file) + { + if (_s == null) + { + return -1; + } + + _s.Dispose(); + _s = null; + return 0; + } + + private int FSeek(IntPtr file, long offset, SeekOrigin origin) + { + try + { + _s.Seek(offset, origin); + return 0; + } + catch (Exception ex) + { + Console.Error.WriteLine(ex); + return -1; + } + } + + public CoreFileStreamWrapper(Stream s) + { + if (!s.CanRead || !s.CanSeek) + { + throw new NotSupportedException("The underlying CHD stream must support reading and seeking!"); + } + + _s = s; + _coreFile.fsize = FSize; + _coreFile.fread = FRead; + _coreFile.fclose = FClose; + _coreFile.fseek = FSeek; + // the pointer here must stay alloc'd on the unmanaged size + // as libchdr expects the memory to not move around + CoreFile = Marshal.AllocCoTaskMem(Marshal.SizeOf()); + Marshal.StructureToPtr(_coreFile, CoreFile, fDeleteOld: false); + } + + public void Dispose() + { + Marshal.DestroyStructure(CoreFile); + Marshal.FreeCoTaskMem(CoreFile); + _s?.Dispose(); + } + } + + [DllImport("chdr")] + public static extern chd_error chd_open_core_file(IntPtr file, int mode, IntPtr parent, out IntPtr chd); + + [DllImport("chdr")] + public static extern void chd_close(IntPtr chd); + + public const int CHD_MD5_BYTES = 16; + public const int CHD_SHA1_BYTES = 20; + + // extracted chd header (not the same as the one on disk, but rather an interpreted one by libchdr) + [StructLayout(LayoutKind.Sequential)] + public struct chd_header + { + public uint length; // length of header data + public uint version; // drive format version + public uint flags; // flags field + public unsafe fixed uint compression[4]; // compression type + public uint hunkbytes; // number of bytes per hunk + public uint totalhunks; // total # of hunks represented + public ulong logicalbytes; // logical size of the data + public ulong metaoffset; // offset in file of first metadata + public ulong mapoffset; // TOOD V5 + public unsafe fixed byte md5[CHD_MD5_BYTES]; // overall MD5 checksum + public unsafe fixed byte parentmd5[CHD_MD5_BYTES]; // overall MD5 checksum of parent + public unsafe fixed byte sha1[CHD_SHA1_BYTES]; // overall SHA1 checksum + public unsafe fixed byte rawsha1[CHD_SHA1_BYTES]; // SHA1 checksum of raw data + public unsafe fixed byte parentsha1[CHD_SHA1_BYTES]; // overall SHA1 checksum of parent + public uint unitbytes; // TODO V5 + public ulong unitcount; // TODO V5 + public uint hunkcount; // TODO V5 + public uint mapentrybytes; // length of each entry in a map (V5) + public unsafe byte* rawmap; // raw map data + public uint obsolete_cylinders; // obsolete field -- do not use! + public uint obsolete_sectors; // obsolete field -- do not use! + public uint obsolete_heads; // obsolete field -- do not use! + public uint obsolete_hunksize; // obsolete field -- do not use! + } + + [DllImport("chdr")] + public static extern IntPtr chd_get_header(IntPtr chd); + + [DllImport("chdr")] + public static extern chd_error chd_read(IntPtr chd, uint hunknum, byte[] buffer); + + public const uint CDROM_TRACK_METADATA2_TAG = 0x43485432; // CHT2 + public const uint CDROM_TRACK_METADATA_TAG = 0x43485452; // CHTR + public const uint CDROM_OLD_METADATA_TAG = 0x43484344; // CHCD + + // these formats are more for sscanf, they aren't suitable for C# + public const string CDROM_TRACK_METADATA2_FORMAT = "TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d PREGAP:%d PGTYPE:%s PGSUB:%s POSTGAP:%d"; + public const string CDROM_TRACK_METADATA_FORMAT = "TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d"; + + public enum chd_track_type : uint + { + CD_TRACK_MODE1 = 0, // mode 1 2048 bytes/sector + CD_TRACK_MODE1_RAW, // mode 1 2352 bytes/sector + CD_TRACK_MODE2, // mode 2 2336 bytes/sector + CD_TRACK_MODE2_FORM1, // mode 2 2048 bytes/sector + CD_TRACK_MODE2_FORM2, // mode 2 2324 bytes/sector + CD_TRACK_MODE2_FORM_MIX, // mode 2 2336 bytes/sector + CD_TRACK_MODE2_RAW, // mode 2 2352 bytes/sector + CD_TRACK_AUDIO, // redbook audio track 2352 bytes/sector (588 samples) + } + + public enum chd_sub_type : uint + { + CD_SUB_NORMAL = 0, // "cooked" 96 bytes per sector + CD_SUB_RAW, // raw uninterleaved 96 bytes per sector + CD_SUB_NONE // no subcode data stored + } + + // hunks should be a multiple of this for cd chds + public const uint CD_FRAME_SIZE = 2352 + 96; + + [DllImport("chdr")] + public static extern chd_error chd_get_metadata( + IntPtr chd, uint searchtag, uint searchindex, byte[] output, uint outputlen, out uint resultlen, out uint resulttag, out byte resultflags); + } +}