Example #1
0
        private static void CopyUncompressedData(Brotli.State state)
        {
            Brotli.BitReader br         = state.br;
            byte[]           ringBuffer = state.ringBuffer;
            // Could happen if block ends at ring buffer end.
            if (state.metaBlockLength <= 0)
            {
                Brotli.BitReader.Reload(br);
                state.runningState = Brotli.RunningState.BlockStart;
                return;
            }
            int chunkLength = System.Math.Min(state.ringBufferSize - state.pos, state.metaBlockLength);

            Brotli.BitReader.CopyBytes(br, ringBuffer, state.pos, chunkLength);
            state.metaBlockLength -= chunkLength;
            state.pos             += chunkLength;
            if (state.pos == state.ringBufferSize)
            {
                state.nextRunningState = Brotli.RunningState.CopyUncompressed;
                state.bytesToWrite     = state.ringBufferSize;
                state.bytesWritten     = 0;
                state.runningState     = Brotli.RunningState.Write;
                return;
            }
            Brotli.BitReader.Reload(br);
            state.runningState = Brotli.RunningState.BlockStart;
        }
Example #2
0
 internal static void Reload(Brotli.BitReader br)
 {
     if (br.bitOffset == 64)
     {
         Prepare(br);
     }
 }
Example #3
0
        private static void DecodeBlockTypeAndLength(Brotli.State state, int treeType)
        {
            Brotli.BitReader br          = state.br;
            int[]            ringBuffers = state.blockTypeRb;
            int offset = treeType * 2;

            Brotli.BitReader.FillBitWindow(br);
            int blockType = ReadSymbol(state.blockTypeTrees, treeType * Brotli.Huffman.HuffmanMaxTableSize, br);

            state.blockLength[treeType] = ReadBlockLength(state.blockLenTrees, treeType * Brotli.Huffman.HuffmanMaxTableSize, br);
            if (blockType == 1)
            {
                blockType = ringBuffers[offset + 1] + 1;
            }
            else if (blockType == 0)
            {
                blockType = ringBuffers[offset];
            }
            else
            {
                blockType -= 2;
            }
            if (blockType >= state.numBlockTypes[treeType])
            {
                blockType -= state.numBlockTypes[treeType];
            }
            ringBuffers[offset]     = ringBuffers[offset + 1];
            ringBuffers[offset + 1] = blockType;
        }
Example #4
0
 private static void Prepare(Brotli.BitReader br)
 {
     ReadMoreInput(br);
     CheckHealth(br, false);
     FillBitWindow(br);
     FillBitWindow(br);
 }
Example #5
0
 /// <summary>Advances the Read buffer by 5 bytes to make room for reading next 24 bits.</summary>
 internal static void FillBitWindow(Brotli.BitReader br)
 {
     if (br.bitOffset >= 32)
     {
         br.accumulator = ((long)br.intBuffer[br.intOffset++] << 32) | ((long)(((ulong)br.accumulator) >> 32));
         br.bitOffset  -= 32;
     }
 }
Example #6
0
        /// <summary>Reads the specified number of bits from Read Buffer.</summary>
        internal static int ReadBits(Brotli.BitReader br, int n)
        {
            FillBitWindow(br);
            int val = (int)((long)(((ulong)br.accumulator) >> br.bitOffset)) & ((1 << n) - 1);

            br.bitOffset += n;
            return(val);
        }
Example #7
0
        private static int ReadBlockLength(int[] table, int offset, Brotli.BitReader br)
        {
            Brotli.BitReader.FillBitWindow(br);
            int code = ReadSymbol(table, offset, br);
            int n    = Brotli.Prefix.BlockLengthNBits[code];

            return(Brotli.Prefix.BlockLengthOffset[code] + Brotli.BitReader.ReadBits(br, n));
        }
Example #8
0
 /// <exception cref="System.IO.IOException"/>
 internal static void Close(Brotli.BitReader br)
 {
     System.IO.Stream @is = br.input;
     br.input = null;
     if (@is != null)
     {
         @is.Close();
     }
 }
Example #9
0
        private static int DecodeContextMap(int contextMapSize, byte[] contextMap, Brotli.BitReader br)
        {
            Brotli.BitReader.ReadMoreInput(br);
            int numTrees = DecodeVarLenUnsignedByte(br) + 1;

            if (numTrees == 1)
            {
                Brotli.Utils.FillWithZeroes(contextMap, 0, contextMapSize);
                return(numTrees);
            }
            bool useRleForZeros     = Brotli.BitReader.ReadBits(br, 1) == 1;
            int  maxRunLengthPrefix = 0;

            if (useRleForZeros)
            {
                maxRunLengthPrefix = Brotli.BitReader.ReadBits(br, 4) + 1;
            }
            int[] table = new int[Brotli.Huffman.HuffmanMaxTableSize];
            ReadHuffmanCode(numTrees + maxRunLengthPrefix, table, 0, br);
            for (int i = 0; i < contextMapSize;)
            {
                Brotli.BitReader.ReadMoreInput(br);
                Brotli.BitReader.FillBitWindow(br);
                int code = ReadSymbol(table, 0, br);
                if (code == 0)
                {
                    contextMap[i] = 0;
                    i++;
                }
                else if (code <= maxRunLengthPrefix)
                {
                    int reps = (1 << code) + Brotli.BitReader.ReadBits(br, code);
                    while (reps != 0)
                    {
                        if (i >= contextMapSize)
                        {
                            throw new Brotli.BrotliRuntimeException("Corrupted context map");
                        }
                        // COV_NF_LINE
                        contextMap[i] = 0;
                        i++;
                        reps--;
                    }
                }
                else
                {
                    contextMap[i] = unchecked ((byte)(code - maxRunLengthPrefix));
                    i++;
                }
            }
            if (Brotli.BitReader.ReadBits(br, 1) == 1)
            {
                InverseMoveToFrontTransform(contextMap, contextMapSize);
            }
            return(numTrees);
        }
