/** * Read and decode the block's Huffman tables * @return A decoder for the Huffman stage that uses the decoded tables * Exception if the input stream reaches EOF before all table data has been read */ private BZip2HuffmanStageDecoder ReadHuffmanTables() { var tableCodeLengths = new byte[HUFFMAN_MAXIMUM_TABLES, BZip2MTFAndRLE2StageEncoder.HUFFMAN_MAXIMUM_ALPHABET_SIZE]; /* Read Huffman symbol to output byte map */ uint huffmanUsedRanges = bitInputStream.ReadBits(16); int huffmanSymbolCount = 0; for (int i = 0; i < 16; i++) { if ((huffmanUsedRanges & ((1 << 15) >> i)) == 0) continue; for (int j = 0, k = i << 4; j < 16; j++, k++) { if (bitInputStream.ReadBoolean()) { huffmanSymbolMap[huffmanSymbolCount++] = (byte)k; } } } var endOfBlockSymbol = huffmanSymbolCount + 1; this.huffmanEndOfBlockSymbol = endOfBlockSymbol; /* Read total number of tables and selectors*/ uint totalTables = bitInputStream.ReadBits(3); uint totalSelectors = bitInputStream.ReadBits(15); if ((totalTables < HUFFMAN_MINIMUM_TABLES) || (totalTables > HUFFMAN_MAXIMUM_TABLES) || (totalSelectors < 1) || (totalSelectors > HUFFMAN_MAXIMUM_SELECTORS)) { throw new Exception("BZip2 block Huffman tables invalid"); } /* Read and decode MTFed Huffman selector list */ var tableMTF = new MoveToFront(); var selectors = new byte[totalSelectors]; for (var selector = 0; selector < totalSelectors; selector++) { selectors[selector] = tableMTF.IndexToFront((int)bitInputStream.ReadUnary()); } /* Read the Canonical Huffman code lengths for each table */ for (var table = 0; table < totalTables; table++) { int currentLength = (int)bitInputStream.ReadBits(5); for (var i = 0; i <= endOfBlockSymbol; i++) { while (bitInputStream.ReadBoolean()) { currentLength += bitInputStream.ReadBoolean() ? -1 : 1; } tableCodeLengths[table, i] = (byte)currentLength; } } return new BZip2HuffmanStageDecoder(bitInputStream, endOfBlockSymbol + 1, tableCodeLengths, selectors); }
/** * Reads the Huffman encoded data from the input stream, performs Run-Length Decoding and * applies the Move To Front transform to reconstruct the Burrows-Wheeler Transform array * @param huffmanDecoder The Huffman decoder through which symbols are read * Exception if an end-of-block symbol was not decoded within the declared block size */ private void DecodeHuffmanData(BZip2HuffmanStageDecoder huffmanDecoder) { var symbolMTF = new MoveToFront(); int _bwtBlockLength = 0; int repeatCount = 0; int repeatIncrement = 1; int mtfValue = 0; while (true) { var nextSymbol = huffmanDecoder.NextSymbol(); if (nextSymbol == BZip2MTFAndRLE2StageEncoder.RLE_SYMBOL_RUNA) { repeatCount += repeatIncrement; repeatIncrement <<= 1; } else if (nextSymbol == BZip2MTFAndRLE2StageEncoder.RLE_SYMBOL_RUNB) { repeatCount += repeatIncrement << 1; repeatIncrement <<= 1; } else { byte nextByte; if (repeatCount > 0) { if (_bwtBlockLength + repeatCount > this.bwtBlock.Length) throw new Exception("BZip2 block exceeds declared block size"); nextByte = huffmanSymbolMap[mtfValue]; bwtByteCounts[nextByte & 0xff] += repeatCount; while (--repeatCount >= 0) { bwtBlock[_bwtBlockLength++] = nextByte; } repeatCount = 0; repeatIncrement = 1; } if (nextSymbol == huffmanEndOfBlockSymbol) break; if (_bwtBlockLength >= this.bwtBlock.Length) throw new Exception("BZip2 block exceeds declared block size"); mtfValue = symbolMTF.IndexToFront(nextSymbol - 1) & 0xff; nextByte = huffmanSymbolMap[mtfValue]; bwtByteCounts[nextByte & 0xff]++; bwtBlock[_bwtBlockLength++] = nextByte; } } this.bwtBlockLength = _bwtBlockLength; }