Exemplo n.º 1
0
        public void ChecksumHashLarge_block_Test()
        {
            using var srcStream    = File.OpenRead($"patches{Path.DirectorySeparatorChar}a.test");
            using var targetStream = File.OpenRead($"patches{Path.DirectorySeparatorChar}b.test");
            using var md5          = MD5.Create();
            var originalHash = md5.ComputeHash(targetStream);

            targetStream.Position = 0;

            using var deltaStream  = new MemoryStream();
            using var outputStream = new MemoryStream();
            using VcEncoder coder  = new VcEncoder(srcStream, targetStream, deltaStream, blockSize: 32);
            VCDiffResult result = coder.Encode(checksumFormat: ChecksumFormat.SDCH); //encodes with no checksum and not interleaved

            Assert.Equal(VCDiffResult.SUCCESS, result);

            srcStream.Position    = 0;
            targetStream.Position = 0;
            deltaStream.Position  = 0;

            using VcDecoder decoder = new VcDecoder(srcStream, deltaStream, outputStream);
            Assert.Equal(VCDiffResult.SUCCESS, decoder.Decode(out long bytesWritten));
            outputStream.Position = 0;
            var outputHash = md5.ComputeHash(outputStream);

            Assert.Equal(originalHash, outputHash);
        }
Exemplo n.º 2
0
        public void MaxFileSize_Test()
        {
            using var srcStream    = File.OpenRead($"patches{Path.DirectorySeparatorChar}a.test");
            using var targetStream = File.OpenRead($"patches{Path.DirectorySeparatorChar}b.test");
            using var deltaStream  = new MemoryStream();
            using var outputStream = new MemoryStream();

            using VcEncoder coder = new VcEncoder(srcStream, targetStream, deltaStream);
            VCDiffResult result = coder.Encode();

            Assert.Equal(VCDiffResult.SUCCESS, result);

            srcStream.Position    = 0;
            targetStream.Position = 0;
            deltaStream.Position  = 0;

            long bytesWritten = 0;

            using VcDecoder decoder = new VcDecoder(srcStream, deltaStream, outputStream, -1);
            ArgumentException ex = Assert.Throws <ArgumentException>(() => decoder.Decode(out bytesWritten));

            Assert.Matches(@"maxWindowSize must be a positive value", ex.Message);

            srcStream.Position    = 0;
            targetStream.Position = 0;
            deltaStream.Position  = 0;

            using VcDecoder decoder1 = new VcDecoder(srcStream, deltaStream, outputStream, 2);
            InvalidOperationException ex1 = Assert.Throws <InvalidOperationException>(() => decoder1.Decode(out bytesWritten));

            Assert.Matches(@"Length of target window \(\d*\) exceeds limit of 2 bytes", ex1.Message);
        }
Exemplo n.º 3
0
        public void Interleaved_Test()
        {
            using var srcStream    = File.OpenRead($"patches{Path.DirectorySeparatorChar}a.test");
            using var targetStream = File.OpenRead($"patches{Path.DirectorySeparatorChar}b.test");
            using var deltaStream  = new MemoryStream();
            using var outputStream = new MemoryStream();
            using var md5          = MD5.Create();
            var originalHash = md5.ComputeHash(targetStream);

            targetStream.Position = 0;

            using VcEncoder coder = new VcEncoder(srcStream, targetStream, deltaStream);
            VCDiffResult result = coder.Encode(interleaved: true); //encodes with no checksum and not interleaved

            Assert.Equal(VCDiffResult.SUCCESS, result);

            srcStream.Position    = 0;
            targetStream.Position = 0;
            deltaStream.Position  = 0;

            using VcDecoder decoder = new VcDecoder(srcStream, deltaStream, outputStream);

            long bytesWritten = 0;

            while (bytesWritten < targetStream.Length)
            {
                Assert.Equal(VCDiffResult.SUCCESS, decoder.Decode(out long chunk));
                bytesWritten += chunk;
            }

            outputStream.Position = 0;
            var outputHash = md5.ComputeHash(outputStream);

            Assert.Equal(originalHash, outputHash);
        }
Exemplo n.º 4
0
        public void Interleaved_Test()
        {
            using var srcStream    = new MemoryStream(ADiffData.ToArray());
            using var targetStream = new MemoryStream(BDiffData.ToArray());
            using var deltaStream  = new MemoryStream();
            using var outputStream = new MemoryStream();
            VcEncoder    coder  = new VcEncoder(srcStream, targetStream, deltaStream);
            VCDiffResult result = coder.Encode(interleaved: true); //encodes with no checksum and not interleaved

            Assert.Equal(VCDiffResult.SUCCESS, result);

            srcStream.Position    = 0;
            targetStream.Position = 0;
            deltaStream.Position  = 0;

            VcDecoder decoder = new VcDecoder(srcStream, deltaStream, outputStream);

            long bytesWritten = 0;

            while (bytesWritten < BDiffData.Length)
            {
                Assert.Equal(VCDiffResult.SUCCESS, decoder.Decode(out long chunk));
                bytesWritten += chunk;
            }
            Assert.Equal("Goodbye World", Encoding.UTF8.GetString(outputStream.ToArray()));
        }