Example #10
0
        internal static int IntAvailable(Brotli.BitReader br)
        {
            int limit = Capacity;

            if (br.endOfStreamReached)
            {
                limit = (br.tailBytes + 3) >> 2;
            }
            return(limit - br.intOffset);
        }
        /// <summary>Decodes Huffman trees from input stream and constructs lookup tables.</summary>
        /// <param name="group">target POJO</param>
        /// <param name="br">data source</param>
        internal static void Decode(Brotli.HuffmanTreeGroup group, Brotli.BitReader br)
        {
            int next = 0;
            int n    = group.trees.Length;

            for (int i = 0; i < n; i++)
            {
                group.trees[i] = next;
                Brotli.Decode.ReadHuffmanCode(group.alphabetSize, group.codes, next, br);
                next += Brotli.Huffman.HuffmanMaxTableSize;
            }
        }
Example #12
0
        private static void DecodeMetaBlockLength(Brotli.BitReader br, Brotli.State state)
        {
            state.inputEnd        = Brotli.BitReader.ReadBits(br, 1) == 1;
            state.metaBlockLength = 0;
            state.isUncompressed  = false;
            state.isMetadata      = false;
            if (state.inputEnd && Brotli.BitReader.ReadBits(br, 1) != 0)
            {
                return;
            }
            int sizeNibbles = Brotli.BitReader.ReadBits(br, 2) + 4;

            if (sizeNibbles == 7)
            {
                state.isMetadata = true;
                if (Brotli.BitReader.ReadBits(br, 1) != 0)
                {
                    throw new Brotli.BrotliRuntimeException("Corrupted reserved bit");
                }
                int sizeBytes = Brotli.BitReader.ReadBits(br, 2);
                if (sizeBytes == 0)
                {
                    return;
                }
                for (int i = 0; i < sizeBytes; i++)
                {
                    int bits = Brotli.BitReader.ReadBits(br, 8);
                    if (bits == 0 && i + 1 == sizeBytes && sizeBytes > 1)
                    {
                        throw new Brotli.BrotliRuntimeException("Exuberant nibble");
                    }
                    state.metaBlockLength |= bits << (i * 8);
                }
            }
            else
            {
                for (int i = 0; i < sizeNibbles; i++)
                {
                    int bits = Brotli.BitReader.ReadBits(br, 4);
                    if (bits == 0 && i + 1 == sizeNibbles && sizeNibbles > 4)
                    {
                        throw new Brotli.BrotliRuntimeException("Exuberant nibble");
                    }
                    state.metaBlockLength |= bits << (i * 4);
                }
            }
            state.metaBlockLength++;
            if (!state.inputEnd)
            {
                state.isUncompressed = Brotli.BitReader.ReadBits(br, 1) == 1;
            }
        }
Example #13
0
        internal static void JumpToByteBoundary(Brotli.BitReader br)
        {
            int padding = (64 - br.bitOffset) & 7;

            if (padding != 0)
            {
                int paddingBits = Brotli.BitReader.ReadBits(br, padding);
                if (paddingBits != 0)
                {
                    throw new Brotli.BrotliRuntimeException("Corrupted padding bits");
                }
            }
        }
Example #14
0
 /// <summary>Initialize bit reader.</summary>
 /// <remarks>
 /// Initialize bit reader.
 /// <p> Initialisation turns bit reader to a ready state. Also a number of bytes is prefetched to
 /// accumulator. Because of that this method may block until enough data could be read from input.
 /// </remarks>
 /// <param name="br">BitReader POJO</param>
 /// <param name="input">data source</param>
 internal static void Init(Brotli.BitReader br, System.IO.Stream input)
 {
     if (br.input != null)
     {
         throw new System.InvalidOperationException("Bit reader already has associated input stream");
     }
     Brotli.IntReader.Init(br.intReader, br.byteBuffer, br.intBuffer);
     br.input              = input;
     br.accumulator        = 0;
     br.bitOffset          = 64;
     br.intOffset          = Capacity;
     br.endOfStreamReached = false;
     Prepare(br);
 }
