private void Initialize(int maxSymbols) { int numTrees = (int)_bitstream.Read(3); if (numTrees < 2 || numTrees > 6) { throw new InvalidDataException("Invalid number of tables"); } int numSelectors = (int)_bitstream.Read(15); if (numSelectors < 1) { throw new InvalidDataException("Invalid number of selectors"); } _selectors = new byte[numSelectors]; MoveToFront mtf = new MoveToFront(numTrees, true); for (int i = 0; i < numSelectors; ++i) { _selectors[i] = mtf.GetAndMove(CountSetBits(numTrees)); } _trees = new HuffmanTree[numTrees]; for (int t = 0; t < numTrees; ++t) { uint[] lengths = new uint[maxSymbols]; uint len = _bitstream.Read(5); for (int i = 0; i < maxSymbols; ++i) { if (len < 1 || len > 20) { throw new InvalidDataException("Invalid length constructing Huffman tree"); } while (_bitstream.Read(1) != 0) { len = (_bitstream.Read(1) == 0) ? len + 1 : len - 1; if (len < 1 || len > 20) { throw new InvalidDataException("Invalid length constructing Huffman tree"); } } lengths[i] = len; } _trees[t] = new HuffmanTree(lengths); } _symbolsToNextSelector = 0; _nextSelector = 0; }
private static int ReadBuffer(BitStream bitstream, byte[] buffer, int offset) { // The MTF state int numInUse = 0; MoveToFront moveFrontTransform = new MoveToFront(); bool[] inUseGroups = new bool[16]; for (int i = 0; i < 16; ++i) { inUseGroups[i] = bitstream.Read(1) != 0; } for (int i = 0; i < 256; ++i) { if (inUseGroups[i / 16]) { if (bitstream.Read(1) != 0) { moveFrontTransform.Set(numInUse, (byte)i); numInUse++; } } } // Initialize 'virtual' Huffman tree from bitstream BZip2CombinedHuffmanTrees huffmanTree = new BZip2CombinedHuffmanTrees(bitstream, numInUse + 2); // Main loop reading data int readBytes = 0; while (true) { uint symbol = huffmanTree.NextSymbol(); if (symbol < 2) { // RLE, with length stored in a binary-style format uint runLength = 0; int bitShift = 0; while (symbol < 2) { runLength += (symbol + 1) << bitShift; bitShift++; symbol = huffmanTree.NextSymbol(); } byte b = moveFrontTransform.Head; while (runLength > 0) { buffer[offset + readBytes] = b; ++readBytes; --runLength; } } if (symbol <= numInUse) { // Single byte byte b = moveFrontTransform.GetAndMove((int)symbol - 1); buffer[offset + readBytes] = b; ++readBytes; } else if (symbol == numInUse + 1) { // End of block marker return readBytes; } else { throw new InvalidDataException("Invalid symbol from Huffman table"); } } }