Exemplo n.º 5
0
        public void MaxFileSize_Test()
        {
            using var srcStream    = File.OpenRead($"patches{Path.DirectorySeparatorChar}a.test");
            using var targetStream = File.OpenRead($"patches{Path.DirectorySeparatorChar}b.test");
            using var deltaStream  = new MemoryStream();
            using var outputStream = new MemoryStream();

            using VcEncoder coder = new VcEncoder(srcStream, targetStream, deltaStream);
            VCDiffResult result = coder.Encode();

            Assert.Equal(VCDiffResult.SUCCESS, result);

            srcStream.Position    = 0;
            targetStream.Position = 0;
            deltaStream.Position  = 0;

            long bytesWritten = 0;

            using VcDecoder decoder = new VcDecoder(srcStream, deltaStream, outputStream, -1);
            Assert.Throws <ArgumentException>(() => decoder.Decode(out bytesWritten));

            srcStream.Position    = 0;
            targetStream.Position = 0;
            deltaStream.Position  = 0;

            using VcDecoder decoder1 = new VcDecoder(srcStream, deltaStream, outputStream, 2);
            Assert.Throws <InvalidOperationException>(() => decoder1.Decode(out bytesWritten));
        }
Exemplo n.º 6
0
        public void NoChecksumGoogleTo_Test()
        {
            using var srcStream    = File.OpenRead($"patches{Path.DirectorySeparatorChar}size-overflow-64");
            using var targetStream = File.OpenRead($"patches{Path.DirectorySeparatorChar}size-overflow-32");
            using var md5          = MD5.Create();
            var originalHash = md5.ComputeHash(targetStream);

            targetStream.Position = 0;

            using var deltaStream  = new MemoryStream();
            using var outputStream = new MemoryStream();
            using VcEncoder coder  = new VcEncoder(srcStream, targetStream, deltaStream);
            VCDiffResult result = coder.Encode();

            Assert.Equal(VCDiffResult.SUCCESS, result);

            srcStream.Position    = 0;
            targetStream.Position = 0;
            deltaStream.Position  = 0;

            using VcDecoder decoder = new VcDecoder(srcStream, deltaStream, outputStream);
            Assert.Equal(VCDiffResult.SUCCESS, decoder.Decode(out long bytesWritten));
            outputStream.Position = 0;
            var outputHash = md5.ComputeHash(outputStream);

            Assert.Equal(originalHash, outputHash);
        }
Exemplo n.º 7
0
        /// <summary>
        /// Function to assemble a file from delta and original and output it to the "output" file
        /// </summary>
        /// <param name="delta">Path to delta file</param>
        /// <param name="original">Path to original file</param>
        /// <param name="output">Path to output file</param>
        private static void DoDecode(string delta, string original, string output)
        {
            using (FileStream outputS = new FileStream(output, FileMode.Create, FileAccess.Write))
                using (FileStream dictS = new FileStream(original, FileMode.Open, FileAccess.Read))
                    using (FileStream targetS = new FileStream(delta, FileMode.Open, FileAccess.Read))
                    {
                        VCDecoder decoder = new VCDecoder(dictS, targetS, outputS);

                        //You must call decoder.Start() first. The header of the delta file must be available before calling decoder.Start()

                        VCDiffResult result = decoder.Start();

                        if (result != VCDiffResult.SUCCESS)
                        {
                            //error abort
                        }

                        result = decoder.Decode(out long bytesWritten);

                        if (result != VCDiffResult.SUCCESS)
                        {
                            //error decoding
                        }

                        //if success bytesWritten will contain the number of bytes that were decoded
                    }
        }
Exemplo n.º 8
0
        /// <summary>
        /// Writes the patched file into the output stream asynchronously.
        /// This method is only asynchronous for the final step of writing the patched data into the output stream.
        /// For large outputs, this may be beneficial.
        /// </summary>
        /// <returns></returns>
        public async Task <(VCDiffResult result, long bytesWritten)> DecodeAsync()
        {
            if (!Decode_Init(out var bytesWritten, out var result, out var decodeAsync))
            {
                return(decodeAsync);
            }
            while (delta.CanRead)
            {
                //delta is streamed in order aka not random access
                using var w = new WindowDecoder <TDeltaBuffer>(source.Length, delta, maxTargetFileSize);

                if (w.Decode(this.IsSDCHFormat))
                {
                    using var body = new BodyDecoder <TDeltaBuffer, TSourceBuffer, TDeltaBuffer>(w, source, delta, outputStream);
                    if (this.IsSDCHFormat && w.AddRunLength == 0 && w.AddressesForCopyLength == 0 && w.InstructionAndSizesLength > 0)
                    {
                        //interleaved
                        //decodedinterleave actually has an internal loop for waiting and streaming the incoming rest of the interleaved window
                        result = await body.DecodeInterleaveAsync();

                        if (result != VCDiffResult.SUCCESS && result != VCDiffResult.EOD)
                        {
                            return(result, bytesWritten);
                        }

                        bytesWritten += body.TotalBytesDecoded;
                    }
                    //technically add could be 0 if it is all copy instructions
                    //so do an or check on those two
                    else if (!this.IsSDCHFormat || (this.IsSDCHFormat && (w.AddRunLength > 0 || w.AddressesForCopyLength > 0) &&
                                                    w.InstructionAndSizesLength > 0))
                    {
                        //not interleaved
                        //expects the full window to be available
                        //in the stream
                        result = await body.DecodeAsync();

                        if (result != VCDiffResult.SUCCESS)
                        {
                            return(result, bytesWritten);
                        }

                        bytesWritten += body.TotalBytesDecoded;
                    }
                    else
                    {
                        //invalid file
                        return(VCDiffResult.ERROR, bytesWritten);
                    }
                }
                else
                {
                    return((VCDiffResult)w.Result, bytesWritten);
                }
            }

            return(result, bytesWritten);
        }
Exemplo n.º 9
0
        internal static void SaveDiffToFile(Stream origStream, Stream modifiedStream, Stream diffStream)
        {
            VCCoder      coder  = new VCCoder(origStream, modifiedStream, diffStream);
            VCDiffResult result = coder.Encode(); //encodes with no checksum and not interleaved

            if (result != VCDiffResult.SUCCESS)
            {
                //error was not able to encode properly
            }
        }
