// TODO: Use specialized versions for smaller tables. internal static void ReadHuffmanCode(int alphabetSize, int[] table, int offset, BitReader br) { bool ok = true; int simpleCodeOrSkip; BitReader.ReadMoreInput(br); // TODO: Avoid allocation. int[] codeLengths = new int[alphabetSize]; simpleCodeOrSkip = 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 = 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] = 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 (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]; 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 BrotliRuntimeException("Can't readHuffmanCode"); } // COV_NF_LINE Huffman.BuildHuffmanTable(table, offset, HuffmanTableBits, codeLengths, alphabetSize); }
private static void ReadHuffmanCodeLengths(int[] codeLengthCodeLengths, int numSymbols, int[] codeLengths, BitReader br) { int symbol = 0; int prevCodeLen = DefaultCodeLength; int repeat = 0; int repeatCodeLen = 0; int space = 32768; int[] table = new int[32]; Huffman.BuildHuffmanTable(table, 0, 5, codeLengthCodeLengths, CodeLengthCodes); while (symbol < numSymbols && space > 0) { BitReader.ReadMoreInput(br); 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 += BitReader.ReadBits(br, extraBits) + 3; int repeatDelta = repeat - oldRepeat; if (symbol + repeatDelta > numSymbols) { throw new 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 BrotliRuntimeException("Unused space"); } // COV_NF_LINE // TODO: Pass max_symbol to Huffman table builder instead? Utils.FillWithZeroes(codeLengths, symbol, numSymbols - symbol); }