UncompressInputStream.java
上传用户:demmber
上传日期:2007-12-22
资源大小:717k
文件大小:10k
源码类别:

Java编程

开发平台:

Java

  1. /*
  2.  * @(#)UncompressInputStream.java 0.3-3 06/05/2001
  3.  *
  4.  *  This file is part of the HTTPClient package
  5.  *  Copyright (C) 1996-2001 Ronald Tschal鋜
  6.  *
  7.  *  This library is free software; you can redistribute it and/or
  8.  *  modify it under the terms of the GNU Lesser General Public
  9.  *  License as published by the Free Software Foundation; either
  10.  *  version 2 of the License, or (at your option) any later version.
  11.  *
  12.  *  This library is distributed in the hope that it will be useful,
  13.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  *  Lesser General Public License for more details.
  16.  *
  17.  *  You should have received a copy of the GNU Lesser General Public
  18.  *  License along with this library; if not, write to the Free
  19.  *  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  20.  *  MA 02111-1307, USA
  21.  *
  22.  *  For questions, suggestions, bug-reports, enhancement-requests etc.
  23.  *  I may be contacted at:
  24.  *
  25.  *  ronald@innovation.ch
  26.  *
  27.  *  The HTTPClient's home page is located at:
  28.  *
  29.  *  http://www.innovation.ch/java/HTTPClient/ 
  30.  *
  31.  */
  32. package HTTPClient;
  33. import java.io.IOException;
  34. import java.io.EOFException;
  35. import java.io.InputStream;
  36. import java.io.FileInputStream;
  37. import java.io.FilterInputStream;
  38. /**
  39.  * This class decompresses an input stream containing data compressed with
  40.  * the unix "compress" utility (LZC, a LZW variant). This code is based
  41.  * heavily on the <var>unlzw.c</var> code in <var>gzip-1.2.4</var> (written
  42.  * by Peter Jannesen) and the original compress code.
  43.  *
  44.  * @version 0.3-3  06/05/2001
  45.  * @author Ronald Tschal鋜
  46.  */
  47. class UncompressInputStream extends FilterInputStream
  48. {
  49.     /**
  50.      * @param is the input stream to decompress
  51.      * @exception IOException if the header is malformed
  52.      */
  53.     public UncompressInputStream(InputStream is)  throws IOException
  54.     {
  55. super(is);
  56. parse_header();
  57.     }
  58.     byte[] one = new byte[1];
  59.     public synchronized int read() throws IOException
  60.     {
  61. int b = in.read(one, 0, 1);
  62. if (b == 1)
  63.     return (one[0] & 0xff);
  64. else
  65.     return -1;
  66.     }
  67.     // string table stuff
  68.     private static final int TBL_CLEAR = 0x100;
  69.     private static final int TBL_FIRST = TBL_CLEAR + 1;
  70.     private int[]  tab_prefix;
  71.     private byte[] tab_suffix;
  72.     private int[]  zeros = new int[256];
  73.     private byte[] stack;
  74.     // various state
  75.     private boolean block_mode;
  76.     private int  n_bits;
  77.     private int  maxbits;
  78.     private int  maxmaxcode;
  79.     private int  maxcode;
  80.     private int  bitmask;
  81.     private int  oldcode;
  82.     private byte finchar;
  83.     private int  stackp;
  84.     private int  free_ent;
  85.     // input buffer
  86.     private byte[]  data = new byte[10000];
  87.     private int     bit_pos = 0, end = 0, got = 0;
  88.     private boolean eof  = false;
  89.     private static final int EXTRA = 64;
  90.     public synchronized int read(byte[] buf, int off, int len)
  91.     throws IOException
  92.     {
  93. if (eof)  return -1;
  94. int start = off;
  95. /* Using local copies of various variables speeds things up by as
  96.  * much as 30% !
  97.  */
  98. int[]  l_tab_prefix = tab_prefix;
  99. byte[] l_tab_suffix = tab_suffix;
  100. byte[] l_stack      = stack;
  101. int    l_n_bits     = n_bits;
  102. int    l_maxcode    = maxcode;
  103. int    l_maxmaxcode = maxmaxcode;
  104. int    l_bitmask    = bitmask;
  105. int    l_oldcode    = oldcode;
  106. byte   l_finchar    = finchar;
  107. int    l_stackp     = stackp;
  108. int    l_free_ent   = free_ent;
  109. byte[] l_data       = data;
  110. int    l_bit_pos    = bit_pos;
  111. // empty stack if stuff still left
  112. int s_size = l_stack.length - l_stackp;
  113. if (s_size > 0)
  114. {
  115.     int num = (s_size >= len) ? len : s_size ;
  116.     System.arraycopy(l_stack, l_stackp, buf, off, num);
  117.     off += num;
  118.     len -= num;
  119.     l_stackp += num;
  120. }
  121. if (len == 0)
  122. {
  123.     stackp = l_stackp;
  124.     return off-start;
  125. }
  126. // loop, filling local buffer until enough data has been decompressed
  127. main_loop: do
  128. {
  129.     if (end < EXTRA)  fill();
  130.     int bit_in = (got > 0) ? (end - end%l_n_bits)<<3 :
  131.      (end<<3)-(l_n_bits-1);
  132.     while (l_bit_pos < bit_in)
  133.     {
  134. // check for code-width expansion
  135. if (l_free_ent > l_maxcode)
  136. {
  137.     int n_bytes = l_n_bits << 3;
  138.     l_bit_pos = (l_bit_pos-1) +
  139. n_bytes - (l_bit_pos-1+n_bytes) % n_bytes;
  140.     l_n_bits++;
  141.     l_maxcode = (l_n_bits==maxbits) ? l_maxmaxcode :
  142.       (1<<l_n_bits) - 1;
  143.     if (debug)
  144. System.err.println("Code-width expanded to " + l_n_bits);
  145.     l_bitmask = (1<<l_n_bits)-1;
  146.     l_bit_pos = resetbuf(l_bit_pos);
  147.     continue main_loop;
  148. }
  149. // read next code
  150. int pos = l_bit_pos>>3;
  151. int code = (((l_data[pos]&0xFF) | ((l_data[pos+1]&0xFF)<<8) |
  152.     ((l_data[pos+2]&0xFF)<<16))
  153.     >> (l_bit_pos & 0x7)) & l_bitmask;
  154. l_bit_pos += l_n_bits;
  155. // handle first iteration
  156. if (l_oldcode == -1)
  157. {
  158.     if (code >= 256)
  159. throw new IOException("corrupt input: " + code +
  160.       " > 255");
  161.     l_finchar = (byte) (l_oldcode = code);
  162.     buf[off++] = l_finchar;
  163.     len--;
  164.     continue;
  165. }
  166. // handle CLEAR code
  167. if (code == TBL_CLEAR && block_mode)
  168. {
  169.     System.arraycopy(zeros, 0, l_tab_prefix, 0, zeros.length);
  170.     l_free_ent = TBL_FIRST - 1;
  171.     int n_bytes = l_n_bits << 3;
  172.     l_bit_pos = (l_bit_pos-1) +
  173. n_bytes - (l_bit_pos-1+n_bytes) % n_bytes;
  174.     l_n_bits  = INIT_BITS;
  175.     l_maxcode = (1 << l_n_bits) - 1;
  176.     l_bitmask = l_maxcode;
  177.     if (debug)  System.err.println("Code tables reset");
  178.     l_bit_pos = resetbuf(l_bit_pos);
  179.     continue main_loop;
  180. }
  181. // setup
  182. int incode = code;
  183. l_stackp = l_stack.length;
  184. // Handle KwK case
  185. if (code >= l_free_ent)
  186. {
  187.     if (code > l_free_ent)
  188. throw new IOException("corrupt input: code=" + code +
  189.       ", free_ent=" + l_free_ent);
  190.     
  191.     l_stack[--l_stackp] = l_finchar;
  192.     code = l_oldcode;
  193. }
  194. // Generate output characters in reverse order
  195. while (code >= 256)
  196. {
  197.     l_stack[--l_stackp] = l_tab_suffix[code];
  198.     code = l_tab_prefix[code];
  199. }
  200. l_finchar  = l_tab_suffix[code];
  201. buf[off++] = l_finchar;
  202. len--;
  203. // And put them out in forward order
  204. s_size = l_stack.length - l_stackp;
  205. int num = (s_size >= len) ? len : s_size ;
  206. System.arraycopy(l_stack, l_stackp, buf, off, num);
  207. off += num;
  208. len -= num;
  209. l_stackp += num;
  210. // generate new entry in table
  211. if (l_free_ent < l_maxmaxcode)
  212. {
  213.     l_tab_prefix[l_free_ent] = l_oldcode;
  214.     l_tab_suffix[l_free_ent] = l_finchar;
  215.     l_free_ent++;
  216. }
  217. // Remember previous code
  218. l_oldcode = incode;
  219. // if output buffer full, then return
  220. if (len == 0)
  221. {
  222.     n_bits   = l_n_bits;
  223.     maxcode  = l_maxcode;
  224.     bitmask  = l_bitmask;
  225.     oldcode  = l_oldcode;
  226.     finchar  = l_finchar;
  227.     stackp   = l_stackp;
  228.     free_ent = l_free_ent;
  229.     bit_pos  = l_bit_pos;
  230.     return off-start;
  231. }
  232.     }
  233.     l_bit_pos = resetbuf(l_bit_pos);
  234. } while (got > 0);
  235. n_bits   = l_n_bits;
  236. maxcode  = l_maxcode;
  237. bitmask  = l_bitmask;
  238. oldcode  = l_oldcode;
  239. finchar  = l_finchar;
  240. stackp   = l_stackp;
  241. free_ent = l_free_ent;
  242. bit_pos  = l_bit_pos;
  243. eof = true;
  244. return off-start;
  245.     }
  246.     /**
  247.      * Moves the unread data in the buffer to the beginning and resets
  248.      * the pointers.
  249.      */
  250.     private final int resetbuf(int bit_pos)
  251.     {
  252. int pos = bit_pos >> 3;
  253. System.arraycopy(data, pos, data, 0, end-pos);
  254. end -= pos;
  255. return 0;
  256.     }
  257.     private final void fill()  throws IOException
  258.     {
  259. got = in.read(data, end, data.length-1-end);
  260. if (got > 0)  end += got;
  261.     }
  262.     public synchronized long skip(long num)  throws IOException
  263.     {
  264. byte[] tmp = new byte[(int) num];
  265. int got = read(tmp, 0, (int) num);
  266. if (got > 0)
  267.     return (long) got;
  268. else
  269.     return 0L;
  270.     }
  271.     public synchronized int available()  throws IOException
  272.     {
  273. if (eof)  return 0;
  274. return in.available();
  275.     }
  276.     private static final int LZW_MAGIC = 0x1f9d;
  277.     private static final int MAX_BITS = 16;
  278.     private static final int INIT_BITS = 9;
  279.     private static final int HDR_MAXBITS  = 0x1f;
  280.     private static final int HDR_EXTENDED = 0x20;
  281.     private static final int HDR_FREE      = 0x40;
  282.     private static final int HDR_BLOCK_MODE = 0x80;
  283.     private void parse_header()  throws IOException
  284.     {
  285. // read in and check magic number 
  286. int t = in.read();
  287. if (t < 0)  throw new EOFException("Failed to read magic number");
  288. int magic = (t & 0xff) << 8;
  289. t = in.read();
  290. if (t < 0)  throw new EOFException("Failed to read magic number");
  291. magic += t & 0xff;
  292. if (magic != LZW_MAGIC)
  293.     throw new IOException("Input not in compress format (read " +
  294.   "magic number 0x" +
  295.   Integer.toHexString(magic) + ")");
  296. // read in header byte
  297. int header = in.read();
  298. if (header < 0)  throw new EOFException("Failed to read header");
  299. block_mode = (header & HDR_BLOCK_MODE) > 0;
  300. maxbits    = header & HDR_MAXBITS;
  301. if (maxbits > MAX_BITS)
  302.     throw new IOException("Stream compressed with " + maxbits +
  303.   " bits, but can only handle " + MAX_BITS +
  304.   " bits");
  305. if ((header & HDR_EXTENDED) > 0)
  306.     throw new IOException("Header extension bit set");
  307. if ((header & HDR_FREE) > 0)
  308.     throw new IOException("Header bit 6 set");
  309. if (debug)
  310. {
  311.     System.err.println("block mode: " + block_mode);
  312.     System.err.println("max bits:   " + maxbits);
  313. }
  314. // initialize stuff
  315. maxmaxcode = 1 << maxbits;
  316. n_bits     = INIT_BITS;
  317. maxcode    = (1 << n_bits) - 1;
  318. bitmask    = maxcode;
  319. oldcode    = -1;
  320. finchar    = 0;
  321. free_ent   = block_mode ? TBL_FIRST : 256;
  322. tab_prefix = new int[1 << maxbits];
  323. tab_suffix = new byte[1 << maxbits];
  324. stack      = new byte[1 << maxbits];
  325. stackp     = stack.length;
  326. for (int idx=255; idx>=0; idx--)
  327.     tab_suffix[idx] = (byte) idx;
  328.     }
  329.     private static final boolean debug = false;
  330.     public static void main (String args[])  throws Exception
  331.     {
  332. if (args.length != 1)
  333. {
  334.     System.err.println("Usage: UncompressInputStream <file>");
  335.     System.exit(1);
  336. }
  337. InputStream in =
  338.     new UncompressInputStream(new FileInputStream(args[0]));
  339. byte[] buf = new byte[100000];
  340. int tot = 0;
  341. long beg = System.currentTimeMillis();
  342. while (true)
  343. {
  344.     int got = in.read(buf);
  345.     if (got < 0)  break;
  346.     System.out.write(buf, 0, got);
  347.     tot += got;
  348. }
  349. long end = System.currentTimeMillis();
  350. System.err.println("Decompressed " + tot + " bytes");
  351. System.err.println("Time: " + (end-beg)/1000. + " seconds");
  352.     }
  353. }