Provides for reading bits from a Stream.
 internal ResourceDecompressor(Stream input, int compressedSize, int uncompressedSize)
 {
     Input = new BitStream(input);
     CompressedSize = compressedSize;
     UncompressedSize = uncompressedSize;
     OutputData = new byte[uncompressedSize];
     InputEnd = input.Position + compressedSize;
     OutputOffset = 0;
 }
Example #2
0
        /// <summary>Decompress the LZW-compressed <see cref="Stream"/> <paramref name="source"/> into the <paramref name="output"/>, returning the number of bytes decompressed.</summary>
        /// <param name="source">The <see cref="Stream"/> to decompress from.</param>
        /// <param name="output">The byte array to write into.</param>
        /// <param name="start">The first byte offset in <paramref name="output"/> to write into.</param>
        /// <param name="count">The number of bytes in <paramref name="source"/> to write to at a maximum.</param>
        /// <returns>The number of bytes written.</returns>
        public static int Decompress(Stream source, byte[] output, int start, int count)
        {
            var bits = new BitStream(source);
            int offset = start, end = start + count;

            int tokenBits = 9; // Number of bits in a token.
            int endToken = 0x1FF; // Last token to cause an increase in the bits.
            int currentToken = 0x0102; // First undefined token.
            int[] tokenOffsets = new int[4096]; // Indexes into output for each token.
            int[] tokenLengths = new int[4096]; // Byte length of each token.

            while (offset < end) {
                int token = bits.ReadLSB(tokenBits);

                if (token == 0x101) {
                    break;
                } else if (token == 0x100) {
                    tokenBits = 9;
                    endToken = 0x1FF;
                    currentToken = 0x0102;
                } else {
                    int tokenLength; // Size of the token in bytes.

                    if (token > 0xFF) {
                        if (token >= currentToken)
                            throw new InvalidDataException("LZW decompression encountered out-of-range token.");

                        tokenLength = tokenLengths[token] + 1;
                        int writeLength = tokenLength;
                        int tokenOffset = tokenOffsets[token];

                        if (end - offset < writeLength)
                            writeLength = end - offset;

                        for (int index = 0; index < writeLength; index++)
                            output[offset++] = output[tokenOffset++];
                    } else {
                        tokenLength = 1;
                        output[offset++] = (byte)token;
                    }

                    if (currentToken > endToken && tokenBits < 12) {
                        tokenBits++;
                        endToken = (endToken << 1) + 1;
                    }

                    if (currentToken <= endToken) {
                        tokenOffsets[currentToken] = offset - tokenLength;
                        tokenLengths[currentToken] = tokenLength;
                        currentToken++;
                    }
                }
            }

            return offset - start;
        }