Example #15
0
 /// <summary>Decodes a number in the range [0..255], by reading 1 - 11 bits.</summary>
 private static int DecodeVarLenUnsignedByte(Brotli.BitReader br)
 {
     if (Brotli.BitReader.ReadBits(br, 1) != 0)
     {
         int n = Brotli.BitReader.ReadBits(br, 3);
         if (n == 0)
         {
             return(1);
         }
         else
         {
             return(Brotli.BitReader.ReadBits(br, n) + (1 << n));
         }
     }
     return(0);
 }
Example #16
0
        internal static void CheckHealth(Brotli.BitReader br, bool endOfStream)
        {
            if (!br.endOfStreamReached)
            {
                return;
            }
            int byteOffset = (br.intOffset << 2) + ((br.bitOffset + 7) >> 3) - 8;

            if (byteOffset > br.tailBytes)
            {
                throw new Brotli.BrotliRuntimeException("Read after end");
            }
            if (endOfStream && (byteOffset != br.tailBytes))
            {
                throw new Brotli.BrotliRuntimeException("Unused bytes after end");
            }
        }
Example #17
0
 /// <summary>Reads next metablock header.</summary>
 /// <param name="state">decoding state</param>
 private static void ReadMetablockInfo(Brotli.State state)
 {
     Brotli.BitReader br = state.br;
     if (state.inputEnd)
     {
         state.nextRunningState = Brotli.RunningState.Finished;
         state.bytesToWrite     = state.pos;
         state.bytesWritten     = 0;
         state.runningState     = Brotli.RunningState.Write;
         return;
     }
     // TODO: Reset? Do we need this?
     state.hGroup0.codes = null;
     state.hGroup0.trees = null;
     state.hGroup1.codes = null;
     state.hGroup1.trees = null;
     state.hGroup2.codes = null;
     state.hGroup2.trees = null;
     Brotli.BitReader.ReadMoreInput(br);
     DecodeMetaBlockLength(br, state);
     if (state.metaBlockLength == 0 && !state.isMetadata)
     {
         return;
     }
     if (state.isUncompressed || state.isMetadata)
     {
         Brotli.BitReader.JumpToByteBoundary(br);
         state.runningState = state.isMetadata ? Brotli.RunningState.ReadMetadata : Brotli.RunningState.CopyUncompressed;
     }
     else
     {
         state.runningState = Brotli.RunningState.CompressedBlockStart;
     }
     if (state.isMetadata)
     {
         return;
     }
     state.expectedTotalSize += state.metaBlockLength;
     if (state.ringBufferSize < state.maxRingBufferSize)
     {
         MaybeReallocateRingBuffer(state);
     }
 }
        // Current meta-block header information.
        // TODO: Update to current spec.
        private static int DecodeWindowBits(Brotli.BitReader br)
        {
            if (Brotli.BitReader.ReadBits(br, 1) == 0)
            {
                return(16);
            }
            int n = Brotli.BitReader.ReadBits(br, 3);

            if (n != 0)
            {
                return(17 + n);
            }
            n = Brotli.BitReader.ReadBits(br, 3);
            if (n != 0)
            {
                return(8 + n);
            }
            return(17);
        }
Example #19
0
        /* Number of bytes in unfinished "int" item. */
        /// <summary>Fills up the input buffer.</summary>
        /// <remarks>
        /// Fills up the input buffer.
        /// <p> No-op if there are at least 36 bytes present after current position.
        /// <p> After encountering the end of the input stream, 64 additional zero bytes are copied to the
        /// buffer.
        /// </remarks>
        internal static void ReadMoreInput(Brotli.BitReader br)
        {
            // TODO: Split to check and read; move read outside of decoding loop.
            if (br.intOffset <= Capacity - 9)
            {
                return;
            }
            if (br.endOfStreamReached)
            {
                if (IntAvailable(br) >= -2)
                {
                    return;
                }
                throw new Brotli.BrotliRuntimeException("No more input");
            }
            int readOffset = br.intOffset << 2;
            int bytesRead  = ByteReadSize - readOffset;

            System.Array.Copy(br.byteBuffer, readOffset, br.byteBuffer, 0, bytesRead);
            br.intOffset = 0;
            try
            {
                while (bytesRead < ByteReadSize)
                {
                    int len = br.input.Read(br.byteBuffer, bytesRead, ByteReadSize - bytesRead);
                    // EOF is -1 in Java, but 0 in C#.
                    if (len <= 0)
                    {
                        br.endOfStreamReached = true;
                        br.tailBytes          = bytesRead;
                        bytesRead            += 3;
                        break;
                    }
                    bytesRead += len;
                }
            }
            catch (System.IO.IOException e)
            {
                throw new Brotli.BrotliRuntimeException("Failed to read input", e);
            }
            Brotli.IntReader.Convert(br.intReader, bytesRead >> 2);
        }
Example #20
0
        /// <summary>Decodes the next Huffman code from bit-stream.</summary>
        private static int ReadSymbol(int[] table, int offset, Brotli.BitReader br)
        {
            int val = (int)((long)(((ulong)br.accumulator) >> br.bitOffset));

            offset += val & HuffmanTableMask;
            int bits = table[offset] >> 16;
            int sym  = table[offset] & unchecked ((int)(0xFFFF));

            if (bits <= HuffmanTableBits)
            {
                br.bitOffset += bits;
                return(sym);
            }
            offset += sym;
            int mask = (1 << bits) - 1;

            offset       += (int)(((uint)(val & mask)) >> HuffmanTableBits);
            br.bitOffset += ((table[offset] >> 16) + HuffmanTableBits);
            return(table[offset] & unchecked ((int)(0xFFFF)));
        }