Exemplo n.º 10
0
        void DoDecode(string outputFile, string oldFile, string patchFile)
        {
            using (FileStream target = new FileStream(patchFile, FileMode.Open, FileAccess.Read))
            {
                byte[] oldHash = new byte[20];
                byte[] newHash = new byte[20];
                target.Read(oldHash, 0, oldHash.Length);
                target.Read(newHash, 0, newHash.Length);

                byte[] realHash = GetSha1FromFile(oldFile);

                bool oldHashMatches = CompareHashes(oldHash, realHash);

                if (!oldHashMatches)
                {
                    if (CompareHashes(realHash, newHash))
                    {
                        File.Copy(oldFile, outputFile);
                        return;
                    }
                    else
                    {
                        throw new Exception("file hash mismatch");
                    }
                }


                using (FileStream dict = new FileStream(oldFile, FileMode.Open, FileAccess.Read))
                    using (FileStream output = new FileStream(outputFile, FileMode.Create, FileAccess.Write))
                    {
                        VCDecoder decoder = new VCDecoder(dict, target, output);

                        //You must call decoder.Start() first. The header of the delta file must be available before calling decoder.Start()

                        VCDiffResult result = decoder.Start();

                        if (result != VCDiffResult.SUCCESS)
                        {
                            //error abort
                            throw new Exception("abort while decoding");
                        }

                        long bytesWritten = 0;
                        result = decoder.Decode(out bytesWritten);

                        if (result != VCDiffResult.SUCCESS)
                        {
                            //error decoding
                            throw new Exception("Error decoding");
                        }

                        //if success bytesWritten will contain the number of bytes that were decoded
                    }
            }
        }
Exemplo n.º 11
0
        /// <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);
        }
Exemplo n.º 12
0
        /// <summary>
        /// Do not run on main thread
        /// </summary>
        /// <param name="id"></param>
        /// <param name="region"></param>
        public static bool Merge(int id, string region)
        {
            if (!HasLocalData(id, region) || !HasLocalDataDiff(id, region))
            {
                return(false);
            }

            byte[] dictData  = GetLocalData(id, region);
            byte[] deltaData = GetLocalDataDiff(id, region);

            if (dictData == null || deltaData == null)
            {
                return(false);
            }

            try
            {
                using (ByteBuffer dictBuffer = new ByteBuffer(dictData))
                    using (ByteBuffer deltaBuffer = new ByteBuffer(deltaData))
                        using (MemoryStream ms = new MemoryStream())
                        {
                            VCDecoder    decoder = new VCDecoder(dictBuffer, deltaBuffer, ms);
                            VCDiffResult result  = decoder.Start();

                            if (result != VCDiffResult.SUCCESS)
                            {
                                return(false);
                            }

                            long bytesWritten = 0;
                            result = decoder.Decode(out bytesWritten);

                            if (result != VCDiffResult.SUCCESS)
                            {
                                return(false);
                            }

                            string fname = string.Format(id >= 0 ? DB_FILE : DB_REGION_FILE, region, id);
                            string fpath = Path.Combine(DirectoryPath, fname);
                            File.WriteAllBytes(fpath, ms.ToArray());
                            return(true);
                        }
            }
            catch (Exception e)
            {
                Debug.WriteLine(e.ToString());
            }

            return(false);
        }
Exemplo n.º 13
0
        /// <summary>
        /// Calculate and write a diff for the file.
        /// </summary>
        /// <param name="interleaved">Whether to output in SDCH interleaved diff format.</param>
        /// <param name="checksumFormat">
        /// Whether to include Adler32 checksums for encoded data windows. If interleaved is true, <see cref="ChecksumFormat.Xdelta3"/>
        /// is not supported.
        /// </param>
        /// <returns>
        /// <see cref="VCDiffResult.SUCCESS"/> if successful, <see cref="VCDiffResult.ERROR"/> if the sourceStream or target are zero-length.</returns>
        /// <exception cref="ArgumentException">If interleaved is true, and <see cref="ChecksumFormat.Xdelta3"/> is chosen.</exception>
        public VCDiffResult Encode(bool interleaved = false,
                                   ChecksumFormat checksumFormat = ChecksumFormat.None)
        {
            if (oldData == null)
            {
                this.oldData = new ByteBuffer(sourceStream);
            }

            if (interleaved && checksumFormat == ChecksumFormat.Xdelta3)
            {
                throw new ArgumentException("Interleaved diffs can not have an xdelta3 checksum!");
            }

            if (targetData.Length == 0 || oldData.Length == 0)
            {
                return(VCDiffResult.ERROR);
            }

            VCDiffResult result = VCDiffResult.SUCCESS;

            oldData.Position    = 0;
            targetData.Position = 0;

            // file header
            // write magic bytes
            if (!interleaved && checksumFormat != ChecksumFormat.SDCH)
            {
                outputStream.Write(MagicBytes);
            }
            else
            {
                outputStream.Write(MagicBytesExtended);
            }

            //read in all the dictionary it is the only thing that needs to be
            BlockHash dictionary = new BlockHash(oldData, 0, hasher, blockSize);

            dictionary.AddAllBlocks();
            oldData.Position = 0;

            ChunkEncoder chunker = new ChunkEncoder(dictionary, oldData, hasher, checksumFormat, interleaved, chunkSize);

            while (targetData.CanRead)
            {
                using ByteBuffer ntarget = new ByteBuffer(targetData.ReadBytesAsBuf(bufferSize));
                chunker.EncodeChunk(ntarget, outputStream);
            }

            return(result);
        }
