private int ReadHuffmanCode(int alphabetSize, int[] codeLengths, Span <HuffmanCode> table) { bool simpleCode = this.bitReader.ReadBit(); for (int i = 0; i < alphabetSize; i++) { codeLengths[i] = 0; } if (simpleCode) { // (i) Simple Code Length Code. // This variant is used in the special case when only 1 or 2 Huffman code lengths are non-zero, // and are in the range of[0, 255]. All other Huffman code lengths are implicitly zeros. // Read symbols, codes & code lengths directly. uint numSymbols = this.bitReader.ReadValue(1) + 1; uint firstSymbolLenCode = this.bitReader.ReadValue(1); // The first code is either 1 bit or 8 bit code. uint symbol = this.bitReader.ReadValue(firstSymbolLenCode == 0 ? 1 : 8); codeLengths[symbol] = 1; // The second code (if present), is always 8 bit long. if (numSymbols == 2) { symbol = this.bitReader.ReadValue(8); codeLengths[symbol] = 1; } } else { // (ii) Normal Code Length Code: // The code lengths of a Huffman code are read as follows: num_code_lengths specifies the number of code lengths; // the rest of the code lengths (according to the order in kCodeLengthCodeOrder) are zeros. int[] codeLengthCodeLengths = new int[NumCodeLengthCodes]; uint numCodes = this.bitReader.ReadValue(4) + 4; if (numCodes > NumCodeLengthCodes) { WebpThrowHelper.ThrowImageFormatException("Bitstream error, numCodes has an invalid value"); } for (int i = 0; i < numCodes; i++) { codeLengthCodeLengths[CodeLengthCodeOrder[i]] = (int)this.bitReader.ReadValue(3); } this.ReadHuffmanCodeLengths(table, codeLengthCodeLengths, alphabetSize, codeLengths); } int size = HuffmanUtils.BuildHuffmanTable(table, HuffmanUtils.HuffmanTableBits, codeLengths, alphabetSize); return(size); }
private void ReadHuffmanCodeLengths(Span <HuffmanCode> table, int[] codeLengthCodeLengths, int numSymbols, int[] codeLengths) { int maxSymbol; int symbol = 0; int prevCodeLen = WebpConstants.DefaultCodeLength; int size = HuffmanUtils.BuildHuffmanTable(table, WebpConstants.LengthTableBits, codeLengthCodeLengths, NumCodeLengthCodes); if (size == 0) { WebpThrowHelper.ThrowImageFormatException("Error building huffman table"); } if (this.bitReader.ReadBit()) { int lengthNBits = 2 + (2 * (int)this.bitReader.ReadValue(3)); maxSymbol = 2 + (int)this.bitReader.ReadValue(lengthNBits); } else { maxSymbol = numSymbols; } while (symbol < numSymbols) { if (maxSymbol-- == 0) { break; } this.bitReader.FillBitWindow(); ulong prefetchBits = this.bitReader.PrefetchBits(); int idx = (int)(prefetchBits & 127); HuffmanCode huffmanCode = table[idx]; this.bitReader.AdvanceBitPosition(huffmanCode.BitsUsed); uint codeLen = huffmanCode.Value; if (codeLen < WebpConstants.CodeLengthLiterals) { codeLengths[symbol++] = (int)codeLen; if (codeLen != 0) { prevCodeLen = (int)codeLen; } } else { bool usePrev = codeLen == WebpConstants.CodeLengthRepeatCode; uint slot = codeLen - WebpConstants.CodeLengthLiterals; int extraBits = WebpConstants.CodeLengthExtraBits[slot]; int repeatOffset = WebpConstants.CodeLengthRepeatOffsets[slot]; int repeat = (int)(this.bitReader.ReadValue(extraBits) + repeatOffset); if (symbol + repeat > numSymbols) { return; } int length = usePrev ? prevCodeLen : 0; while (repeat-- > 0) { codeLengths[symbol++] = length; } } } }