Ejemplo n.º 1
0
        /// <summary>
        /// Gets the optimal compression lengths for each start of a compressed block using Dynamic Programming.
        /// This takes O(n^2) time.
        /// </summary>
        /// <param name="indata">The data to compress.</param>
        /// <param name="inLength">The length of the data to compress.</param>
        /// <param name="lengths">The optimal 'length' of the compressed blocks. For each byte in the input data,
        /// this value is the optimal 'length' value. If it is 1, the block should not be compressed.</param>
        /// <param name="disps">The 'disp' values of the compressed blocks. May be less than 3, in which case the
        /// corresponding length will never be anything other than 1.</param>
        private unsafe void GetOptimalCompressionLengths(byte *indata, int inLength, out int[] lengths, out int[] disps)
        {
            lengths = new int[inLength];
            disps   = new int[inLength];
            int[] minLengths = new int[inLength];

            for (int i = inLength - 1; i >= 0; i--)
            {
                // first get the compression length when the next byte is not compressed
                minLengths[i] = int.MaxValue;
                lengths[i]    = 1;
                if (i + 1 >= inLength)
                {
                    minLengths[i] = 1;
                }
                else
                {
                    minLengths[i] = 1 + minLengths[i + 1];
                }
                // then the optimal compressed length
                int oldLength = Math.Min(0x1001, i);
                // get the appropriate disp while at it. Takes at most O(n) time if oldLength is considered O(n)
                // be sure to bound the input length with 0x12, as that's the maximum length for LZ-Ovl compressed blocks.
                int maxLen = LZUtil.GetOccurrenceLength(indata + i, Math.Min(inLength - i, 0x12),
                                                        indata + i - oldLength, oldLength, out disps[i]);
                if (disps[i] > i)
                {
                    throw new Exception("disp is too large");
                }
                // disp < 3 cannot be stored explicitly.
                if (disps[i] < 3)
                {
                    maxLen = 1;
                }
                for (int j = 3; j <= maxLen; j++)
                {
                    int newCompLen;
                    if (i + j >= inLength)
                    {
                        newCompLen = 2;
                    }
                    else
                    {
                        newCompLen = 2 + minLengths[i + j];
                    }
                    if (newCompLen < minLengths[i])
                    {
                        lengths[i]    = j;
                        minLengths[i] = newCompLen;
                    }
                }
            }

            // we could optimize this further to also optimize it with regard to the flag-bytes, but that would require 8 times
            // more space and time (one for each position in the block) for only a potentially tiny increase in compression ratio.
        }
Ejemplo n.º 2
0
 private unsafe void GetOptimalCompressionLengths(byte *indata, int inLength, out int[] lengths, out int[] disps)
 {
     lengths = new int[inLength];
     disps   = new int[inLength];
     int[] numArray = new int[inLength];
     for (int i = inLength - 1; i >= 0; i--)
     {
         numArray[i] = 0x7fffffff;
         lengths[i]  = 1;
         if ((i + 1) >= inLength)
         {
             numArray[i] = 1;
         }
         else
         {
             numArray[i] = 1 + numArray[i + 1];
         }
         int oldLength = Math.Min(0x1000, i);
         int num3      = LZUtil.GetOccurrenceLength(indata + i, Math.Min(inLength - i, 0x10110), (indata + i) - oldLength, oldLength, out disps[i]);
         for (int j = 3; j <= num3; j++)
         {
             int num5;
             int num6;
             if (j > 0x110)
             {
                 num5 = 4;
             }
             else if (j > 0x10)
             {
                 num5 = 3;
             }
             else
             {
                 num5 = 2;
             }
             if ((i + j) >= inLength)
             {
                 num6 = num5;
             }
             else
             {
                 num6 = num5 + numArray[i + j];
             }
             if (num6 < numArray[i])
             {
                 lengths[i]  = j;
                 numArray[i] = num6;
             }
         }
     }
 }