Example #21
0
        /// <summary>Actual decompress implementation.</summary>
        internal static void Decompress(Brotli.State state)
        {
            if (state.runningState == Brotli.RunningState.Uninitialized)
            {
                throw new System.InvalidOperationException("Can't decompress until initialized");
            }
            if (state.runningState == Brotli.RunningState.Closed)
            {
                throw new System.InvalidOperationException("Can't decompress after close");
            }
            Brotli.BitReader br = state.br;
            int ringBufferMask  = state.ringBufferSize - 1;

            byte[] ringBuffer = state.ringBuffer;
            while (state.runningState != Brotli.RunningState.Finished)
            {
                switch (state.runningState)
                {
                case Brotli.RunningState.BlockStart:
                {
                    // TODO: extract cases to methods for the better readability.
                    if (state.metaBlockLength < 0)
                    {
                        throw new Brotli.BrotliRuntimeException("Invalid metablock length");
                    }
                    ReadMetablockInfo(state);
                    /* Ring-buffer would be reallocated here. */
                    ringBufferMask = state.ringBufferSize - 1;
                    ringBuffer     = state.ringBuffer;
                    continue;
                }

                case Brotli.RunningState.CompressedBlockStart:
                {
                    ReadMetablockHuffmanCodesAndContextMaps(state);
                    state.runningState = Brotli.RunningState.MainLoop;
                    goto case Brotli.RunningState.MainLoop;
                }

                case Brotli.RunningState.MainLoop:
                {
                    // Fall through
                    if (state.metaBlockLength <= 0)
                    {
                        state.runningState = Brotli.RunningState.BlockStart;
                        continue;
                    }
                    Brotli.BitReader.ReadMoreInput(br);
                    if (state.blockLength[1] == 0)
                    {
                        DecodeCommandBlockSwitch(state);
                    }
                    state.blockLength[1]--;
                    Brotli.BitReader.FillBitWindow(br);
                    int cmdCode  = ReadSymbol(state.hGroup1.codes, state.treeCommandOffset, br);
                    int rangeIdx = (int)(((uint)cmdCode) >> 6);
                    state.distanceCode = 0;
                    if (rangeIdx >= 2)
                    {
                        rangeIdx          -= 2;
                        state.distanceCode = -1;
                    }
                    int insertCode = Brotli.Prefix.InsertRangeLut[rangeIdx] + (((int)(((uint)cmdCode) >> 3)) & 7);
                    int copyCode   = Brotli.Prefix.CopyRangeLut[rangeIdx] + (cmdCode & 7);
                    state.insertLength = Brotli.Prefix.InsertLengthOffset[insertCode] + Brotli.BitReader.ReadBits(br, Brotli.Prefix.InsertLengthNBits[insertCode]);
                    state.copyLength   = Brotli.Prefix.CopyLengthOffset[copyCode] + Brotli.BitReader.ReadBits(br, Brotli.Prefix.CopyLengthNBits[copyCode]);
                    state.j            = 0;
                    state.runningState = Brotli.RunningState.InsertLoop;
                    goto case Brotli.RunningState.InsertLoop;
                }

                case Brotli.RunningState.InsertLoop:
                {
                    // Fall through
                    if (state.trivialLiteralContext)
                    {
                        while (state.j < state.insertLength)
                        {
                            Brotli.BitReader.ReadMoreInput(br);
                            if (state.blockLength[0] == 0)
                            {
                                DecodeLiteralBlockSwitch(state);
                            }
                            state.blockLength[0]--;
                            Brotli.BitReader.FillBitWindow(br);
                            ringBuffer[state.pos] = unchecked ((byte)ReadSymbol(state.hGroup0.codes, state.literalTree, br));
                            state.j++;
                            if (state.pos++ == ringBufferMask)
                            {
                                state.nextRunningState = Brotli.RunningState.InsertLoop;
                                state.bytesToWrite     = state.ringBufferSize;
                                state.bytesWritten     = 0;
                                state.runningState     = Brotli.RunningState.Write;
                                break;
                            }
                        }
                    }
                    else
                    {
                        int prevByte1 = ringBuffer[(state.pos - 1) & ringBufferMask] & unchecked ((int)(0xFF));
                        int prevByte2 = ringBuffer[(state.pos - 2) & ringBufferMask] & unchecked ((int)(0xFF));
                        while (state.j < state.insertLength)
                        {
                            Brotli.BitReader.ReadMoreInput(br);
                            if (state.blockLength[0] == 0)
                            {
                                DecodeLiteralBlockSwitch(state);
                            }
                            int literalTreeIndex = state.contextMap[state.contextMapSlice + (Brotli.Context.Lookup[state.contextLookupOffset1 + prevByte1] | Brotli.Context.Lookup[state.contextLookupOffset2 + prevByte2])] & unchecked ((int)(0xFF));
                            state.blockLength[0]--;
                            prevByte2 = prevByte1;
                            Brotli.BitReader.FillBitWindow(br);
                            prevByte1             = ReadSymbol(state.hGroup0.codes, state.hGroup0.trees[literalTreeIndex], br);
                            ringBuffer[state.pos] = unchecked ((byte)prevByte1);
                            state.j++;
                            if (state.pos++ == ringBufferMask)
                            {
                                state.nextRunningState = Brotli.RunningState.InsertLoop;
                                state.bytesToWrite     = state.ringBufferSize;
                                state.bytesWritten     = 0;
                                state.runningState     = Brotli.RunningState.Write;
                                break;
                            }
                        }
                    }
                    if (state.runningState != Brotli.RunningState.InsertLoop)
                    {
                        continue;
                    }
                    state.metaBlockLength -= state.insertLength;
                    if (state.metaBlockLength <= 0)
                    {
                        state.runningState = Brotli.RunningState.MainLoop;
                        continue;
                    }
                    if (state.distanceCode < 0)
                    {
                        Brotli.BitReader.ReadMoreInput(br);
                        if (state.blockLength[2] == 0)
                        {
                            DecodeDistanceBlockSwitch(state);
                        }
                        state.blockLength[2]--;
                        Brotli.BitReader.FillBitWindow(br);
                        state.distanceCode = ReadSymbol(state.hGroup2.codes, state.hGroup2.trees[state.distContextMap[state.distContextMapSlice + (state.copyLength > 4 ? 3 : state.copyLength - 2)] & unchecked ((int)(0xFF))], br);
                        if (state.distanceCode >= state.numDirectDistanceCodes)
                        {
                            state.distanceCode -= state.numDirectDistanceCodes;
                            int postfix = state.distanceCode & state.distancePostfixMask;
                            state.distanceCode = (int)(((uint)state.distanceCode) >> state.distancePostfixBits);
                            int n      = ((int)(((uint)state.distanceCode) >> 1)) + 1;
                            int offset = ((2 + (state.distanceCode & 1)) << n) - 4;
                            state.distanceCode = state.numDirectDistanceCodes + postfix + ((offset + Brotli.BitReader.ReadBits(br, n)) << state.distancePostfixBits);
                        }
                    }
                    // Convert the distance code to the actual distance by possibly looking up past distances
                    // from the ringBuffer.
                    state.distance = TranslateShortCodes(state.distanceCode, state.distRb, state.distRbIdx);
                    if (state.distance < 0)
                    {
                        throw new Brotli.BrotliRuntimeException("Negative distance");
                    }
                    // COV_NF_LINE
                    if (state.maxDistance != state.maxBackwardDistance && state.pos < state.maxBackwardDistance)
                    {
                        state.maxDistance = state.pos;
                    }
                    else
                    {
                        state.maxDistance = state.maxBackwardDistance;
                    }
                    state.copyDst = state.pos;
                    if (state.distance > state.maxDistance)
                    {
                        state.runningState = Brotli.RunningState.Transform;
                        continue;
                    }
                    if (state.distanceCode > 0)
                    {
                        state.distRb[state.distRbIdx & 3] = state.distance;
                        state.distRbIdx++;
                    }
                    if (state.copyLength > state.metaBlockLength)
                    {
                        throw new Brotli.BrotliRuntimeException("Invalid backward reference");
                    }
                    // COV_NF_LINE
                    state.j            = 0;
                    state.runningState = Brotli.RunningState.CopyLoop;
                    goto case Brotli.RunningState.CopyLoop;
                }

                case Brotli.RunningState.CopyLoop:
                {
                    // fall through
                    int src        = (state.pos - state.distance) & ringBufferMask;
                    int dst        = state.pos;
                    int copyLength = state.copyLength - state.j;
                    if ((src + copyLength < ringBufferMask) && (dst + copyLength < ringBufferMask))
                    {
                        for (int k = 0; k < copyLength; ++k)
                        {
                            ringBuffer[dst++] = ringBuffer[src++];
                        }
                        state.j += copyLength;
                        state.metaBlockLength -= copyLength;
                        state.pos             += copyLength;
                    }
                    else
                    {
                        for (; state.j < state.copyLength;)
                        {
                            ringBuffer[state.pos] = ringBuffer[(state.pos - state.distance) & ringBufferMask];
                            state.metaBlockLength--;
                            state.j++;
                            if (state.pos++ == ringBufferMask)
                            {
                                state.nextRunningState = Brotli.RunningState.CopyLoop;
                                state.bytesToWrite     = state.ringBufferSize;
                                state.bytesWritten     = 0;
                                state.runningState     = Brotli.RunningState.Write;
                                break;
                            }
                        }
                    }
                    if (state.runningState == Brotli.RunningState.CopyLoop)
                    {
                        state.runningState = Brotli.RunningState.MainLoop;
                    }
                    continue;
                }

                case Brotli.RunningState.Transform:
                {
                    if (state.copyLength >= Brotli.Dictionary.MinWordLength && state.copyLength <= Brotli.Dictionary.MaxWordLength)
                    {
                        int offset       = Brotli.Dictionary.OffsetsByLength[state.copyLength];
                        int wordId       = state.distance - state.maxDistance - 1;
                        int shift        = Brotli.Dictionary.SizeBitsByLength[state.copyLength];
                        int mask         = (1 << shift) - 1;
                        int wordIdx      = wordId & mask;
                        int transformIdx = (int)(((uint)wordId) >> shift);
                        offset += wordIdx * state.copyLength;
                        if (transformIdx < Brotli.Transform.Transforms.Length)
                        {
                            int len = Brotli.Transform.TransformDictionaryWord(ringBuffer, state.copyDst, Brotli.Dictionary.GetData(), offset, state.copyLength, Brotli.Transform.Transforms[transformIdx]);
                            state.copyDst         += len;
                            state.pos             += len;
                            state.metaBlockLength -= len;
                            if (state.copyDst >= state.ringBufferSize)
                            {
                                state.nextRunningState = Brotli.RunningState.CopyWrapBuffer;
                                state.bytesToWrite     = state.ringBufferSize;
                                state.bytesWritten     = 0;
                                state.runningState     = Brotli.RunningState.Write;
                                continue;
                            }
                        }
                        else
                        {
                            throw new Brotli.BrotliRuntimeException("Invalid backward reference");
                        }
                    }
                    else
                    {
                        // COV_NF_LINE
                        throw new Brotli.BrotliRuntimeException("Invalid backward reference");
                    }
                    // COV_NF_LINE
                    state.runningState = Brotli.RunningState.MainLoop;
                    continue;
                }

                case Brotli.RunningState.CopyWrapBuffer:
                {
                    System.Array.Copy(ringBuffer, state.ringBufferSize, ringBuffer, 0, state.copyDst - state.ringBufferSize);
                    state.runningState = Brotli.RunningState.MainLoop;
                    continue;
                }

                case Brotli.RunningState.ReadMetadata:
                {
                    while (state.metaBlockLength > 0)
                    {
                        Brotli.BitReader.ReadMoreInput(br);
                        // Optimize
                        Brotli.BitReader.ReadBits(br, 8);
                        state.metaBlockLength--;
                    }
                    state.runningState = Brotli.RunningState.BlockStart;
                    continue;
                }

                case Brotli.RunningState.CopyUncompressed:
                {
                    CopyUncompressedData(state);
                    continue;
                }

                case Brotli.RunningState.Write:
                {
                    if (!WriteRingBuffer(state))
                    {
                        // Output buffer is full.
                        return;
                    }
                    if (state.pos >= state.maxBackwardDistance)
                    {
                        state.maxDistance = state.maxBackwardDistance;
                    }
                    state.pos         &= ringBufferMask;
                    state.runningState = state.nextRunningState;
                    continue;
                }

                default:
                {
                    throw new Brotli.BrotliRuntimeException("Unexpected state " + state.runningState);
                }
                }
            }
            if (state.runningState == Brotli.RunningState.Finished)
            {
                if (state.metaBlockLength < 0)
                {
                    throw new Brotli.BrotliRuntimeException("Invalid metablock length");
                }
                Brotli.BitReader.JumpToByteBoundary(br);
                Brotli.BitReader.CheckHealth(state.br, true);
            }
        }
