private PngHuffmanTables(PngDecodingDataStream stream) throws IOException { int literals = PngLzBlockReader.FIRST_LENGTH_CODE + stream.getNextIdatBits(5); int distances = PngLzBlockReader.FIRST_DISTANCE_CODE + stream.getNextIdatBits(5); int codeLengthCodes = PngLzBlockReader.FIRST_CODE_LENGTH_CODE + stream.getNextIdatBits(4); if (codeLengthCodes > PngLzBlockReader.LAST_CODE_LENGTH_CODE) { stream.error(); } /* Tricky, tricky, tricky. The length codes are stored in * a very odd order. (For the order, see the definition of * the static field lengthCodeOrder.) Also, the data may * not contain values for all the codes. It may just contain * values for the first X number of codes. The table should * be of size <LengthCodeTableSize> regardless of the number * of values actually given in the table. */ int[] lengthCodes = new int[LengthCodeTableSize]; for (int i = 0; i < codeLengthCodes; i++) { lengthCodes[LengthCodeOrder[i]] = stream.getNextIdatBits(3); } PngHuffmanTable codeLengthsTable = new PngHuffmanTable(lengthCodes); int[] literalLengths = readLengths(stream, literals, codeLengthsTable, LiteralTableSize); int[] distanceLengths = readLengths(stream, distances, codeLengthsTable, DistanceTableSize); literalTable = new PngHuffmanTable(literalLengths); distanceTable = new PngHuffmanTable(distanceLengths); }
private int[] readLengths( PngDecodingDataStream stream, int numLengths, PngHuffmanTable lengthsTable, int tableSize) throws IOException { int[] lengths = new int[tableSize]; for (int index = 0; index < numLengths; ) { int value = lengthsTable.getNextValue(stream); if (value < 16) { // Literal value lengths[index] = value; index++; } else if (value == 16) { // Repeat the previous code 3-6 times. int count = stream.getNextIdatBits(2) + 3; for (int i = 0; i < count; i++) { lengths[index] = lengths[index - 1]; index++; } } else if (value == 17) { // Repeat 0 3-10 times. int count = stream.getNextIdatBits(3) + 3; for (int i = 0; i < count; i++) { lengths[index] = 0; index++; } } else if (value == 18) { // Repeat 0 11-138 times. int count = stream.getNextIdatBits(7) + 11; for (int i = 0; i < count; i++) { lengths[index] = 0; index++; } } else { stream.error(); } } return lengths; }
int getNextValue(PngDecodingDataStream stream) throws IOException { int code = stream.getNextIdatBit(); int codelength = 0; // Here we are taking advantage of the fact that 1 bits are used as // a prefix to the longer codeValues. while (codelength < MAX_CODE_LENGTH && code > codeLengthInfo[codelength].max) { code = ((code << 1) | stream.getNextIdatBit()); codelength++; } if (codelength >= MAX_CODE_LENGTH) stream.error(); // Now we have a Huffman code of length (codelength + 1) that // is somewhere in the range // minCodesByLength[codelength]..maxCodesByLength[codelength]. // This code is the (offset + 1)'th code of (codelength + 1); int offset = code - codeLengthInfo[codelength].min; // indexesByLength[codelength] is the first code of length (codelength + 1) // so now we can look up the value for the Huffman code in the table. int index = codeLengthInfo[codelength].baseIndex + offset; return codeValues[index]; }