Exemplo n.º 14
0
        public void NoChecksumNoInterleaved_Test()
        {
            using var srcStream    = File.OpenRead($"patches{Path.DirectorySeparatorChar}a.test");
            using var targetStream = File.OpenRead($"patches{Path.DirectorySeparatorChar}b.test");
            using var deltaStream  = new MemoryStream();
            using var outputStream = new MemoryStream();
            using VcEncoder coder  = new VcEncoder(srcStream, targetStream, deltaStream);
            VCDiffResult result = coder.Encode(); //encodes with no checksum and not interleaved

            Assert.Equal(VCDiffResult.SUCCESS, result);

            srcStream.Position    = 0;
            targetStream.Position = 0;
            deltaStream.Position  = 0;

            using VcDecoder decoder = new VcDecoder(srcStream, deltaStream, outputStream);
            Assert.Equal(VCDiffResult.SUCCESS, decoder.Decode(out long bytesWritten));
            Assert.NotEqual(0, bytesWritten);
        }
Exemplo n.º 15
0
        private void DoEncode(string outPatchFile, string oldFile, string newFile)
        {
            byte[] hash    = GetSha1FromFile(oldFile);
            byte[] newHash = GetSha1FromFile(newFile);
            using (FileStream output = new FileStream(outPatchFile, FileMode.Create, FileAccess.Write))
                using (FileStream dict = new FileStream(oldFile, FileMode.Open, FileAccess.Read))
                    using (FileStream target = new FileStream(newFile, FileMode.Open, FileAccess.Read))
                    {
                        output.Write(hash, 0, 20);
                        output.Write(newHash, 0, 20);

                        VCCoder      coder  = new VCCoder(dict, target, output);
                        VCDiffResult result = coder.Encode(); //encodes with no checksum and not interleaved
                        if (result != VCDiffResult.SUCCESS)
                        {
                            throw new Exception("DoEncode was not able to encode properly file: " + Path.GetFileName(oldFile));
                        }
                    }
        }
Exemplo n.º 16
0
        internal static void MergeDiffToDat(Stream origStream, Stream modifiedStream, Stream mergedStream)
        {
            VCDecoder    decoder = new VCDecoder(origStream, modifiedStream, mergedStream);
            VCDiffResult result  = decoder.Start(); //encodes with no checksum and not interleaved

            if (result != VCDiffResult.SUCCESS)
            {
                //error was not able to encode properly
            }
            else
            {
                long bytesWritten = 0;
                result = decoder.Decode(out bytesWritten);

                if (result != VCDiffResult.SUCCESS)
                {
                }
            }
        }
Exemplo n.º 17
0
        /// <summary>
        /// Create delta file from 2 files
        /// </summary>
        /// <param name="modified">File that the delta will update to</param>
        /// <param name="original">File that the delta file will use as the base</param>
        /// <param name="output">Output path for the delta file</param>
        private static void DoEncode(string modified, string original, string output)
        {
            using (FileStream outputS = new FileStream(output, FileMode.CreateNew, FileAccess.Write))
                using (FileStream dictS = new FileStream(original, FileMode.Open, FileAccess.Read))
                    using (FileStream targetS = new FileStream(modified, FileMode.Open, FileAccess.Read))
                    {
                        VCCoder      coder  = new VCCoder(dictS, targetS, outputS);
                        VCDiffResult result = coder.Encode(true, true);         //encodes with no checksum and not interleaved
                        if (result != VCDiffResult.SUCCESS)
                        {
                            Debug.WriteLine($"Something got f****d up, how to check please help");
                            //error was not able to encode properly
                        }

                        if (outputS.Length <= 5)
                        {
                            outputS.Close();
                            File.Delete(output);
                        }
                    }
        }
Exemplo n.º 18
0
        public void Checksum_Test()
        {
            using var srcStream    = new MemoryStream(ADiffData.ToArray());
            using var targetStream = new MemoryStream(BDiffData.ToArray());
            using var deltaStream  = new MemoryStream();
            using var outputStream = new MemoryStream();
            VcEncoder    coder  = new VcEncoder(srcStream, targetStream, deltaStream);
            VCDiffResult result = coder.Encode(checksumFormat: ChecksumFormat.SDCH); //encodes with no checksum and not interleaved

            Assert.Equal(VCDiffResult.SUCCESS, result);

            srcStream.Position    = 0;
            targetStream.Position = 0;
            deltaStream.Position  = 0;

            VcDecoder decoder = new VcDecoder(srcStream, deltaStream, outputStream);

            Assert.Equal(VCDiffResult.SUCCESS, decoder.Decode(out long bytesWritten));

            Assert.Equal("Goodbye World", Encoding.UTF8.GetString(outputStream.ToArray()));
        }