Example #22
0
        private static void ReadHuffmanCodeLengths(int[] codeLengthCodeLengths, int numSymbols, int[] codeLengths, Brotli.BitReader br)
        {
            int symbol        = 0;
            int prevCodeLen   = DefaultCodeLength;
            int repeat        = 0;
            int repeatCodeLen = 0;
            int space         = 32768;

            int[] table = new int[32];
            Brotli.Huffman.BuildHuffmanTable(table, 0, 5, codeLengthCodeLengths, CodeLengthCodes);
            while (symbol < numSymbols && space > 0)
            {
                Brotli.BitReader.ReadMoreInput(br);
                Brotli.BitReader.FillBitWindow(br);
                int p = (int)(((long)(((ulong)br.accumulator) >> br.bitOffset))) & 31;
                br.bitOffset += table[p] >> 16;
                int codeLen = table[p] & unchecked ((int)(0xFFFF));
                if (codeLen < CodeLengthRepeatCode)
                {
                    repeat = 0;
                    codeLengths[symbol++] = codeLen;
                    if (codeLen != 0)
                    {
                        prevCodeLen = codeLen;
                        space      -= 32768 >> codeLen;
                    }
                }
                else
                {
                    int extraBits = codeLen - 14;
                    int newLen    = 0;
                    if (codeLen == CodeLengthRepeatCode)
                    {
                        newLen = prevCodeLen;
                    }
                    if (repeatCodeLen != newLen)
                    {
                        repeat        = 0;
                        repeatCodeLen = newLen;
                    }
                    int oldRepeat = repeat;
                    if (repeat > 0)
                    {
                        repeat  -= 2;
                        repeat <<= extraBits;
                    }
                    repeat += Brotli.BitReader.ReadBits(br, extraBits) + 3;
                    int repeatDelta = repeat - oldRepeat;
                    if (symbol + repeatDelta > numSymbols)
                    {
                        throw new Brotli.BrotliRuntimeException("symbol + repeatDelta > numSymbols");
                    }
                    // COV_NF_LINE
                    for (int i = 0; i < repeatDelta; i++)
                    {
                        codeLengths[symbol++] = repeatCodeLen;
                    }
                    if (repeatCodeLen != 0)
                    {
                        space -= repeatDelta << (15 - repeatCodeLen);
                    }
                }
            }
            if (space != 0)
            {
                throw new Brotli.BrotliRuntimeException("Unused space");
            }
            // COV_NF_LINE
            // TODO: Pass max_symbol to Huffman table builder instead?
            Brotli.Utils.FillWithZeroes(codeLengths, symbol, numSymbols - symbol);
        }
