public 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++; } 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: 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[CODE_LENGTH_CODES]; int space = 32; int numCodes = 0; for (int i = simpleCodeOrSkip; i < CODE_LENGTH_CODES && space > 0; i++) { int codeLenIdx = CODE_LENGTH_CODE_ORDER[i]; BitReader.FillBitWindow(br); int p = (int)((ulong)br.accumulator >> br.bitOffset) & 15; // TODO: Demultiplex FIXED_TABLE. br.bitOffset += FIXED_TABLE[p] >> 16; int v = FIXED_TABLE[p] & 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, HUFFMAN_TABLE_BITS, codeLengths, alphabetSize); }
private static void ReadHuffmanCodeLengths( int[] codeLengthCodeLengths, int numSymbols, int[] codeLengths, BitReader br) { int symbol = 0; int prevCodeLen = DEFAULT_CODE_LENGTH; int repeat = 0; int repeatCodeLen = 0; int space = 32768; int[] table = new int[32]; Huffman.BuildHuffmanTable(table, 0, 5, codeLengthCodeLengths, CODE_LENGTH_CODES); while (symbol < numSymbols && space > 0) { BitReader.ReadMoreInput(br); BitReader.FillBitWindow(br); int p = (int)(((ulong)br.accumulator >> br.bitOffset)) & 31; br.bitOffset += table[p] >> 16; int codeLen = table[p] & 0xFFFF; if (codeLen < CODE_LENGTH_REPEAT_CODE) { repeat = 0; codeLengths[symbol++] = codeLen; if (codeLen != 0) { prevCodeLen = codeLen; space -= 32768 >> codeLen; } } else { int extraBits = codeLen - 14; int newLen = 0; if (codeLen == CODE_LENGTH_REPEAT_CODE) { 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); }