private ZipReturn ReadBody(bool deepScan) { using (BinaryReader zipBr = new BinaryReader(_zipFs, Encoding.UTF8, true)) { byte ID1 = zipBr.ReadByte(); byte ID2 = zipBr.ReadByte(); if ((ID1 != 0x1f) || (ID2 != 0x8b)) { _zipFs.Close(); return(ZipReturn.ZipSignatureError); } byte CM = zipBr.ReadByte(); if (CM != 8) { _zipFs.Close(); return(ZipReturn.ZipUnsupportedCompression); } byte FLG = zipBr.ReadByte(); uint MTime = zipBr.ReadUInt32(); byte XFL = zipBr.ReadByte(); byte OS = zipBr.ReadByte(); //if FLG.FEXTRA set if ((FLG & 0x4) == 0x4) { int XLen = zipBr.ReadInt16(); byte[] bytes = zipBr.ReadBytes(XLen); if (XLen == 28) { md5Hash = new byte[16]; Array.Copy(bytes, 0, md5Hash, 0, 16); crc = new byte[4]; Array.Copy(bytes, 16, crc, 0, 4); uncompressedSize = BitConverter.ToUInt64(bytes, 20); } if (XLen == 77) { md5Hash = new byte[16]; Array.Copy(bytes, 0, md5Hash, 0, 16); crc = new byte[4]; Array.Copy(bytes, 16, crc, 0, 4); uncompressedSize = BitConverter.ToUInt64(bytes, 20); altType = (HeaderFileType)bytes[28]; altmd5Hash = new byte[16]; Array.Copy(bytes, 29, altmd5Hash, 0, 16); altsha1Hash = new byte[20]; Array.Copy(bytes, 45, altsha1Hash, 0, 20); altcrc = new byte[4]; Array.Copy(bytes, 65, altcrc, 0, 4); uncompressedAltSize = BitConverter.ToUInt64(bytes, 69); } } //if FLG.FNAME set if ((FLG & 0x8) == 0x8) { int XLen = zipBr.ReadInt16(); byte[] bytes = zipBr.ReadBytes(XLen); } //if FLG.FComment set if ((FLG & 0x10) == 0x10) { int XLen = zipBr.ReadInt16(); byte[] bytes = zipBr.ReadBytes(XLen); } //if FLG.FHCRC set if ((FLG & 0x2) == 0x2) { uint crc16 = zipBr.ReadUInt16(); } } compressedSize = (ulong)(_zipFs.Length - _zipFs.Position) - 8; datapos = _zipFs.Position; if (deepScan) { if (Buffer0 == null) { Buffer0 = new byte[Buffersize]; } if (Buffer1 == null) { Buffer1 = new byte[Buffersize]; } Stream ds = new ZlibBaseStream(_zipFs, CompressionMode.Decompress, CompressionLevel.Default, ZlibStreamFlavor.DEFLATE, true); ThreadLoadBuffer lbuffer = new ThreadLoadBuffer(ds); ThreadCRC crc32 = new ThreadCRC(); ThreadMD5 md5 = new ThreadMD5(); ThreadSHA1 sha1 = new ThreadSHA1(); ulong uncompressedRead = 0; int bufferRead = ds.Read(Buffer0, 0, Buffersize); uncompressedRead += (ulong)bufferRead; bool whichBuffer = true; while (bufferRead > 0) { // trigger the buffer loading worker lbuffer.Trigger(whichBuffer ? Buffer1 : Buffer0, Buffersize); byte[] buffer = whichBuffer ? Buffer0 : Buffer1; // trigger the hashing workers crc32.Trigger(buffer, bufferRead); md5.Trigger(buffer, bufferRead); sha1.Trigger(buffer, bufferRead); lbuffer.Wait(); crc32.Wait(); md5.Wait(); sha1.Wait(); // setup next loop around bufferRead = lbuffer.SizeRead; uncompressedRead += (ulong)bufferRead; whichBuffer = !whichBuffer; } // tell all the workers we are finished lbuffer.Finish(); crc32.Finish(); md5.Finish(); sha1.Finish(); // get the results byte[] testcrc = crc32.Hash; byte[] testmd5 = md5.Hash; byte[] testsha1 = sha1.Hash; // cleanup lbuffer.Dispose(); crc32.Dispose(); md5.Dispose(); sha1.Dispose(); ds.Close(); ds.Dispose(); if (uncompressedSize != 0) { if (uncompressedSize != uncompressedRead) { _zipFs.Close(); return(ZipReturn.ZipDecodeError); } } else { uncompressedSize = uncompressedRead; } if (crc != null) { for (int i = 0; i < 4; i++) { if (crc[i] == testcrc[i]) { continue; } _zipFs.Close(); return(ZipReturn.ZipDecodeError); } } else { crc = testcrc; } if (md5Hash != null) { for (int i = 0; i < 16; i++) { if (md5Hash[i] == testmd5[i]) { continue; } _zipFs.Close(); return(ZipReturn.ZipDecodeError); } } else { md5Hash = testmd5; } if (sha1Hash != null) { for (int i = 0; i < 20; i++) { if (sha1Hash[i] == testsha1[i]) { continue; } _zipFs.Close(); return(ZipReturn.ZipDecodeError); } } else { sha1Hash = testsha1; } } _zipFs.Position = _zipFs.Length - 8; byte[] gzcrc; uint gzLength; using (BinaryReader zipBr = new BinaryReader(_zipFs, Encoding.UTF8, true)) { gzcrc = zipBr.ReadBytes(4); gzLength = zipBr.ReadUInt32(); } if (crc != null) { for (int i = 0; i < 4; i++) { if (gzcrc[3 - i] == crc[i]) { continue; } _zipFs.Close(); return(ZipReturn.ZipDecodeError); } } else { crc = new[] { gzcrc[3], gzcrc[2], gzcrc[1], gzcrc[0] }; } if (uncompressedSize != 0) { if (gzLength != (uncompressedSize & 0xffffffff)) { _zipFs.Close(); return(ZipReturn.ZipDecodeError); } } return(ZipReturn.ZipGood); }
/// <summary> /// Retrieve file information for a single file /// </summary> /// <param name="input">Filename to get information from</param> /// <param name="size">Size of the input stream</param> /// <param name="hashes">Hashes to include in the information</param> /// <param name="keepReadOpen">True if the underlying read stream should be kept open, false otherwise</param> /// <returns>Populated BaseFile object if success, empty one on error</returns> public static BaseFile GetInfo(Stream input, long size = -1, Hash hashes = Hash.Standard, bool keepReadOpen = false) { // If we want to automatically set the size if (size == -1) { size = input.Length; } try { // Get a list of hashers to run over the buffer List <Hasher> hashers = new List <Hasher>(); if (hashes.HasFlag(Hash.CRC)) { hashers.Add(new Hasher(Hash.CRC)); } if (hashes.HasFlag(Hash.MD5)) { hashers.Add(new Hasher(Hash.MD5)); } if (hashes.HasFlag(Hash.SHA1)) { hashers.Add(new Hasher(Hash.SHA1)); } if (hashes.HasFlag(Hash.SHA256)) { hashers.Add(new Hasher(Hash.SHA256)); } if (hashes.HasFlag(Hash.SHA384)) { hashers.Add(new Hasher(Hash.SHA384)); } if (hashes.HasFlag(Hash.SHA512)) { hashers.Add(new Hasher(Hash.SHA512)); } if (hashes.HasFlag(Hash.SpamSum)) { hashers.Add(new Hasher(Hash.SpamSum)); } // Initialize the hashing helpers var loadBuffer = new ThreadLoadBuffer(input); int buffersize = 3 * 1024 * 1024; byte[] buffer0 = new byte[buffersize]; byte[] buffer1 = new byte[buffersize]; /* * Please note that some of the following code is adapted from * RomVault. This is a modified version of how RomVault does * threaded hashing. As such, some of the terminology and code * is the same, though variable names and comments may have * been tweaked to better fit this code base. */ // Pre load the first buffer long refsize = size; int next = refsize > buffersize ? buffersize : (int)refsize; input.Read(buffer0, 0, next); int current = next; refsize -= next; bool bufferSelect = true; while (current > 0) { // Trigger the buffer load on the second buffer next = refsize > buffersize ? buffersize : (int)refsize; if (next > 0) { loadBuffer.Trigger(bufferSelect ? buffer1 : buffer0, next); } byte[] buffer = bufferSelect ? buffer0 : buffer1; // Run hashes in parallel Parallel.ForEach(hashers, Globals.ParallelOptions, h => h.Process(buffer, current)); // Wait for the load buffer worker, if needed if (next > 0) { loadBuffer.Wait(); } // Setup for the next hashing step current = next; refsize -= next; bufferSelect = !bufferSelect; } // Finalize all hashing helpers loadBuffer.Finish(); Parallel.ForEach(hashers, Globals.ParallelOptions, h => h.Terminate()); // Get the results BaseFile baseFile = new BaseFile() { Size = size, CRC = hashes.HasFlag(Hash.CRC) ? hashers.First(h => h.HashType == Hash.CRC).GetHash() : null, MD5 = hashes.HasFlag(Hash.MD5) ? hashers.First(h => h.HashType == Hash.MD5).GetHash() : null, SHA1 = hashes.HasFlag(Hash.SHA1) ? hashers.First(h => h.HashType == Hash.SHA1).GetHash() : null, SHA256 = hashes.HasFlag(Hash.SHA256) ? hashers.First(h => h.HashType == Hash.SHA256).GetHash() : null, SHA384 = hashes.HasFlag(Hash.SHA384) ? hashers.First(h => h.HashType == Hash.SHA384).GetHash() : null, SHA512 = hashes.HasFlag(Hash.SHA512) ? hashers.First(h => h.HashType == Hash.SHA512).GetHash() : null, SpamSum = hashes.HasFlag(Hash.SpamSum) ? hashers.First(h => h.HashType == Hash.SpamSum).GetHash() : null, }; // Dispose of the hashers loadBuffer.Dispose(); hashers.ForEach(h => h.Dispose()); return(baseFile); } catch (IOException ex) { LoggerImpl.Warning(ex, "An exception occurred during hashing."); return(new BaseFile()); } finally { if (!keepReadOpen) { input.Dispose(); } else { input.SeekIfPossible(); } } }
public static int CheckSumRead(string filename, bool testDeep, out byte[] crc, out byte[] bMD5, out byte[] bSHA1) { bMD5 = null; bSHA1 = null; crc = null; Stream ds = null; ThreadLoadBuffer lbuffer = null; ThreadCRC tcrc32 = null; ThreadMD5 tmd5 = null; ThreadSHA1 tsha1 = null; try { int errorCode = FileStream.OpenFileRead(filename, out ds); if (errorCode != 0) { return(errorCode); } lbuffer = new ThreadLoadBuffer(ds); tcrc32 = new ThreadCRC(); if (testDeep) { tmd5 = new ThreadMD5(); tsha1 = new ThreadSHA1(); } long sizetogo = ds.Length; // Pre load the first buffer0 int sizeNext = sizetogo > Buffersize ? Buffersize : (int)sizetogo; ds.Read(Buffer0, 0, sizeNext); int sizebuffer = sizeNext; sizetogo -= sizeNext; bool whichBuffer = true; while ((sizebuffer > 0) && !lbuffer.errorState) { sizeNext = sizetogo > Buffersize ? Buffersize : (int)sizetogo; if (sizeNext > 0) { lbuffer.Trigger(whichBuffer ? Buffer1 : Buffer0, sizeNext); } byte[] buffer = whichBuffer ? Buffer0 : Buffer1; tcrc32.Trigger(buffer, sizebuffer); tmd5?.Trigger(buffer, sizebuffer); tsha1?.Trigger(buffer, sizebuffer); if (sizeNext > 0) { lbuffer.Wait(); } tcrc32.Wait(); tmd5?.Wait(); tsha1?.Wait(); sizebuffer = sizeNext; sizetogo -= sizeNext; whichBuffer = !whichBuffer; } lbuffer.Finish(); tcrc32.Finish(); tmd5?.Finish(); tsha1?.Finish(); ds.Close(); } catch { ds?.Close(); lbuffer?.Dispose(); tcrc32?.Dispose(); tmd5?.Dispose(); tsha1?.Dispose(); return(0x17); // need to remember what this number is for } if (lbuffer.errorState) { ds?.Close(); lbuffer?.Dispose(); tcrc32?.Dispose(); tmd5?.Dispose(); tsha1?.Dispose(); return(0x17); // need to remember what this number is for } crc = tcrc32.Hash; if (testDeep) { bMD5 = tmd5.Hash; bSHA1 = tsha1.Hash; } lbuffer.Dispose(); tcrc32.Dispose(); tmd5?.Dispose(); tsha1?.Dispose(); return(0); }
private int CheckSumRead(Stream inStream, FileResults fileResults, ulong totalSize, bool testcrc, bool testDeep) { if (_buffer0 == null) { _buffer0 = new byte[Buffersize]; _buffer1 = new byte[Buffersize]; } fileResults.MD5 = null; fileResults.SHA1 = null; fileResults.CRC = null; ThreadLoadBuffer lbuffer = null; ThreadCRC tcrc32 = null; ThreadMD5 tmd5 = null; ThreadSHA1 tsha1 = null; ThreadCRC altCrc32 = null; ThreadMD5 altMd5 = null; ThreadSHA1 altSha1 = null; try { int maxHeaderSize = 128; long sizetogo = (long)totalSize; int sizenow = maxHeaderSize < sizetogo ? maxHeaderSize : (int)sizetogo; inStream.Read(_buffer0, 0, sizenow); fileResults.HeaderFileType = FileHeaderReader.GetType(_buffer0, sizenow, out int actualHeaderSize); // if the file has no header then just use the main hash checkers. if (fileResults.HeaderFileType == HeaderFileType.Nothing || actualHeaderSize == 0) { // no header found & not reading hashes. if (!(testcrc || testDeep)) { return(0); } // no header found so just push the initial buffer read into the hash checkers. // and then continue with the rest of the file. tcrc32 = new ThreadCRC(); if (testDeep) { tmd5 = new ThreadMD5(); tsha1 = new ThreadSHA1(); } tcrc32.Trigger(_buffer0, sizenow); tmd5?.Trigger(_buffer0, sizenow); tsha1?.Trigger(_buffer0, sizenow); tcrc32.Wait(); tmd5?.Wait(); tsha1?.Wait(); sizetogo -= sizenow; } else { // header found fileResults.AltSize = (ulong)((long)totalSize - actualHeaderSize); //setup main hash checkers if (testcrc || testDeep) { tcrc32 = new ThreadCRC(); } altCrc32 = new ThreadCRC(); if (testDeep) { tmd5 = new ThreadMD5(); tsha1 = new ThreadSHA1(); altMd5 = new ThreadMD5(); altSha1 = new ThreadSHA1(); } if (sizenow > actualHeaderSize) { // Already read more than the header, so we need to split what we read into the 2 hash checkers // first scan the header part from what we have already read. // scan what we read so far with just the main hashers tcrc32?.Trigger(_buffer0, actualHeaderSize); tmd5?.Trigger(_buffer0, actualHeaderSize); tsha1?.Trigger(_buffer0, actualHeaderSize); tcrc32?.Wait(); tmd5?.Wait(); tsha1?.Wait(); // put the rest of what we read into the second buffer, and scan with all hashers int restSize = sizenow - actualHeaderSize; for (int i = 0; i < restSize; i++) { _buffer1[i] = _buffer0[actualHeaderSize + i]; } tcrc32?.Trigger(_buffer1, restSize); tmd5?.Trigger(_buffer1, restSize); tsha1?.Trigger(_buffer1, restSize); altCrc32.Trigger(_buffer1, restSize); altMd5?.Trigger(_buffer1, restSize); altSha1?.Trigger(_buffer1, restSize); tcrc32?.Wait(); tmd5?.Wait(); tsha1?.Wait(); altCrc32.Wait(); altMd5?.Wait(); altSha1?.Wait(); sizetogo -= sizenow; } else { // Read less than the length of the header so read the rest of the header. // then continue to reader the full rest of the file. // scan what we read so far tcrc32?.Trigger(_buffer0, sizenow); tmd5?.Trigger(_buffer0, sizenow); tsha1?.Trigger(_buffer0, sizenow); tcrc32?.Wait(); tmd5?.Wait(); tsha1?.Wait(); sizetogo -= sizenow; // now read the rest of the header. sizenow = actualHeaderSize - sizenow; inStream.Read(_buffer0, 0, sizenow); // scan the rest of the header tcrc32?.Trigger(_buffer0, sizenow); tmd5?.Trigger(_buffer0, sizenow); tsha1?.Trigger(_buffer0, sizenow); tcrc32?.Wait(); tmd5?.Wait(); tsha1?.Wait(); sizetogo -= sizenow; } } lbuffer = new ThreadLoadBuffer(inStream); // Pre load the first buffer0 int sizeNext = sizetogo > Buffersize ? Buffersize : (int)sizetogo; inStream.Read(_buffer0, 0, sizeNext); int sizebuffer = sizeNext; sizetogo -= sizeNext; bool whichBuffer = true; while (sizebuffer > 0 && !lbuffer.errorState) { sizeNext = sizetogo > Buffersize ? Buffersize : (int)sizetogo; if (sizeNext > 0) { lbuffer.Trigger(whichBuffer ? _buffer1 : _buffer0, sizeNext); } byte[] buffer = whichBuffer ? _buffer0 : _buffer1; tcrc32?.Trigger(buffer, sizebuffer); tmd5?.Trigger(buffer, sizebuffer); tsha1?.Trigger(buffer, sizebuffer); altCrc32?.Trigger(buffer, sizebuffer); altMd5?.Trigger(buffer, sizebuffer); altSha1?.Trigger(buffer, sizebuffer); if (sizeNext > 0) { lbuffer.Wait(); } tcrc32?.Wait(); tmd5?.Wait(); tsha1?.Wait(); altCrc32?.Wait(); altMd5?.Wait(); altSha1?.Wait(); sizebuffer = sizeNext; sizetogo -= sizeNext; whichBuffer = !whichBuffer; } lbuffer.Finish(); tcrc32?.Finish(); tmd5?.Finish(); tsha1?.Finish(); altCrc32?.Finish(); altMd5?.Finish(); altSha1?.Finish(); } catch { lbuffer?.Dispose(); tcrc32?.Dispose(); tmd5?.Dispose(); tsha1?.Dispose(); altCrc32?.Dispose(); altMd5?.Dispose(); altSha1?.Dispose(); return(0x17); // need to remember what this number is for } if (lbuffer.errorState) { lbuffer.Dispose(); tcrc32?.Dispose(); tmd5?.Dispose(); tsha1?.Dispose(); altCrc32?.Dispose(); altMd5?.Dispose(); altSha1?.Dispose(); return(0x17); // need to remember what this number is for } fileResults.CRC = tcrc32?.Hash; fileResults.SHA1 = tsha1?.Hash; fileResults.MD5 = tmd5?.Hash; fileResults.AltCRC = altCrc32?.Hash; fileResults.AltSHA1 = altSha1?.Hash; fileResults.AltMD5 = altMd5?.Hash; lbuffer.Dispose(); tcrc32?.Dispose(); tmd5?.Dispose(); tsha1?.Dispose(); altCrc32?.Dispose(); altMd5?.Dispose(); altSha1?.Dispose(); return(0); }
/// <summary> /// Get hashes from an input file path /// </summary> /// <param name="filename">Path to the input file</param> /// <returns>True if hashing was successful, false otherwise</returns> protected static bool GetFileHashes(string filename, out long size, out string crc32, out string md5, out string sha1) { // Set all initial values size = -1; crc32 = null; md5 = null; sha1 = null; // If the file doesn't exist, we can't do anything if (!File.Exists(filename)) { return(false); } // Set the file size size = new FileInfo(filename).Length; // Open the input file var input = File.OpenRead(filename); try { // Get a list of hashers to run over the buffer List <Hasher> hashers = new List <Hasher> { new Hasher(Hash.CRC), new Hasher(Hash.MD5), new Hasher(Hash.SHA1), new Hasher(Hash.SHA256), new Hasher(Hash.SHA384), new Hasher(Hash.SHA512), }; // Initialize the hashing helpers var loadBuffer = new ThreadLoadBuffer(input); int buffersize = 3 * 1024 * 1024; byte[] buffer0 = new byte[buffersize]; byte[] buffer1 = new byte[buffersize]; /* * Please note that some of the following code is adapted from * RomVault. This is a modified version of how RomVault does * threaded hashing. As such, some of the terminology and code * is the same, though variable names and comments may have * been tweaked to better fit this code base. */ // Pre load the first buffer long refsize = size; int next = refsize > buffersize ? buffersize : (int)refsize; input.Read(buffer0, 0, next); int current = next; refsize -= next; bool bufferSelect = true; while (current > 0) { // Trigger the buffer load on the second buffer next = refsize > buffersize ? buffersize : (int)refsize; if (next > 0) { loadBuffer.Trigger(bufferSelect ? buffer1 : buffer0, next); } byte[] buffer = bufferSelect ? buffer0 : buffer1; // Run hashes in parallel Parallel.ForEach(hashers, h => h.Process(buffer, current)); // Wait for the load buffer worker, if needed if (next > 0) { loadBuffer.Wait(); } // Setup for the next hashing step current = next; refsize -= next; bufferSelect = !bufferSelect; } // Finalize all hashing helpers loadBuffer.Finish(); Parallel.ForEach(hashers, h => h.Terminate()); // Get the results crc32 = hashers.First(h => h.HashType == Hash.CRC).GetHashString(); md5 = hashers.First(h => h.HashType == Hash.MD5).GetHashString(); sha1 = hashers.First(h => h.HashType == Hash.SHA1).GetHashString(); //sha256 = hashers.First(h => h.HashType == Hash.SHA256).GetHashString(); //sha384 = hashers.First(h => h.HashType == Hash.SHA384).GetHashString(); //sha512 = hashers.First(h => h.HashType == Hash.SHA512).GetHashString(); // Dispose of the hashers loadBuffer.Dispose(); hashers.ForEach(h => h.Dispose()); return(true); } catch (IOException ex) { return(false); } finally { input.Dispose(); } return(false); }
public void DeepScan() { if (_buffer0 == null) { _buffer0 = new byte[Buffersize]; _buffer1 = new byte[Buffersize]; } for (int index = 0; index < _localFiles.Count; index++) { if (_localFiles[index].isDirectory || (_localFiles[index].UncompressedSize == 0)) { _localFiles[index].md5 = new byte[] { 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04, 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e }; _localFiles[index].sha1 = new byte[] { 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09 }; _localFiles[index].FileStatus = ZipReturn.ZipGood; continue; } ulong sizetogo; Stream inStream; ZipReturn zr = ZipFileOpenReadStream(index, out inStream, out sizetogo); if (zr != ZipReturn.ZipGood) { continue; } if (inStream == null) { continue; } ThreadLoadBuffer lbuffer = new ThreadLoadBuffer(inStream); ThreadCRC tcrc32 = new ThreadCRC(); ThreadMD5 tmd5 = new ThreadMD5(); ThreadSHA1 tsha1 = new ThreadSHA1(); // Pre load the first buffer0 int sizeNext = sizetogo > Buffersize ? Buffersize : (int)sizetogo; inStream.Read(_buffer0, 0, sizeNext); int sizebuffer = sizeNext; sizetogo -= (ulong)sizeNext; bool whichBuffer = true; while ((sizebuffer > 0) && !lbuffer.errorState) { sizeNext = sizetogo > Buffersize ? Buffersize : (int)sizetogo; if (sizeNext > 0) { lbuffer.Trigger(whichBuffer ? _buffer1 : _buffer0, sizeNext); } byte[] buffer = whichBuffer ? _buffer0 : _buffer1; tcrc32.Trigger(buffer, sizebuffer); tmd5.Trigger(buffer, sizebuffer); tsha1.Trigger(buffer, sizebuffer); if (sizeNext > 0) { lbuffer.Wait(); } tcrc32.Wait(); tmd5.Wait(); tsha1.Wait(); sizebuffer = sizeNext; sizetogo -= (ulong)sizeNext; whichBuffer = !whichBuffer; } if (lbuffer.errorState) { lbuffer.Dispose(); tcrc32.Dispose(); tmd5.Dispose(); tsha1.Dispose(); _localFiles[index].FileStatus = ZipReturn.ZipDecodeError; continue; } lbuffer.Finish(); tcrc32.Finish(); tmd5.Finish(); tsha1.Finish(); byte[] testcrc = tcrc32.Hash; _localFiles[index].md5 = tmd5.Hash; _localFiles[index].sha1 = tsha1.Hash; lbuffer.Dispose(); tcrc32.Dispose(); tmd5.Dispose(); tsha1.Dispose(); _localFiles[index].FileStatus = Util.ByteArrCompare(_localFiles[index].crc, testcrc) ? ZipReturn.ZipGood : ZipReturn.ZipCRCDecodeError; } }
/// <summary> /// Retrieve file information for a single file /// </summary> /// <param name="input">Filename to get information from</param> /// <returns>Formatted string representing the hashes, null on error</returns> public static string GetInfo(string input) { // If the file doesn't exist, return null if (!File.Exists(input)) { return(null); } // Get the file length long size = new FileInfo(input).Length; // Open the file Stream inputStream = File.OpenRead(input); try { // Get a list of hashers to run over the buffer List <Hasher> hashers = new List <Hasher> { new Hasher(Hash.CRC), new Hasher(Hash.MD5), new Hasher(Hash.SHA1), new Hasher(Hash.SHA256), }; // Initialize the hashing helpers var loadBuffer = new ThreadLoadBuffer(inputStream); int buffersize = 3 * 1024 * 1024; byte[] buffer0 = new byte[buffersize]; byte[] buffer1 = new byte[buffersize]; /* * Please note that some of the following code is adapted from * RomVault. This is a modified version of how RomVault does * threaded hashing. As such, some of the terminology and code * is the same, though variable names and comments may have * been tweaked to better fit this code base. */ // Pre load the first buffer long refsize = size; int next = refsize > buffersize ? buffersize : (int)refsize; inputStream.Read(buffer0, 0, next); int current = next; refsize -= next; bool bufferSelect = true; while (current > 0) { // Trigger the buffer load on the second buffer next = refsize > buffersize ? buffersize : (int)refsize; if (next > 0) { loadBuffer.Trigger(bufferSelect ? buffer1 : buffer0, next); } byte[] buffer = bufferSelect ? buffer0 : buffer1; // Run hashes in parallel Parallel.ForEach(hashers, h => h.Process(buffer, current)); // Wait for the load buffer worker, if needed if (next > 0) { loadBuffer.Wait(); } // Setup for the next hashing step current = next; refsize -= next; bufferSelect = !bufferSelect; } // Finalize all hashing helpers loadBuffer.Finish(); Parallel.ForEach(hashers, h => h.Terminate()); // Get the results string result = $"Size: {size}\n" + $"CRC32: {ByteArrayToString(hashers.First(h => h.HashType == Hash.CRC).GetHash()) ?? ""}\n" + $"MD5: {ByteArrayToString(hashers.First(h => h.HashType == Hash.MD5).GetHash()) ?? ""}\n" + $"SHA1: {ByteArrayToString(hashers.First(h => h.HashType == Hash.SHA1).GetHash()) ?? ""}\n" + $"SHA256: {ByteArrayToString(hashers.First(h => h.HashType == Hash.SHA256).GetHash()) ?? ""}\n"; // Dispose of the hashers loadBuffer.Dispose(); hashers.ForEach(h => h.Dispose()); return(result); } catch { return(null); } finally { inputStream.Dispose(); } }