Example #23
0
        internal static void CopyBytes(Brotli.BitReader br, byte[] data, int offset, int length)
        {
            if ((br.bitOffset & 7) != 0)
            {
                throw new Brotli.BrotliRuntimeException("Unaligned copyBytes");
            }
            // Drain accumulator.
            while ((br.bitOffset != 64) && (length != 0))
            {
                data[offset++] = unchecked ((byte)((long)(((ulong)br.accumulator) >> br.bitOffset)));
                br.bitOffset  += 8;
                length--;
            }
            if (length == 0)
            {
                return;
            }
            // Get data from shadow buffer with "sizeof(int)" granularity.
            int copyInts = System.Math.Min(IntAvailable(br), length >> 2);

            if (copyInts > 0)
            {
                int readOffset = br.intOffset << 2;
                System.Array.Copy(br.byteBuffer, readOffset, data, offset, copyInts << 2);
                offset       += copyInts << 2;
                length       -= copyInts << 2;
                br.intOffset += copyInts;
            }
            if (length == 0)
            {
                return;
            }
            // Read tail bytes.
            if (IntAvailable(br) > 0)
            {
                // length = 1..3
                FillBitWindow(br);
                while (length != 0)
                {
                    data[offset++] = unchecked ((byte)((long)(((ulong)br.accumulator) >> br.bitOffset)));
                    br.bitOffset  += 8;
                    length--;
                }
                CheckHealth(br, false);
                return;
            }
            // Now it is possible to copy bytes directly.
            try
            {
                while (length > 0)
                {
                    int len = br.input.Read(data, offset, length);
                    if (len == -1)
                    {
                        throw new Brotli.BrotliRuntimeException("Unexpected end of input");
                    }
                    offset += len;
                    length -= len;
                }
            }
            catch (System.IO.IOException e)
            {
                throw new Brotli.BrotliRuntimeException("Failed to read input", e);
            }
        }
