/** * Generate the fixed huffman trees as described in the rfc * * @param huffmanCode - pointer to where the code shall be inserted * @param huffmanCodeLength * @param distHuffCode * @param distHuffCodeLength */ public static void genFixedTree( int[] huffmanCode, byte[] huffmanCodeLength, int[] distHuffCode, byte[] distHuffCodeLength) { int i; // huffmanCodes for (i = 0; i <= 143; i++) { huffmanCode[i] = 48 + i; // 48==00110000 huffmanCodeLength[i] = 8; } for (i = 144; i <= 255; i++) { huffmanCode[i] = 400 + i - 144; // 400==110010000 huffmanCodeLength[i] = 9; } for (i = 256; i <= 279; i++) { huffmanCode[i] = i - 256; // 0==0 huffmanCodeLength[i] = 7; } for (i = 280; i < 286; i++) { huffmanCode[i] = 192 + i - 280; // 192==11000000 huffmanCodeLength[i] = 8; } // reverse all: ZipHelper.revHuffTree(huffmanCode, huffmanCodeLength); // distHuffCode for non fixed DISTANCE tree for (int j = 0; j < distHuffCode.length; j++) { distHuffCode[j] = j; distHuffCodeLength[j] = 5; } // reverse all: ZipHelper.revHuffTree(distHuffCode, distHuffCodeLength); }
private void processHeader() throws IOException { // #debug System.out.println("processHeader()"); int val; int HLIT; // number of miniHuff fragments int HDIST; // number of distance codes (should somehow lead to the same) int HCLEN; // number of length codes int[] distHuffCode = new int[30]; int[] distHuffData = new int[30]; byte[] distHuffCodeLength = new byte[30]; int[] huffmanCode = new int[286]; // this contains the codes according to the huffman tree/mapping int[] huffmanData = new int[286]; // this contains the data referring to the code. byte[] huffmanCodeLength = new byte[286]; this.BFINAL = (popSmallBuffer(1) == 1); this.BTYPE = popSmallBuffer(2); if (this.BTYPE == 3) { throw new IllegalArgumentException(); } else if (this.BTYPE == 1) { // System.out.println(this.allPocessed + ": fixed tree"); ZipHelper.genFixedTree(huffmanCode, huffmanCodeLength, distHuffCode, distHuffCodeLength); for (int i = 0; i < 286; i++) { huffmanData[i] = i; } for (int i = 0; i < 30; i++) { distHuffData[i] = i; } // convert literal table to tree ZipHelper.convertTable2Tree(huffmanCode, huffmanCodeLength, huffmanData, this.huffmanTree); // convert distance table to tree ZipHelper.convertTable2Tree( distHuffCode, distHuffCodeLength, distHuffData, this.distHuffTree); } else if (this.BTYPE == 2) { // System.out.println(this.allPocessed + ": dynamic tree"); // read/parse the length codes HLIT = popSmallBuffer(5); HDIST = popSmallBuffer(5); HCLEN = popSmallBuffer(4); // miniTree int[] miniHuffData = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; int[] seq = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}; byte[] miniHuffCodeLength = new byte[19]; int[] miniHuffCode = new int[19]; // read the miniHuffCodeLength for (int i = 0; i < HCLEN + 4; i++) { miniHuffCodeLength[miniHuffData[i]] = (byte) popSmallBuffer(3); } ZipHelper.genHuffTree(miniHuffCode, miniHuffCodeLength); ZipHelper.revHuffTree(miniHuffCode, miniHuffCodeLength); short[] miniTree = new short[19 * 4]; ZipHelper.convertTable2Tree(miniHuffCode, miniHuffCodeLength, seq, miniTree); // parse the length code for the normal Tree and the distance Tree using the miniTree for (int i = 0; i < huffmanCodeLength.length; i++) { huffmanCodeLength[i] = 0; } for (int i = 0; i < distHuffCodeLength.length; i++) { distHuffCodeLength[i] = 0; } byte lastVal = 0; for (int j = 0; j < HLIT + 257 + HDIST + 1; ) { if (this.smallCodeBuffer[1] < 15) { refillSmallCodeBuffer(); } val = ZipHelper.deHuffNext(this.smallCodeBuffer, miniTree); // data if (val < 16) { lastVal = (byte) val; val = 1; } else { // repeat code if (val == 16) { val = popSmallBuffer(2) + 3; } else if (val == 17) { lastVal = 0; val = popSmallBuffer(3) + 3; } else if (val == 18) { lastVal = 0; val = popSmallBuffer(7) + 11; } } // fill the value in for (int k = 0; k < val; k++, j++) { if (j < HLIT + 257) { huffmanCodeLength[j] = lastVal; } else { distHuffCodeLength[j - (HLIT + 257)] = lastVal; } } } // final tree: fill this.huffmanCode this.huffmanData ZipHelper.genHuffTree(huffmanCode, huffmanCodeLength); for (int i = 0; i < huffmanData.length; i++) { huffmanData[i] = i; } // converting literal table to tree ZipHelper.revHuffTree(huffmanCode, huffmanCodeLength); ZipHelper.convertTable2Tree(huffmanCode, huffmanCodeLength, huffmanData, this.huffmanTree); // Distance Tree // distHuffData for non fixed distance tree // this.distHuffCodeLength is read together with this.huffmanCodeLength for (int j = 0; j < distHuffCode.length; j++) { distHuffData[j] = j; } ZipHelper.genHuffTree(distHuffCode, distHuffCodeLength); ZipHelper.revHuffTree(distHuffCode, distHuffCodeLength); ZipHelper.convertTable2Tree( distHuffCode, distHuffCodeLength, distHuffData, this.distHuffTree); } else { // just skip bits up to the next boundary popSmallBuffer(this.smallCodeBuffer[1] & 7); // &7 == %8 // read and check the header this.B0len = popSmallBuffer(8) | popSmallBuffer(8) << 8; if (this.smallCodeBuffer[1] < 15) { refillSmallCodeBuffer(); } if (this.B0len + (popSmallBuffer(8) | popSmallBuffer(8) << 8) != 0xffff) { // Error: the header for the uncompressed is wrong; throw new IOException("3"); } // clear the buffer while (this.smallCodeBuffer[1] != 0 && this.B0len > 0) { val = popSmallBuffer(8); this.window[this.pProcessed] = (byte) val; this.pProcessed = (this.pProcessed + 1) & 32767; // == % (1<<15); this.outBuff[this.outEnd] = (byte) val; this.outEnd++; this.B0len--; } } this.status = GZipInputStream.EXPECTING_DATA; distHuffCode = null; distHuffData = null; distHuffCodeLength = null; huffmanCodeLength = null; huffmanCode = null; huffmanData = null; }