Exemplo n.º 19
0
        /// <summary>
        /// Use this after calling Start
        /// Each time the decode is called it is expected
        /// that at least 1 Window header is available in the stream
        /// </summary>
        /// <param name="bytesWritten">bytes decoded for all available windows</param>
        /// <returns></returns>
        public VCDiffResult Decode(out long bytesWritten)
        {
            if (!isStarted)
            {
                bytesWritten = 0;
                return(VCDiffResult.ERRROR);
            }

            VCDiffResult result = VCDiffResult.SUCCESS;

            bytesWritten = 0;

            if (!delta.CanRead)
            {
                return(VCDiffResult.EOD);
            }

            while (delta.CanRead)
            {
                //delta is streamed in order aka not random access
                WindowDecoder w = new WindowDecoder(dict.Length, delta);

                if (w.Decode(googleVersion))
                {
                    using (BodyDecoder body = new BodyDecoder(w, dict, delta, sout))
                    {
                        if (googleVersion && w.AddRunLength == 0 && w.AddressesForCopyLength == 0 && w.InstructionAndSizesLength > 0)
                        {
                            //interleaved
                            //decodedinterleave actually has an internal loop for waiting and streaming the incoming rest of the interleaved window
                            result = body.DecodeInterleave();

                            if (result != VCDiffResult.SUCCESS && result != VCDiffResult.EOD)
                            {
                                return(result);
                            }

                            bytesWritten += body.Decoded;
                        }
                        //technically add could be 0 if it is all copy instructions
                        //so do an or check on those two
                        else if (googleVersion && (w.AddRunLength > 0 || w.AddressesForCopyLength > 0) && w.InstructionAndSizesLength > 0)
                        {
                            //not interleaved
                            //expects the full window to be available
                            //in the stream

                            result = body.Decode();

                            if (result != VCDiffResult.SUCCESS)
                            {
                                return(result);
                            }

                            bytesWritten += body.Decoded;
                        }
                        else if (!googleVersion)
                        {
                            //not interleaved
                            //expects the full window to be available
                            //in the stream
                            result = body.Decode();

                            if (result != VCDiffResult.SUCCESS)
                            {
                                return(result);
                            }

                            bytesWritten += body.Decoded;
                        }
                        else
                        {
                            //invalid file
                            return(VCDiffResult.ERRROR);
                        }
                    }
                }
                else
                {
                    return((VCDiffResult)w.Result);
                }
            }

            return(result);
        }
Exemplo n.º 20
0
        private VCDiffResult DecodeInterleaveCore()
        {
            VCDiffResult result = VCDiffResult.SUCCESS;
            //since interleave expected then the last point that was most likely decoded was the lengths section
            //so following is all data for the add run copy etc
            long interleaveLength = window.InstructionAndSizesLength;

            using var previous = new MemoryStream();
            int lastDecodedSize = 0;
            VCDiffInstructionType lastDecodedInstruction = VCDiffInstructionType.NOOP;

            while (interleaveLength > 0)
            {
                if (!delta.CanRead)
                {
                    continue;
                }
                //read in
                var didBreakBeforeComplete = false;

                //try to read in all interleaved bytes
                //if not then it will buffer for next time
                previous.Write(delta.ReadBytes((int)interleaveLength).Span);
                using ByteBuffer incoming = new ByteBuffer(previous.ToArray());
                previous.SetLength(0);
                long initialLength = incoming.Length;

                InstructionDecoder instrDecoder = new InstructionDecoder(incoming, customTable);

                while (incoming.CanRead && TotalBytesDecoded < window.TargetWindowLength)
                {
                    int  decodedSize = 0;
                    byte mode        = 0;
                    VCDiffInstructionType instruction = VCDiffInstructionType.NOOP;

                    if (lastDecodedSize > 0 && lastDecodedInstruction != VCDiffInstructionType.NOOP)
                    {
                        decodedSize = lastDecodedSize;
                        instruction = lastDecodedInstruction;
                    }
                    else
                    {
                        instruction = instrDecoder.Next(out decodedSize, out mode);

                        switch (instruction)
                        {
                        case VCDiffInstructionType.EOD:
                            didBreakBeforeComplete = true;
                            break;

                        case VCDiffInstructionType.ERROR:
                            targetData.SetLength(0);
                            return(VCDiffResult.ERROR);
                        }
                    }

                    //if instruction is EOD then decodedSize will be 0 as well
                    //the last part of the buffer containing the instruction will be
                    //buffered for the next loop
                    lastDecodedInstruction = instruction;
                    lastDecodedSize        = decodedSize;

                    if (didBreakBeforeComplete)
                    {
                        //we don't have all the data so store this pointer into a temporary list to resolve next loop
                        didBreakBeforeComplete = true;
                        interleaveLength      -= incoming.Position;

                        if (initialLength - incoming.Position > 0)
                        {
                            previous.Write(incoming.ReadBytes((int)(initialLength - incoming.Position)).Span);
                        }

                        break;
                    }

                    switch (instruction)
                    {
                    case VCDiffInstructionType.ADD:
                        result = DecodeAdd(decodedSize, incoming);
                        break;

                    case VCDiffInstructionType.RUN:
                        result = DecodeRun(decodedSize, incoming);
                        break;

                    case VCDiffInstructionType.COPY:
                        result = DecodeCopy(decodedSize, mode, incoming);
                        break;

                    default:
                        targetData.SetLength(0);
                        return(VCDiffResult.ERROR);
                    }

                    if (result == VCDiffResult.EOD)
                    {
                        //we don't have all the data so store this pointer into a temporary list to resolve next loop
                        didBreakBeforeComplete = true;
                        interleaveLength      -= incoming.Position;

                        if (initialLength - incoming.Position > 0)
                        {
                            previous.Write(incoming.ReadBytes((int)(initialLength - incoming.Position)).Span);
                        }

                        break;
                    }

                    //reset these as we have successfully used them
                    lastDecodedInstruction = VCDiffInstructionType.NOOP;
                    lastDecodedSize        = 0;
                }

                if (!didBreakBeforeComplete)
                {
                    interleaveLength -= initialLength;
                }
            }

            if (window.ChecksumFormat == ChecksumFormat.SDCH)
            {
                uint adler = Checksum.ComputeGoogleAdler32(targetData.GetBuffer().AsMemory(0, (int)targetData.Length));

                if (adler != window.Checksum)
                {
                    result = VCDiffResult.ERROR;
                }
            }

            return(result);
        }