Ejemplo n.º 3
0
        /// <summary>
        /// Gets the optimal compression lengths for each start of a compressed block using Dynamic Programming.
        /// This takes O(n^2) time, although in practice it will often be O(n^3) since one of the constants is 0x10110
        /// (the maximum length of a compressed block)
        /// </summary>
        /// <param name="indata">The data to compress.</param>
        /// <param name="inLength">The length of the data to compress.</param>
        /// <param name="lengths">The optimal 'length' of the compressed blocks. For each byte in the input data,
        /// this value is the optimal 'length' value. If it is 1, the block should not be compressed.</param>
        /// <param name="disps">The 'disp' values of the compressed blocks. May be 0, in which case the
        /// corresponding length will never be anything other than 1.</param>
        private unsafe void GetOptimalCompressionLengths(byte* indata, int inLength, out int[] lengths, out int[] disps)
        {
            lengths = new int[inLength];
            disps = new int[inLength];
            int[] minLengths = new int[inLength];

            for (int i = inLength - 1; i >= 0; i--)
            {
                // first get the compression length when the next byte is not compressed
                minLengths[i] = int.MaxValue;
                lengths[i] = 1;
                if (i + 1 >= inLength)
                    minLengths[i] = 1;
                else
                    minLengths[i] = 1 + minLengths[i + 1];
                // then the optimal compressed length
                int oldLength = Math.Min(0x1000, i);
                // get the appropriate disp while at it. Takes at most O(n) time if oldLength is considered O(n) and 0x10110 constant.
                // however since a lot of files will not be larger than 0x10110, this will often take ~O(n^2) time.
                // be sure to bound the input length with 0x10110, as that's the maximum length for LZ-11 compressed blocks.
                int maxLen = LZUtil.GetOccurrenceLength(indata + i, Math.Min(inLength - i, 0x10110),
                                                 indata + i - oldLength, oldLength, out disps[i]);
                if (disps[i] > i)
                    throw new Exception(Main.Get_Traduction("S02"));
                for (int j = 3; j <= maxLen; j++)
                {
                    int blocklen;
                    if (j > 0x110)
                        blocklen = 4;
                    else if (j > 0x10)
                        blocklen = 3;
                    else
                        blocklen = 2;
                    int newCompLen;
                    if (i + j >= inLength)
                        newCompLen = blocklen;
                    else
                        newCompLen = blocklen + minLengths[i + j];
                    if (newCompLen < minLengths[i])
                    {
                        lengths[i] = j;
                        minLengths[i] = newCompLen;
                    }
                }
            }

            // we could optimize this further to also optimize it with regard to the flag-bytes, but that would require 8 times
            // more space and time (one for each position in the block) for only a potentially tiny increase in compression ratio.
        }
