static void CreateInternal(byte[] oldData, byte[] newData, Stream output)
        {
            // check arguments
            if (oldData == null)
            {
                throw new ArgumentNullException("oldData");
            }
            if (newData == null)
            {
                throw new ArgumentNullException("newData");
            }
            if (output == null)
            {
                throw new ArgumentNullException("output");
            }
            if (!output.CanSeek)
            {
                throw new ArgumentException("Output stream must be seekable.", "output");
            }
            if (!output.CanWrite)
            {
                throw new ArgumentException("Output stream must be writable.", "output");
            }

            /* Header is
             *  0   8    "BSDIFF40"
             *  8   8   length of bzip2ed ctrl block
             *  16  8   length of bzip2ed diff block
             *  24  8   length of new file */
            /* File is
             *  0   32  Header
             *  32  ??  Bzip2ed ctrl block
             *  ??  ??  Bzip2ed diff block
             *  ??  ??  Bzip2ed extra block */
            byte[] header = new byte[c_headerSize];
            WriteInt64(c_fileSignature, header, 0); // "BSDIFF40"
            WriteInt64(0, header, 8);
            WriteInt64(0, header, 16);
            WriteInt64(newData.Length, header, 24);

            long startPosition = output.Position;

            output.Write(header, 0, header.Length);

            int[] I = SuffixSort(oldData);

            byte[] db = new byte[newData.Length];
            byte[] eb = new byte[newData.Length];

            int dblen = 0;
            int eblen = 0;

            using (WrappingStream wrappingStream = new WrappingStream(output, Ownership.None))
                using (var bz2Stream = new BZip2Stream(wrappingStream, CompressionMode.Compress))
                {
                    // compute the differences, writing ctrl as we go
                    int scan       = 0;
                    int pos        = 0;
                    int len        = 0;
                    int lastscan   = 0;
                    int lastpos    = 0;
                    int lastoffset = 0;
                    while (scan < newData.Length)
                    {
                        int oldscore = 0;

                        for (int scsc = scan += len; scan < newData.Length; scan++)
                        {
                            len = Search(I, oldData, newData, scan, 0, oldData.Length, out pos);

                            for (; scsc < scan + len; scsc++)
                            {
                                if ((scsc + lastoffset < oldData.Length) && (oldData[scsc + lastoffset] == newData[scsc]))
                                {
                                    oldscore++;
                                }
                            }

                            if ((len == oldscore && len != 0) || (len > oldscore + 8))
                            {
                                break;
                            }

                            if ((scan + lastoffset < oldData.Length) && (oldData[scan + lastoffset] == newData[scan]))
                            {
                                oldscore--;
                            }
                        }

                        if (len != oldscore || scan == newData.Length)
                        {
                            int s    = 0;
                            int sf   = 0;
                            int lenf = 0;
                            for (int i = 0; (lastscan + i < scan) && (lastpos + i < oldData.Length);)
                            {
                                if (oldData[lastpos + i] == newData[lastscan + i])
                                {
                                    s++;
                                }
                                i++;
                                if (s * 2 - i > sf * 2 - lenf)
                                {
                                    sf   = s;
                                    lenf = i;
                                }
                            }

                            int lenb = 0;
                            if (scan < newData.Length)
                            {
                                s = 0;
                                int sb = 0;
                                for (int i = 1; (scan >= lastscan + i) && (pos >= i); i++)
                                {
                                    if (oldData[pos - i] == newData[scan - i])
                                    {
                                        s++;
                                    }
                                    if (s * 2 - i > sb * 2 - lenb)
                                    {
                                        sb   = s;
                                        lenb = i;
                                    }
                                }
                            }

                            if (lastscan + lenf > scan - lenb)
                            {
                                int overlap = (lastscan + lenf) - (scan - lenb);
                                s = 0;
                                int ss   = 0;
                                int lens = 0;
                                for (int i = 0; i < overlap; i++)
                                {
                                    if (newData[lastscan + lenf - overlap + i] == oldData[lastpos + lenf - overlap + i])
                                    {
                                        s++;
                                    }
                                    if (newData[scan - lenb + i] == oldData[pos - lenb + i])
                                    {
                                        s--;
                                    }
                                    if (s > ss)
                                    {
                                        ss   = s;
                                        lens = i + 1;
                                    }
                                }

                                lenf += lens - overlap;
                                lenb -= lens;
                            }

                            for (int i = 0; i < lenf; i++)
                            {
                                db[dblen + i] = (byte)(newData[lastscan + i] - oldData[lastpos + i]);
                            }
                            for (int i = 0; i < (scan - lenb) - (lastscan + lenf); i++)
                            {
                                eb[eblen + i] = newData[lastscan + lenf + i];
                            }

                            dblen += lenf;
                            eblen += (scan - lenb) - (lastscan + lenf);

                            byte[] buf = new byte[8];
                            WriteInt64(lenf, buf, 0);
                            bz2Stream.Write(buf, 0, 8);

                            WriteInt64((scan - lenb) - (lastscan + lenf), buf, 0);
                            bz2Stream.Write(buf, 0, 8);

                            WriteInt64((pos - lenb) - (lastpos + lenf), buf, 0);
                            bz2Stream.Write(buf, 0, 8);

                            lastscan   = scan - lenb;
                            lastpos    = pos - lenb;
                            lastoffset = pos - scan;
                        }
                    }
                }

            // compute size of compressed ctrl data
            long controlEndPosition = output.Position;

            WriteInt64(controlEndPosition - startPosition - c_headerSize, header, 8);

            // write compressed diff data
            using (WrappingStream wrappingStream = new WrappingStream(output, Ownership.None))
                using (var bz2Stream = new BZip2Stream(wrappingStream, CompressionMode.Compress))
                {
                    bz2Stream.Write(db, 0, dblen);
                }

            // compute size of compressed diff data
            long diffEndPosition = output.Position;

            WriteInt64(diffEndPosition - controlEndPosition, header, 16);

            // write compressed extra data, if any
            if (eblen > 0)
            {
                using (WrappingStream wrappingStream = new WrappingStream(output, Ownership.None))
                    using (var bz2Stream = new BZip2Stream(wrappingStream, CompressionMode.Compress))
                    {
                        bz2Stream.Write(eb, 0, eblen);
                    }
            }

            // seek to the beginning, write the header, then seek back to end
            long endPosition = output.Position;

            output.Position = startPosition;
            output.Write(header, 0, header.Length);
            output.Position = endPosition;
        }