Exemplo n.º 21
0
        private VCDiffResult DecodeCore()
        {
            using ByteBuffer instructionBuffer = new ByteBuffer(window.InstructionsAndSizesData);
            using ByteBuffer addressBuffer     = new ByteBuffer(window.AddressesForCopyData);
            using ByteBuffer addRunBuffer      = new ByteBuffer(window.AddRunData);

            InstructionDecoder instrDecoder = new InstructionDecoder(instructionBuffer, customTable);

            VCDiffResult result = VCDiffResult.SUCCESS;

            while (this.TotalBytesDecoded < window.TargetWindowLength)
            {
                VCDiffInstructionType instruction = instrDecoder.Next(out int decodedSize, out byte mode);

                switch (instruction)
                {
                case VCDiffInstructionType.EOD:
                    targetData.SetLength(0);
                    return(VCDiffResult.EOD);

                case VCDiffInstructionType.ERROR:
                    targetData.SetLength(0);
                    return(VCDiffResult.ERROR);
                }

                switch (instruction)
                {
                case VCDiffInstructionType.ADD:
                    result = DecodeAdd(decodedSize, addRunBuffer);
                    break;

                case VCDiffInstructionType.RUN:
                    result = DecodeRun(decodedSize, addRunBuffer);
                    break;

                case VCDiffInstructionType.COPY:
                    result = DecodeCopy(decodedSize, mode, addressBuffer);
                    break;

                default:
                    targetData.SetLength(0);
                    return(VCDiffResult.ERROR);
                }
            }

            if (window.ChecksumFormat == ChecksumFormat.SDCH)
            {
                uint adler = Checksum.ComputeGoogleAdler32(targetData.GetBuffer().AsMemory(0, (int)targetData.Length));

                if (adler != window.Checksum)
                {
                    result = VCDiffResult.ERROR;
                }
            }
            else if (window.ChecksumFormat == ChecksumFormat.Xdelta3)
            {
                uint adler = Checksum.ComputeXdelta3Adler32(targetData.GetBuffer().AsMemory(0, (int)targetData.Length));

                if (adler != window.Checksum)
                {
                    result = VCDiffResult.ERROR;
                }
            }

            return(result);
        }
        public async override Task <ISaveGame> CreateSave(IIndelibleDirectory saveContents)
        {
            if (!this.ProfileRoot.ContainsDirectory("base"))
            {
                await this.CreateBaseSave(saveContents);
            }
            using var rollingHash = new RollingHash(32);

            // setup
            var newGuid          = Guid.NewGuid();
            var saveName         = $"{DateTimeOffset.UtcNow.ToString(DateFormat)}-{newGuid}";
            var saveDirectory    = this.ProfileRoot.OpenDirectory(saveName);
            var contentDirectory = saveDirectory.OpenDirectory("content");

            // diff is for anything that exists in the base directory
            var diffDir = contentDirectory.OpenDirectory("diff");

            // copy is for anything that does not and can not be diffed.
            var copyDir = contentDirectory.OpenDirectory("copy");

            // Traverse base directory in tandem with saveContents
            var baseDir = this.ProfileRoot.OpenDirectory("base/content").AsReadOnly();

            foreach (var f in saveContents.EnumerateFiles())
            {
                if (!baseDir.ContainsFile(f.Name))
                {
                    await copyDir.CopyFromAsync(f);

                    continue;
                }

                using var targetStream = f.OpenReadStream();
                using var baseStream   = baseDir.OpenFile(f.Name).OpenReadStream();

                using var outStream = diffDir.OpenFile(f.Name).OpenStream();
                using var decoder   = new VcEncoder(baseStream, targetStream, outStream,
                                                    rollingHash: rollingHash, blockSize: 32);
                VCDiffResult result = await decoder.EncodeAsync();

                if (result != VCDiffResult.SUCCESS)
                {
                    throw new IOException($"Failed to encode delta for {f.Name}");
                }
            }

            foreach (var d in saveContents.EnumerateDirectories().Where(d => !baseDir.ContainsDirectory(d.Name)))
            {
                // Copy all directories not in the base.
                await foreach (var _ in copyDir.OpenDirectory(d.Name).CopyFromDirectory(d))
                {
                }
                ;
            }

            var queuedDirs = (from targetDir in saveContents.EnumerateDirectories()
                              where baseDir.ContainsDirectory(targetDir.Name)
                              select(diffDir, baseDir.OpenDirectory(targetDir.Name), targetDir)).ToList();

            Queue <(IDirectory parentDir, IReadOnlyDirectory baseDir, IDirectory targetDir)> dirsToProcess =
                new Queue <(IDirectory, IReadOnlyDirectory, IDirectory)>(queuedDirs);

            while (dirsToProcess.Count > 0)
            {
                var(parent, src, diff) = dirsToProcess.Dequeue();
                var dst = parent.OpenDirectory(src.Name);
                foreach (var f in src.EnumerateFiles())
                {
                    if (!diff.ContainsFile(f.Name))
                    {
                        continue;
                    }
                    using var baseStream   = f.OpenReadStream();
                    using var targetStream = diff.OpenFile(f.Name).OpenReadStream();
                    using var outStream    = dst.OpenFile(f.Name).OpenStream();
                    using var decoder      = new VcEncoder(baseStream, targetStream, outStream,
                                                           rollingHash: rollingHash, blockSize: 32);
                    VCDiffResult result = await decoder.EncodeAsync();

                    if (result != VCDiffResult.SUCCESS)
                    {
                        throw new IOException($"Failed to decode delta for {f.Name}");
                    }
                }

                var children = from targetDir in diff.EnumerateDirectories()
                               where src.ContainsDirectory(targetDir.Name)
                               select(dst, src.OpenDirectory(targetDir.Name), targetDir);

                foreach (var childDirectory in children)
                {
                    dirsToProcess.Enqueue(childDirectory);
                }
            }

            this.ProfileRoot.OpenFile("latest").WriteAllText(saveName, Encoding.UTF8);
            return(this.GetSave(saveDirectory) !);
        }
