/// <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); }
/// <summary> /// Call this before calling decode /// This expects at least the header part of the delta file /// is available in the stream /// </summary> /// <returns></returns> public VCDiffResult Start() { if (!delta.CanRead) { return(VCDiffResult.EOD); } byte V = delta.ReadByte(); if (!delta.CanRead) { return(VCDiffResult.EOD); } byte C = delta.ReadByte(); if (!delta.CanRead) { return(VCDiffResult.EOD); } byte D = delta.ReadByte(); if (!delta.CanRead) { return(VCDiffResult.EOD); } byte version = delta.ReadByte(); if (!delta.CanRead) { return(VCDiffResult.EOD); } byte hdr = delta.ReadByte(); if (V != MagicBytes[0]) { return(VCDiffResult.ERRROR); } if (C != MagicBytes[1]) { return(VCDiffResult.ERRROR); } if (D != MagicBytes[2]) { return(VCDiffResult.ERRROR); } if (version != 0x00 && version != 'S') { return(VCDiffResult.ERRROR); } //compression not supported if ((hdr & (int)VCDiffCodeFlags.VCDDECOMPRESS) != 0) { return(VCDiffResult.ERRROR); } //custom code table! if ((hdr & (int)VCDiffCodeFlags.VCDCODETABLE) != 0) { if (!delta.CanRead) { return(VCDiffResult.EOD); } //try decoding the custom code table //since we don't support the compress the next line should be the length of the code table customTable = new CustomCodeTableDecoder(); VCDiffResult result = customTable.Decode(delta); if (result != VCDiffResult.SUCCESS) { return(result); } } googleVersion = version == 'S'; isStarted = true; //buffer all the dictionary up front dict.BufferAll(); return(VCDiffResult.SUCCESS); }