diff --git a/SabreTools.Library/DatFiles/DatFile.cs b/SabreTools.Library/DatFiles/DatFile.cs index 3e9f4b6a..c57ab37d 100644 --- a/SabreTools.Library/DatFiles/DatFile.cs +++ b/SabreTools.Library/DatFiles/DatFile.cs @@ -3705,7 +3705,7 @@ namespace SabreTools.Library.DatFiles bool addDate, string headerToCheckAgainst) { Globals.Logger.Verbose("'{0}' treated like a file", Path.GetFileName(item)); - Rom rom = FileTools.GetFileInfo(item, omitFromScan: omitFromScan, date: addDate, header: headerToCheckAgainst); + DatItem rom = FileTools.GetFileInfo(item, omitFromScan: omitFromScan, date: addDate, header: headerToCheckAgainst); ProcessFileHelper(item, rom, basePath, parent); } @@ -4211,7 +4211,7 @@ namespace SabreTools.Library.DatFiles if (shouldExternalProcess) { // TODO: All instances of Hash.DeepHashes should be made into 0x0 eventually - Rom fileinfo = FileTools.GetFileInfo(file, omitFromScan: (quickScan ? Hash.SecureHashes : Hash.DeepHashes), header: headerToCheckAgainst); + DatItem fileinfo = FileTools.GetFileInfo(file, omitFromScan: (quickScan ? Hash.SecureHashes : Hash.DeepHashes), header: headerToCheckAgainst); usedExternally = RebuildIndividualFile(fileinfo, file, outDir, tempSubDir, date, inverse, outputFormat, romba, updateDat, null /* isZip */, headerToCheckAgainst); } @@ -4242,7 +4242,7 @@ namespace SabreTools.Library.DatFiles if (entries == null && File.Exists(file)) { // TODO: All instances of Hash.DeepHashes should be made into 0x0 eventually - Rom fileinfo = FileTools.GetFileInfo(file, omitFromScan: (quickScan ? Hash.SecureHashes : Hash.DeepHashes)); + DatItem fileinfo = FileTools.GetFileInfo(file, omitFromScan: (quickScan ? Hash.SecureHashes : Hash.DeepHashes)); usedExternally = RebuildIndividualFile(fileinfo, file, outDir, tempSubDir, date, inverse, outputFormat, romba, updateDat, null /* isZip */, headerToCheckAgainst); } @@ -4454,7 +4454,7 @@ namespace SabreTools.Library.DatFiles } // Get the item from the current file - Rom item = FileTools.GetStreamInfo(fileStream, fileStream.Length, keepReadOpen: true); + Rom item = (Rom)FileTools.GetStreamInfo(fileStream, fileStream.Length, keepReadOpen: true); item.MachineName = Style.GetFileNameWithoutExtension(item.Name); item.MachineDescription = Style.GetFileNameWithoutExtension(item.Name); @@ -4565,7 +4565,7 @@ namespace SabreTools.Library.DatFiles if (rule.TransformStream(fileStream, transformStream, keepReadOpen: true, keepWriteOpen: true)) { // Get the file informations that we will be using - Rom headerless = FileTools.GetStreamInfo(transformStream, transformStream.Length, keepReadOpen: true); + Rom headerless = (Rom)FileTools.GetStreamInfo(transformStream, transformStream.Length, keepReadOpen: true); // Find if the file has duplicates in the DAT hasDuplicates = headerless.HasDuplicates(this); diff --git a/SabreTools.Library/Data/Constants.cs b/SabreTools.Library/Data/Constants.cs index a01effcb..dc6e7171 100644 --- a/SabreTools.Library/Data/Constants.cs +++ b/SabreTools.Library/Data/Constants.cs @@ -13,7 +13,7 @@ namespace SabreTools.Library.Data /// /// The current toolset version to be used by all child applications /// - public static string Version = "v0.9.8.1-" + Assembly.GetExecutingAssembly().GetLinkerTime().ToString("yyyy-MM-dd HH:mm:ss"); + public readonly static string Version = "v0.9.8.1-" + Assembly.GetExecutingAssembly().GetLinkerTime().ToString("yyyy-MM-dd HH:mm:ss"); public const int HeaderHeight = 3; #region 0-byte file constants @@ -31,26 +31,36 @@ namespace SabreTools.Library.Data #region Byte (1000-based) size comparisons public const long KiloByte = 1000; - public static long MegaByte = (long)Math.Pow(KiloByte, 2); - public static long GigaByte = (long)Math.Pow(KiloByte, 3); - public static long TeraByte = (long)Math.Pow(KiloByte, 4); - public static long PetaByte = (long)Math.Pow(KiloByte, 5); - public static long ExaByte = (long)Math.Pow(KiloByte, 6); - public static long ZettaByte = (long)Math.Pow(KiloByte, 7); - public static long YottaByte = (long)Math.Pow(KiloByte, 8); + public readonly static long MegaByte = (long)Math.Pow(KiloByte, 2); + public readonly static long GigaByte = (long)Math.Pow(KiloByte, 3); + public readonly static long TeraByte = (long)Math.Pow(KiloByte, 4); + public readonly static long PetaByte = (long)Math.Pow(KiloByte, 5); + public readonly static long ExaByte = (long)Math.Pow(KiloByte, 6); + public readonly static long ZettaByte = (long)Math.Pow(KiloByte, 7); + public readonly static long YottaByte = (long)Math.Pow(KiloByte, 8); #endregion #region Byte (1024-based) size comparisons public const long KibiByte = 1024; - public static long MibiByte = (long)Math.Pow(KibiByte, 2); - public static long GibiByte = (long)Math.Pow(KibiByte, 3); - public static long TibiByte = (long)Math.Pow(KibiByte, 4); - public static long PibiByte = (long)Math.Pow(KibiByte, 5); - public static long ExiByte = (long)Math.Pow(KibiByte, 6); - public static long ZittiByte = (long)Math.Pow(KibiByte, 7); - public static long YittiByte = (long)Math.Pow(KibiByte, 8); + public readonly static long MibiByte = (long)Math.Pow(KibiByte, 2); + public readonly static long GibiByte = (long)Math.Pow(KibiByte, 3); + public readonly static long TibiByte = (long)Math.Pow(KibiByte, 4); + public readonly static long PibiByte = (long)Math.Pow(KibiByte, 5); + public readonly static long ExiByte = (long)Math.Pow(KibiByte, 6); + public readonly static long ZittiByte = (long)Math.Pow(KibiByte, 7); + public readonly static long YittiByte = (long)Math.Pow(KibiByte, 8); + + #endregion + + #region CHD header values + + public readonly static byte[] CHDSignature = { 0x4d, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x48, 0x44 }; // "MComprHD" + public const int CHD_HEADER_VERSION = 5; + public const int CHD_V3_HEADER_SIZE = 120; + public const int CHD_V4_HEADER_SIZE = 108; + public const int CHD_V5_HEADER_SIZE = 124; #endregion @@ -109,7 +119,7 @@ namespace SabreTools.Library.Data 0A-0B Last mod file time (0x00, 0xBC) 0C-0D Last mod file date (0x98, 0x21) */ - public static byte[] TorrentZipHeader = new byte[] { 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x02, 0x00, 0x08, 0x00, 0x00, 0xbc, 0x98, 0x21 }; + public readonly static byte[] TorrentZipHeader = new byte[] { 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x02, 0x00, 0x08, 0x00, 0x00, 0xbc, 0x98, 0x21 }; /* Torrent7z Header Format http://cpansearch.perl.org/src/BJOERN/Compress-Deflate7-1.0/7zip/DOC/7zFormat.txt @@ -118,8 +128,8 @@ namespace SabreTools.Library.Data 06-07 ArchiveVersion (0x00, 0x03) The rest is unknown */ - public static byte[] Torrent7ZipHeader = new byte[] { 0x37, 0x7a, 0xbc, 0xaf, 0x27, 0x1c, 0x00, 0x03 }; - public static byte[] Torrent7ZipSignature = new byte[] { 0xa9, 0xa9, 0x9f, 0xd1, 0x57, 0x08, 0xa9, 0xd7, 0xea, 0x29, 0x64, 0xb2, + public readonly static byte[] Torrent7ZipHeader = new byte[] { 0x37, 0x7a, 0xbc, 0xaf, 0x27, 0x1c, 0x00, 0x03 }; + public readonly static byte[] Torrent7ZipSignature = new byte[] { 0xa9, 0xa9, 0x9f, 0xd1, 0x57, 0x08, 0xa9, 0xd7, 0xea, 0x29, 0x64, 0xb2, 0x36, 0x1b, 0x83, 0x52, 0x33, 0x00, 0x74, 0x6f, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x37, 0x7a, 0x5f, 0x30, 0x2e, 0x39, 0x62, 0x65, 0x74, 0x61 }; /* (Torrent)GZ Header Format @@ -138,7 +148,7 @@ namespace SabreTools.Library.Data 1C-1F CRC hash 20-27 Int64 size (mirrored) */ - public static byte[] TorrentGZHeader = new byte[] { 0x1f, 0x8b, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00 }; + public readonly static byte[] TorrentGZHeader = new byte[] { 0x1f, 0x8b, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00 }; #endregion diff --git a/SabreTools.Library/Data/Enums.cs b/SabreTools.Library/Data/Enums.cs index 32f8147a..22d6db62 100644 --- a/SabreTools.Library/Data/Enums.cs +++ b/SabreTools.Library/Data/Enums.cs @@ -31,6 +31,33 @@ TorrentZip64 = 45, } + /// + /// Availible CHD codec formats + /// + public enum CHDCodecType : uint + { + CHD_CODEC_NONE = 0, + + // general codecs + CHD_CODEC_ZLIB = 0x7a6c6962, // zlib + CHD_CODEC_LZMA = 0x6c7a6d61, // lzma + CHD_CODEC_HUFFMAN = 0x68756666, // huff + CHD_CODEC_FLAC = 0x666c6163, // flac + + // general codecs with CD frontend + CHD_CODEC_CD_ZLIB = 0x63647a6c, // cdzl + CHD_CODEC_CD_LZMA = 0x63646c7a, // cdlz + CHD_CODEC_CD_FLAC = 0x6364666c, // cdfl + + // A/V codecs + CHD_CODEC_AVHUFF = 0x61766875, // avhu + + // pseudo-codecs returned by hunk_info + CHD_CODEC_SELF = 1, // copy of another hunk + CHD_CODEC_PARENT = 2, // copy of a parent's hunk + CHD_CODEC_MINI = 3, // legacy "mini" 8-byte repeat + } + /// /// Compression method based on flag /// diff --git a/SabreTools.Library/External/CHDFile.cs b/SabreTools.Library/External/CHDFile.cs new file mode 100644 index 00000000..efaf4dfe --- /dev/null +++ b/SabreTools.Library/External/CHDFile.cs @@ -0,0 +1,350 @@ +using System; + +using SabreTools.Library.Data; +using SabreTools.Library.Items; +using SabreTools.Library.Tools; + +#if MONO +using System.IO; +#else +using BinaryReader = System.IO.BinaryReader; +using FileStream = System.IO.FileStream; +using SeekOrigin = System.IO.SeekOrigin; +#endif + +namespace SabreTools.Library.External +{ + /// + /// This is code adapted from chd.h and chd.cpp in MAME + /// + public class CHDFile + { + // core parameters from the header + private uint m_version; // version of the header + private ulong m_logicalbytes; // logical size of the raw CHD data in bytes + private ulong m_mapoffset; // offset of map + private ulong m_metaoffset; // offset to first metadata bit + private uint m_hunkbytes; // size of each raw hunk in bytes + private ulong m_hunkcount; // number of hunks represented + private uint m_unitbytes; // size of each unit in bytes + private ulong m_unitcount; // number of units represented + private CHDCodecType[] m_compression = new CHDCodecType[4]; // array of compression types used + + // key offsets within the header + private long m_mapoffset_offset; // offset of map offset field + private long m_metaoffset_offset;// offset of metaoffset field + private long m_sha1_offset; // offset of SHA1 field + private long m_rawsha1_offset; // offset of raw SHA1 field + private long m_parentsha1_offset;// offset of paren SHA1 field + + // map information + uint m_mapentrybytes; // length of each entry in a map + + /// + /// Get internal metadata from a CHD + /// + /// Filename of possible CHD + /// A Disk object with internal SHA-1 on success, null on error, empty Disk otherwise + /// + /// Original code had a "writable" param. This is not required for metadata checking + /// + public DatItem GetCHDInfo(string filename) + { + FileStream fs = FileTools.TryOpenRead(filename); + DatItem datItem = GetCHDInfo(fs); + fs.Dispose(); + return datItem; + } + + /// + /// Get internal metadata from a CHD + /// + /// FileStreams of possible CHD + /// A Disk object with internal SHA-1 on success, null on error, empty Disk otherwise + /// + /// Original code had a "writable" param. This is not required for metadata checking + /// + public DatItem GetCHDInfo(FileStream fs) + { + // Create a blank Disk to populate and return + Disk datItem = new Disk(); + + // Get a binary reader to make life easier + BinaryReader br = new BinaryReader(fs); + + // Read and verify the CHD signature + // read the raw header + byte[] signature = br.ReadBytes(8); + + // verify the signature + bool correct = true; + for (int i = 0; i < signature.Length; i++) + { + correct &= (signature[i] == Constants.CHDSignature[i]); + } + if (!correct) + { + // throw CHDERR_INVALID_FILE; + return null; + } + + // only allow writes to the most recent version + br.BaseStream.Seek(12, SeekOrigin.Begin); + m_version = br.ReadUInt32(); + + // read the header if we support it + byte[] sha1 = new byte[20]; + switch (m_version) + { + case 3: + ParseV3Header(br, out sha1); + break; + case 4: + ParseV4Header(br, out sha1); + break; + case 5: + ParseV5Header(br, out sha1); + break; + default: + // throw CHDERR_UNSUPPORTED_VERSION; + return null; + } + + datItem.SHA1 = BitConverter.ToString(sha1).Replace("-", string.Empty).ToLowerInvariant(); + + return datItem; + } + + /// + /// Parse a CHD v3 header, populate the fields, and return the SHA-1 + /// + /// BinaryReader representing the file to read + /// Out parameter representing the SHA-1 + /// True if the header was parsed properly, false otherwise + /// + /// CHD v3 header layout: + /// 0x00-0x07 - CHD signature + /// 0x08-0x0B - Header size + /// 0x0C-0x0F - [UNUSED] + /// 0x10-0x13 - Flags (1: Has parent SHA-1, 2: Disallow writes) + /// 0x14-0x17 - Compression + /// 0x18-0x1B - Hunk count + /// 0x1C-0x23 - Logical Bytes + /// 0x24-0x2C - Metadata Offset + /// ... + /// 0x4C-0x4F - Hunk Bytes + /// 0x50-0x63 - SHA-1 + /// 0x64-0x77 - Parent SHA-1 + /// 0x78-0x87 - Map + /// + private bool ParseV3Header(BinaryReader br, out byte[] sha1) + { + // Set the blank SHA-1 hash + sha1 = null; + + // Set offsets and defaults + m_mapoffset_offset = 0; + m_rawsha1_offset = 0; + m_mapoffset = 120; + m_metaoffset_offset = 36; + m_sha1_offset = 80; + m_parentsha1_offset = 100; + m_mapentrybytes = 16; + + // Ensure the proper starting position + br.BaseStream.Seek(8, SeekOrigin.Begin); + + // Verify header length + if (br.ReadInt32() != Constants.CHD_V3_HEADER_SIZE) + { + // throw CHDERR_INVALID_FILE; + return false; + } + + // Skip over the 0x0C-0x0F block + br.ReadUInt32(); + + // Read the CHD flags + uint flags = br.ReadUInt32(); + + // Determine compression + switch (br.ReadUInt32()) + { + case 0: m_compression[0] = CHDCodecType.CHD_CODEC_NONE; break; + case 1: m_compression[0] = CHDCodecType.CHD_CODEC_ZLIB; break; + case 2: m_compression[0] = CHDCodecType.CHD_CODEC_ZLIB; break; + case 3: m_compression[0] = CHDCodecType.CHD_CODEC_AVHUFF; break; + default: /* throw CHDERR_UNKNOWN_COMPRESSION; */ return false; + } + + m_compression[1] = m_compression[2] = m_compression[3] = CHDCodecType.CHD_CODEC_NONE; + + m_hunkcount = br.ReadUInt32(); + m_logicalbytes = br.ReadUInt64(); + m_metaoffset = br.ReadUInt64(); + + br.BaseStream.Seek(76, SeekOrigin.Begin); + m_hunkbytes = br.ReadUInt32(); + + br.BaseStream.Seek(m_sha1_offset, SeekOrigin.Begin); + sha1 = br.ReadBytes(20); + + // guess at the units based on snooping the metadata + // m_unitbytes = guess_unitbytes(); + m_unitcount = (m_logicalbytes + m_unitbytes - 1) / m_unitbytes; + + return true; + } + + /// + /// Parse a CHD v4 header, populate the fields, and return the SHA-1 + /// + /// BinaryReader representing the file to read + /// Out parameter representing the SHA-1 + /// True if the header was parsed properly, false otherwise + /// + /// CHD v4 header layout: + /// 0x00-0x07 - CHD signature + /// 0x08-0x0B - Header size + /// 0x0C-0x0F - [UNUSED] + /// 0x10-0x13 - Flags (1: Has parent SHA-1, 2: Disallow writes) + /// 0x14-0x17 - Compression + /// 0x18-0x1B - Hunk count + /// 0x1C-0x23 - Logical Bytes + /// 0x24-0x2C - Metadata Offset + /// ... + /// 0x2C-0x2F - Hunk Bytes + /// 0x30-0x43 - SHA-1 + /// 0x44-0x57 - Parent SHA-1 + /// 0x58-0x6b - Raw SHA-1 + /// 0x6c-0x7b - Map + /// + private bool ParseV4Header(BinaryReader br, out byte[] sha1) + { + // Set the blank SHA-1 hash + sha1 = null; + + // Set offsets and defaults + m_mapoffset_offset = 0; + m_metaoffset_offset = 36; + m_sha1_offset = 48; + m_parentsha1_offset = 68; + m_rawsha1_offset = 88; + m_mapoffset = 108; + m_mapentrybytes = 16; + + // Ensure the proper starting position + br.BaseStream.Seek(8, SeekOrigin.Begin); + + // Verify header length + if (br.ReadUInt32() != Constants.CHD_V4_HEADER_SIZE) + { + // throw CHDERR_INVALID_FILE; + return false; + } + + // Read the CHD flags + uint flags = br.ReadUInt32(); + + // Determine compression + switch (br.ReadUInt32()) + { + case 0: m_compression[0] = CHDCodecType.CHD_CODEC_NONE; break; + case 1: m_compression[0] = CHDCodecType.CHD_CODEC_ZLIB; break; + case 2: m_compression[0] = CHDCodecType.CHD_CODEC_ZLIB; break; + case 3: m_compression[0] = CHDCodecType.CHD_CODEC_AVHUFF; break; + default: /* throw CHDERR_UNKNOWN_COMPRESSION; */ return false; + } + + m_compression[1] = m_compression[2] = m_compression[3] = CHDCodecType.CHD_CODEC_NONE; + + m_hunkcount = br.ReadUInt32(); + m_logicalbytes = br.ReadUInt64(); + m_metaoffset = br.ReadUInt64(); + + br.BaseStream.Seek(44, SeekOrigin.Begin); + m_hunkbytes = br.ReadUInt32(); + + br.BaseStream.Seek(m_sha1_offset, SeekOrigin.Begin); + sha1 = br.ReadBytes(20); + + // guess at the units based on snooping the metadata + // m_unitbytes = guess_unitbytes(); + m_unitcount = (m_logicalbytes + m_unitbytes - 1) / m_unitbytes; + + return true; + } + + /// + /// Parse a CHD v5 header, populate the fields, and return the SHA-1 + /// + /// BinaryReader representing the file to read + /// Out parameter representing the SHA-1 + /// True if the header was parsed properly, false otherwise + /// + /// CHD v5 header layout: + /// 0x00-0x07 - CHD signature + /// 0x08-0x0B - Header size + /// 0x0C-0x0F - [UNUSED] + /// 0x10-0x13 - Compression format 1 + /// 0x14-0x17 - Compression format 2 + /// 0x18-0x1B - Compression format 3 + /// 0x1C-0x1F - Compression format 4 + /// 0x18-0x1B - Hunk count + /// 0x20-0x27 - Logical Bytes + /// 0x28-0x2F - Map Offset + /// 0x30-0x37 - Metadata Offset + /// 0x38-0x3B - Hunk Bytes + /// 0x3C-0x3F - Unit Bytes + /// 0x40-0x53 - Raw SHA-1 + /// 0x54-0x67 - SHA-1 + /// 0x68-0x7b - Parent SHA-1 + /// + private bool ParseV5Header(BinaryReader br, out byte[] sha1) + { + // Set the blank SHA-1 hash + sha1 = null; + + // Set offsets and defaults + m_mapoffset_offset = 40; + m_metaoffset_offset = 48; + m_rawsha1_offset = 64; + m_sha1_offset = 84; + m_parentsha1_offset = 104; + + // Ensure the proper starting position + br.BaseStream.Seek(8, SeekOrigin.Begin); + + // Verify header length + if (br.ReadUInt32() != Constants.CHD_V5_HEADER_SIZE) + { + // throw CHDERR_INVALID_FILE + return false; + } + + // Determine compression + m_compression[0] = (CHDCodecType)br.ReadUInt32(); + m_compression[1] = (CHDCodecType)br.ReadUInt32(); + m_compression[2] = (CHDCodecType)br.ReadUInt32(); + m_compression[3] = (CHDCodecType)br.ReadUInt32(); + + m_logicalbytes = br.ReadUInt64(); + m_mapoffset = br.ReadUInt64(); + m_metaoffset = br.ReadUInt64(); + m_hunkbytes = br.ReadUInt32(); + m_hunkcount = (m_logicalbytes + m_hunkbytes - 1) / m_hunkbytes; + m_unitbytes = br.ReadUInt32(); + m_unitcount = (m_logicalbytes + m_unitbytes - 1) / m_unitbytes; + + // m_allow_writes = !compressed(); + + // determine properties of map entries + // m_mapentrybytes = compressed() ? 12 : 4; + + br.BaseStream.Seek(m_sha1_offset, SeekOrigin.Begin); + sha1 = br.ReadBytes(20); + + return true; + } + } +} diff --git a/SabreTools.Library/SabreTools.Library.csproj b/SabreTools.Library/SabreTools.Library.csproj index 1cc1a3f3..54fff118 100644 --- a/SabreTools.Library/SabreTools.Library.csproj +++ b/SabreTools.Library/SabreTools.Library.csproj @@ -130,6 +130,7 @@ + diff --git a/SabreTools.Library/Tools/ArchiveTools.cs b/SabreTools.Library/Tools/ArchiveTools.cs index 15022e15..c267ee48 100644 --- a/SabreTools.Library/Tools/ArchiveTools.cs +++ b/SabreTools.Library/Tools/ArchiveTools.cs @@ -644,7 +644,7 @@ namespace SabreTools.Library.Tools else { Stream entryStream = entry.OpenEntryStream(); - Rom sevenZipEntryRom = FileTools.GetStreamInfo(entryStream, entry.Size, omitFromScan: omitFromScan); + Rom sevenZipEntryRom = (Rom)FileTools.GetStreamInfo(entryStream, entry.Size, omitFromScan: omitFromScan); sevenZipEntryRom.Name = entry.Key; sevenZipEntryRom.MachineName = gamename; sevenZipEntryRom.Date = (date && entry.LastModifiedTime != null ? entry.LastModifiedTime?.ToString("yyyy/MM/dd hh:mm:ss") : null); @@ -677,7 +677,7 @@ namespace SabreTools.Library.Tools else { GZipStream gzstream = new GZipStream(FileTools.TryOpenRead(input), Ionic.Zlib.CompressionMode.Decompress); - Rom gzipEntryRom = FileTools.GetStreamInfo(gzstream, gzstream.Length, omitFromScan: omitFromScan); + Rom gzipEntryRom = (Rom)FileTools.GetStreamInfo(gzstream, gzstream.Length, omitFromScan: omitFromScan); gzipEntryRom.Name = gzstream.FileName; gzipEntryRom.MachineName = gamename; gzipEntryRom.Date = (date && gzstream.LastModified != null ? gzstream.LastModified?.ToString("yyyy/MM/dd hh:mm:ss") : null); @@ -709,7 +709,7 @@ namespace SabreTools.Library.Tools else { Stream entryStream = entry.OpenEntryStream(); - Rom rarEntryRom = FileTools.GetStreamInfo(entryStream, entry.Size, omitFromScan: omitFromScan); + Rom rarEntryRom = (Rom)FileTools.GetStreamInfo(entryStream, entry.Size, omitFromScan: omitFromScan); rarEntryRom.Name = entry.Key; rarEntryRom.MachineName = gamename; rarEntryRom.Date = entry.LastModifiedTime?.ToString("yyyy/MM/dd hh:mm:ss"); @@ -745,7 +745,7 @@ namespace SabreTools.Library.Tools else { Stream entryStream = entry.OpenEntryStream(); - Rom tarEntryRom = FileTools.GetStreamInfo(entryStream, entry.Size, omitFromScan: omitFromScan); + Rom tarEntryRom = (Rom)FileTools.GetStreamInfo(entryStream, entry.Size, omitFromScan: omitFromScan); tarEntryRom.Name = entry.Key; tarEntryRom.MachineName = gamename; tarEntryRom.Date = entry.LastModifiedTime?.ToString("yyyy/MM/dd hh:mm:ss"); @@ -802,7 +802,7 @@ namespace SabreTools.Library.Tools // Otherwise, use the stream directly else { - Rom zipEntryRom = FileTools.GetStreamInfo(readStream, (long)zf.Entries[i].UncompressedSize, omitFromScan: omitFromScan); + Rom zipEntryRom = (Rom)FileTools.GetStreamInfo(readStream, (long)zf.Entries[i].UncompressedSize, omitFromScan: omitFromScan); zipEntryRom.Name = zf.Entries[i].FileName; zipEntryRom.MachineName = gamename; string convertedDate = Style.ConvertMsDosTimeFormatToDateTime(zf.Entries[i].LastMod).ToString("yyyy/MM/dd hh:mm:ss"); @@ -2216,7 +2216,7 @@ namespace SabreTools.Library.Tools outDir = Path.GetFullPath(outDir); // Now get the Rom info for the file so we have hashes and size - Rom rom = FileTools.GetStreamInfo(inputStream, inputStream.Length, keepReadOpen: true); + Rom rom = (Rom)FileTools.GetStreamInfo(inputStream, inputStream.Length, keepReadOpen: true); // Get the output file name string outfile = null; diff --git a/SabreTools.Library/Tools/FileTools.cs b/SabreTools.Library/Tools/FileTools.cs index 55d1cff5..29ba850e 100644 --- a/SabreTools.Library/Tools/FileTools.cs +++ b/SabreTools.Library/Tools/FileTools.cs @@ -216,7 +216,7 @@ namespace SabreTools.Library.Tools /// /// TODO: Add CHD parsing logic here to get internal hash data /// - public static Rom GetFileInfo(string input, Hash omitFromScan = 0x0, + public static DatItem GetFileInfo(string input, Hash omitFromScan = 0x0, long offset = 0, bool date = false, string header = null) { // Add safeguard if file doesn't exist @@ -240,7 +240,7 @@ namespace SabreTools.Library.Tools // Transform the stream and get the information from it rule.TransformStream(inputStream, outputStream, keepReadOpen: false, keepWriteOpen: true); - rom = GetStreamInfo(outputStream, outputStream.Length, omitFromScan: omitFromScan, keepReadOpen: false); + rom = (Rom)GetStreamInfo(outputStream, outputStream.Length, omitFromScan: omitFromScan, keepReadOpen: false); // Dispose of the streams outputStream.Dispose(); @@ -250,13 +250,13 @@ namespace SabreTools.Library.Tools else { long length = new FileInfo(input).Length; - rom = GetStreamInfo(TryOpenRead(input), length, omitFromScan, offset, false); + rom = (Rom)GetStreamInfo(TryOpenRead(input), length, omitFromScan, offset, false); } } else { long length = new FileInfo(input).Length; - rom = GetStreamInfo(TryOpenRead(input), length, omitFromScan, offset, false); + rom = (Rom)GetStreamInfo(TryOpenRead(input), length, omitFromScan, offset, false); } // Add unique data from the file @@ -409,7 +409,7 @@ namespace SabreTools.Library.Tools } // Now add the information to the database if it's not already there - Rom rom = GetFileInfo(newfile); + Rom rom = (Rom)GetFileInfo(newfile); DatabaseTools.AddHeaderToDatabase(hstr, rom.SHA1, rule.SourceFile); return true; @@ -508,7 +508,7 @@ namespace SabreTools.Library.Tools } // First, get the SHA-1 hash of the file - Rom rom = GetFileInfo(file); + Rom rom = (Rom)GetFileInfo(file); // Retrieve a list of all related headers from the database List headers = DatabaseTools.RetrieveHeadersFromDatabase(rom.SHA1); @@ -733,7 +733,7 @@ namespace SabreTools.Library.Tools /// Set a >0 number for getting hash for part of the file, 0 otherwise (default) /// True if the underlying read stream should be kept open, false otherwise /// Populated DatItem object if success, empty one on error - public static Rom GetStreamInfo(Stream input, long size, Hash omitFromScan = 0x0, + public static DatItem GetStreamInfo(Stream input, long size, Hash omitFromScan = 0x0, long offset = 0, bool keepReadOpen = false) { Rom rom = new Rom