Exemplo n.º 23
0
        /// <summary>
        /// Decode if as expecting interleave
        /// </summary>
        /// <returns></returns>
        public VCDiffResult DecodeInterleave()
        {
            VCDiffResult result = VCDiffResult.SUCCESS;
            //since interleave expected then the last point that was most likely decoded was the lengths section
            //so following is all data for the add run copy etc
            long                  interleaveLength       = window.InstructionAndSizesLength;
            List <byte>           previous               = new List <byte>();
            bool                  didBreakBeforeComplete = false;
            int                   lastDecodedSize        = 0;
            VCDiffInstructionType lastDecodedInstruction = VCDiffInstructionType.NOOP;

            while (interleaveLength > 0)
            {
                if (target.CanRead)
                {
                    //read in
                    didBreakBeforeComplete = false;

                    //try to read in all interleaved bytes
                    //if not then it will buffer for next time
                    previous.AddRange(target.ReadBytes((int)interleaveLength));
                    ByteBuffer incoming = new ByteBuffer(previous.ToArray());
                    previous.Clear();
                    long initialLength = incoming.Length;

                    InstructionDecoder instrDecoder = new InstructionDecoder(incoming, this.customTable);

                    while (incoming.CanRead && decodedOnly < window.DecodedDeltaLength)
                    {
                        int  decodedSize = 0;
                        byte mode        = 0;
                        VCDiffInstructionType instruction = VCDiffInstructionType.NOOP;

                        if (lastDecodedSize > 0 && lastDecodedInstruction != VCDiffInstructionType.NOOP)
                        {
                            decodedSize = lastDecodedSize;
                            instruction = lastDecodedInstruction;
                        }
                        else
                        {
                            instruction = instrDecoder.Next(out decodedSize, out mode);

                            switch (instruction)
                            {
                            case VCDiffInstructionType.EOD:
                                didBreakBeforeComplete = true;
                                break;

                            case VCDiffInstructionType.ERROR:
                                targetData.Clear();
                                return(VCDiffResult.ERRROR);

                            default:
                                break;
                            }
                        }

                        //if instruction is EOD then decodedSize will be 0 as well
                        //the last part of the buffer containing the instruction will be
                        //buffered for the next loop
                        lastDecodedInstruction = instruction;
                        lastDecodedSize        = decodedSize;

                        if (didBreakBeforeComplete)
                        {
                            //we don't have all the data so store this pointer into a temporary list to resolve next loop
                            didBreakBeforeComplete = true;
                            interleaveLength      -= incoming.Position;

                            if (initialLength - incoming.Position > 0)
                            {
                                previous.AddRange(incoming.ReadBytes((int)(initialLength - incoming.Position)));
                            }

                            break;
                        }

                        switch (instruction)
                        {
                        case VCDiffInstructionType.ADD:
                            result = DecodeAdd(decodedSize, incoming);
                            break;

                        case VCDiffInstructionType.RUN:
                            result = DecodeRun(decodedSize, incoming);
                            break;

                        case VCDiffInstructionType.COPY:
                            result = DecodeCopy(decodedSize, mode, incoming);
                            break;

                        default:
                            targetData.Clear();
                            return(VCDiffResult.ERRROR);
                        }

                        if (result == VCDiffResult.EOD)
                        {
                            //we don't have all the data so store this pointer into a temporary list to resolve next loop
                            didBreakBeforeComplete = true;
                            interleaveLength      -= incoming.Position;

                            if (initialLength - incoming.Position > 0)
                            {
                                previous.AddRange(incoming.ReadBytes((int)(initialLength - incoming.Position)));
                            }

                            break;
                        }

                        //reset these as we have successfully used them
                        lastDecodedInstruction = VCDiffInstructionType.NOOP;
                        lastDecodedSize        = 0;
                    }

                    if (!didBreakBeforeComplete)
                    {
                        interleaveLength -= initialLength;
                    }
                }
            }

            if (window.HasChecksum)
            {
                uint adler = Checksum.ComputeAdler32(targetData.ToArray());

                if (adler != window.Checksum)
                {
                    result = VCDiffResult.ERRROR;
                }
            }

            targetData.Clear();
            return(result);
        }
Exemplo n.º 24
0
        /// <summary>
        /// Decode normally
        /// </summary>
        /// <returns></returns>
        public VCDiffResult Decode()
        {
            ByteBuffer instructionBuffer = new ByteBuffer(window.InstructionsAndSizesData);
            ByteBuffer addressBuffer     = new ByteBuffer(window.AddressesForCopyData);
            ByteBuffer addRunBuffer      = new ByteBuffer(window.AddRunData);

            InstructionDecoder instrDecoder = new InstructionDecoder(instructionBuffer, this.customTable);

            VCDiffResult result = VCDiffResult.SUCCESS;

            while (decodedOnly < window.DecodedDeltaLength && instructionBuffer.CanRead)
            {
                int  decodedSize = 0;
                byte mode        = 0;

                VCDiffInstructionType instruction = instrDecoder.Next(out decodedSize, out mode);

                switch (instruction)
                {
                case VCDiffInstructionType.EOD:
                    targetData.Clear();
                    return(VCDiffResult.EOD);

                case VCDiffInstructionType.ERROR:
                    targetData.Clear();
                    return(VCDiffResult.ERRROR);

                default:
                    break;
                }

                switch (instruction)
                {
                case VCDiffInstructionType.ADD:
                    result = DecodeAdd(decodedSize, addRunBuffer);
                    break;

                case VCDiffInstructionType.RUN:
                    result = DecodeRun(decodedSize, addRunBuffer);
                    break;

                case VCDiffInstructionType.COPY:
                    result = DecodeCopy(decodedSize, mode, addressBuffer);
                    break;

                default:
                    targetData.Clear();
                    return(VCDiffResult.ERRROR);
                }
            }

            if (window.HasChecksum)
            {
                uint adler = Checksum.ComputeAdler32(targetData.ToArray());

                if (adler != window.Checksum)
                {
                    result = VCDiffResult.ERRROR;
                }
            }

            targetData.Clear();
            return(result);
        }