Example #24
0
        // TODO: Use specialized versions for smaller tables.
        internal static void ReadHuffmanCode(int alphabetSize, int[] table, int offset, Brotli.BitReader br)
        {
            bool ok = true;
            int  simpleCodeOrSkip;

            Brotli.BitReader.ReadMoreInput(br);
            // TODO: Avoid allocation.
            int[] codeLengths = new int[alphabetSize];
            simpleCodeOrSkip = Brotli.BitReader.ReadBits(br, 2);
            if (simpleCodeOrSkip == 1)
            {
                // Read symbols, codes & code lengths directly.
                int   maxBitsCounter = alphabetSize - 1;
                int   maxBits        = 0;
                int[] symbols        = new int[4];
                int   numSymbols     = Brotli.BitReader.ReadBits(br, 2) + 1;
                while (maxBitsCounter != 0)
                {
                    maxBitsCounter >>= 1;
                    maxBits++;
                }
                // TODO: uncomment when codeLengths is reused.
                // Utils.fillWithZeroes(codeLengths, 0, alphabetSize);
                for (int i = 0; i < numSymbols; i++)
                {
                    symbols[i] = Brotli.BitReader.ReadBits(br, maxBits) % alphabetSize;
                    codeLengths[symbols[i]] = 2;
                }
                codeLengths[symbols[0]] = 1;
                switch (numSymbols)
                {
                case 1:
                {
                    break;
                }

                case 2:
                {
                    ok = symbols[0] != symbols[1];
                    codeLengths[symbols[1]] = 1;
                    break;
                }

                case 3:
                {
                    ok = symbols[0] != symbols[1] && symbols[0] != symbols[2] && symbols[1] != symbols[2];
                    break;
                }

                case 4:
                default:
                {
                    ok = symbols[0] != symbols[1] && symbols[0] != symbols[2] && symbols[0] != symbols[3] && symbols[1] != symbols[2] && symbols[1] != symbols[3] && symbols[2] != symbols[3];
                    if (Brotli.BitReader.ReadBits(br, 1) == 1)
                    {
                        codeLengths[symbols[2]] = 3;
                        codeLengths[symbols[3]] = 3;
                    }
                    else
                    {
                        codeLengths[symbols[0]] = 2;
                    }
                    break;
                }
                }
            }
            else
            {
                // Decode Huffman-coded code lengths.
                int[] codeLengthCodeLengths = new int[CodeLengthCodes];
                int   space    = 32;
                int   numCodes = 0;
                for (int i = simpleCodeOrSkip; i < CodeLengthCodes && space > 0; i++)
                {
                    int codeLenIdx = CodeLengthCodeOrder[i];
                    Brotli.BitReader.FillBitWindow(br);
                    int p = (int)((long)(((ulong)br.accumulator) >> br.bitOffset)) & 15;
                    // TODO: Demultiplex FIXED_TABLE.
                    br.bitOffset += FixedTable[p] >> 16;
                    int v = FixedTable[p] & unchecked ((int)(0xFFFF));
                    codeLengthCodeLengths[codeLenIdx] = v;
                    if (v != 0)
                    {
                        space -= (32 >> v);
                        numCodes++;
                    }
                }
                ok = (numCodes == 1 || space == 0);
                ReadHuffmanCodeLengths(codeLengthCodeLengths, alphabetSize, codeLengths, br);
            }
            if (!ok)
            {
                throw new Brotli.BrotliRuntimeException("Can't readHuffmanCode");
            }
            // COV_NF_LINE
            Brotli.Huffman.BuildHuffmanTable(table, offset, HuffmanTableBits, codeLengths, alphabetSize);
        }
