VCDiffResult DecodeCopy(int size, byte mode, ByteBuffer addresses) { long here = window.SourceLength + decodedOnly; long decoded = addressCache.DecodeAddress(here, mode, addresses); switch ((VCDiffResult)decoded) { case VCDiffResult.ERRROR: return(VCDiffResult.ERRROR); case VCDiffResult.EOD: return(VCDiffResult.EOD); default: if (decoded < 0 || decoded > here) { return(VCDiffResult.ERRROR); } break; } if (decoded + size <= window.SourceLength) { dict.Position = decoded; byte[] rbytes = dict.ReadBytes(size); sout.writeBytes(rbytes); targetData.AddRange(rbytes); decodedOnly += size; return(VCDiffResult.SUCCESS); } ///will come back to this once ///target data reading is implemented /*if(decoded < window.SourceLength) * { * long partial = window.SourceLength - decoded; * dict.Position = decoded; * sout.writeBytes(dict.ReadBytes((int)partial)); * bytesWritten += partial; * size -= (int)partial; * } * * decoded -= window.SourceLength; * * while(size > (bytesDecoded - decoded)) * { * long partial = bytesDecoded - decoded; * target.Position = decoded; * sout.writeBytes(target.ReadBytes((int)partial)); * decoded += partial; * size -= (int)partial; * bytesWritten += partial; * } * * target.Position = decoded; * sout.writeBytes(target.ReadBytes(size));*/ return(VCDiffResult.ERRROR); }
/// <summary> /// Encodes the file /// </summary> /// <param name="interleaved">Set this to true to enable SDHC interleaved vcdiff google format</param> /// <param name="checksum">Set this to true to add checksum for encoded data windows</param> /// <returns></returns> public VCDiffResult Encode(bool interleaved = false, bool checksum = false) { if (newData.Length == 0 || oldData.Length == 0) { return(VCDiffResult.Error); } VCDiffResult result = VCDiffResult.Succes; oldData.Position = 0; newData.Position = 0; //file header //write magic bytes if (!interleaved && !checksum) { sout.writeBytes(MagicBytes); } else { sout.writeBytes(MagicBytesExtended); } //buffer the whole olddata (dictionary) //otherwise it will be a slow process //even Google's version reads in the entire dictionary file to memory //it is just faster that way because of having to move the memory pointer around //to find all the hash comparisons and stuff. //It is much slower trying to random access read from file with FileStream class //however the newData is read in chunks and processed for memory efficiency and speed oldData.BufferAll(); //read in all the dictionary it is the only thing that needs to be BlockHash dictionary = new BlockHash(oldData, 0, hasher); dictionary.AddAllBlocks(); oldData.Position = 0; ChunkEncoder chunker = new ChunkEncoder(dictionary, oldData, hasher, interleaved, checksum); while (newData.CanRead) { using (ByteBuffer ntarget = new ByteBuffer(newData.ReadBytes(bufferSize))) { chunker.EncodeChunk(ntarget, sout); } //just in case // System.GC.Collect(); } return(result); }
public void Output(ByteStreamWriter sout) { int lengthOfDelta = CalculateLengthOfTheDeltaEncoding(); int windowSize = lengthOfDelta + 1 + VarIntBE.CalcInt32Length((int)dictionarySize) + VarIntBE.CalcInt32Length(0); VarIntBE.CalcInt32Length(lengthOfDelta); //Google's Checksum Implementation Support if (hasChecksum) { sout.writeByte((byte)VCDiffWindowFlags.VCDSOURCE | (byte)VCDiffWindowFlags.VCDCHECKSUM); //win indicator } else { sout.writeByte((byte)VCDiffWindowFlags.VCDSOURCE); //win indicator } VarIntBE.AppendInt32((int)dictionarySize, sout); //dictionary size VarIntBE.AppendInt32(0, sout); //dictionary start position 0 is default aka encompass the whole dictionary VarIntBE.AppendInt32(lengthOfDelta, sout); //length of delta //begin of delta encoding Int64 sizeBeforeDelta = sout.Position; VarIntBE.AppendInt32((int)targetLength, sout); //final target length after decoding sout.writeByte(0x00); //uncompressed // [Here is where a secondary compressor would be used // if the encoder and decoder supported that feature.] //non interleaved then it is separata areas for each type if (!interleaved) { VarIntBE.AppendInt32(dataForAddAndRun.Count, sout); //length of add/run VarIntBE.AppendInt32(instructionAndSizes.Count, sout); //length of instructions and sizes VarIntBE.AppendInt32(addressForCopy.Count, sout); //length of addresses for copys //Google Checksum Support if (hasChecksum) { VarIntBE.AppendInt64(checksum, sout); } sout.writeBytes(dataForAddAndRun.ToArray()); //data section for adds and runs sout.writeBytes(instructionAndSizes.ToArray()); //data for instructions and sizes sout.writeBytes(addressForCopy.ToArray()); //data for addresses section copys } else { //interleaved everything is woven in and out in one block VarIntBE.AppendInt32(0, sout); //length of add/run VarIntBE.AppendInt32(instructionAndSizes.Count, sout); //length of instructions and sizes + other data for interleaved VarIntBE.AppendInt32(0, sout); //length of addresses for copys //Google Checksum Support if (hasChecksum) { VarIntBE.AppendInt64(checksum, sout); } sout.writeBytes(instructionAndSizes.ToArray()); //data for instructions and sizes, in interleaved it is everything } //end of delta encoding Int64 sizeAfterDelta = sout.Position; if (lengthOfDelta != sizeAfterDelta - sizeBeforeDelta) { Console.WriteLine("Delta output length does not match"); } dataForAddAndRun.Clear(); instructionAndSizes.Clear(); addressForCopy.Clear(); if (targetLength == 0) { Console.WriteLine("Empty target window"); } addrCache = new AddressCache(); }