Exemplo n.º 25
0
 private bool Decode_Init(out long bytesWritten, out VCDiffResult result, out (VCDiffResult result, long bytesWritten) decodeAsync)
Exemplo n.º 26
0
        /// <summary>
        /// Writes the patched file into the output stream.
        /// </summary>
        /// <param name="bytesWritten">Number of bytes written into the output stream.</param>
        /// <returns></returns>
        public VCDiffResult Decode(out long bytesWritten)
        {
            if (!this.IsInitialized)
            {
                var initializeResult = this.Initialize();
                if (initializeResult != VCDiffResult.SUCCESS || !this.IsInitialized)
                {
                    bytesWritten = 0;
                    return initializeResult;
                }
            }

            VCDiffResult result = VCDiffResult.SUCCESS;
            bytesWritten = 0;

            if (!delta.CanRead) return VCDiffResult.EOD;

            while (delta.CanRead)
            {
                //delta is streamed in order aka not random access
                WindowDecoder w = new WindowDecoder(source.Length, delta);

                if (w.Decode(this.IsSDCHFormat))
                {
                    using BodyDecoder body = new BodyDecoder(w, source, delta, outputStream);
                    if (this.IsSDCHFormat && w.AddRunLength == 0 && w.AddressesForCopyLength == 0 && w.InstructionAndSizesLength > 0)
                    {
                        //interleaved
                        //decodedinterleave actually has an internal loop for waiting and streaming the incoming rest of the interleaved window
                        result = body.DecodeInterleave();

                        if (result != VCDiffResult.SUCCESS && result != VCDiffResult.EOD)
                        {
                            return result;
                        }

                        bytesWritten += body.TotalBytesDecoded;
                    }
                    //technically add could be 0 if it is all copy instructions
                    //so do an or check on those two
                    else if (!this.IsSDCHFormat || (this.IsSDCHFormat && (w.AddRunLength > 0 || w.AddressesForCopyLength > 0) && w.InstructionAndSizesLength > 0))
                    {
                        //not interleaved
                        //expects the full window to be available
                        //in the stream

                        result = body.Decode();

                        if (result != VCDiffResult.SUCCESS)
                        {
                            return result;
                        }

                        bytesWritten += body.TotalBytesDecoded;
                    }
                    else
                    {
                        //invalid file
                        return VCDiffResult.ERROR;
                    }
                }
                else
                {
                    return (VCDiffResult)w.Result;
                }
            }

            return result;
        }
Exemplo n.º 27
0
        /// <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>
        private VCDiffResult Initialize()
        {
            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.ERROR;
            }

            if (C != MagicBytes[1])
            {
                return VCDiffResult.ERROR;
            }

            if (D != MagicBytes[2])
            {
                return VCDiffResult.ERROR;
            }

            if (version != 0x00 && version != 'S')
            {
                return VCDiffResult.ERROR;
            }

            //compression not supported
            if ((hdr & (int)VCDiffCodeFlags.VCDDECOMPRESS) != 0)
            {
                return VCDiffResult.ERROR;
            }

            //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;
                }
            }

            if ((hdr & (int)VCDiffCodeFlags.VCDAPPHEADER) != 0)
            {
                if (!delta.CanRead) return VCDiffResult.EOD;
                
                int headerLength = VarIntBE.ParseInt32(delta);
                // skip the app header
                delta.ReadBytes(headerLength);
            }


            this.IsSDCHFormat = version == 'S';

            this.IsInitialized = true;

            return VCDiffResult.SUCCESS;
        }
Exemplo n.º 28
0
        /// <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);
        }
        public VCDiffResult Decode(IByteBuffer source)
        {
            VCDiffResult result = VCDiffResult.Succes;

            //the custom codetable itself is a VCDiff file but it is required to be encoded with the standard table
            //the length should be the first thing after the hdr_indicator if not supporting compression
            //at least according to the RFC specs.
            int lengthOfCodeTable = VarIntBE.ParseInt32(source);

            if (lengthOfCodeTable == 0)
            {
                return(VCDiffResult.Error);
            }

            ByteBuffer codeTable = new ByteBuffer(source.ReadBytes(lengthOfCodeTable));

            //according to the RFC specifications the next two items will be the size of near and size of same
            //they are bytes in the RFC spec, but for some reason Google uses the varint to read which does
            //the same thing if it is a single byte
            //but I am going to just read in bytes because it is the RFC standard
            NearSize = codeTable.ReadByte();
            SameSize = codeTable.ReadByte();

            if (NearSize == 0 || SameSize == 0 || NearSize > byte.MaxValue || SameSize > byte.MaxValue)
            {
                return(VCDiffResult.Error);
            }

            CustomTable = new CodeTable();
            //get the original bytes of the default codetable to use as a dictionary
            IByteBuffer dictionary = CustomTable.GetBytes();

            //Decode the code table VCDiff file itself
            //stream the decoded output into a memory stream
            using (MemoryStream sout = new MemoryStream())
            {
                VCDecoder decoder = new VCDecoder(dictionary, codeTable, sout);
                result = decoder.Start();

                if (result != VCDiffResult.Succes)
                {
                    return(result);
                }

                long bytesWritten = 0;
                result = decoder.Decode(out bytesWritten);

                if (result != VCDiffResult.Succes || bytesWritten == 0)
                {
                    return(VCDiffResult.Error);
                }

                //set the new table data that was decoded
                if (!CustomTable.SetBytes(sout.ToArray()))
                {
                    result = VCDiffResult.Error;
                }
            }

            return(result);
        }