Ejemplo n.º 4
0
    public override unsafe int Compress(Stream instream, long inLength, Stream outstream)
    {
        if (lookAhead)
        {
            return(CompressWithLA(instream, inLength, outstream));
        }
        byte[] buffer = new byte[inLength];
        int    num    = instream.Read(buffer, 0, (int)inLength);

        outstream.WriteByte(base.magicByte);
        outstream.WriteByte((byte)(inLength & 0xffL));
        outstream.WriteByte((byte)((inLength >> 8) & 0xffL));
        outstream.WriteByte((byte)((inLength >> 0x10) & 0xffL));
        int num2 = 4;

        fixed(byte *numRef = buffer)
        {
            byte[] buffer2 = new byte[0x21];
            buffer2[0] = 0;
            int count = 1;
            int num4  = 0;
            int num5  = 0;

            while (num5 < inLength)
            {
                int num6;
                if (num4 == 8)
                {
                    outstream.Write(buffer2, 0, count);
                    num2      += count;
                    buffer2[0] = 0;
                    count      = 1;
                    num4       = 0;
                }
                int oldLength = Math.Min(num5, 0x1000);
                int num8      = LZUtil.GetOccurrenceLength(numRef + num5, (int)Math.Min((long)(inLength - num5), (long)0x10110L), (numRef + num5) - oldLength, oldLength, out num6);
                if (num8 < 3)
                {
                    buffer2[count++] = numRef[num5++];
                }
                else
                {
                    num5      += num8;
                    buffer2[0] = (byte)(buffer2[0] | ((byte)(((int)1) << (7 - num4))));
                    if (num8 > 0x110)
                    {
                        buffer2[count] = 0x10;
                        buffer2[count] = (byte)(buffer2[count] | ((byte)(((num8 - 0x111) >> 12) & 15)));
                        count++;
                        buffer2[count] = (byte)(((num8 - 0x111) >> 4) & 0xff);
                        count++;
                        buffer2[count] = (byte)(((num8 - 0x111) << 4) & 240);
                    }
                    else if (num8 > 0x10)
                    {
                        buffer2[count] = 0;
                        buffer2[count] = (byte)(buffer2[count] | ((byte)(((num8 - 0x111) >> 4) & 15)));
                        count++;
                        buffer2[count] = (byte)(((num8 - 0x111) << 4) & 240);
                    }
                    else
                    {
                        buffer2[count] = (byte)(((num8 - 1) << 4) & 240);
                    }
                    buffer2[count] = (byte)(buffer2[count] | ((byte)(((num6 - 1) >> 8) & 15)));
                    count++;
                    buffer2[count] = (byte)((num6 - 1) & 0xff);
                    count++;
                }
                num4++;
            }
            if (num4 > 0)
            {
                outstream.Write(buffer2, 0, count);
                num2 += count;
            }
        }

        return(num2);
    }
