Example #1
0
        public void FormatPatch(PatchFileInformation fileInfo, IList<SameBlock> sameBlocks, Stream target, Stream output)
        {
            using (var bw = new BinaryWriter(output)) {
                #region Patch File Preface
                bw.Write((UInt32)0x54415056); // Write magic header
                UInt32 fileCount = 0x80000000; // MD5 mode. Top byte is for extensions.
                fileCount += 1; // We're only packing one file in.
                bw.Write((UInt32)fileCount); // Go ahead and put the file count in.
                #endregion

                #region Current File Preface
                long bodySize = 0;
                long noBlocks = 0;
                long noBlocksOffset = output.Position;
                bw.Write((UInt32)noBlocks);
                bw.Write(fileInfo.SourceChecksum, 0, 16);
                bw.Write(fileInfo.TargetChecksum, 0, 16);
                long bodySizeOffset = output.Position;
                bw.Write((UInt32)bodySize);
                #endregion

                byte[] copyBuffer = new byte[COPY_BUF_SIZE];
                for(int iter = 0; iter < sameBlocks.Count; iter++) {
                    SameBlock current = sameBlocks[iter];

                    // store current block
                    if(current.Size > 0) {
                        // copy block from sourceFile
                        if(current.Size < 256) {
                            bw.Write((byte)1);
                            bw.Write((byte)current.Size);
                            bodySize += 2;
                        } else if(current.Size < 65536) {
                            bw.Write((byte)2);
                            bw.Write((UInt16)current.Size);
                            bodySize += 3;
                        } else {
                            bw.Write((byte)3);
                            bw.Write((UInt32)current.Size);
                            bodySize += 5;
                        }
                        bw.Write((UInt32)current.SourceOffset);
                        bodySize += 4;
                        noBlocks++;
                    }
                    iter++;
                    if(iter >= sameBlocks.Count) break;
                    SameBlock next = sameBlocks[iter];
                    iter--;

                    // calculate area inbetween this block and the next
                    long notFoundStart = current.TargetOffset+current.Size;
                    if(notFoundStart > next.TargetOffset) {
                        throw new InvalidOperationException("makeBinaryPatch input problem: there was overlap");
                    }
                    long notFoundSize = next.TargetOffset - notFoundStart;
                    if(notFoundSize > 0) {
                        // we need to include this area in the patch directly
                        if(notFoundSize < 256) {
                            bw.Write((byte)5);
                            bw.Write((byte)notFoundSize);
                            bodySize += 2;
                        } else if(notFoundSize < 65536) {
                            bw.Write((byte)6);
                            bw.Write((UInt16)notFoundSize);
                            bodySize += 3;
                        } else {
                            bw.Write((byte)7);
                            bw.Write((UInt32)notFoundSize);
                            bodySize += 5;
                        }
                        // copy from target...
                        target.Seek(notFoundStart, SeekOrigin.Begin);
                        for(long i = 0; i < notFoundSize; i += COPY_BUF_SIZE) {
                            long j = notFoundSize - i;
                            if(j > COPY_BUF_SIZE) j = COPY_BUF_SIZE;
                            target.Read(copyBuffer, 0, (int)j);
                            output.Write(copyBuffer, 0, (int)j);
                        }
                        bodySize += notFoundSize;
                        noBlocks++;
                    }
                }

                // we are done, now add just one extra block with the target file time
                bw.Write((byte)255);
                long time = fileInfo.TargetDateTime.ToBinary();

                bw.Write((Int64)time);

                noBlocks++;
                bodySize += 9;

                long curPos = output.Position;
                output.Seek(noBlocksOffset, SeekOrigin.Begin);
                bw.Write((UInt32)noBlocks);
                output.Seek(bodySizeOffset, SeekOrigin.Begin);
                bw.Write((UInt32)bodySize);
                output.Seek(curPos, SeekOrigin.Begin);
            }
        }
Example #2
0
 public void Clear()
 {
     mPatFileInfo = new PatchFileInformation();
 }
Example #3
0
        /// <summary>
        /// Takes a stream for an old version of a file, preparing a
        /// block-by-block patch to transform it in to the new version of a
        /// file. The given formatter is used to output the prepared data,
        /// which is finally written to the output stream.
        /// </summary>
        /// <param name="oldVersionFile">
        /// Seekable and readable stream for the old version of data.
        /// </param>
        /// <param name="newVersionFile">
        /// Seekable and readable stream for the new version of data.
        /// </param>
        /// <param name="formatter">
        /// Formatter to transform prepared patch data to a useful output.
        /// </param>
        /// <param name="output"></param>
        public void CreatePatch(Stream oldVersionFile, Stream newVersionFile, IPatchFormatter formatter, IPatchProgress prog, Stream output)
        {
            if (oldVersionFile == null)
                throw new NullReferenceException();
            if (newVersionFile == null)
                throw new NullReferenceException();
            if (output == null)
                throw new NullReferenceException();

            if (oldVersionFile.CanSeek == false)
                throw new NotSupportedException();
            if (newVersionFile.CanSeek == false)
                throw new NotSupportedException();

            oldVersionFile.Seek(0, SeekOrigin.Begin);
            newVersionFile.Seek(0, SeekOrigin.Begin);

            var fileInfo = new PatchFileInformation();

            fileInfo.SourceChecksum = MD5.Check(oldVersionFile);
            oldVersionFile.Seek(0, SeekOrigin.Begin);
            fileInfo.TargetChecksum = MD5.Check(newVersionFile);
            newVersionFile.Seek(0, SeekOrigin.Begin);

            var patchGenerator = new PatchGenerator(oldVersionFile, oldVersionFile.Length,
                                                   newVersionFile, newVersionFile.Length);
            patchGenerator.BlockSize = BlockSize;
            patchGenerator.MaximumMatches = MaximumMatches;

            List<SameBlock> sameBlocks = new List<SameBlock>();
            patchGenerator.Execute(sameBlocks, prog);

            if (formatter != null) formatter.FormatPatch(fileInfo, sameBlocks, newVersionFile, output);
            sameBlocks.Clear();
        }