Example #25
0
        private static void ReadMetablockHuffmanCodesAndContextMaps(Brotli.State state)
        {
            Brotli.BitReader br = state.br;
            for (int i = 0; i < 3; i++)
            {
                state.numBlockTypes[i] = DecodeVarLenUnsignedByte(br) + 1;
                state.blockLength[i]   = 1 << 28;
                if (state.numBlockTypes[i] > 1)
                {
                    ReadHuffmanCode(state.numBlockTypes[i] + 2, state.blockTypeTrees, i * Brotli.Huffman.HuffmanMaxTableSize, br);
                    ReadHuffmanCode(NumBlockLengthCodes, state.blockLenTrees, i * Brotli.Huffman.HuffmanMaxTableSize, br);
                    state.blockLength[i] = ReadBlockLength(state.blockLenTrees, i * Brotli.Huffman.HuffmanMaxTableSize, br);
                }
            }
            Brotli.BitReader.ReadMoreInput(br);
            state.distancePostfixBits    = Brotli.BitReader.ReadBits(br, 2);
            state.numDirectDistanceCodes = NumDistanceShortCodes + (Brotli.BitReader.ReadBits(br, 4) << state.distancePostfixBits);
            state.distancePostfixMask    = (1 << state.distancePostfixBits) - 1;
            int numDistanceCodes = state.numDirectDistanceCodes + (48 << state.distancePostfixBits);

            // TODO: Reuse?
            state.contextModes = new byte[state.numBlockTypes[0]];
            for (int i = 0; i < state.numBlockTypes[0];)
            {
                /* Ensure that less than 256 bits read between readMoreInput. */
                int limit = System.Math.Min(i + 96, state.numBlockTypes[0]);
                for (; i < limit; ++i)
                {
                    state.contextModes[i] = unchecked ((byte)(Brotli.BitReader.ReadBits(br, 2) << 1));
                }
                Brotli.BitReader.ReadMoreInput(br);
            }
            // TODO: Reuse?
            state.contextMap = new byte[state.numBlockTypes[0] << LiteralContextBits];
            int numLiteralTrees = DecodeContextMap(state.numBlockTypes[0] << LiteralContextBits, state.contextMap, br);

            state.trivialLiteralContext = true;
            for (int j = 0; j < state.numBlockTypes[0] << LiteralContextBits; j++)
            {
                if (state.contextMap[j] != j >> LiteralContextBits)
                {
                    state.trivialLiteralContext = false;
                    break;
                }
            }
            // TODO: Reuse?
            state.distContextMap = new byte[state.numBlockTypes[2] << DistanceContextBits];
            int numDistTrees = DecodeContextMap(state.numBlockTypes[2] << DistanceContextBits, state.distContextMap, br);

            Brotli.HuffmanTreeGroup.Init(state.hGroup0, NumLiteralCodes, numLiteralTrees);
            Brotli.HuffmanTreeGroup.Init(state.hGroup1, NumInsertAndCopyCodes, state.numBlockTypes[1]);
            Brotli.HuffmanTreeGroup.Init(state.hGroup2, numDistanceCodes, numDistTrees);
            Brotli.HuffmanTreeGroup.Decode(state.hGroup0, br);
            Brotli.HuffmanTreeGroup.Decode(state.hGroup1, br);
            Brotli.HuffmanTreeGroup.Decode(state.hGroup2, br);
            state.contextMapSlice      = 0;
            state.distContextMapSlice  = 0;
            state.contextLookupOffset1 = Brotli.Context.LookupOffsets[state.contextModes[0]];
            state.contextLookupOffset2 = Brotli.Context.LookupOffsets[state.contextModes[0] + 1];
            state.literalTreeIndex     = 0;
            state.literalTree          = state.hGroup0.trees[0];
            state.treeCommandOffset    = state.hGroup1.trees[0];
            // TODO: == 0?
            state.blockTypeRb[0] = state.blockTypeRb[2] = state.blockTypeRb[4] = 1;
            state.blockTypeRb[1] = state.blockTypeRb[3] = state.blockTypeRb[5] = 0;
        }