Ejemplo n.º 5
0
        public unsafe override int Compress(Stream instream, long inLength, Stream outstream)
        {
            // make sure the decompressed size fits in 3 bytes.
            // There should be room for four bytes, however I'm not 100% sure if that can be used
            // in every game, as it may not be a built-in function.
            if (inLength > 0xFFFFFF)
            {
                throw new InputTooLargeException();
            }

            // use the other method if lookahead is enabled
            if (lookAhead)
            {
                return(CompressWithLA(instream, inLength, outstream));
            }

            // save the input data in an array to prevent having to go back and forth in a file
            byte[] indata       = new byte[inLength];
            int    numReadBytes = instream.Read(indata, 0, (int)inLength);

            if (numReadBytes != inLength)
            {
                throw new StreamTooShortException();
            }

            // write the compression header first
            outstream.WriteByte(this.magicByte);
            outstream.WriteByte((byte)(inLength & 0xFF));
            outstream.WriteByte((byte)((inLength >> 8) & 0xFF));
            outstream.WriteByte((byte)((inLength >> 16) & 0xFF));

            int compressedLength = 4;

            fixed(byte *instart = &indata[0])
            {
                // we do need to buffer the output, as the first byte indicates which blocks are compressed.
                // this version does not use a look-ahead, so we do not need to buffer more than 8 blocks at a time.
                // (a block is at most 4 bytes long)
                byte[] outbuffer = new byte[8 * 4 + 1];
                outbuffer[0] = 0;
                int bufferlength = 1, bufferedBlocks = 0;
                int readBytes = 0;

                while (readBytes < inLength)
                {
                    #region If 8 blocks are bufferd, write them and reset the buffer
                    // we can only buffer 8 blocks at a time.
                    if (bufferedBlocks == 8)
                    {
                        outstream.Write(outbuffer, 0, bufferlength);
                        compressedLength += bufferlength;
                        // reset the buffer
                        outbuffer[0]   = 0;
                        bufferlength   = 1;
                        bufferedBlocks = 0;
                    }
                    #endregion

                    // determine if we're dealing with a compressed or raw block.
                    // it is a compressed block when the next 3 or more bytes can be copied from
                    // somewhere in the set of already compressed bytes.
                    int disp;
                    int oldLength = Math.Min(readBytes, 0x1000);
                    int length    = LZUtil.GetOccurrenceLength(instart + readBytes, (int)Math.Min(inLength - readBytes, 0x10110),
                                                               instart + readBytes - oldLength, oldLength, out disp);

                    // length not 3 or more? next byte is raw data
                    if (length < 3)
                    {
                        outbuffer[bufferlength++] = *(instart + (readBytes++));
                    }
                    else
                    {
                        // 3 or more bytes can be copied? next (length) bytes will be compressed into 2 bytes
                        readBytes += length;

                        // mark the next block as compressed
                        outbuffer[0] |= (byte)(1 << (7 - bufferedBlocks));

                        if (length > 0x110)
                        {
                            // case 1: 1(B CD E)(F GH) + (0x111)(0x1) = (LEN)(DISP)
                            outbuffer[bufferlength]  = 0x10;
                            outbuffer[bufferlength] |= (byte)(((length - 0x111) >> 12) & 0x0F);
                            bufferlength++;
                            outbuffer[bufferlength] = (byte)(((length - 0x111) >> 4) & 0xFF);
                            bufferlength++;
                            outbuffer[bufferlength] = (byte)(((length - 0x111) << 4) & 0xF0);
                        }
                        else if (length > 0x10)
                        {
                            // case 0; 0(B C)(D EF) + (0x11)(0x1) = (LEN)(DISP)
                            outbuffer[bufferlength]  = 0x00;
                            outbuffer[bufferlength] |= (byte)(((length - 0x111) >> 4) & 0x0F);
                            bufferlength++;
                            outbuffer[bufferlength] = (byte)(((length - 0x111) << 4) & 0xF0);
                        }
                        else
                        {
                            // case > 1: (A)(B CD) + (0x1)(0x1) = (LEN)(DISP)
                            outbuffer[bufferlength] = (byte)(((length - 1) << 4) & 0xF0);
                        }
                        // the last 1.5 bytes are always the disp
                        outbuffer[bufferlength] |= (byte)(((disp - 1) >> 8) & 0x0F);
                        bufferlength++;
                        outbuffer[bufferlength] = (byte)((disp - 1) & 0xFF);
                        bufferlength++;
                    }
                    bufferedBlocks++;
                }

                // copy the remaining blocks to the output
                if (bufferedBlocks > 0)
                {
                    outstream.Write(outbuffer, 0, bufferlength);
                    compressedLength += bufferlength;

                    /*/ make the compressed file 4-byte aligned.
                     * while ((compressedLength % 4) != 0)
                     * {
                     *  outstream.WriteByte(0);
                     *  compressedLength++;
                     * }/**/
                }
            }

            return(compressedLength);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Compresses the given input stream with the LZ-Ovl compression, but compresses _forward_
        /// instad of backwards.
        /// </summary>
        /// <param name="instream">The input stream to compress.</param>
        /// <param name="inLength">The length of the input stream.</param>
        /// <param name="outstream">The stream to write to.</param>
        private unsafe int CompressNormal(Stream instream, long inLength, Stream outstream)
        {
            // make sure the decompressed size fits in 3 bytes.
            // There should be room for four bytes, however I'm not 100% sure if that can be used
            // in every game, as it may not be a built-in function.
            if (inLength > 0xFFFFFF)
            {
                throw new InputTooLargeException();
            }

            // use the other method if lookahead is enabled
            if (lookAhead)
            {
                return(CompressWithLA(instream, inLength, outstream));
            }

            // save the input data in an array to prevent having to go back and forth in a file
            byte[] indata       = new byte[inLength];
            int    numReadBytes = instream.Read(indata, 0, (int)inLength);

            if (numReadBytes != inLength)
            {
                throw new StreamTooShortException();
            }

            int compressedLength = 0;

            fixed(byte *instart = &indata[0])
            {
                // we do need to buffer the output, as the first byte indicates which blocks are compressed.
                // this version does not use a look-ahead, so we do not need to buffer more than 8 blocks at a time.
                byte[] outbuffer = new byte[8 * 2 + 1];
                outbuffer[0] = 0;
                int bufferlength = 1, bufferedBlocks = 0;
                int readBytes = 0;

                while (readBytes < inLength)
                {
                    #region If 8 blocks are bufferd, write them and reset the buffer
                    // we can only buffer 8 blocks at a time.
                    if (bufferedBlocks == 8)
                    {
                        outstream.Write(outbuffer, 0, bufferlength);
                        compressedLength += bufferlength;
                        // reset the buffer
                        outbuffer[0]   = 0;
                        bufferlength   = 1;
                        bufferedBlocks = 0;
                    }
                    #endregion

                    // determine if we're dealing with a compressed or raw block.
                    // it is a compressed block when the next 3 or more bytes can be copied from
                    // somewhere in the set of already compressed bytes.
                    int disp;
                    int oldLength = Math.Min(readBytes, 0x1001);
                    int length    = LZUtil.GetOccurrenceLength(instart + readBytes, (int)Math.Min(inLength - readBytes, 0x12),
                                                               instart + readBytes - oldLength, oldLength, out disp);

                    // disp = 1 cannot be stored.
                    if (disp == 1)
                    {
                        length = 1;
                    }
                    // disp = 2 cannot be saved properly. use a too large disp instead.
                    // however since I'm not sure if that's actually how that's handled, don't compress instead.
                    else if (disp == 2)
                    {
                        length = 1;

                        /*if (readBytes < 0x1001)
                         *  disp = readBytes + 1;
                         * else
                         *  length = 1;/**/
                    }

                    // length not 3 or more? next byte is raw data
                    if (length < 3)
                    {
                        outbuffer[bufferlength++] = *(instart + (readBytes++));
                    }
                    else
                    {
                        // 3 or more bytes can be copied? next (length) bytes will be compressed into 2 bytes
                        readBytes += length;

                        // mark the next block as compressed
                        outbuffer[0] |= (byte)(1 << (7 - bufferedBlocks));

                        outbuffer[bufferlength]  = (byte)(((length - 3) << 4) & 0xF0);
                        outbuffer[bufferlength] |= (byte)(((disp - 3) >> 8) & 0x0F);
                        bufferlength++;
                        outbuffer[bufferlength] = (byte)((disp - 3) & 0xFF);
                        bufferlength++;
                    }
                    bufferedBlocks++;
                }

                // copy the remaining blocks to the output
                if (bufferedBlocks > 0)
                {
                    outstream.Write(outbuffer, 0, bufferlength);
                    compressedLength += bufferlength;

                    /*/ make the compressed file 4-byte aligned.
                     * while ((compressedLength % 4) != 0)
                     * {
                     *  outstream.WriteByte(0);
                     *  compressedLength++;
                     * }/**/
                }
            }

            return(compressedLength);
        }
Ejemplo n.º 7
0
        public unsafe override int Compress(System.IO.Stream instream, long inLength, System.IO.Stream outstream)
        {
            // block type 0: stores at most 3+0xF  = 0x12 = 18 bytes (in 2 bytes)
            // block type 1: stores at most 2+0x3F = 0x41 = 65 bytes (in 1 byte)
            // block type 2: 1 raw byte
            // block type 3: 3 raw bytes

            if (LookAhead)
            {
                return(CompressWithLA(instream, inLength, outstream));
            }


            // save the input data in an array to prevent having to go back and forth in a file
            byte[] indata       = new byte[inLength];
            int    numReadBytes = instream.Read(indata, 0, (int)inLength);

            if (numReadBytes != inLength)
            {
                throw new StreamTooShortException();
            }

            // write the compression head first
            outstream.WriteByte((byte)'L');
            outstream.WriteByte((byte)'e');
            outstream.WriteByte((byte)(inLength & 0xFF));
            outstream.WriteByte((byte)((inLength >> 8) & 0xFF));
            outstream.WriteByte((byte)((inLength >> 16) & 0xFF));
            outstream.WriteByte((byte)((inLength >> 24) & 0xFF));

            int compressedLength = 6;

            fixed(byte *instart = &indata[0])
            {
                // we do need to buffer the output, as the first byte indicates which blocks are compressed.
                // this version does not use a look-ahead, so we do not need to buffer more than 4 blocks at a time.
                // (a block is at most 3 bytes long)
                byte[] outbuffer = new byte[4 * 3 + 1];
                outbuffer[0] = 0;
                int bufferlength = 1, bufferedBlocks = 0;
                int readBytes = 0;

                int cacheByte = -1;

                while (readBytes < inLength)
                {
                    #region If 4 blocks are bufferd, write them and reset the buffer
                    // we can only buffer 4 blocks at a time.
                    if (bufferedBlocks == 4)
                    {
                        outstream.Write(outbuffer, 0, bufferlength);
                        compressedLength += bufferlength;
                        // reset the buffer
                        outbuffer[0]   = 0;
                        bufferlength   = 1;
                        bufferedBlocks = 0;
                    }
                    #endregion

                    // type 0: 3 <= len <= 18; 5 <= disp <= 0x1004
                    // type 1: 2 <= len <= 65; 1 <= disp <= 4
                    // type 2: 1 raw byte
                    // type 3: 3 raw bytes

                    // check if we can compress it using type 1 first (only 1 byte-long block)
                    int disp;
                    int oldLength = Math.Min(readBytes, 0x1004);
                    int length    = LZUtil.GetOccurrenceLength(instart + readBytes, (int)Math.Min(inLength - readBytes, 65),
                                                               instart + readBytes - oldLength, oldLength, out disp, 1);
                    if (disp >= 1 && ((disp <= 4 && length >= 2) || (disp >= 5 && length >= 3)))
                    {
                        if (cacheByte >= 0)
                        {
                            // write a single raw byte block (the previous byte could not be the start of any compressed block)
                            outbuffer[bufferlength++] = (byte)(cacheByte & 0xFF);
                            outbuffer[0] |= (byte)(2 << (bufferedBlocks * 2));
                            cacheByte     = -1;
                            bufferedBlocks++;
                            // the block set may be full; just retry this iteration.
                            continue;
                        }
                        if (disp >= 5)
                        {
                            #region compress using type 0

                            // type 0: store len/disp in 2 bytes:
                            // AB CD, with len = C + 3, disp = DAB + 5

                            // make sure we do not try to compress more than fits into the block
                            length = Math.Min(length, 0xF + 3);

                            readBytes += length;

                            outbuffer[bufferlength++]  = (byte)((disp - 5) & 0xFF);
                            outbuffer[bufferlength]    = (byte)(((disp - 5) >> 8) & 0xF);
                            outbuffer[bufferlength++] |= (byte)(((length - 3) & 0xF) << 4);

                            #endregion
                        }
                        else // 1 <= disp <= 4
                        {
                            #region compress using type 1

                            // type 1: store len/disp in 1 byte:
                            // ABCDEFGH, wih len = ABCDEF + 2, disp = GH + 1

                            readBytes += length;

                            outbuffer[bufferlength]  = (byte)(((length - 2) << 2) & 0xFC);
                            outbuffer[bufferlength] |= (byte)((disp - 1) & 0x3);
                            bufferlength++;

                            outbuffer[0] |= (byte)(1 << (bufferedBlocks * 2));

                            #endregion
                        }
                    }
                    else
                    {
                        if (cacheByte < 0)
                        {
                            // first fail? remember byte, try to compress starting at next byte
                            cacheByte = *(instart + (readBytes++));
                            continue;
                        }
                        else
                        {
                            // 2 consecutive fails -> store 3 raw bytes (type 3) if possible.
                            if (inLength - readBytes >= 2)
                            {
                                outbuffer[bufferlength++] = (byte)(cacheByte & 0xFF);
                                outbuffer[bufferlength++] = *(instart + (readBytes++));
                                outbuffer[bufferlength++] = *(instart + (readBytes++));
                                outbuffer[0] |= (byte)(3 << (bufferedBlocks * 2));
                                cacheByte     = -1;
                            }
                            else
                            {
                                // there are only two bytes remaining (incl. the cched byte)
                                // so write the cached byte first as single raw byte.
                                // keep the next/last byte as new cache, since the block buffer may be full.
                                outbuffer[bufferlength++] = (byte)(cacheByte & 0xFF);
                                outbuffer[0] |= (byte)(2 << (bufferedBlocks * 2));
                                cacheByte     = *(instart + (readBytes++));
                            }
                        }
                    }

                    bufferedBlocks++;
                }

                // there may be one cache-byte left.
                if (cacheByte >= 0)
                {
                    // if the current set of blocks is full, empty it first
                    if (bufferedBlocks == 4)
                    {
                        #region empty block buffer

                        outstream.Write(outbuffer, 0, bufferlength);
                        compressedLength += bufferlength;
                        // reset the buffer
                        outbuffer[0]   = 0;
                        bufferlength   = 1;
                        bufferedBlocks = 0;

                        #endregion
                    }

                    outbuffer[bufferlength++] = (byte)(cacheByte & 0xFF);
                    cacheByte     = -1;
                    outbuffer[0] |= (byte)(2 << (bufferedBlocks * 2));
                    bufferedBlocks++;
                }

                // copy any remaining blocks to the output
                if (bufferedBlocks > 0)
                {
                    outstream.Write(outbuffer, 0, bufferlength);
                    compressedLength += bufferlength;
                }
            }

            return(compressedLength);
        }
Ejemplo n.º 8
0
    public unsafe int CompressNormal(Stream instream, long inLength, Stream outstream)
    {
        if (lookAhead)
        {
            return(CompressWithLA(instream, inLength, outstream));
        }
        byte[] buffer = new byte[inLength];
        int    num    = instream.Read(buffer, 0, (int)inLength);
        int    num2   = 0;

        fixed(byte *numRef = buffer)
        {
            byte[] buffer2 = new byte[0x11];
            buffer2[0] = 0;
            int count = 1;
            int num4  = 0;
            int num5  = 0;

            while (num5 < inLength)
            {
                int num6;
                if (num4 == 8)
                {
                    outstream.Write(buffer2, 0, count);
                    num2      += count;
                    buffer2[0] = 0;
                    count      = 1;
                    num4       = 0;
                }
                int oldLength = Math.Min(num5, 0x1001);
                int num8      = LZUtil.GetOccurrenceLength(numRef + num5, (int)Math.Min((long)(inLength - num5), (long)0x12L), (numRef + num5) - oldLength, oldLength, out num6);
                if (num6 == 1)
                {
                    num8 = 1;
                }
                else if (num6 == 2)
                {
                    num8 = 1;
                }
                if (num8 < 3)
                {
                    buffer2[count++] = numRef[num5++];
                }
                else
                {
                    num5          += num8;
                    buffer2[0]     = (byte)(buffer2[0] | ((byte)(((int)1) << (7 - num4))));
                    buffer2[count] = (byte)(((num8 - 3) << 4) & 240);
                    buffer2[count] = (byte)(buffer2[count] | ((byte)(((num6 - 3) >> 8) & 15)));
                    count++;
                    buffer2[count] = (byte)((num6 - 3) & 0xff);
                    count++;
                }
                num4++;
            }
            if (num4 > 0)
            {
                outstream.Write(buffer2, 0, count);
                num2 += count;
            }
        }

        return(num2);
    }