From cef409cb928857f530455f70f37d12cf938b47b1 Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Fri, 16 Feb 2018 00:25:28 -0800 Subject: [PATCH] [CHDFile, Utilities] The great CHD cleanup --- SabreTools.Library/FileTypes/CHDFile.cs | 193 ++++++++++++++++-------- SabreTools.Library/Tools/Utilities.cs | 86 +---------- 2 files changed, 136 insertions(+), 143 deletions(-) diff --git a/SabreTools.Library/FileTypes/CHDFile.cs b/SabreTools.Library/FileTypes/CHDFile.cs index d95cb821..8c543c9f 100644 --- a/SabreTools.Library/FileTypes/CHDFile.cs +++ b/SabreTools.Library/FileTypes/CHDFile.cs @@ -1,7 +1,4 @@ -using System; -using System.Linq; - -using SabreTools.Library.Data; +using SabreTools.Library.Data; using SabreTools.Library.Tools; #if MONO @@ -88,7 +85,7 @@ namespace SabreTools.Library.FileTypes /// 0x68-0x7b - Parent SHA-1 /// ---------------------------------------------- /// - public class CHDFile : BaseFile, IDisposable + public class CHDFile : BaseFile { #region Private instance variables @@ -110,12 +107,61 @@ namespace SabreTools.Library.FileTypes private uint m_mapentrybytes; // length of each entry in a map // additional required vars + private uint? _headerVersion; private BinaryReader m_br; // Binary reader representing the CHD stream #endregion + #region Pubically facing variables + + public uint? Version + { + get + { + if (_headerVersion == null) + { + _headerVersion = ValidateHeaderVersion(); + } + + return _headerVersion; + } + } + + #endregion + #region Constructors + /// + /// Create a new, blank CHDFile + /// + public CHDFile() + { + this._fileType = FileType.CHD; + } + + /// + /// Create a new CHDFile from an input file + /// + /// + public CHDFile(string filename) + : base(filename) + { + _fileType = FileType.CHD; + m_br = new BinaryReader(Utilities.TryOpenRead(filename)); + + _headerVersion = ValidateHeaderVersion(); + + byte[] hash = GetHashFromHeader(); + if (hash.Length == Constants.MD5Length) + { + _md5 = hash; + } + else if (hash.Length == Constants.SHA1Length) + { + _sha1 = hash; + } + } + /// /// Create a new CHDFile from an input stream /// @@ -124,14 +170,18 @@ namespace SabreTools.Library.FileTypes { _fileType = FileType.CHD; m_br = new BinaryReader(chdstream); - } - /// - /// Dispose of the CHDFile - /// - public void Dispose() - { - m_br.Dispose(); + _headerVersion = ValidateHeaderVersion(); + + byte[] hash = GetHashFromHeader(); + if (hash.Length == Constants.MD5Length) + { + _md5 = hash; + } + else if (hash.Length == Constants.SHA1Length) + { + _sha1 = hash; + } } #endregion @@ -142,50 +192,57 @@ namespace SabreTools.Library.FileTypes /// Validate the initial signature, version, and header size /// /// Unsigned int containing the version number, null if invalid - public uint? ValidateHeaderVersion() + private uint? ValidateHeaderVersion() { - // Seek to the beginning to make sure we're reading the correct bytes - m_br.BaseStream.Seek(0, SeekOrigin.Begin); + try + { + // Seek to the beginning to make sure we're reading the correct bytes + m_br.BaseStream.Seek(0, SeekOrigin.Begin); - // Read and verify the CHD signature - m_signature = m_br.ReadBytes(8); + // Read and verify the CHD signature + m_signature = m_br.ReadBytes(8); - // If no signature could be read, return null - if (m_signature == null || m_signature.Length == 0) + // If no signature could be read, return null + if (m_signature == null || m_signature.Length == 0) + { + return null; + } + + if (!m_signature.StartsWith(Constants.CHDSignature, exact: true)) + { + // throw CHDERR_INVALID_FILE; + return null; + } + + // Get the header size and version + m_headersize = m_br.ReadUInt32Reverse(); + m_version = m_br.ReadUInt32Reverse(); + + // If we have an invalid combination of size and version + if ((m_version == 1 && m_headersize != Constants.CHD_V1_HEADER_SIZE) + || (m_version == 2 && m_headersize != Constants.CHD_V2_HEADER_SIZE) + || (m_version == 3 && m_headersize != Constants.CHD_V3_HEADER_SIZE) + || (m_version == 4 && m_headersize != Constants.CHD_V4_HEADER_SIZE) + || (m_version == 5 && m_headersize != Constants.CHD_V5_HEADER_SIZE) + || (m_version < 1 || m_version > 5)) + { + // throw CHDERR_UNSUPPORTED_VERSION; + return null; + } + + return m_version; + } + catch { return null; } - - if (!m_signature.StartsWith(Constants.CHDSignature, exact: true)) - { - // throw CHDERR_INVALID_FILE; - return null; - } - - // Get the header size and version - m_headersize = m_br.ReadUInt32Reverse(); - m_version = m_br.ReadUInt32Reverse(); - - // If we have an invalid combination of size and version - if ((m_version == 1 && m_headersize != Constants.CHD_V1_HEADER_SIZE) - || (m_version == 2 && m_headersize != Constants.CHD_V2_HEADER_SIZE) - || (m_version == 3 && m_headersize != Constants.CHD_V3_HEADER_SIZE) - || (m_version == 4 && m_headersize != Constants.CHD_V4_HEADER_SIZE) - || (m_version == 5 && m_headersize != Constants.CHD_V5_HEADER_SIZE) - || (m_version < 1 || m_version > 5)) - { - // throw CHDERR_UNSUPPORTED_VERSION; - return null; - } - - return m_version; } /// /// Get the internal MD5 (v1, v2) or SHA-1 (v3, v4, v5) from the CHD /// /// MD5 as a byte array, null on error - public byte[] GetHashFromHeader() + private byte[] GetHashFromHeader() { // Validate the header by default just in case uint? version = ValidateHeaderVersion(); @@ -194,27 +251,35 @@ namespace SabreTools.Library.FileTypes byte[] hash; // Now parse the rest of the header according to the version - switch (version) + try { - case 1: - hash = ParseCHDv1Header(); - break; - case 2: - hash = ParseCHDv2Header(); - break; - case 3: - hash = ParseCHDv3Header(); - break; - case 4: - hash = ParseCHDv4Header(); - break; - case 5: - hash = ParseCHDv5Header(); - break; - case null: - default: - // throw CHDERR_INVALID_FILE; - return null; + switch (version) + { + case 1: + hash = ParseCHDv1Header(); + break; + case 2: + hash = ParseCHDv2Header(); + break; + case 3: + hash = ParseCHDv3Header(); + break; + case 4: + hash = ParseCHDv4Header(); + break; + case 5: + hash = ParseCHDv5Header(); + break; + case null: + default: + // throw CHDERR_INVALID_FILE; + return null; + } + } + catch + { + // throw CHDERR_INVALID_FILE; + return null; } return hash; diff --git a/SabreTools.Library/Tools/Utilities.cs b/SabreTools.Library/Tools/Utilities.cs index 7578e2dc..70e4fe7c 100644 --- a/SabreTools.Library/Tools/Utilities.cs +++ b/SabreTools.Library/Tools/Utilities.cs @@ -1040,9 +1040,9 @@ namespace SabreTools.Library.Tools public static BaseFile GetCHDInfo(string input) { FileStream fs = TryOpenRead(input); - BaseFile datItem = GetCHDInfo(fs); + BaseFile chd = GetCHDInfo(fs); fs.Dispose(); - return datItem; + return chd; } /// @@ -1371,32 +1371,6 @@ namespace SabreTools.Library.Tools } } - /// - /// Get if file has a known CHD header - /// - /// Filename of possible CHD - /// True if the file has a valid CHD header, false otherwise - public static bool HasCHDHeader(string input) - { - FileStream fs = TryOpenRead(input); - bool output = HasCHDHeader(fs); - fs.Dispose(); - return output; - } - - /// - /// Get if file is a valid CHD - /// - /// Filename of possible CHD - /// True if the file is a valid CHD, false otherwise - public static bool IsValidCHD(string input) - { - BaseFile baseFile = GetCHDInfo(input); - return baseFile != null - && (((CHDFile)baseFile).MD5 != null - || ((CHDFile)baseFile).SHA1 != null); - } - /// /// Retrieve a list of files from a directory recursively in proper order /// @@ -1925,7 +1899,7 @@ namespace SabreTools.Library.Tools long offset = 0, bool keepReadOpen = false, bool chdsAsFiles = true) { // We first check to see if it's a CHD - if (chdsAsFiles == false && HasCHDHeader(input)) + if (chdsAsFiles == false && GetCHDInfo(input) != null) { // Seek to the starting position, if one is set try @@ -1952,8 +1926,8 @@ namespace SabreTools.Library.Tools Globals.Logger.Warning("Stream does not support seeking. Stream position not changed"); } - // Get the Disk from the information - BaseFile disk = GetCHDInfo(input); + // Get the BaseFile from the information + BaseFile chd = GetCHDInfo(input); // Seek to the beginning of the stream if possible try @@ -1974,7 +1948,7 @@ namespace SabreTools.Library.Tools input.Dispose(); } - return disk; + return chd; } BaseFile rom = new BaseFile() @@ -2130,54 +2104,8 @@ namespace SabreTools.Library.Tools /// public static BaseFile GetCHDInfo(Stream input) { - // Get a CHD object to store the data CHDFile chd = new CHDFile(input); - - // Ensure that the header is valid - byte[] hash = chd.GetHashFromHeader(); - - // Set the proper hash of the Disk to return - if (hash.Length == Constants.MD5Length) - { - chd.MD5 = hash; - return chd; - } - else if (hash.Length == Constants.SHA1Length) - { - chd.SHA1 = hash; - return chd; - } - - return null; - } - - /// - /// Get if stream has a known CHD header - /// - /// Stream of possible CHD - /// True if the stream has a valid CHD header, false otherwise - public static bool HasCHDHeader(Stream input) - { - // Get a CHD object to store the data - CHDFile chd = new CHDFile(input); - - // Now try to get the header version - uint? version = chd.ValidateHeaderVersion(); - - return version != null; - } - - /// - /// Get if stream is a valid CHD - /// - /// Stream of possible CHD - /// True if the stream is a valid CHD, false otherwise - public static bool IsValidCHD(Stream input) - { - BaseFile baseFile = GetCHDInfo(input); - return baseFile != null - && (((CHDFile)baseFile).MD5 != null - || ((CHDFile)baseFile).SHA1 != null); + return (chd.Version != null && (chd.MD5 != null || chd.SHA1 != null) ? chd : null); } #endregion