public static void WriteCommonHeader(Signature signature) { // Writing the initial header signature.Output.Write(RDiffBinary.SIGNATURE_MAGIC, 0, RDiffBinary.SIGNATURE_MAGIC.Length); signature.Output.Write(RDiffBinary.FixEndian(BitConverter.GetBytes(signature.BlockLength)), 0, 4); signature.Output.Write(RDiffBinary.FixEndian(BitConverter.GetBytes(signature.StrongLength)), 0, 4); }
/// <summary> /// Adds a chunck of data to checksum list /// </summary> /// <param name="buffer">The data to add a checksum entry for</param> /// <param name="index">The index in the buffer to start reading from</param> /// <param name="count">The number of bytes to extract from the array</param> private static void AddChunk(Signature signature, byte[] buffer, int index, int count) { //Add weak checksum (Adler-32) to the chunk signature.Output.Write(RDiffBinary.FixEndian(BitConverter.GetBytes(Adler32Checksum.Calculate(buffer, index, count))), 0, 4); //Add strong checksum signature.Output.Write(Utility.Hash.ComputeHash(buffer, index, count), 0, signature.StrongLength); }
/// <summary> /// Writes a literal command to a delta stream /// </summary> /// <param name="data">The literal data to write</param> /// <param name="output">The output delta stream</param> private static void WriteLiteral(byte[] data, DeltaBlock <int> block, Stream output) { byte[] lengthArray; output.WriteByte((byte)RDiffBinary.FindLiteralDeltaCommand(block.Size)); lengthArray = RDiffBinary.EncodeLength(block.Size); output.Write(lengthArray, 0, lengthArray.Length); output.Write(data, block.Offset, block.Size); }
/// <summary> /// Write a copy command to a delta stream /// </summary> /// <param name="offset">The offset in the basefile where the data is located</param> /// <param name="length">The length of the data to copy</param> /// <param name="output">The output delta stream</param> private static void WriteCopy(DeltaBlock <long> block, Stream output) { byte[] lengthArray; output.WriteByte((byte)RDiffBinary.FindCopyDeltaCommand(block)); lengthArray = RDiffBinary.EncodeLength(block.Offset); output.Write(lengthArray, 0, lengthArray.Length); lengthArray = RDiffBinary.EncodeLength(block.Size); output.Write(lengthArray, 0, lengthArray.Length); }
private int ReadStrongLength(Stream input, byte[] buffer) { int response; Utility.ReadChunk(input, buffer); response = BitConverter.ToInt32(RDiffBinary.FixEndian(buffer), 0); if (response < 1 || response > (Utility.Hash.HashSize / 8)) { throw new Exception(string.Format(Strings.ChecksumFile.InvalidStrongsizeError, response)); } return(response); }
private int ReadBlockLength(Stream input, byte[] buffer) { int response; // Reading block lenght (stram must be in the right position Utility.ReadChunk(input, buffer); // Getting the block length response = BitConverter.ToInt32(RDiffBinary.FixEndian(buffer), 0); // Validating the block length if (response < 1 || response > int.MaxValue / 2) { throw new Exception(string.Format(Strings.ChecksumFile.InvalidBlocksizeError, response)); } return(response); }
public ChecksumGenerator(Stream inputFileStream) { byte[] tempBuffer; int byteCounter; _signatureByteList = new List <byte>(); _signatureByteList.AddRange(RDiffBinary.SIGNATURE_MAGIC); _signatureByteList.AddRange(RDiffBinary.FixEndian(BitConverter.GetBytes(DEFAULT_BLOCK_SIZE))); _signatureByteList.AddRange(RDiffBinary.FixEndian(BitConverter.GetBytes(DEFAULT_STRONG_LEN))); tempBuffer = new byte[DEFAULT_BLOCK_SIZE]; while ((byteCounter = inputFileStream.Read(tempBuffer, 0, tempBuffer.Length)) != 0) { AddSignatureChunk(tempBuffer, 0, byteCounter); } _signature = _signatureByteList.ToArray(); }
/// <summary> /// Adds a chunck of data to checksum list /// </summary> /// <param name="buffer">The data to add a checksum entry for</param> /// <param name="index">The index in the buffer to start reading from</param> /// <param name="count">The number of bytes to extract from the array</param> private void AddSignatureChunk(byte[] buffer, int index, int count) { byte[] tempBuffer; //if (!hashAlgorithm.CanReuseTransform) //{ // hashAlgorithm = MD5.Create(); //} _signatureByteList.AddRange( RDiffBinary.FixEndian( BitConverter.GetBytes( Adler32Checksum.Calculate(buffer, index, count)))); //Add first half of the computed hash tempBuffer = Utility.Hash.ComputeHash(buffer, index, count); for (int i = 0; i < DEFAULT_STRONG_LEN; i++) { _signatureByteList.Add(tempBuffer[i]); } }
/// <summary> /// Reads a ChecksumFile from a stream /// </summary> /// <param name="input">The stream to read from</param> public ChecksumFileReader(Stream input) { #region Variables byte[] readBuffer; int strongLength; long chunkCount; uint weak; byte[] strongBuffer; List <ulong> tempStrongIndex; #endregion readBuffer = new byte[4]; Utility.ValidateSignature(input, readBuffer, RDiffBinary.SIGNATURE_MAGIC); // Saving the block length for future reference _checksumBlockLenght = ReadBlockLength(input, readBuffer); /// The number of bytes used for storing a single strong signature strongLength = ReadBlockLength(input, readBuffer); //Prepare the data structures _weakLookup = new HashSet <uint>(); //new bool[ushort.MaxValue + 1]; //bool[0x10000]; _longsPerStrong = (strongLength + (BYTES_PER_LONG - 1)) / BYTES_PER_LONG; strongBuffer = new byte[_longsPerStrong * BYTES_PER_LONG]; //We would like to use static allocation for these lists, but unfortunately // the zip stream does not report the correct length _weakKeysIndex = new Dictionary <uint, List <long> >(); tempStrongIndex = new List <ulong>(); chunkCount = 0; //Repeat until the stream is exhausted while (Utility.ForceStreamRead(input, readBuffer, 4) == 4) { weak = BitConverter.ToUInt32(RDiffBinary.FixEndian(readBuffer), 0); if (Utility.ForceStreamRead(input, strongBuffer, strongLength) != strongLength) { throw new Exception(Strings.ChecksumFile.EndofstreamInStrongSignatureError); } // Ensure key existance if (!_weakKeysIndex.ContainsKey(weak)) { _weakKeysIndex.Add(weak, new List <long>()); } //Record the entries _weakKeysIndex[weak].Add(chunkCount); for (int i = 0; i < _longsPerStrong; i++) { tempStrongIndex.Add(BitConverter.ToUInt64(strongBuffer, i * BYTES_PER_LONG)); } chunkCount++; } // Storing the indexes in permanent arrays _strongIndex = tempStrongIndex.ToArray(); }
/// <summary> /// Creates a new file based on the basefile and the delta information. /// The basefile and output stream cannot point to the same resource (ea. file). /// The base file MUST be seekable. /// </summary> /// <param name="basefile">A seekable stream with the baseinformation</param> /// <param name="output">The stream to write the patched data to. Must not point to the same resource as the basefile.</param> public static void PatchFile(Stream basefile, Stream output, Stream deltaFile) { #region Variables byte[] readBuffer; int command; int commandLength; byte[] commandBuffer; long chunkSize; long baseFileOffset; #endregion readBuffer = new byte[4]; Utility.ValidateSignature(deltaFile, readBuffer, RDiffBinary.DELTA_MAGIC); // Reading the first command command = deltaFile.ReadByte(); //Keep reading until we hit the end command while (command != RDiffBinary.EndCommand) { // It is an error to omit the end command if (command < 0) { throw new Exception(Strings.DeltaFile.EndofstreamWithoutMarkerError); } if (Enum.IsDefined(typeof(LiteralDeltaCommand), (LiteralDeltaCommand)command)) { // Find out how many bytes of literal data there is commandLength = RDiffBinary.GetLiteralLength((LiteralDeltaCommand)command); commandBuffer = new byte[commandLength]; if (Utility.ForceStreamRead(deltaFile, commandBuffer, commandBuffer.Length) != commandBuffer.Length) { throw new Exception(Strings.DeltaFile.UnexpectedEndofstreamError); } chunkSize = RDiffBinary.DecodeLength(commandBuffer); if (chunkSize < 0) { throw new Exception(Strings.DeltaFile.InvalidLitteralSizeError); } // Copy the literal data from the patch to the output Utility.StreamCopy(deltaFile, output, chunkSize); } else if (Enum.IsDefined(typeof(CopyDeltaCommand), (CopyDeltaCommand)command)) { // Find the offset of the data in the base file commandLength = RDiffBinary.GetCopyOffsetSize((CopyDeltaCommand)command); commandBuffer = new byte[commandLength]; if (Utility.ForceStreamRead(deltaFile, commandBuffer, commandBuffer.Length) != commandBuffer.Length) { throw new Exception(Strings.DeltaFile.UnexpectedEndofstreamError); } baseFileOffset = RDiffBinary.DecodeLength(commandBuffer); if (baseFileOffset < 0) { throw new Exception(Strings.DeltaFile.InvalidCopyOffsetError); } //Find the length of the data to copy from the basefile commandLength = RDiffBinary.GetCopyLengthSize((CopyDeltaCommand)command); commandBuffer = new byte[commandLength]; if (Utility.ForceStreamRead(deltaFile, commandBuffer, commandBuffer.Length) != commandBuffer.Length) { throw new Exception(Strings.DeltaFile.UnexpectedEndofstreamError); } chunkSize = RDiffBinary.DecodeLength(commandBuffer); if (chunkSize < 0) { throw new Exception(Strings.DeltaFile.InvalidCopyLengthError); } //Seek to the begining, and copy basefile.Position = baseFileOffset; Utility.StreamCopy(basefile, output, chunkSize); } else if (command <= RDiffBinary.LiteralLimit) { //Literal data less than 64 bytes are found, copy it Utility.StreamCopy(deltaFile, output, command); } else { throw new Exception(Strings.DeltaFile.UnknownCommandError); } // Read the next command command = deltaFile.ReadByte(); } output.Flush(); }