diff --git a/SabreTools.Helper/Tools/FileTools.cs b/SabreTools.Helper/Tools/FileTools.cs index 63ba7642..2c6cd695 100644 --- a/SabreTools.Helper/Tools/FileTools.cs +++ b/SabreTools.Helper/Tools/FileTools.cs @@ -471,8 +471,7 @@ namespace SabreTools.Helper /// Integer representing the archive handling level for Zip /// Logger object for file and console output /// True if the extraction was a success, false otherwise - public static bool ExtractArchive(string input, string tempDir, int sevenzip, - int gz, int rar, int zip, Logger logger) + public static bool ExtractArchive(string input, string tempDir, int sevenzip, int gz, int rar, int zip, Logger logger) { return ExtractArchive(input, tempDir, (ArchiveScanLevel)sevenzip, (ArchiveScanLevel)gz, (ArchiveScanLevel)rar, (ArchiveScanLevel)zip, logger); } @@ -584,8 +583,7 @@ namespace SabreTools.Helper /// Temporary directory for archive extraction /// Logger object for file and console output /// Name of the extracted file, null on error - public static string ExtractSingleItemFromArchive(string input, string entryname, - string tempDir, Logger logger) + public static string ExtractSingleItemFromArchive(string input, string entryname, string tempDir, Logger logger) { string outfile = null; @@ -698,94 +696,6 @@ namespace SabreTools.Helper return rom; } - /// - /// Retrieve file information for a single file - /// - /// Filename to get information from - /// True if MD5 hashes should not be calculated, false otherwise (default) - /// True if SHA-1 hashes should not be calcluated, false otherwise (default) - /// 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 RomData object if success, empty one on error - public static Rom GetSingleStreamInfo(Stream input, bool noMD5 = false, bool noSHA1 = false, long offset = 0, bool keepReadOpen = false) - { - // If we have a negative offset, zero it out since we don't support it yet - if (offset < 0) - { - offset = 0; - } - - Rom rom = new Rom - { - Type = ItemType.Rom, - Size = input.Length - Math.Abs(offset), - CRC = string.Empty, - MD5 = string.Empty, - SHA1 = string.Empty, - }; - - try - { - // Initialize the hashers - OptimizedCRC crc = new OptimizedCRC(); - MD5 md5 = MD5.Create(); - SHA1 sha1 = SHA1.Create(); - - // Seek to the starting position, if one is set - if (offset > 0) - { - input.Seek(offset, SeekOrigin.Begin); - } - - byte[] buffer = new byte[1024]; - int read; - while ((read = input.Read(buffer, 0, buffer.Length)) > 0) - { - crc.Update(buffer, 0, read); - if (!noMD5) - { - md5.TransformBlock(buffer, 0, read, buffer, 0); - } - if (!noSHA1) - { - sha1.TransformBlock(buffer, 0, read, buffer, 0); - } - } - - crc.Update(buffer, 0, 0); - rom.CRC = crc.Value.ToString("X8").ToLowerInvariant(); - - if (!noMD5) - { - md5.TransformFinalBlock(buffer, 0, 0); - rom.MD5 = BitConverter.ToString(md5.Hash).Replace("-", "").ToLowerInvariant(); - } - if (!noSHA1) - { - sha1.TransformFinalBlock(buffer, 0, 0); - rom.SHA1 = BitConverter.ToString(sha1.Hash).Replace("-", "").ToLowerInvariant(); - } - - // Dispose of the hashers - crc.Dispose(); - md5.Dispose(); - sha1.Dispose(); - } - catch (IOException) - { - return new Rom(); - } - finally - { - if (!keepReadOpen) - { - input.Dispose(); - } - } - - return rom; - } - /// /// Generate a list of RomData objects from the header values in an archive /// @@ -1076,6 +986,98 @@ namespace SabreTools.Helper #endregion + #region Stream Information + + /// + /// Retrieve file information for a single file + /// + /// Filename to get information from + /// True if MD5 hashes should not be calculated, false otherwise (default) + /// True if SHA-1 hashes should not be calcluated, false otherwise (default) + /// 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 RomData object if success, empty one on error + public static Rom GetSingleStreamInfo(Stream input, bool noMD5 = false, bool noSHA1 = false, long offset = 0, bool keepReadOpen = false) + { + // If we have a negative offset, zero it out since we don't support it yet + if (offset < 0) + { + offset = 0; + } + + Rom rom = new Rom + { + Type = ItemType.Rom, + Size = input.Length - Math.Abs(offset), + CRC = string.Empty, + MD5 = string.Empty, + SHA1 = string.Empty, + }; + + try + { + // Initialize the hashers + OptimizedCRC crc = new OptimizedCRC(); + MD5 md5 = MD5.Create(); + SHA1 sha1 = SHA1.Create(); + + // Seek to the starting position, if one is set + if (offset > 0) + { + input.Seek(offset, SeekOrigin.Begin); + } + + byte[] buffer = new byte[1024]; + int read; + while ((read = input.Read(buffer, 0, buffer.Length)) > 0) + { + crc.Update(buffer, 0, read); + if (!noMD5) + { + md5.TransformBlock(buffer, 0, read, buffer, 0); + } + if (!noSHA1) + { + sha1.TransformBlock(buffer, 0, read, buffer, 0); + } + } + + crc.Update(buffer, 0, 0); + rom.CRC = crc.Value.ToString("X8").ToLowerInvariant(); + + if (!noMD5) + { + md5.TransformFinalBlock(buffer, 0, 0); + rom.MD5 = BitConverter.ToString(md5.Hash).Replace("-", "").ToLowerInvariant(); + } + if (!noSHA1) + { + sha1.TransformFinalBlock(buffer, 0, 0); + rom.SHA1 = BitConverter.ToString(sha1.Hash).Replace("-", "").ToLowerInvariant(); + } + + // Dispose of the hashers + crc.Dispose(); + md5.Dispose(); + sha1.Dispose(); + } + catch (IOException) + { + return new Rom(); + } + finally + { + if (!keepReadOpen) + { + input.Dispose(); + } + } + + return rom; + } + + #endregion + #region File Manipulation /// @@ -1093,32 +1095,14 @@ namespace SabreTools.Helper return; } - // Read the input file and write to the fail - BinaryReader br = new BinaryReader(File.OpenRead(input)); - BinaryWriter bw = new BinaryWriter(File.OpenWrite(output)); + // Get the streams + FileStream fsr = File.OpenRead(input); + FileStream fsw = File.OpenWrite(output); - int bufferSize = 1024; - long adjustedLength = br.BaseStream.Length - bytesToRemoveFromTail; + RemoveBytesFromStream(fsr, fsw, bytesToRemoveFromHead, bytesToRemoveFromTail); - // Seek to the correct position - br.BaseStream.Seek((bytesToRemoveFromHead < 0 ? 0 : bytesToRemoveFromHead), SeekOrigin.Begin); - - // Now read the file in chunks and write out - byte[] buffer = new byte[bufferSize]; - while (br.BaseStream.Position <= (adjustedLength - bufferSize)) - { - buffer = br.ReadBytes(bufferSize); - bw.Write(buffer); - } - - // For the final chunk, if any, write out only that number of bytes - int length = (int)(adjustedLength - br.BaseStream.Position); - buffer = new byte[length]; - buffer = br.ReadBytes(length); - bw.Write(buffer); - - br.Dispose(); - bw.Dispose(); + fsr.Dispose(); + fsw.Dispose(); } /// @@ -1160,37 +1144,13 @@ namespace SabreTools.Helper return; } - BinaryReader br = new BinaryReader(File.OpenRead(input)); - BinaryWriter bw = new BinaryWriter(File.OpenWrite(output)); + FileStream fsr = File.OpenRead(input); + FileStream fsw = File.OpenWrite(output); - if (bytesToAddToHead.Count() > 0) - { - bw.Write(bytesToAddToHead); - } + AppendBytesToStream(fsr, fsw, bytesToAddToHead, bytesToAddToTail); - int bufferSize = 1024; - - // Now read the file in chunks and write out - byte[] buffer = new byte[bufferSize]; - while (br.BaseStream.Position <= (br.BaseStream.Length - bufferSize)) - { - buffer = br.ReadBytes(bufferSize); - bw.Write(buffer); - } - - // For the final chunk, if any, write out only that number of bytes - int length = (int)(br.BaseStream.Length - br.BaseStream.Position); - buffer = new byte[length]; - buffer = br.ReadBytes(length); - bw.Write(buffer); - - if (bytesToAddToTail.Count() > 0) - { - bw.Write(bytesToAddToTail); - } - - br.Dispose(); - bw.Dispose(); + fsr.Dispose(); + fsw.Dispose(); } /// @@ -1287,5 +1247,106 @@ namespace SabreTools.Helper } #endregion + + #region Stream Manipulation + + // + /// Remove an arbitrary number of bytes from the inputted stream + /// + /// Stream to be cropped + /// Stream to output to + /// Bytes to be removed from head of stream + /// Bytes to be removed from tail of stream + public static void RemoveBytesFromStream(Stream input, Stream output, long bytesToRemoveFromHead, long bytesToRemoveFromTail) + { + // Read the input file and write to the fail + BinaryReader br = new BinaryReader(input); + BinaryWriter bw = new BinaryWriter(output); + + int bufferSize = 1024; + long adjustedLength = br.BaseStream.Length - bytesToRemoveFromTail; + + // Seek to the correct position + br.BaseStream.Seek((bytesToRemoveFromHead < 0 ? 0 : bytesToRemoveFromHead), SeekOrigin.Begin); + + // Now read the file in chunks and write out + byte[] buffer = new byte[bufferSize]; + while (br.BaseStream.Position <= (adjustedLength - bufferSize)) + { + buffer = br.ReadBytes(bufferSize); + bw.Write(buffer); + } + + // For the final chunk, if any, write out only that number of bytes + int length = (int)(adjustedLength - br.BaseStream.Position); + buffer = new byte[length]; + buffer = br.ReadBytes(length); + bw.Write(buffer); + } + + /// + /// Add an aribtrary number of bytes to the inputted stream + /// + /// Stream to be appended to + /// Outputted stream + /// String representing bytes to be added to head of stream + /// String representing bytes to be added to tail of stream + public static void AppendBytesToStream(Stream input, Stream output, string bytesToAddToHead, string bytesToAddToTail) + { + // Source: http://stackoverflow.com/questions/311165/how-do-you-convert-byte-array-to-hexadecimal-string-and-vice-versa + byte[] bytesToAddToHeadArray = new byte[bytesToAddToHead.Length / 2]; + for (int i = 0; i < bytesToAddToHead.Length; i += 2) + { + bytesToAddToHeadArray[i / 2] = Convert.ToByte(bytesToAddToHead.Substring(i, 2), 16); + } + byte[] bytesToAddToTailArray = new byte[bytesToAddToTail.Length / 2]; + for (int i = 0; i < bytesToAddToTail.Length; i += 2) + { + bytesToAddToTailArray[i / 2] = Convert.ToByte(bytesToAddToTail.Substring(i, 2), 16); + } + + AppendBytesToStream(input, output, bytesToAddToHeadArray, bytesToAddToTailArray); + } + + /// + /// Add an aribtrary number of bytes to the inputted stream + /// + /// Stream to be appended to + /// Outputted stream + /// Bytes to be added to head of stream + /// Bytes to be added to tail of stream + public static void AppendBytesToStream(Stream input, Stream output, byte[] bytesToAddToHead, byte[] bytesToAddToTail) + { + BinaryReader br = new BinaryReader(input); + BinaryWriter bw = new BinaryWriter(output); + + if (bytesToAddToHead.Count() > 0) + { + bw.Write(bytesToAddToHead); + } + + int bufferSize = 1024; + + // Now read the file in chunks and write out + byte[] buffer = new byte[bufferSize]; + while (br.BaseStream.Position <= (br.BaseStream.Length - bufferSize)) + { + buffer = br.ReadBytes(bufferSize); + bw.Write(buffer); + } + + // For the final chunk, if any, write out only that number of bytes + int length = (int)(br.BaseStream.Length - br.BaseStream.Position); + buffer = new byte[length]; + buffer = br.ReadBytes(length); + bw.Write(buffer); + + if (bytesToAddToTail.Count() > 0) + { + bw.Write(bytesToAddToTail); + } + } + + #endregion } }