public static MainPacket Create(PacketHeader header, byte[] bytes, int index) { MainPacket tmpPacket = new MainPacket(); tmpPacket.header = header; int offset = 0; tmpPacket.blocksize = BitConverter.ToUInt64(bytes, index + offset); offset += sizeof(UInt64); tmpPacket.recoverablefilecount = BitConverter.ToUInt32(bytes, index + offset); offset += sizeof(UInt32); tmpPacket.totalfilecount = ((uint)header.length - ((uint)header.GetSize() + sizeof(UInt64) + sizeof(UInt32))) / (16 * sizeof(byte)); for (int i = 0; i < tmpPacket.totalfilecount; i++) { byte[] fileid = new byte[16]; Buffer.BlockCopy(bytes, index + offset, fileid, 0, fileid.Length * sizeof(byte)); offset += fileid.Length * sizeof(byte); tmpPacket.fileids.Add(fileid); } System.Threading.Tasks.Task.Factory.StartNew((b) => { //FastCRC32.FastCRC32 crc32 = new FastCRC32.FastCRC32((ulong)b); FastCRC32.FastCRC32 crc32 = FastCRC32.FastCRC32.GetCRC32Instance((ulong)b); }, tmpPacket.blocksize); return(tmpPacket); }
internal void InitialiseSourceBlocks(ref List <DataBlock> sourceblocks, ulong blocksize) { //crc32 = new FastCRC32.FastCRC32(blocksize); crc32 = FastCRC32.FastCRC32.GetCRC32Instance(blocksize); //contextfull = MD5.Create(); for (uint blocknum = 0; blocknum < blockcount; blocknum++) { // Configure each source block to an appropriate offset and length within the source file. DataBlock sourceblock = new DataBlock(); sourceblock.SetLocation(targetfile, blocknum * blocksize); sourceblock.SetLength(Math.Min(blocksize, filesize - (blocknum * blocksize))); sourceblocks.Add(sourceblock); } }
public static MainPacket Create(Par2LibraryArguments args) { MainPacket tmpPacket = new MainPacket(); tmpPacket.header = new PacketHeader(); tmpPacket.header.setid = new byte[16]; tmpPacket.header.magic = Par2FileReader.packet_magic; tmpPacket.header.type = Par2FileReader.mainpacket_type; tmpPacket.blocksize = (ulong)args.blocksize; tmpPacket.recoverablefilecount = (uint)args.inputFiles.Length; tmpPacket.fileids = new List <byte[]>(); tmpPacket.header.length = (ulong)(tmpPacket.GetSize() + (16 * sizeof(byte) * args.inputFiles.Length)); // setid calculation and fileids insertion will occur in Par2RecoverySet.OpenSourceFiles method System.Threading.Tasks.Task.Factory.StartNew((b) => { //FastCRC32.FastCRC32 crc32 = new FastCRC32.FastCRC32((ulong)b); FastCRC32.FastCRC32 crc32 = FastCRC32.FastCRC32.GetCRC32Instance((ulong)b); }, tmpPacket.blocksize); return(tmpPacket); }
internal void InitialiseSourceBlocks(ref List<DataBlock> sourceblocks, ulong blocksize) { //crc32 = new FastCRC32.FastCRC32(blocksize); crc32 = FastCRC32.FastCRC32.GetCRC32Instance(blocksize); //contextfull = MD5.Create(); for (uint blocknum = 0; blocknum < blockcount; blocknum++) { // Configure each source block to an appropriate offset and length within the source file. DataBlock sourceblock = new DataBlock(); sourceblock.SetLocation(targetfile, blocknum * blocksize); sourceblock.SetLength(Math.Min(blocksize, filesize - (blocknum * blocksize))); sourceblocks.Add(sourceblock); } }
private static void CheckBuffer(byte[] buffer, DiskFile diskFile, string filename, int blocksize, Dictionary <uint, FileVerificationEntry> hashfull, ref MatchType matchType, int globalOffset) { uint partial_key = (uint)(Path.GetFileName(filename).GetHashCode()); MD5 md5Hasher = MD5.Create(); //FastCRC32.FastCRC32 crc32 = new FastCRC32.FastCRC32((ulong)blocksize); FastCRC32.FastCRC32 crc32 = FastCRC32.FastCRC32.GetCRC32Instance((ulong)blocksize); int offset = 0; byte inch = 0; byte outch = 0; uint crc32Value = 0; crc32Value = crc32.CRCUpdateBlock(0xFFFFFFFF, (uint)blocksize, buffer, (uint)offset) ^ 0xFFFFFFFF; while (offset < (buffer.Length - blocksize)) { uint key = crc32Value ^ partial_key; FileVerificationEntry entry = null; if (hashfull.ContainsKey(key)) { entry = hashfull[key]; byte[] blockhash = md5Hasher.ComputeHash(buffer, offset, blocksize); if (ToolKit.ToHex(blockhash) == ToolKit.ToHex(entry.hash)) { // We found a complete match, so go to next block ! //Console.WriteLine("block found at offset {0}, crc {1}", globalOffset + offset, entry.crc); if (entry.datablock.diskfile == null) { lock (entry) { if (entry.datablock.diskfile == null) { entry.SetBlock(diskFile, (int)(globalOffset + offset)); } } } offset += blocksize; crc32Value = crc32.CRCUpdateBlock(0xFFFFFFFF, (uint)(Math.Min(blocksize, buffer.Length - offset)), buffer, (uint)offset) ^ 0xFFFFFFFF; } else { if (offset + blocksize > buffer.Length) { return; } matchType = MatchType.PartialMatch; inch = buffer[offset + blocksize]; outch = buffer[offset]; crc32Value = crc32.windowMask ^ crc32.CRCSlideChar(crc32.windowMask ^ crc32Value, inch, outch); ++offset; } } else { if (offset + blocksize > buffer.Length) { return; } matchType = MatchType.PartialMatch; inch = buffer[offset + blocksize]; outch = buffer[offset]; crc32Value = crc32.windowMask ^ crc32.CRCSlideChar(crc32.windowMask ^ crc32Value, inch, outch); ++offset; } } }
// Open the source file, compute the MD5 Hash of the whole file and the first // 16k of the file, and then compute the FileId and store the results // in a file description packet and a file verification packet. public bool Open(string filename, ulong blocksize, bool deferhashcomputation) { // Get the filename and filesize targetfilename = filename; filesize = (ulong)new FileInfo(filename).Length; // Work out how many blocks the file will be sliced into blockcount = (uint)((filesize + blocksize - 1) / blocksize); // Determine what filename to record in the PAR2 files parfilename = Path.GetFileName(filename); // Create the Description and Verification packets FileDescriptionPacket = Packets.FileDescriptionPacket.Create(parfilename, filesize); FileVerificationPacket = Packets.FileVerificationPacket.Create(blockcount); // Create the diskfile object targetfile = new DiskFile(); // Open the source file if (!targetfile.Open(targetfilename, filesize)) { return(false); } // Do we want to defer the computation of the full file hash, and // the block crc and hashes. This is only permitted if there // is sufficient memory available to create all recovery blocks // in one pass of the source files (i.e. chunksize == blocksize) if (deferhashcomputation) { // Initialise a buffer to read the first 16k of the source file uint buffersize = Math.Min((uint)filesize, 16 * 1024); byte[] buffer = new byte[buffersize]; // Read the data from the file if (!targetfile.Read(0, buffer, buffersize)) { targetfile.Close(); return(false); } // Compute the hash of the data read from the file // Store the hash in the descriptionpacket and compute the file id MD5 md5Hasher = MD5.Create(); FileDescriptionPacket.hash16k = md5Hasher.ComputeHash(buffer); // Compute the fileid and store it in the verification packet. FileDescriptionPacket.ComputeFileId(); FileVerificationPacket.fileid = (byte[])FileDescriptionPacket.fileid.Clone(); //// Allocate an MD5 context for computing the file hash //// during the recovery data generation phase contextfull = MD5.Create(); //contextfull = new MD5Context; } else { // Compute 16k MD5 hash using (BinaryReader br = new BinaryReader(new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))) { MD5 md5Hasher = MD5.Create(); byte[] buffer16k = br.ReadBytes(16 * 1024); FileDescriptionPacket.hash16k = md5Hasher.ComputeHash(buffer16k); } // Compute the fileid and store it in the verification packet. FileDescriptionPacket.ComputeFileId(); FileVerificationPacket.fileid = (byte[])FileDescriptionPacket.fileid.Clone(); // Compute full file MD5 hash & block CRC32 and MD5 hashes //long readSize = 5 * (long)blocksize; long readSize = (long)blocksize; long fileSize = new FileInfo(filename).Length; long nbSteps = fileSize / readSize; long remaining = fileSize % readSize; uint blocknumber = 0; // TODO : switch to async filestream using (BinaryReader br = new BinaryReader(new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))) { MD5 md5FullHasher = MD5.Create(); MD5 md5Hasher = MD5.Create(); //FastCRC32.FastCRC32 crc32 = new FastCRC32.FastCRC32(blocksize); FastCRC32.FastCRC32 crc32 = FastCRC32.FastCRC32.GetCRC32Instance(blocksize); byte[] blockHash = new byte[16]; uint blockCRC32 = 0; for (int i = 0; i < nbSteps + 1; ++i) { byte[] buffer = br.ReadBytes((int)(i == nbSteps ? remaining : readSize)); // Global MD5 hash if (i == nbSteps) { md5FullHasher.TransformFinalBlock(buffer, 0, buffer.Length); } else { md5FullHasher.TransformBlock(buffer, 0, buffer.Length, null, 0); } //for (uint j = 0; j < 5; ++j) //{ // Block MD5 hash & CRC32 uint length = (uint)blocksize; //if (i == nbSteps && j == 4) //if (i == nbSteps && (buffer.Length - (uint)(j * blocksize)) < (int)blocksize) if (i == nbSteps && remaining != 0) { // We need arry padding since calculation **MUST** always be done on blocksize-length buffers byte[] smallBuffer = buffer; buffer = new byte[blocksize]; Buffer.BlockCopy(smallBuffer, 0, buffer, 0, smallBuffer.Length); } blockCRC32 = crc32.CRCUpdateBlock(0xFFFFFFFF, (uint)blocksize, buffer, 0) ^ 0xFFFFFFFF; blockHash = md5Hasher.ComputeHash(buffer, 0, (int)blocksize); //Console.WriteLine("blocknumber:{0},hash:{1},crc32:{2}", blocknumber, blockHash, blockCRC32); FileVerificationPacket.SetBlockHashAndCRC(blocknumber++, blockHash, blockCRC32); //} } FileDescriptionPacket.hashfull = md5FullHasher.Hash; } } return(true); }