예제 #1
0
        public static byte[] Apply(byte[] origin, byte[] delta)
        {
            uint   limit, total = 0;
            uint   lenSrc   = (uint)origin.Length;
            uint   lenDelta = (uint)delta.Length;
            Reader zDelta   = new Reader(delta);

            limit = zDelta.GetInt();
            if (zDelta.GetChar() != '\n')
            {
                throw new Exception("size integer not terminated by \'\\n\'");
            }

            Writer zOut = new Writer();

            while (zDelta.HaveBytes())
            {
                uint cnt, ofst;
                cnt = zDelta.GetInt();

                switch (zDelta.GetChar())
                {
                case '@':
                    ofst = zDelta.GetInt();
                    if (zDelta.HaveBytes() && zDelta.GetChar() != ',')
                    {
                        throw new Exception("copy command not terminated by \',\'");
                    }
                    total += cnt;
                    if (total > limit)
                    {
                        throw new Exception("copy exceeds output file size");
                    }
                    if (ofst + cnt > lenSrc)
                    {
                        throw new Exception("copy extends past end of input");
                    }
                    zOut.PutArray(origin, (int)ofst, (int)(ofst + cnt));
                    break;

                case ':':
                    total += cnt;
                    if (total > limit)
                    {
                        throw new Exception("insert command gives an output larger than predicted");
                    }
                    if (cnt > lenDelta)
                    {
                        throw new Exception("insert count exceeds size of delta");
                    }
                    zOut.PutArray(zDelta.a, (int)zDelta.pos, (int)(zDelta.pos + cnt));
                    zDelta.pos += cnt;
                    break;

                case ';':
                    byte[] output = zOut.ToArray();
                    //
                    // Checksum is optional (2017-10-05)
                    // http://fossil-scm.org/xfer/info/d3a46b2a45b92bbc
                    //
                    //if (cnt != Checksum (output))
                    //	throw new Exception("bad checksum");
                    if (total != limit)
                    {
                        throw new Exception("generated size does not match predicted size");
                    }
                    return(output);

                default:
                    throw new Exception("unknown delta operator");
                }
            }
            throw new Exception("unterminated delta");
        }
예제 #2
0
        public static void Apply(Stream origin, byte[] delta, Stream target)
        {
            uint   limit, total = 0;
            uint   lenSrc   = (uint)origin.Length;
            uint   lenDelta = (uint)delta.Length;
            Reader zDelta   = new Reader(delta);

            limit = zDelta.GetInt();
            if (zDelta.GetChar() != '\n')
            {
                throw new Exception("size integer not terminated by \'\\n\'");
            }

            uint      checksum   = 0;
            const int BufferSize = 64 * 1024;
            // We need additional 4 for bytes that might remain unprocessed from previous loop traversal
            var buffer = new byte[BufferSize + 4];
            int remainingChecksumBytes = 0;

            while (zDelta.HaveBytes())
            {
                uint cnt, ofst;
                cnt = zDelta.GetInt();

                switch (zDelta.GetChar())
                {
                case '@':
                    ofst = zDelta.GetInt();
                    if (zDelta.HaveBytes() && zDelta.GetChar() != ',')
                    {
                        throw new Exception("copy command not terminated by \',\'");
                    }
                    total += cnt;
                    if (total > limit)
                    {
                        throw new Exception("copy exceeds output file size");
                    }
                    if (ofst + cnt > lenSrc)
                    {
                        throw new Exception("copy extends past end of input");
                    }

                    origin.Position = ofst;
                    int remainingBytes = (int)cnt;
                    while (remainingBytes > 0)
                    {
                        int totalRead = origin.Read(buffer, remainingChecksumBytes, Math.Min(remainingBytes, BufferSize));
                        remainingBytes -= totalRead;
                        target.Write(buffer, remainingChecksumBytes, totalRead);

                        totalRead += remainingChecksumBytes;

                        remainingChecksumBytes = totalRead % 4;
                        int checksumBytes = totalRead - remainingChecksumBytes;
                        checksum = Checksum(buffer, checksumBytes, checksum);
                        for (int i = 0; i < remainingChecksumBytes; i++)
                        {
                            buffer[i] = buffer[i + checksumBytes];
                        }
                    }
                    break;

                case ':':
                    total += cnt;
                    if (total > limit)
                    {
                        throw new Exception("insert command gives an output larger than predicted");
                    }
                    if (cnt > lenDelta)
                    {
                        throw new Exception("insert count exceeds size of delta");
                    }
                    remainingBytes = (int)cnt;
                    int pos = (int)zDelta.pos;
                    while (remainingBytes > 0)
                    {
                        var totalCopied = Math.Min(remainingBytes, BufferSize);
                        Array.Copy(zDelta.a, pos, buffer, remainingChecksumBytes, totalCopied);
                        remainingBytes -= totalCopied;

                        totalCopied += remainingChecksumBytes;

                        remainingChecksumBytes = totalCopied % 4;
                        int checksumBytes = totalCopied - remainingChecksumBytes;
                        checksum = Checksum(buffer, checksumBytes, checksum);
                        for (int i = 0; i < remainingChecksumBytes; i++)
                        {
                            buffer[i] = buffer[i + checksumBytes];
                        }
                    }

                    target.Write(zDelta.a, (int)zDelta.pos, (int)cnt);
                    zDelta.pos += cnt;
                    break;

                case ';':
                    if (remainingChecksumBytes > 0)
                    {
                        checksum = Checksum(buffer, remainingChecksumBytes, checksum);
                    }
                    if (cnt != checksum)
                    {
                        throw new Exception("bad checksum");
                    }
                    if (total != limit)
                    {
                        throw new Exception("generated size does not match predicted size");
                    }
                    return;

                default:
                    throw new Exception("unknown delta operator");
                }
            }
            throw new Exception("unterminated delta");
        }