Exemple #2
0
        private static void CreateInternal(byte[] oldData, byte[] newData, Stream output)
        {
            long num4;

            if (oldData == null)
            {
                throw new ArgumentNullException("oldData");
            }
            if (newData == null)
            {
                throw new ArgumentNullException("newData");
            }
            if (output == null)
            {
                throw new ArgumentNullException("output");
            }
            if (!output.CanSeek)
            {
                throw new ArgumentException("Output stream must be seekable.", "output");
            }
            if (!output.CanWrite)
            {
                throw new ArgumentException("Output stream must be writable.", "output");
            }
            byte[] buf = new byte[0x20];
            WriteInt64(0x3034464649445342L, buf, 0);
            WriteInt64(0L, buf, 8);
            WriteInt64(0L, buf, 0x10);
            WriteInt64((long)newData.Length, buf, 0x18);
            long position = output.Position;

            output.Write(buf, 0, buf.Length);
            int[]  i       = SuffixSort(oldData);
            byte[] buffer  = new byte[newData.Length];
            byte[] buffer3 = new byte[newData.Length];
            int    count   = 0;
            int    num3    = 0;

            using (WrappingStream stream = new WrappingStream(output, Ownership.None))
            {
                using (BZip2OutputStream stream2 = new BZip2OutputStream(stream))
                {
                    int num12;
                    int newOffset = 0;
                    int pos       = 0;
                    int num8      = 0;
                    int num9      = 0;
                    int num10     = 0;
                    int num11     = 0;
                    goto TR_0059;
TR_0049:
                    if ((num8 != num12) || (newOffset == newData.Length))
                    {
                        int num14 = 0;
                        int num15 = 0;
                        int num16 = 0;
                        int num18 = 0;
                        while (true)
                        {
                            if (((num9 + num18) >= newOffset) || ((num10 + num18) >= oldData.Length))
                            {
                                int num17 = 0;
                                if (newOffset < newData.Length)
                                {
                                    num14 = 0;
                                    int num19 = 0;
                                    for (int j = 1; (newOffset >= (num9 + j)) && (pos >= j); j++)
                                    {
                                        if (oldData[pos - j] == newData[newOffset - j])
                                        {
                                            num14++;
                                        }
                                        if (((num14 * 2) - j) > ((num19 * 2) - num17))
                                        {
                                            num19 = num14;
                                            num17 = j;
                                        }
                                    }
                                }
                                if ((num9 + num16) > (newOffset - num17))
                                {
                                    int num21 = (num9 + num16) - (newOffset - num17);
                                    num14 = 0;
                                    int num22 = 0;
                                    int num23 = 0;
                                    int num24 = 0;
                                    while (true)
                                    {
                                        if (num24 >= num21)
                                        {
                                            num16 += num23 - num21;
                                            num17 -= num23;
                                            break;
                                        }
                                        if (newData[((num9 + num16) - num21) + num24] == oldData[((num10 + num16) - num21) + num24])
                                        {
                                            num14++;
                                        }
                                        if (newData[(newOffset - num17) + num24] == oldData[(pos - num17) + num24])
                                        {
                                            num14--;
                                        }
                                        if (num14 > num22)
                                        {
                                            num22 = num14;
                                            num23 = num24 + 1;
                                        }
                                        num24++;
                                    }
                                }
                                int num25 = 0;
                                while (true)
                                {
                                    if (num25 >= num16)
                                    {
                                        int num26 = 0;
                                        while (true)
                                        {
                                            if (num26 >= ((newOffset - num17) - (num9 + num16)))
                                            {
                                                count += num16;
                                                num3  += (newOffset - num17) - (num9 + num16);
                                                byte[] buffer4 = new byte[8];
                                                WriteInt64((long)num16, buffer4, 0);
                                                stream2.Write(buffer4, 0, 8);
                                                WriteInt64((long)((newOffset - num17) - (num9 + num16)), buffer4, 0);
                                                stream2.Write(buffer4, 0, 8);
                                                WriteInt64((long)((pos - num17) - (num10 + num16)), buffer4, 0);
                                                stream2.Write(buffer4, 0, 8);
                                                num9  = newOffset - num17;
                                                num10 = pos - num17;
                                                num11 = pos - newOffset;
                                                break;
                                            }
                                            buffer3[num3 + num26] = newData[(num9 + num16) + num26];
                                            num26++;
                                        }
                                        break;
                                    }
                                    buffer[count + num25] = (byte)(newData[num9 + num25] - oldData[num10 + num25]);
                                    num25++;
                                }
                                break;
                            }
                            if (oldData[num10 + num18] == newData[num9 + num18])
                            {
                                num14++;
                            }
                            num18++;
                            if (((num14 * 2) - num18) > ((num15 * 2) - num16))
                            {
                                num15 = num14;
                                num16 = num18;
                            }
                        }
                    }
TR_0059:
                    while (true)
                    {
                        if (newOffset < newData.Length)
                        {
                            num12 = 0;
                            int num1  = newOffset + num8;
                            int index = newOffset = num1;
                            while (true)
                            {
                                if (newOffset >= newData.Length)
                                {
                                    break;
                                }
                                num8 = Search(i, oldData, newData, newOffset, 0, oldData.Length, out pos);
                                while (true)
                                {
                                    if (index < (newOffset + num8))
                                    {
                                        if (((index + num11) < oldData.Length) && (oldData[index + num11] == newData[index]))
                                        {
                                            num12++;
                                        }
                                        index++;
                                        continue;
                                    }
                                    if (((num8 != num12) || (num8 == 0)) && (num8 <= (num12 + 8)))
                                    {
                                        if (((newOffset + num11) < oldData.Length) && (oldData[newOffset + num11] == newData[newOffset]))
                                        {
                                            num12--;
                                        }
                                        newOffset++;
                                        break;
                                    }
                                    break;
                                }
                            }
                        }
                        else
                        {
                            goto TR_0021;
                        }
                        break;
                    }
                    goto TR_0049;
                }
            }
TR_0021:
            num4 = output.Position;
            WriteInt64((num4 - position) - 0x20, buf, 8);
            using (WrappingStream stream3 = new WrappingStream(output, Ownership.None))
            {
                using (BZip2OutputStream stream4 = new BZip2OutputStream(stream3))
                {
                    stream4.Write(buffer, 0, count);
                }
            }
            WriteInt64(output.Position - num4, buf, 0x10);
            using (WrappingStream stream5 = new WrappingStream(output, Ownership.None))
            {
                using (BZip2OutputStream stream6 = new BZip2OutputStream(stream5))
                {
                    stream6.Write(buffer3, 0, num3);
                }
            }
            long num5 = output.Position;

            output.Position = position;
            output.Write(buf, 0, buf.Length);
            output.Position = num5;
        }