# HG changeset patch
# User Jaroslav Tulach
+ * Note: When using the 'nowrap' option it is also necessary to provide
+ * an extra "dummy" byte as input. This is required by the ZLIB native
+ * library in order to support certain optimizations.
+ *
+ * @param nowrap if true then support GZIP compatible compression
*/
-
- if ((header & 0x0020) == 0) // Dictionary flag?
- {
- mode = DECODE_BLOCKS;
- }
- else
- {
- mode = DECODE_DICT;
- neededBits = 32;
- }
- return true;
- }
-
- /**
- * Decodes the dictionary checksum after the deflate header.
- * @return false if more input is needed.
- */
- private boolean decodeDict ()
- {
- while (neededBits > 0)
- {
- int dictByte = input.peekBits(8);
- if (dictByte < 0)
- return false;
- input.dropBits(8);
- readAdler = (readAdler << 8) | dictByte;
- neededBits -= 8;
- }
- return false;
- }
-
- /**
- * Decodes the huffman encoded symbols in the input stream.
- * @return false if more input is needed, true if output window is
- * full or the current block ends.
- * @exception DataFormatException if deflated stream is invalid.
- */
- private boolean decodeHuffman () throws DataFormatException
- {
- int free = outputWindow.getFreeSpace();
- while (free >= 258)
- {
- int symbol;
- switch (mode)
- {
- case DECODE_HUFFMAN:
- /* This is the inner loop so it is optimized a bit */
- while (((symbol = litlenTree.getSymbol(input)) & ~0xff) == 0)
- {
- outputWindow.write(symbol);
- if (--free < 258)
- return true;
- }
- if (symbol < 257)
- {
- if (symbol < 0)
- return false;
- else
- {
- /* symbol == 256: end of block */
- distTree = null;
- litlenTree = null;
- mode = DECODE_BLOCKS;
- return true;
- }
- }
-
- try
- {
- repLength = CPLENS[symbol - 257];
- neededBits = CPLEXT[symbol - 257];
- }
- catch (ArrayIndexOutOfBoundsException ex)
- {
- throw new DataFormatException("Illegal rep length code");
- }
- /* fall through */
- case DECODE_HUFFMAN_LENBITS:
- if (neededBits > 0)
- {
- mode = DECODE_HUFFMAN_LENBITS;
- int i = input.peekBits(neededBits);
- if (i < 0)
- return false;
- input.dropBits(neededBits);
- repLength += i;
- }
- mode = DECODE_HUFFMAN_DIST;
- /* fall through */
- case DECODE_HUFFMAN_DIST:
- symbol = distTree.getSymbol(input);
- if (symbol < 0)
- return false;
- try
- {
- repDist = CPDIST[symbol];
- neededBits = CPDEXT[symbol];
- }
- catch (ArrayIndexOutOfBoundsException ex)
- {
- throw new DataFormatException("Illegal rep dist code");
- }
- /* fall through */
- case DECODE_HUFFMAN_DISTBITS:
- if (neededBits > 0)
- {
- mode = DECODE_HUFFMAN_DISTBITS;
- int i = input.peekBits(neededBits);
- if (i < 0)
- return false;
- input.dropBits(neededBits);
- repDist += i;
- }
- outputWindow.repeat(repLength, repDist);
- free -= repLength;
- mode = DECODE_HUFFMAN;
- break;
- default:
- throw new IllegalStateException();
- }
- }
- return true;
- }
-
- /**
- * Decodes the adler checksum after the deflate stream.
- * @return false if more input is needed.
- * @exception DataFormatException if checksum doesn't match.
- */
- private boolean decodeChksum () throws DataFormatException
- {
- while (neededBits > 0)
- {
- int chkByte = input.peekBits(8);
- if (chkByte < 0)
- return false;
- input.dropBits(8);
- readAdler = (readAdler << 8) | chkByte;
- neededBits -= 8;
- }
- if ((int) adler.getValue() != readAdler)
- throw new DataFormatException("Adler chksum doesn't match: "
- +Integer.toHexString((int)adler.getValue())
- +" vs. "+Integer.toHexString(readAdler));
- mode = FINISHED;
- return false;
- }
-
- /**
- * Decodes the deflated stream.
- * @return false if more input is needed, or if finished.
- * @exception DataFormatException if deflated stream is invalid.
- */
- private boolean decode () throws DataFormatException
- {
- switch (mode)
- {
- case DECODE_HEADER:
- return decodeHeader();
- case DECODE_DICT:
- return decodeDict();
- case DECODE_CHKSUM:
- return decodeChksum();
-
- case DECODE_BLOCKS:
- if (isLastBlock)
- {
- if (nowrap)
- {
- mode = FINISHED;
- return false;
- }
- else
- {
- input.skipToByteBoundary();
- neededBits = 32;
- mode = DECODE_CHKSUM;
- return true;
- }
- }
-
- int type = input.peekBits(3);
- if (type < 0)
- return false;
- input.dropBits(3);
-
- if ((type & 1) != 0)
- isLastBlock = true;
- switch (type >> 1)
- {
- case DeflaterConstants.STORED_BLOCK:
- input.skipToByteBoundary();
- mode = DECODE_STORED_LEN1;
- break;
- case DeflaterConstants.STATIC_TREES:
- litlenTree = InflaterHuffmanTree.defLitLenTree;
- distTree = InflaterHuffmanTree.defDistTree;
- mode = DECODE_HUFFMAN;
- break;
- case DeflaterConstants.DYN_TREES:
- dynHeader = new InflaterDynHeader();
- mode = DECODE_DYN_HEADER;
- break;
- default:
- throw new DataFormatException("Unknown block type "+type);
- }
- return true;
-
- case DECODE_STORED_LEN1:
- {
- if ((uncomprLen = input.peekBits(16)) < 0)
- return false;
- input.dropBits(16);
- mode = DECODE_STORED_LEN2;
- }
- /* fall through */
- case DECODE_STORED_LEN2:
- {
- int nlen = input.peekBits(16);
- if (nlen < 0)
- return false;
- input.dropBits(16);
- if (nlen != (uncomprLen ^ 0xffff))
- throw new DataFormatException("broken uncompressed block");
- mode = DECODE_STORED;
- }
- /* fall through */
- case DECODE_STORED:
- {
- int more = outputWindow.copyStored(input, uncomprLen);
- uncomprLen -= more;
- if (uncomprLen == 0)
- {
- mode = DECODE_BLOCKS;
- return true;
- }
- return !input.needsInput();
- }
-
- case DECODE_DYN_HEADER:
- if (!dynHeader.decode(input))
- return false;
- litlenTree = dynHeader.buildLitLenTree();
- distTree = dynHeader.buildDistTree();
- mode = DECODE_HUFFMAN;
- /* fall through */
- case DECODE_HUFFMAN:
- case DECODE_HUFFMAN_LENBITS:
- case DECODE_HUFFMAN_DIST:
- case DECODE_HUFFMAN_DISTBITS:
- return decodeHuffman();
- case FINISHED:
- return false;
- default:
- throw new IllegalStateException();
- }
- }
-
-
- interface DeflaterConstants {
- final static boolean DEBUGGING = false;
-
- final static int STORED_BLOCK = 0;
- final static int STATIC_TREES = 1;
- final static int DYN_TREES = 2;
- final static int PRESET_DICT = 0x20;
-
- final static int DEFAULT_MEM_LEVEL = 8;
-
- final static int MAX_MATCH = 258;
- final static int MIN_MATCH = 3;
-
- final static int MAX_WBITS = 15;
- final static int WSIZE = 1 << MAX_WBITS;
- final static int WMASK = WSIZE - 1;
-
- final static int HASH_BITS = DEFAULT_MEM_LEVEL + 7;
- final static int HASH_SIZE = 1 << HASH_BITS;
- final static int HASH_MASK = HASH_SIZE - 1;
- final static int HASH_SHIFT = (HASH_BITS + MIN_MATCH - 1) / MIN_MATCH;
-
- final static int MIN_LOOKAHEAD = MAX_MATCH + MIN_MATCH + 1;
- final static int MAX_DIST = WSIZE - MIN_LOOKAHEAD;
-
- final static int PENDING_BUF_SIZE = 1 << (DEFAULT_MEM_LEVEL + 8);
- final static int MAX_BLOCK_SIZE = Math.min(65535, PENDING_BUF_SIZE-5);
-
- final static int DEFLATE_STORED = 0;
- final static int DEFLATE_FAST = 1;
- final static int DEFLATE_SLOW = 2;
-
- final static int GOOD_LENGTH[] = { 0,4, 4, 4, 4, 8, 8, 8, 32, 32 };
- final static int MAX_LAZY[] = { 0,4, 5, 6, 4,16, 16, 32, 128, 258 };
- final static int NICE_LENGTH[] = { 0,8,16,32,16,32,128,128, 258, 258 };
- final static int MAX_CHAIN[] = { 0,4, 8,32,16,32,128,256,1024,4096 };
- final static int COMPR_FUNC[] = { 0,1, 1, 1, 1, 2, 2, 2, 2, 2 };
- }
- private static class InflaterHuffmanTree {
- private final static int MAX_BITLEN = 15;
- private short[] tree;
-
- public static InflaterHuffmanTree defLitLenTree, defDistTree;
-
- static
- {
- try
- {
- byte[] codeLengths = new byte[288];
- int i = 0;
- while (i < 144)
- codeLengths[i++] = 8;
- while (i < 256)
- codeLengths[i++] = 9;
- while (i < 280)
- codeLengths[i++] = 7;
- while (i < 288)
- codeLengths[i++] = 8;
- defLitLenTree = new InflaterHuffmanTree(codeLengths);
-
- codeLengths = new byte[32];
- i = 0;
- while (i < 32)
- codeLengths[i++] = 5;
- defDistTree = new InflaterHuffmanTree(codeLengths);
- }
- catch (DataFormatException ex)
- {
- throw new IllegalStateException
- ("InflaterHuffmanTree: static tree length illegal");
- }
- }
-
- /**
- * Constructs a Huffman tree from the array of code lengths.
- *
- * @param codeLengths the array of code lengths
- */
- public InflaterHuffmanTree(byte[] codeLengths) throws DataFormatException
- {
- buildTree(codeLengths);
- }
-
- private void buildTree(byte[] codeLengths) throws DataFormatException
- {
- int[] blCount = new int[MAX_BITLEN+1];
- int[] nextCode = new int[MAX_BITLEN+1];
- for (int i = 0; i < codeLengths.length; i++)
- {
- int bits = codeLengths[i];
- if (bits > 0)
- blCount[bits]++;
- }
-
- int code = 0;
- int treeSize = 512;
- for (int bits = 1; bits <= MAX_BITLEN; bits++)
- {
- nextCode[bits] = code;
- code += blCount[bits] << (16 - bits);
- if (bits >= 10)
- {
- /* We need an extra table for bit lengths >= 10. */
- int start = nextCode[bits] & 0x1ff80;
- int end = code & 0x1ff80;
- treeSize += (end - start) >> (16 - bits);
- }
- }
- if (code != 65536)
- throw new DataFormatException("Code lengths don't add up properly.");
-
- fillTable1(treeSize, code, blCount);
-
- for (int i = 0; i < codeLengths.length; i++)
- {
- int bits = codeLengths[i];
- if (bits == 0)
- continue;
- code = nextCode[bits];
- int revcode = bitReverse(code);
- if (bits <= 9)
- {
- do
- {
- tree[revcode] = (short) ((i << 4) | bits);
- revcode += 1 << bits;
- }
- while (revcode < 512);
- }
- else
- {
- int subTree = tree[revcode & 511];
- int treeLen = 1 << (subTree & 15);
- subTree = -(subTree >> 4);
- do
- {
- tree[subTree | (revcode >> 9)] = (short) ((i << 4) | bits);
- revcode += 1 << bits;
- }
- while (revcode < treeLen);
- }
- nextCode[bits] = code + (1 << (16 - bits));
- }
- }
- private final static String bit4Reverse =
- "\000\010\004\014\002\012\006\016\001\011\005\015\003\013\007\017";
- static short bitReverse(int value) {
- return (short) (bit4Reverse.charAt(value & 0xf) << 12
- | bit4Reverse.charAt((value >> 4) & 0xf) << 8
- | bit4Reverse.charAt((value >> 8) & 0xf) << 4
- | bit4Reverse.charAt(value >> 12));
- }
-
- /**
- * Reads the next symbol from input. The symbol is encoded using the
- * huffman tree.
- * @param input the input source.
- * @return the next symbol, or -1 if not enough input is available.
- */
- public int getSymbol(StreamManipulator input) throws DataFormatException
- {
- int lookahead, symbol;
- if ((lookahead = input.peekBits(9)) >= 0)
- {
- if ((symbol = tree[lookahead]) >= 0)
- {
- input.dropBits(symbol & 15);
- return symbol >> 4;
- }
- int subtree = -(symbol >> 4);
- int bitlen = symbol & 15;
- if ((lookahead = input.peekBits(bitlen)) >= 0)
- {
- symbol = tree[subtree | (lookahead >> 9)];
- input.dropBits(symbol & 15);
- return symbol >> 4;
- }
- else
- {
- int bits = input.getAvailableBits();
- lookahead = input.peekBits(bits);
- symbol = tree[subtree | (lookahead >> 9)];
- if ((symbol & 15) <= bits)
- {
- input.dropBits(symbol & 15);
- return symbol >> 4;
- }
- else
- return -1;
- }
- }
- else
- {
- int bits = input.getAvailableBits();
- lookahead = input.peekBits(bits);
- symbol = tree[lookahead];
- if (symbol >= 0 && (symbol & 15) <= bits)
- {
- input.dropBits(symbol & 15);
- return symbol >> 4;
- }
- else
- return -1;
- }
- }
-
- private void fillTable1(int treeSize, int code, int[] blCount) {
- /* Now create and fill the extra tables from longest to shortest
- * bit len. This way the sub trees will be aligned.
- */
- tree = new short[treeSize];
- int treePtr = 512;
- for (int bits = MAX_BITLEN; bits >= 10; bits--) {
- int end = code & 0x1ff80;
- code -= blCount[bits] << (16 - bits);
- int start = code & 0x1ff80;
- final int inc = 1 << 7;
- fillTable2(start, end, inc, treePtr, bits);
- }
- }
-
- private void fillTable2(int start, int end, final int inc, int treePtr, int bits) {
- for (int i = start; i < end; i += inc) {
- final short br = bitReverse(i);
- tree[br] = (short) ((-treePtr << 4) | bits);
- treePtr += 1 << (bits - 9);
- }
+ public Inflater(boolean nowrap) {
+ if (getClass() == org.apidesign.bck2brwsr.emul.zip.Inflater.class) {
+ impl = null;
+ } else {
+ impl = new org.apidesign.bck2brwsr.emul.zip.Inflater(nowrap);
}
}
- private static class InflaterDynHeader
+
+ /**
+ * Creates a new decompressor.
+ */
+ public Inflater() {
+ this(false);
+ }
+
+ /**
+ * Sets input data for decompression. Should be called whenever
+ * needsInput() returns true indicating that more input data is
+ * required.
+ * @param b the input data bytes
+ * @param off the start offset of the input data
+ * @param len the length of the input data
+ * @see Inflater#needsInput
+ */
+ public void setInput(byte[] b, int off, int len) {
+ impl.setInput(b, off, len);
+ }
+
+ /**
+ * Sets input data for decompression. Should be called whenever
+ * needsInput() returns true indicating that more input data is
+ * required.
+ * @param b the input data bytes
+ * @see Inflater#needsInput
+ */
+ public void setInput(byte[] b) {
+ impl.setInput(b);
+ }
+
+ /**
+ * Sets the preset dictionary to the given array of bytes. Should be
+ * called when inflate() returns 0 and needsDictionary() returns true
+ * indicating that a preset dictionary is required. The method getAdler()
+ * can be used to get the Adler-32 value of the dictionary needed.
+ * @param b the dictionary data bytes
+ * @param off the start offset of the data
+ * @param len the length of the data
+ * @see Inflater#needsDictionary
+ * @see Inflater#getAdler
+ */
+ public void setDictionary(byte[] b, int off, int len) {
+ impl.setDictionary(b, off, len);
+ }
+
+ /**
+ * Sets the preset dictionary to the given array of bytes. Should be
+ * called when inflate() returns 0 and needsDictionary() returns true
+ * indicating that a preset dictionary is required. The method getAdler()
+ * can be used to get the Adler-32 value of the dictionary needed.
+ * @param b the dictionary data bytes
+ * @see Inflater#needsDictionary
+ * @see Inflater#getAdler
+ */
+ public void setDictionary(byte[] b) {
+ impl.setDictionary(b);
+ }
+
+ /**
+ * Returns the total number of bytes remaining in the input buffer.
+ * This can be used to find out what bytes still remain in the input
+ * buffer after decompression has finished.
+ * @return the total number of bytes remaining in the input buffer
+ */
+ public int getRemaining() {
+ return impl.getRemaining();
+ }
+
+ /**
+ * Returns true if no data remains in the input buffer. This can
+ * be used to determine if #setInput should be called in order
+ * to provide more input.
+ * @return true if no data remains in the input buffer
+ */
+ public boolean needsInput() {
+ return impl.needsInput();
+ }
+
+ /**
+ * Returns true if a preset dictionary is needed for decompression.
+ * @return true if a preset dictionary is needed for decompression
+ * @see Inflater#setDictionary
+ */
+ public boolean needsDictionary() {
+ return impl.needsDictionary();
+ }
+
+ /**
+ * Returns true if the end of the compressed data stream has been
+ * reached.
+ * @return true if the end of the compressed data stream has been
+ * reached
+ */
+ public boolean finished() {
+ return impl.finished();
+ }
+
+ /**
+ * Uncompresses bytes into specified buffer. Returns actual number
+ * of bytes uncompressed. A return value of 0 indicates that
+ * needsInput() or needsDictionary() should be called in order to
+ * determine if more input data or a preset dictionary is required.
+ * In the latter case, getAdler() can be used to get the Adler-32
+ * value of the dictionary required.
+ * @param b the buffer for the uncompressed data
+ * @param off the start offset of the data
+ * @param len the maximum number of uncompressed bytes
+ * @return the actual number of uncompressed bytes
+ * @exception DataFormatException if the compressed data format is invalid
+ * @see Inflater#needsInput
+ * @see Inflater#needsDictionary
+ */
+ public int inflate(byte[] b, int off, int len)
+ throws DataFormatException
{
- private static final int LNUM = 0;
- private static final int DNUM = 1;
- private static final int BLNUM = 2;
- private static final int BLLENS = 3;
- private static final int LENS = 4;
- private static final int REPS = 5;
+ return impl.inflate(b, off, len);
+ }
- private static final int repMin[] = { 3, 3, 11 };
- private static final int repBits[] = { 2, 3, 7 };
+ /**
+ * Uncompresses bytes into specified buffer. Returns actual number
+ * of bytes uncompressed. A return value of 0 indicates that
+ * needsInput() or needsDictionary() should be called in order to
+ * determine if more input data or a preset dictionary is required.
+ * In the latter case, getAdler() can be used to get the Adler-32
+ * value of the dictionary required.
+ * @param b the buffer for the uncompressed data
+ * @return the actual number of uncompressed bytes
+ * @exception DataFormatException if the compressed data format is invalid
+ * @see Inflater#needsInput
+ * @see Inflater#needsDictionary
+ */
+ public int inflate(byte[] b) throws DataFormatException {
+ return impl.inflate(b);
+ }
+ /**
+ * Returns the ADLER-32 value of the uncompressed data.
+ * @return the ADLER-32 value of the uncompressed data
+ */
+ public int getAdler() {
+ return impl.getAdler();
+ }
- private byte[] blLens;
- private byte[] litdistLens;
+ /**
+ * Returns the total number of compressed bytes input so far.
+ *
+ * Since the number of bytes may be greater than
+ * Integer.MAX_VALUE, the {@link #getBytesRead()} method is now
+ * the preferred means of obtaining this information.setInput()
, then inflate() it. If inflate doesn't
- * inflate any bytes there may be three reasons:
- *
- *
- * Once the first output byte is produced, a dictionary will not be
- * needed at a later stage.
- *
- * @author John Leuner, Jochen Hoenicke
- * @author Tom Tromey
- * @date May 17, 1999
- * @since JDK 1.1
- */
-public class Inflater
-{
- /* Copy lengths for literal codes 257..285 */
- private static final int CPLENS[] =
- {
- 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
- 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258
- };
-
- /* Extra bits for literal codes 257..285 */
- private static final int CPLEXT[] =
- {
- 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
- 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0
- };
-
- /* Copy offsets for distance codes 0..29 */
- private static final int CPDIST[] = {
- 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
- 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
- 8193, 12289, 16385, 24577
- };
-
- /* Extra bits for distance codes */
- private static final int CPDEXT[] = {
- 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
- 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
- 12, 12, 13, 13
- };
-
- /* This are the state in which the inflater can be. */
- private static final int DECODE_HEADER = 0;
- private static final int DECODE_DICT = 1;
- private static final int DECODE_BLOCKS = 2;
- private static final int DECODE_STORED_LEN1 = 3;
- private static final int DECODE_STORED_LEN2 = 4;
- private static final int DECODE_STORED = 5;
- private static final int DECODE_DYN_HEADER = 6;
- private static final int DECODE_HUFFMAN = 7;
- private static final int DECODE_HUFFMAN_LENBITS = 8;
- private static final int DECODE_HUFFMAN_DIST = 9;
- private static final int DECODE_HUFFMAN_DISTBITS = 10;
- private static final int DECODE_CHKSUM = 11;
- private static final int FINISHED = 12;
-
- /** This variable contains the current state. */
- private int mode;
-
- /**
- * The adler checksum of the dictionary or of the decompressed
- * stream, as it is written in the header resp. footer of the
- * compressed stream. setInput()
.
- * NOTE: needsInput() also returns true when, the stream is finished.
- * setDictionary()
.
- *
- * Only valid if mode is DECODE_DICT or DECODE_CHKSUM.
- */
- private int readAdler;
- /**
- * The number of bits needed to complete the current state. This
- * is valid, if mode is DECODE_DICT, DECODE_CHKSUM,
- * DECODE_HUFFMAN_LENBITS or DECODE_HUFFMAN_DISTBITS.
- */
- private int neededBits;
- private int repLength, repDist;
- private int uncomprLen;
- /**
- * True, if the last block flag was set in the last block of the
- * inflated stream. This means that the stream ends after the
- * current block.
- */
- private boolean isLastBlock;
-
- /**
- * The total number of inflated bytes.
- */
- private long totalOut;
- /**
- * The total number of bytes set with setInput(). This is not the
- * value returned by getTotalIn(), since this also includes the
- * unprocessed input.
- */
- private long totalIn;
- /**
- * This variable stores the nowrap flag that was given to the constructor.
- * True means, that the inflated stream doesn't contain a header nor the
- * checksum in the footer.
- */
- private boolean nowrap;
-
- private StreamManipulator input;
- private OutputWindow outputWindow;
- private InflaterDynHeader dynHeader;
- private InflaterHuffmanTree litlenTree, distTree;
- private Adler32 adler;
-
- /**
- * Creates a new inflater.
- */
- public Inflater ()
- {
- this (false);
- }
-
- /**
- * Creates a new inflater.
- * @param nowrap true if no header and checksum field appears in the
- * stream. This is used for GZIPed input. For compatibility with
- * Sun JDK you should provide one byte of input more than needed in
- * this case.
- */
- public Inflater (boolean nowrap)
- {
- this.nowrap = nowrap;
- this.adler = new Adler32();
- input = new StreamManipulator();
- outputWindow = new OutputWindow();
- mode = nowrap ? DECODE_BLOCKS : DECODE_HEADER;
- }
-
- /**
- * Finalizes this object.
- */
- protected void finalize ()
- {
- /* Exists only for compatibility */
- }
-
- /**
- * Frees all objects allocated by the inflater. There's no reason
- * to call this, since you can just rely on garbage collection (even
- * for the Sun implementation). Exists only for compatibility
- * with Sun's JDK, where the compressor allocates native memory.
- * If you call any method (even reset) afterwards the behaviour is
- * undefined.
- * @deprecated Just clear all references to inflater instead.
- */
- public void end ()
- {
- outputWindow = null;
- input = null;
- dynHeader = null;
- litlenTree = null;
- distTree = null;
- adler = null;
- }
-
- /**
- * Returns true, if the inflater has finished. This means, that no
- * input is needed and no output can be produced.
- */
- public boolean finished()
- {
- return mode == FINISHED && outputWindow.getAvailable() == 0;
- }
-
- /**
- * Gets the adler checksum. This is either the checksum of all
- * uncompressed bytes returned by inflate(), or if needsDictionary()
- * returns true (and thus no output was yet produced) this is the
- * adler checksum of the expected dictionary.
- * @returns the adler checksum.
- */
- public int getAdler()
- {
- return needsDictionary() ? readAdler : (int) adler.getValue();
- }
-
- /**
- * Gets the number of unprocessed input. Useful, if the end of the
- * stream is reached and you want to further process the bytes after
- * the deflate stream.
- * @return the number of bytes of the input which were not processed.
- */
- public int getRemaining()
- {
- return input.getAvailableBytes();
- }
-
- /**
- * Gets the total number of processed compressed input bytes.
- * @return the total number of bytes of processed input bytes.
- */
- public int getTotalIn()
- {
- return (int)getBytesRead();
- }
-
- /**
- * Gets the total number of output bytes returned by inflate().
- * @return the total number of output bytes.
- */
- public int getTotalOut()
- {
- return (int)totalOut;
- }
-
- public long getBytesWritten() {
- return totalOut;
- }
-
- public long getBytesRead() {
- return totalIn - getRemaining();
- }
-
-
- /**
- * Inflates the compressed stream to the output buffer. If this
- * returns 0, you should check, whether needsDictionary(),
- * needsInput() or finished() returns true, to determine why no
- * further output is produced.
- * @param buffer the output buffer.
- * @return the number of bytes written to the buffer, 0 if no further
- * output can be produced.
- * @exception DataFormatException if deflated stream is invalid.
- * @exception IllegalArgumentException if buf has length 0.
- */
- public int inflate (byte[] buf) throws DataFormatException
- {
- return inflate (buf, 0, buf.length);
- }
-
- /**
- * Inflates the compressed stream to the output buffer. If this
- * returns 0, you should check, whether needsDictionary(),
- * needsInput() or finished() returns true, to determine why no
- * further output is produced.
- * @param buffer the output buffer.
- * @param off the offset into buffer where the output should start.
- * @param len the maximum length of the output.
- * @return the number of bytes written to the buffer, 0 if no further
- * output can be produced.
- * @exception DataFormatException if deflated stream is invalid.
- * @exception IndexOutOfBoundsException if the off and/or len are wrong.
- */
- public int inflate (byte[] buf, int off, int len) throws DataFormatException
- {
- /* Special case: len may be zero */
- if (len == 0)
- return 0;
- /* Check for correct buff, off, len triple */
- if (0 > off || off > off + len || off + len > buf.length)
- throw new ArrayIndexOutOfBoundsException();
- int count = 0;
- int more;
- do
- {
- if (mode != DECODE_CHKSUM)
- {
- /* Don't give away any output, if we are waiting for the
- * checksum in the input stream.
- *
- * With this trick we have always:
- * needsInput() and not finished()
- * implies more output can be produced.
- */
- more = outputWindow.copyOutput(buf, off, len);
- adler.update(buf, off, more);
- off += more;
- count += more;
- totalOut += more;
- len -= more;
- if (len == 0)
- return count;
- }
- }
- while (decode() || (outputWindow.getAvailable() > 0
- && mode != DECODE_CHKSUM));
- return count;
- }
-
- /**
- * Returns true, if a preset dictionary is needed to inflate the input.
- */
- public boolean needsDictionary ()
- {
- return mode == DECODE_DICT && neededBits == 0;
- }
-
- /**
- * Returns true, if the input buffer is empty.
- * You should then call setInput().
- *
- * NOTE: This method also returns true when the stream is finished.
- */
- public boolean needsInput ()
- {
- return input.needsInput ();
- }
-
- /**
- * Resets the inflater so that a new stream can be decompressed. All
- * pending input and output will be discarded.
- */
- public void reset ()
- {
- mode = nowrap ? DECODE_BLOCKS : DECODE_HEADER;
- totalIn = totalOut = 0;
- input.reset();
- outputWindow.reset();
- dynHeader = null;
- litlenTree = null;
- distTree = null;
- isLastBlock = false;
- adler.reset();
- }
-
- /**
- * Sets the preset dictionary. This should only be called, if
- * needsDictionary() returns true and it should set the same
- * dictionary, that was used for deflating. The getAdler()
- * function returns the checksum of the dictionary needed.
- * @param buffer the dictionary.
- * @exception IllegalStateException if no dictionary is needed.
- * @exception IllegalArgumentException if the dictionary checksum is
- * wrong.
- */
- public void setDictionary (byte[] buffer)
- {
- setDictionary(buffer, 0, buffer.length);
- }
-
- /**
- * Sets the preset dictionary. This should only be called, if
- * needsDictionary() returns true and it should set the same
- * dictionary, that was used for deflating. The getAdler()
- * function returns the checksum of the dictionary needed.
- * @param buffer the dictionary.
- * @param off the offset into buffer where the dictionary starts.
- * @param len the length of the dictionary.
- * @exception IllegalStateException if no dictionary is needed.
- * @exception IllegalArgumentException if the dictionary checksum is
- * wrong.
- * @exception IndexOutOfBoundsException if the off and/or len are wrong.
- */
- public void setDictionary (byte[] buffer, int off, int len)
- {
- if (!needsDictionary())
- throw new IllegalStateException();
-
- adler.update(buffer, off, len);
- if ((int) adler.getValue() != readAdler)
- throw new IllegalArgumentException("Wrong adler checksum");
- adler.reset();
- outputWindow.copyDict(buffer, off, len);
- mode = DECODE_BLOCKS;
- }
-
- /**
- * Sets the input. This should only be called, if needsInput()
- * returns true.
- * @param buffer the input.
- * @exception IllegalStateException if no input is needed.
- */
- public void setInput (byte[] buf)
- {
- setInput (buf, 0, buf.length);
- }
-
- /**
- * Sets the input. This should only be called, if needsInput()
- * returns true.
- * @param buffer the input.
- * @param off the offset into buffer where the input starts.
- * @param len the length of the input.
- * @exception IllegalStateException if no input is needed.
- * @exception IndexOutOfBoundsException if the off and/or len are wrong.
- */
- public void setInput (byte[] buf, int off, int len)
- {
- input.setInput (buf, off, len);
- totalIn += len;
- }
- private static final int DEFLATED = 8;
- /**
- * Decodes the deflate header.
- * @return false if more input is needed.
- * @exception DataFormatException if header is invalid.
- */
- private boolean decodeHeader () throws DataFormatException
- {
- int header = input.peekBits(16);
- if (header < 0)
- return false;
- input.dropBits(16);
+public
+class Inflater {
+ private final org.apidesign.bck2brwsr.emul.zip.Inflater impl;
- /* The header is written in "wrong" byte order */
- header = ((header << 8) | (header >> 8)) & 0xffff;
- if (header % 31 != 0)
- throw new DataFormatException("Header checksum illegal");
-
- if ((header & 0x0f00) != (DEFLATED << 8))
- throw new DataFormatException("Compression Method unknown");
-
- /* Maximum size of the backwards window in bits.
- * We currently ignore this, but we could use it to make the
- * inflater window more space efficient. On the other hand the
- * full window (15 bits) is needed most times, anyway.
- int max_wbits = ((header & 0x7000) >> 12) + 8;
+ /**
+ * Creates a new decompressor. If the parameter 'nowrap' is true then
+ * the ZLIB header and checksum fields will not be used. This provides
+ * compatibility with the compression format used by both GZIP and PKZIP.
+ *
Since the number of bytes may be greater than + * Integer.MAX_VALUE, the {@link #getBytesWritten()} method is now + * the preferred means of obtaining this information.
+ * + * @return the total number of uncompressed bytes output so far + */ + public int getTotalOut() { + return impl.getTotalOut(); + } - private static final int[] BL_ORDER = - { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; + /** + * Returns the total number of uncompressed bytes output so far. + * + * @return the total (non-negative) number of uncompressed bytes output so far + * @since 1.5 + */ + public long getBytesWritten() { + return impl.getBytesWritten(); + } - public InflaterDynHeader() - { - } + /** + * Resets inflater so that a new set of input data can be processed. + */ + public void reset() { + impl.reset(); + } - public boolean decode(StreamManipulator input) throws DataFormatException - { - decode_loop: - for (;;) - { - switch (mode) - { - case LNUM: - lnum = input.peekBits(5); - if (lnum < 0) - return false; - lnum += 257; - input.dropBits(5); - // System.err.println("LNUM: "+lnum); - mode = DNUM; - /* fall through */ - case DNUM: - dnum = input.peekBits(5); - if (dnum < 0) - return false; - dnum++; - input.dropBits(5); - // System.err.println("DNUM: "+dnum); - num = lnum+dnum; - litdistLens = new byte[num]; - mode = BLNUM; - /* fall through */ - case BLNUM: - blnum = input.peekBits(4); - if (blnum < 0) - return false; - blnum += 4; - input.dropBits(4); - blLens = new byte[19]; - ptr = 0; - // System.err.println("BLNUM: "+blnum); - mode = BLLENS; - /* fall through */ - case BLLENS: - while (ptr < blnum) - { - int len = input.peekBits(3); - if (len < 0) - return false; - input.dropBits(3); - // System.err.println("blLens["+BL_ORDER[ptr]+"]: "+len); - blLens[BL_ORDER[ptr]] = (byte) len; - ptr++; - } - blTree = new InflaterHuffmanTree(blLens); - blLens = null; - ptr = 0; - mode = LENS; - /* fall through */ - case LENS: - { - int symbol; - while (((symbol = blTree.getSymbol(input)) & ~15) == 0) - { - /* Normal case: symbol in [0..15] */ + /** + * Closes the decompressor and discards any unprocessed input. + * This method should be called when the decompressor is no longer + * being used, but will also be called automatically by the finalize() + * method. Once this method is called, the behavior of the Inflater + * object is undefined. + */ + public void end() { + impl.end(); + } - // System.err.println("litdistLens["+ptr+"]: "+symbol); - litdistLens[ptr++] = lastLen = (byte) symbol; - - if (ptr == num) - { - /* Finished */ - return true; - } - } - - /* need more input ? */ - if (symbol < 0) - return false; - - /* otherwise repeat code */ - if (symbol >= 17) - { - /* repeat zero */ - // System.err.println("repeating zero"); - lastLen = 0; - } - else - { - if (ptr == 0) - throw new DataFormatException(); - } - repSymbol = symbol-16; - mode = REPS; - } - /* fall through */ - - case REPS: - { - int bits = repBits[repSymbol]; - int count = input.peekBits(bits); - if (count < 0) - return false; - input.dropBits(bits); - count += repMin[repSymbol]; - // System.err.println("litdistLens repeated: "+count); - - if (ptr + count > num) - throw new DataFormatException(); - while (count-- > 0) - litdistLens[ptr++] = lastLen; - - if (ptr == num) - { - /* Finished */ - return true; - } - } - mode = LENS; - continue decode_loop; - } - } - } - - public InflaterHuffmanTree buildLitLenTree() throws DataFormatException - { - byte[] litlenLens = new byte[lnum]; - System.arraycopy(litdistLens, 0, litlenLens, 0, lnum); - return new InflaterHuffmanTree(litlenLens); - } - - public InflaterHuffmanTree buildDistTree() throws DataFormatException - { - byte[] distLens = new byte[dnum]; - System.arraycopy(litdistLens, lnum, distLens, 0, dnum); - return new InflaterHuffmanTree(distLens); - } + /** + * Closes the decompressor when garbage is collected. + */ + protected void finalize() { + end(); } - /** - * This class allows us to retrieve a specified amount of bits from - * the input buffer, as well as copy big byte blocks. - * - * It uses an int buffer to store up to 31 bits for direct - * manipulation. This guarantees that we can get at least 16 bits, - * but we only need at most 15, so this is all safe. - * - * There are some optimizations in this class, for example, you must - * never peek more then 8 bits more than needed, and you must first - * peek bits before you may drop them. This is not a general purpose - * class but optimized for the behaviour of the Inflater. - * - * @author John Leuner, Jochen Hoenicke - */ - - private static class StreamManipulator - { - private byte[] window; - private int window_start = 0; - private int window_end = 0; - - private int buffer = 0; - private int bits_in_buffer = 0; - - /** - * Get the next n bits but don't increase input pointer. n must be - * less or equal 16 and if you if this call succeeds, you must drop - * at least n-8 bits in the next call. - * - * @return the value of the bits, or -1 if not enough bits available. */ - public final int peekBits(int n) - { - if (bits_in_buffer < n) - { - if (window_start == window_end) - return -1; - buffer |= (window[window_start++] & 0xff - | (window[window_start++] & 0xff) << 8) << bits_in_buffer; - bits_in_buffer += 16; - } - return buffer & ((1 << n) - 1); - } - - /* Drops the next n bits from the input. You should have called peekBits - * with a bigger or equal n before, to make sure that enough bits are in - * the bit buffer. - */ - public final void dropBits(int n) - { - buffer >>>= n; - bits_in_buffer -= n; - } - - /** - * Gets the next n bits and increases input pointer. This is equivalent - * to peekBits followed by dropBits, except for correct error handling. - * @return the value of the bits, or -1 if not enough bits available. - */ - public final int getBits(int n) - { - int bits = peekBits(n); - if (bits >= 0) - dropBits(n); - return bits; - } - /** - * Gets the number of bits available in the bit buffer. This must be - * only called when a previous peekBits() returned -1. - * @return the number of bits available. - */ - public final int getAvailableBits() - { - return bits_in_buffer; - } - - /** - * Gets the number of bytes available. - * @return the number of bytes available. - */ - public final int getAvailableBytes() - { - return window_end - window_start + (bits_in_buffer >> 3); - } - - /** - * Skips to the next byte boundary. - */ - public void skipToByteBoundary() - { - buffer >>= (bits_in_buffer & 7); - bits_in_buffer &= ~7; - } - - public final boolean needsInput() { - return window_start == window_end; - } - - - /* Copies length bytes from input buffer to output buffer starting - * at output[offset]. You have to make sure, that the buffer is - * byte aligned. If not enough bytes are available, copies fewer - * bytes. - * @param length the length to copy, 0 is allowed. - * @return the number of bytes copied, 0 if no byte is available. - */ - public int copyBytes(byte[] output, int offset, int length) - { - if (length < 0) - throw new IllegalArgumentException("length negative"); - if ((bits_in_buffer & 7) != 0) - /* bits_in_buffer may only be 0 or 8 */ - throw new IllegalStateException("Bit buffer is not aligned!"); - - int count = 0; - while (bits_in_buffer > 0 && length > 0) - { - output[offset++] = (byte) buffer; - buffer >>>= 8; - bits_in_buffer -= 8; - length--; - count++; - } - if (length == 0) - return count; - - int avail = window_end - window_start; - if (length > avail) - length = avail; - System.arraycopy(window, window_start, output, offset, length); - window_start += length; - - if (((window_start - window_end) & 1) != 0) - { - /* We always want an even number of bytes in input, see peekBits */ - buffer = (window[window_start++] & 0xff); - bits_in_buffer = 8; - } - return count + length; - } - - public StreamManipulator() - { - } - - public void reset() - { - window_start = window_end = buffer = bits_in_buffer = 0; - } - - public void setInput(byte[] buf, int off, int len) - { - if (window_start < window_end) - throw new IllegalStateException - ("Old input was not completely processed"); - - int end = off + len; - - /* We want to throw an ArrayIndexOutOfBoundsException early. The - * check is very tricky: it also handles integer wrap around. - */ - if (0 > off || off > end || end > buf.length) - throw new ArrayIndexOutOfBoundsException(); - - if ((len & 1) != 0) - { - /* We always want an even number of bytes in input, see peekBits */ - buffer |= (buf[off++] & 0xff) << bits_in_buffer; - bits_in_buffer += 8; - } - - window = buf; - window_start = off; - window_end = end; - } - } - /* - * Contains the output from the Inflation process. - * - * We need to have a window so that we can refer backwards into the output stream - * to repeat stuff. - * - * @author John Leuner - * @since JDK 1.1 - */ - - private static class OutputWindow - { - private final int WINDOW_SIZE = 1 << 15; - private final int WINDOW_MASK = WINDOW_SIZE - 1; - - private byte[] window = new byte[WINDOW_SIZE]; //The window is 2^15 bytes - private int window_end = 0; - private int window_filled = 0; - - public void write(int abyte) - { - if (window_filled++ == WINDOW_SIZE) - throw new IllegalStateException("Window full"); - window[window_end++] = (byte) abyte; - window_end &= WINDOW_MASK; - } - - - private final void slowRepeat(int rep_start, int len, int dist) - { - while (len-- > 0) - { - window[window_end++] = window[rep_start++]; - window_end &= WINDOW_MASK; - rep_start &= WINDOW_MASK; - } - } - - public void repeat(int len, int dist) - { - if ((window_filled += len) > WINDOW_SIZE) - throw new IllegalStateException("Window full"); - - int rep_start = (window_end - dist) & WINDOW_MASK; - int border = WINDOW_SIZE - len; - if (rep_start <= border && window_end < border) - { - if (len <= dist) - { - System.arraycopy(window, rep_start, window, window_end, len); - window_end += len; - } - else - { - /* We have to copy manually, since the repeat pattern overlaps. - */ - while (len-- > 0) - window[window_end++] = window[rep_start++]; - } - } - else - slowRepeat(rep_start, len, dist); - } - - public int copyStored(StreamManipulator input, int len) - { - len = Math.min(Math.min(len, WINDOW_SIZE - window_filled), - input.getAvailableBytes()); - int copied; - - int tailLen = WINDOW_SIZE - window_end; - if (len > tailLen) - { - copied = input.copyBytes(window, window_end, tailLen); - if (copied == tailLen) - copied += input.copyBytes(window, 0, len - tailLen); - } - else - copied = input.copyBytes(window, window_end, len); - - window_end = (window_end + copied) & WINDOW_MASK; - window_filled += copied; - return copied; - } - - public void copyDict(byte[] dict, int offset, int len) - { - if (window_filled > 0) - throw new IllegalStateException(); - - if (len > WINDOW_SIZE) - { - offset += len - WINDOW_SIZE; - len = WINDOW_SIZE; - } - System.arraycopy(dict, offset, window, 0, len); - window_end = len & WINDOW_MASK; - } - - public int getFreeSpace() - { - return WINDOW_SIZE - window_filled; - } - - public int getAvailable() - { - return window_filled; - } - - public int copyOutput(byte[] output, int offset, int len) - { - int copy_end = window_end; - if (len > window_filled) - len = window_filled; - else - copy_end = (window_end - window_filled + len) & WINDOW_MASK; - - int copied = len; - int tailLen = len - copy_end; - - if (tailLen > 0) - { - System.arraycopy(window, WINDOW_SIZE - tailLen, - output, offset, tailLen); - offset += tailLen; - len = copy_end; - } - System.arraycopy(window, copy_end - len, output, offset, len); - window_filled -= copied; - if (window_filled < 0) - throw new IllegalStateException(); - return copied; - } - - public void reset() { - window_filled = window_end = 0; - } - } - } diff -r d088fc482c65 -r 0d277415ed02 emul/mini/src/main/java/java/util/zip/ZipConstants64.java --- a/emul/mini/src/main/java/java/util/zip/ZipConstants64.java Wed Feb 06 18:24:53 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,84 +0,0 @@ -/* - * Copyright (c) 1995, 1996, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.util.zip; - -/* - * This class defines the constants that are used by the classes - * which manipulate Zip64 files. - */ - -class ZipConstants64 { - - /* - * ZIP64 constants - */ - static final long ZIP64_ENDSIG = 0x06064b50L; // "PK\006\006" - static final long ZIP64_LOCSIG = 0x07064b50L; // "PK\006\007" - static final int ZIP64_ENDHDR = 56; // ZIP64 end header size - static final int ZIP64_LOCHDR = 20; // ZIP64 end loc header size - static final int ZIP64_EXTHDR = 24; // EXT header size - static final int ZIP64_EXTID = 0x0001; // Extra field Zip64 header ID - - static final int ZIP64_MAGICCOUNT = 0xFFFF; - static final long ZIP64_MAGICVAL = 0xFFFFFFFFL; - - /* - * Zip64 End of central directory (END) header field offsets - */ - static final int ZIP64_ENDLEN = 4; // size of zip64 end of central dir - static final int ZIP64_ENDVEM = 12; // version made by - static final int ZIP64_ENDVER = 14; // version needed to extract - static final int ZIP64_ENDNMD = 16; // number of this disk - static final int ZIP64_ENDDSK = 20; // disk number of start - static final int ZIP64_ENDTOD = 24; // total number of entries on this disk - static final int ZIP64_ENDTOT = 32; // total number of entries - static final int ZIP64_ENDSIZ = 40; // central directory size in bytes - static final int ZIP64_ENDOFF = 48; // offset of first CEN header - static final int ZIP64_ENDEXT = 56; // zip64 extensible data sector - - /* - * Zip64 End of central directory locator field offsets - */ - static final int ZIP64_LOCDSK = 4; // disk number start - static final int ZIP64_LOCOFF = 8; // offset of zip64 end - static final int ZIP64_LOCTOT = 16; // total number of disks - - /* - * Zip64 Extra local (EXT) header field offsets - */ - static final int ZIP64_EXTCRC = 4; // uncompressed file crc-32 value - static final int ZIP64_EXTSIZ = 8; // compressed size, 8-byte - static final int ZIP64_EXTLEN = 16; // uncompressed size, 8-byte - - /* - * Language encoding flag EFS - */ - static final int EFS = 0x800; // If this bit is set the filename and - // comment fields for this file must be - // encoded using UTF-8. - - private ZipConstants64() {} -} diff -r d088fc482c65 -r 0d277415ed02 emul/mini/src/main/java/java/util/zip/ZipInputStream.java --- a/emul/mini/src/main/java/java/util/zip/ZipInputStream.java Wed Feb 06 18:24:53 2013 +0100 +++ b/emul/mini/src/main/java/java/util/zip/ZipInputStream.java Thu Feb 07 12:58:12 2013 +0100 @@ -27,10 +27,6 @@ import java.io.InputStream; import java.io.IOException; -import java.io.EOFException; -import java.io.PushbackInputStream; -import static java.util.zip.ZipConstants64.*; -import org.apidesign.bck2brwsr.core.JavaScriptBody; /** * This class implements an input stream filter for reading files in the @@ -41,28 +37,7 @@ */ public class ZipInputStream extends InflaterInputStream implements ZipConstants { - private ZipEntry entry; - private int flag; - private CRC32 crc = new CRC32(); - private long remaining; - private byte[] tmpbuf = new byte[512]; - - private static final int STORED = ZipEntry.STORED; - private static final int DEFLATED = ZipEntry.DEFLATED; - - private boolean closed = false; - // this flag is set to true after EOF has reached for - // one entry - private boolean entryEOF = false; - - /** - * Check to make sure that this stream has not been closed - */ - private void ensureOpen() throws IOException { - if (closed) { - throw new IOException("Stream closed"); - } - } + private final org.apidesign.bck2brwsr.emul.zip.ZipInputStream impl; /** * Creates a new ZIP input stream. @@ -73,12 +48,8 @@ * @param in the actual input stream */ public ZipInputStream(InputStream in) { -// this(in, "UTF-8"); - super(new PushbackInputStream(in, 512), new Inflater(true), 512); - usesDefaultInflater = true; - if(in == null) { - throw new NullPointerException("in is null"); - } + super(null); + impl = new org.apidesign.bck2brwsr.emul.zip.ZipInputStream(in); } /** @@ -115,20 +86,7 @@ * @exception IOException if an I/O error has occurred */ public ZipEntry getNextEntry() throws IOException { - ensureOpen(); - if (entry != null) { - closeEntry(); - } - crc.reset(); - inf.reset(); - if ((entry = readLOC()) == null) { - return null; - } - if (entry.method == STORED) { - remaining = entry.size; - } - entryEOF = false; - return entry; + return impl.getNextEntry(); } /** @@ -138,9 +96,7 @@ * @exception IOException if an I/O error has occurred */ public void closeEntry() throws IOException { - ensureOpen(); - while (read(tmpbuf, 0, tmpbuf.length) != -1) ; - entryEOF = true; + impl.closeEntry(); } /** @@ -155,12 +111,7 @@ * */ public int available() throws IOException { - ensureOpen(); - if (entryEOF) { - return 0; - } else { - return 1; - } + return impl.available(); } /** @@ -181,51 +132,7 @@ * @exception IOException if an I/O error has occurred */ public int read(byte[] b, int off, int len) throws IOException { - ensureOpen(); - if (off < 0 || len < 0 || off > b.length - len) { - throw new IndexOutOfBoundsException(); - } else if (len == 0) { - return 0; - } - - if (entry == null) { - return -1; - } - switch (entry.method) { - case DEFLATED: - len = super.read(b, off, len); - if (len == -1) { - readEnd(entry); - entryEOF = true; - entry = null; - } else { - crc.update(b, off, len); - } - return len; - case STORED: - if (remaining <= 0) { - entryEOF = true; - entry = null; - return -1; - } - if (len > remaining) { - len = (int)remaining; - } - len = in.read(b, off, len); - if (len == -1) { - throw new ZipException("unexpected EOF"); - } - crc.update(b, off, len); - remaining -= len; - if (remaining == 0 && entry.crc != crc.getValue()) { - throw new ZipException( - "invalid entry CRC (expected 0x" + Long.toHexString(entry.crc) + - " but got 0x" + Long.toHexString(crc.getValue()) + ")"); - } - return len; - default: - throw new ZipException("invalid compression method"); - } + return impl.read(b, off, len); } /** @@ -237,25 +144,7 @@ * @exception IllegalArgumentException if n < 0 */ public long skip(long n) throws IOException { - if (n < 0) { - throw new IllegalArgumentException("negative skip length"); - } - ensureOpen(); - int max = (int)Math.min(n, Integer.MAX_VALUE); - int total = 0; - while (total < max) { - int len = max - total; - if (len > tmpbuf.length) { - len = tmpbuf.length; - } - len = read(tmpbuf, 0, len); - if (len == -1) { - entryEOF = true; - break; - } - total += len; - } - return total; + return impl.skip(n); } /** @@ -264,89 +153,7 @@ * @exception IOException if an I/O error has occurred */ public void close() throws IOException { - if (!closed) { - super.close(); - closed = true; - } - } - - private byte[] b = new byte[256]; - - /* - * Reads local file (LOC) header for next entry. - */ - private ZipEntry readLOC() throws IOException { - try { - readFully(tmpbuf, 0, LOCHDR); - } catch (EOFException e) { - return null; - } - if (get32(tmpbuf, 0) != LOCSIG) { - return null; - } - // get flag first, we need check EFS. - flag = get16(tmpbuf, LOCFLG); - // get the entry name and create the ZipEntry first - int len = get16(tmpbuf, LOCNAM); - int blen = b.length; - if (len > blen) { - do - blen = blen * 2; - while (len > blen); - b = new byte[blen]; - } - readFully(b, 0, len); - // Force to use UTF-8 if the EFS bit is ON, even the cs is NOT UTF-8 - ZipEntry e = createZipEntry(((flag & EFS) != 0) - ? toStringUTF8(b, len) - : toString(b, len)); - // now get the remaining fields for the entry - if ((flag & 1) == 1) { - throw new ZipException("encrypted ZIP entry not supported"); - } - e.method = get16(tmpbuf, LOCHOW); - e.time = get32(tmpbuf, LOCTIM); - if ((flag & 8) == 8) { - /* "Data Descriptor" present */ - if (e.method != DEFLATED) { - throw new ZipException( - "only DEFLATED entries can have EXT descriptor"); - } - } else { - e.crc = get32(tmpbuf, LOCCRC); - e.csize = get32(tmpbuf, LOCSIZ); - e.size = get32(tmpbuf, LOCLEN); - } - len = get16(tmpbuf, LOCEXT); - if (len > 0) { - byte[] bb = new byte[len]; - readFully(bb, 0, len); - e.setExtra(bb); - // extra fields are in "HeaderID(2)DataSize(2)Data... format - if (e.csize == ZIP64_MAGICVAL || e.size == ZIP64_MAGICVAL) { - int off = 0; - while (off + 4 < len) { - int sz = get16(bb, off + 2); - if (get16(bb, off) == ZIP64_EXTID) { - off += 4; - // LOC extra zip64 entry MUST include BOTH original and - // compressed file size fields - if (sz < 16 || (off + sz) > len ) { - // Invalid zip64 extra fields, simply skip. Even it's - // rare, it's possible the entry size happens to be - // the magic value and it "accidnetly" has some bytes - // in extra match the id. - return e; - } - e.size = get64(bb, off); - e.csize = get64(bb, off + 8); - break; - } - off += (sz + 4); - } - } - } - return e; + impl.close(); } /** @@ -360,108 +167,28 @@ return new ZipEntry(name); } - /* - * Reads end of deflated entry as well as EXT descriptor if present. - */ - private void readEnd(ZipEntry e) throws IOException { - int n = inf.getRemaining(); - if (n > 0) { - ((PushbackInputStream)in).unread(buf, len - n, n); - } - if ((flag & 8) == 8) { - /* "Data Descriptor" present */ - if (inf.getBytesWritten() > ZIP64_MAGICVAL || - inf.getBytesRead() > ZIP64_MAGICVAL) { - // ZIP64 format - readFully(tmpbuf, 0, ZIP64_EXTHDR); - long sig = get32(tmpbuf, 0); - if (sig != EXTSIG) { // no EXTSIG present - e.crc = sig; - e.csize = get64(tmpbuf, ZIP64_EXTSIZ - ZIP64_EXTCRC); - e.size = get64(tmpbuf, ZIP64_EXTLEN - ZIP64_EXTCRC); - ((PushbackInputStream)in).unread( - tmpbuf, ZIP64_EXTHDR - ZIP64_EXTCRC - 1, ZIP64_EXTCRC); - } else { - e.crc = get32(tmpbuf, ZIP64_EXTCRC); - e.csize = get64(tmpbuf, ZIP64_EXTSIZ); - e.size = get64(tmpbuf, ZIP64_EXTLEN); - } - } else { - readFully(tmpbuf, 0, EXTHDR); - long sig = get32(tmpbuf, 0); - if (sig != EXTSIG) { // no EXTSIG present - e.crc = sig; - e.csize = get32(tmpbuf, EXTSIZ - EXTCRC); - e.size = get32(tmpbuf, EXTLEN - EXTCRC); - ((PushbackInputStream)in).unread( - tmpbuf, EXTHDR - EXTCRC - 1, EXTCRC); - } else { - e.crc = get32(tmpbuf, EXTCRC); - e.csize = get32(tmpbuf, EXTSIZ); - e.size = get32(tmpbuf, EXTLEN); - } - } - } - if (e.size != inf.getBytesWritten()) { - throw new ZipException( - "invalid entry size (expected " + e.size + - " but got " + inf.getBytesWritten() + " bytes)"); - } - if (e.csize != inf.getBytesRead()) { - throw new ZipException( - "invalid entry compressed size (expected " + e.csize + - " but got " + inf.getBytesRead() + " bytes)"); - } - if (e.crc != crc.getValue()) { - throw new ZipException( - "invalid entry CRC (expected 0x" + Long.toHexString(e.crc) + - " but got 0x" + Long.toHexString(crc.getValue()) + ")"); - } + @Override + public int read() throws IOException { + return impl.read(); } - /* - * Reads bytes, blocking until all bytes are read. - */ - private void readFully(byte[] b, int off, int len) throws IOException { - while (len > 0) { - int n = in.read(b, off, len); - if (n == -1) { - throw new EOFException(); - } - off += n; - len -= n; - } + @Override + public boolean markSupported() { + return impl.markSupported(); } - /* - * Fetches unsigned 16-bit value from byte array at specified offset. - * The bytes are assumed to be in Intel (little-endian) byte order. - */ - private static final int get16(byte b[], int off) { - return (b[off] & 0xff) | ((b[off+1] & 0xff) << 8); + @Override + public void mark(int readlimit) { + impl.mark(readlimit); } - /* - * Fetches unsigned 32-bit value from byte array at specified offset. - * The bytes are assumed to be in Intel (little-endian) byte order. - */ - private static final long get32(byte b[], int off) { - return (get16(b, off) | ((long)get16(b, off+2) << 16)) & 0xffffffffL; + @Override + public void reset() throws IOException { + impl.reset(); } - /* - * Fetches signed 64-bit value from byte array at specified offset. - * The bytes are assumed to be in Intel (little-endian) byte order. - */ - private static final long get64(byte b[], int off) { - return get32(b, off) | (get32(b, off+4) << 32); - } - - private static String toStringUTF8(byte[] arr, int len) { - return new String(arr, 0, len); - } - - private static String toString(byte[] b, int len) { - return new String(b, 0, len); + @Override + public int read(byte[] b) throws IOException { + return impl.read(b); } } diff -r d088fc482c65 -r 0d277415ed02 emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/lang/System.java --- a/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/lang/System.java Wed Feb 06 18:24:53 2013 +0100 +++ b/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/lang/System.java Thu Feb 07 12:58:12 2013 +0100 @@ -17,6 +17,7 @@ */ package org.apidesign.bck2brwsr.emul.lang; +import java.lang.reflect.Method; import org.apidesign.bck2brwsr.core.JavaScriptBody; /** @@ -38,7 +39,15 @@ " }\n" + "}" ) - public static native void arraycopy(Object value, int srcBegin, Object dst, int dstBegin, int count); + public static void arraycopy(Object src, int srcBegin, Object dst, int dstBegin, int count) { + try { + Class> system = Class.forName("java.lang.System"); + Method m = system.getMethod("arraycopy", Object.class, int.class, Object.class, int.class, int.class); + m.invoke(null, src, srcBegin, dst, dstBegin, count); + } catch (Exception ex) { + throw new IllegalStateException(ex); + } + } @JavaScriptBody(args = { "arr", "expectedSize" }, body = "while (expectedSize-- > arr.length) { arr.push(0); }; return arr;" diff -r d088fc482c65 -r 0d277415ed02 emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/zip/Adler32.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/zip/Adler32.java Thu Feb 07 12:58:12 2013 +0100 @@ -0,0 +1,139 @@ +/* -*-mode:java; c-basic-offset:2; -*- */ +/* +Copyright (c) 2000-2011 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +package org.apidesign.bck2brwsr.emul.zip; + +final class Adler32 implements Checksum { + + // largest prime smaller than 65536 + static final private int BASE=65521; + // NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 + static final private int NMAX=5552; + + private long s1=1L; + private long s2=0L; + + public void reset(long init){ + s1=init&0xffff; + s2=(init>>16)&0xffff; + } + + public void reset(){ + s1=1L; + s2=0L; + } + + public long getValue(){ + return ((s2<<16)|s1); + } + + public void update(byte[] buf, int index, int len){ + + if(len==1){ + s1+=buf[index++]&0xff; s2+=s1; + s1%=BASE; + s2%=BASE; + return; + } + + int len1 = len/NMAX; + int len2 = len%NMAX; + while(len1-->0) { + int k=NMAX; + len-=k; + while(k-->0){ + s1+=buf[index++]&0xff; s2+=s1; + } + s1%=BASE; + s2%=BASE; + } + + int k=len2; + len-=k; + while(k-->0){ + s1+=buf[index++]&0xff; s2+=s1; + } + s1%=BASE; + s2%=BASE; + } + + public Adler32 copy(){ + Adler32 foo = new Adler32(); + foo.s1 = this.s1; + foo.s2 = this.s2; + return foo; + } + + // The following logic has come from zlib.1.2. + static long combine(long adler1, long adler2, long len2){ + long BASEL = (long)BASE; + long sum1; + long sum2; + long rem; // unsigned int + + rem = len2 % BASEL; + sum1 = adler1 & 0xffffL; + sum2 = rem * sum1; + sum2 %= BASEL; // MOD(sum2); + sum1 += (adler2 & 0xffffL) + BASEL - 1; + sum2 += ((adler1 >> 16) & 0xffffL) + ((adler2 >> 16) & 0xffffL) + BASEL - rem; + if (sum1 >= BASEL) sum1 -= BASEL; + if (sum1 >= BASEL) sum1 -= BASEL; + if (sum2 >= (BASEL << 1)) sum2 -= (BASEL << 1); + if (sum2 >= BASEL) sum2 -= BASEL; + return sum1 | (sum2 << 16); + } + +/* + private java.util.zip.Adler32 adler=new java.util.zip.Adler32(); + public void update(byte[] buf, int index, int len){ + if(buf==null) {adler.reset();} + else{adler.update(buf, index, len);} + } + public void reset(){ + adler.reset(); + } + public void reset(long init){ + if(init==1L){ + adler.reset(); + } + else{ + System.err.println("unsupported operation"); + } + } + public long getValue(){ + return adler.getValue(); + } +*/ +} diff -r d088fc482c65 -r 0d277415ed02 emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/zip/CRC32.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/zip/CRC32.java Thu Feb 07 12:58:12 2013 +0100 @@ -0,0 +1,181 @@ +/* -*-mode:java; c-basic-offset:2; -*- */ +/* +Copyright (c) 2011 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +package org.apidesign.bck2brwsr.emul.zip; + +import org.apidesign.bck2brwsr.emul.lang.System; + +final class CRC32 implements Checksum { + + /* + * The following logic has come from RFC1952. + */ + private int v = 0; + private static int[] crc_table = null; + static { + crc_table = new int[256]; + for (int n = 0; n < 256; n++) { + int c = n; + for (int k = 8; --k >= 0; ) { + if ((c & 1) != 0) + c = 0xedb88320 ^ (c >>> 1); + else + c = c >>> 1; + } + crc_table[n] = c; + } + } + + public void update (byte[] buf, int index, int len) { + int c = ~v; + while (--len >= 0) + c = crc_table[(c^buf[index++])&0xff]^(c >>> 8); + v = ~c; + } + + public void reset(){ + v = 0; + } + + public void reset(long vv){ + v = (int)(vv&0xffffffffL); + } + + public long getValue(){ + return (long)(v&0xffffffffL); + } + + // The following logic has come from zlib.1.2. + private static final int GF2_DIM = 32; + static long combine(long crc1, long crc2, long len2){ + long row; + long[] even = new long[GF2_DIM]; + long[] odd = new long[GF2_DIM]; + + // degenerate case (also disallow negative lengths) + if (len2 <= 0) + return crc1; + + // put operator for one zero bit in odd + odd[0] = 0xedb88320L; // CRC-32 polynomial + row = 1; + for (int n = 1; n < GF2_DIM; n++) { + odd[n] = row; + row <<= 1; + } + + // put operator for two zero bits in even + gf2_matrix_square(even, odd); + + // put operator for four zero bits in odd + gf2_matrix_square(odd, even); + + // apply len2 zeros to crc1 (first square will put the operator for one + // zero byte, eight zero bits, in even) + do { + // apply zeros operator for this bit of len2 + gf2_matrix_square(even, odd); + if ((len2 & 1)!=0) + crc1 = gf2_matrix_times(even, crc1); + len2 >>= 1; + + // if no more bits set, then done + if (len2 == 0) + break; + + // another iteration of the loop with odd and even swapped + gf2_matrix_square(odd, even); + if ((len2 & 1)!=0) + crc1 = gf2_matrix_times(odd, crc1); + len2 >>= 1; + + // if no more bits set, then done + } while (len2 != 0); + + /* return combined crc */ + crc1 ^= crc2; + return crc1; + } + + private static long gf2_matrix_times(long[] mat, long vec){ + long sum = 0; + int index = 0; + while (vec!=0) { + if ((vec & 1)!=0) + sum ^= mat[index]; + vec >>= 1; + index++; + } + return sum; + } + + static final void gf2_matrix_square(long[] square, long[] mat) { + for (int n = 0; n < GF2_DIM; n++) + square[n] = gf2_matrix_times(mat, mat[n]); + } + + /* + private java.util.zip.CRC32 crc32 = new java.util.zip.CRC32(); + + public void update(byte[] buf, int index, int len){ + if(buf==null) {crc32.reset();} + else{crc32.update(buf, index, len);} + } + public void reset(){ + crc32.reset(); + } + public void reset(long init){ + if(init==0L){ + crc32.reset(); + } + else{ + System.err.println("unsupported operation"); + } + } + public long getValue(){ + return crc32.getValue(); + } +*/ + public CRC32 copy(){ + CRC32 foo = new CRC32(); + foo.v = this.v; + return foo; + } + + public static int[] getCRC32Table(){ + int[] tmp = new int[crc_table.length]; + System.arraycopy(crc_table, 0, tmp, 0, tmp.length); + return tmp; + } +} diff -r d088fc482c65 -r 0d277415ed02 emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/zip/Checksum.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/zip/Checksum.java Thu Feb 07 12:58:12 2013 +0100 @@ -0,0 +1,43 @@ +/* -*-mode:java; c-basic-offset:2; -*- */ +/* +Copyright (c) 2011 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +package org.apidesign.bck2brwsr.emul.zip; + +interface Checksum { + void update(byte[] buf, int index, int len); + void reset(); + void reset(long init); + long getValue(); + Checksum copy(); +} diff -r d088fc482c65 -r 0d277415ed02 emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/zip/GZIPHeader.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/zip/GZIPHeader.java Thu Feb 07 12:58:12 2013 +0100 @@ -0,0 +1,215 @@ +/* -*-mode:java; c-basic-offset:2; -*- */ +/* +Copyright (c) 2011 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +package org.apidesign.bck2brwsr.emul.zip; + +import org.apidesign.bck2brwsr.emul.lang.System; +import java.io.UnsupportedEncodingException; + +/** + * @see "http://www.ietf.org/rfc/rfc1952.txt" + */ +final class GZIPHeader implements Cloneable { + + public static final byte OS_MSDOS = (byte) 0x00; + public static final byte OS_AMIGA = (byte) 0x01; + public static final byte OS_VMS = (byte) 0x02; + public static final byte OS_UNIX = (byte) 0x03; + public static final byte OS_ATARI = (byte) 0x05; + public static final byte OS_OS2 = (byte) 0x06; + public static final byte OS_MACOS = (byte) 0x07; + public static final byte OS_TOPS20 = (byte) 0x0a; + public static final byte OS_WIN32 = (byte) 0x0b; + public static final byte OS_VMCMS = (byte) 0x04; + public static final byte OS_ZSYSTEM = (byte) 0x08; + public static final byte OS_CPM = (byte) 0x09; + public static final byte OS_QDOS = (byte) 0x0c; + public static final byte OS_RISCOS = (byte) 0x0d; + public static final byte OS_UNKNOWN = (byte) 0xff; + + boolean text = false; + private boolean fhcrc = false; + long time; + int xflags; + int os = 255; + byte[] extra; + byte[] name; + byte[] comment; + int hcrc; + long crc; + boolean done = false; + long mtime = 0; + + public void setModifiedTime(long mtime) { + this.mtime = mtime; + } + + public long getModifiedTime() { + return mtime; + } + + public void setOS(int os) { + if((0<=os && os <=13) || os==255) + this.os=os; + else + throw new IllegalArgumentException("os: "+os); + } + + public int getOS(){ + return os; + } + + public void setName(String name) { + try{ + this.name=name.getBytes("ISO-8859-1"); + } + catch(UnsupportedEncodingException e){ + throw new IllegalArgumentException("name must be in ISO-8859-1 "+name); + } + } + + public String getName(){ + if(name==null) return ""; + try { + return new String(name, "ISO-8859-1"); + } + catch (UnsupportedEncodingException e) { + throw new IllegalArgumentException(e.toString()); + } + } + + public void setComment(String comment) { + try{ + this.comment=comment.getBytes("ISO-8859-1"); + } + catch(UnsupportedEncodingException e){ + throw new IllegalArgumentException("comment must be in ISO-8859-1 "+name); + } + } + + public String getComment(){ + if(comment==null) return ""; + try { + return new String(comment, "ISO-8859-1"); + } + catch (UnsupportedEncodingException e) { + throw new IllegalArgumentException(e.toString()); + } + } + + public void setCRC(long crc){ + this.crc = crc; + } + + public long getCRC(){ + return crc; + } +/* + void put(Deflate d){ + int flag = 0; + if(text){ + flag |= 1; // FTEXT + } + if(fhcrc){ + flag |= 2; // FHCRC + } + if(extra!=null){ + flag |= 4; // FEXTRA + } + if(name!=null){ + flag |= 8; // FNAME + } + if(comment!=null){ + flag |= 16; // FCOMMENT + } + int xfl = 0; + if(d.level == JZlib.Z_BEST_SPEED){ + xfl |= 4; + } + else if (d.level == JZlib.Z_BEST_COMPRESSION){ + xfl |= 2; + } + + d.put_short((short)0x8b1f); // ID1 ID2 + d.put_byte((byte)8); // CM(Compression Method) + d.put_byte((byte)flag); + d.put_byte((byte)mtime); + d.put_byte((byte)(mtime>>8)); + d.put_byte((byte)(mtime>>16)); + d.put_byte((byte)(mtime>>24)); + d.put_byte((byte)xfl); + d.put_byte((byte)os); + + if(extra!=null){ + d.put_byte((byte)extra.length); + d.put_byte((byte)(extra.length>>8)); + d.put_byte(extra, 0, extra.length); + } + + if(name!=null){ + d.put_byte(name, 0, name.length); + d.put_byte((byte)0); + } + + if(comment!=null){ + d.put_byte(comment, 0, comment.length); + d.put_byte((byte)0); + } + } +*/ + @Override + public Object clone() throws CloneNotSupportedException { + GZIPHeader gheader = (GZIPHeader)super.clone(); + byte[] tmp; + if(gheader.extra!=null){ + tmp=new byte[gheader.extra.length]; + System.arraycopy(gheader.extra, 0, tmp, 0, tmp.length); + gheader.extra = tmp; + } + + if(gheader.name!=null){ + tmp=new byte[gheader.name.length]; + System.arraycopy(gheader.name, 0, tmp, 0, tmp.length); + gheader.name = tmp; + } + + if(gheader.comment!=null){ + tmp=new byte[gheader.comment.length]; + System.arraycopy(gheader.comment, 0, tmp, 0, tmp.length); + gheader.comment = tmp; + } + + return gheader; + } +} diff -r d088fc482c65 -r 0d277415ed02 emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/zip/InfBlocks.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/zip/InfBlocks.java Thu Feb 07 12:58:12 2013 +0100 @@ -0,0 +1,616 @@ +/* -*-mode:java; c-basic-offset:2; -*- */ +/* +Copyright (c) 2011 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +package org.apidesign.bck2brwsr.emul.zip; + +import org.apidesign.bck2brwsr.emul.lang.System; + +final class InfBlocks{ + static final private int MANY=1440; + + // And'ing with mask[n] masks the lower n bits + static final private int[] inflate_mask = { + 0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f, + 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 0x000001ff, + 0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff, + 0x00007fff, 0x0000ffff + }; + + // Table for deflate from PKZIP's appnote.txt. + static final int[] border = { // Order of the bit length code lengths + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 + }; + + static final private int Z_OK=0; + static final private int Z_STREAM_END=1; + static final private int Z_NEED_DICT=2; + static final private int Z_ERRNO=-1; + static final private int Z_STREAM_ERROR=-2; + static final private int Z_DATA_ERROR=-3; + static final private int Z_MEM_ERROR=-4; + static final private int Z_BUF_ERROR=-5; + static final private int Z_VERSION_ERROR=-6; + + static final private int TYPE=0; // get type bits (3, including end bit) + static final private int LENS=1; // get lengths for stored + static final private int STORED=2;// processing stored block + static final private int TABLE=3; // get table lengths + static final private int BTREE=4; // get bit lengths tree for a dynamic block + static final private int DTREE=5; // get length, distance trees for a dynamic block + static final private int CODES=6; // processing fixed or dynamic block + static final private int DRY=7; // output remaining window bytes + static final private int DONE=8; // finished last block, done + static final private int BAD=9; // ot a data error--stuck here + + int mode; // current inflate_block mode + + int left; // if STORED, bytes left to copy + + int table; // table lengths (14 bits) + int index; // index into blens (or border) + int[] blens; // bit lengths of codes + int[] bb=new int[1]; // bit length tree depth + int[] tb=new int[1]; // bit length decoding tree + + int[] bl=new int[1]; + int[] bd=new int[1]; + + int[][] tl=new int[1][]; + int[][] td=new int[1][]; + int[] tli=new int[1]; // tl_index + int[] tdi=new int[1]; // td_index + + private final InfCodes codes; // if CODES, current state + + int last; // true if this block is the last block + + // mode independent information + int bitk; // bits in bit buffer + int bitb; // bit buffer + int[] hufts; // single malloc for tree space + byte[] window; // sliding window + int end; // one byte after sliding window + int read; // window read pointer + int write; // window write pointer + private boolean check; + + private final InfTree inftree=new InfTree(); + + private final ZStream z; + + InfBlocks(ZStream z, int w){ + this.z=z; + this.codes=new InfCodes(this.z, this); + hufts=new int[MANY*3]; + window=new byte[w]; + end=w; + this.check = (z.istate.wrap==0) ? false : true; + mode = TYPE; + reset(); + } + + void reset(){ + if(mode==BTREE || mode==DTREE){ + } + if(mode==CODES){ + codes.free(z); + } + mode=TYPE; + bitk=0; + bitb=0; + read=write=0; + if(check){ + z.adler.reset(); + } + } + + int proc(int r){ + int t; // temporary storage + int b; // bit buffer + int k; // bits in bit buffer + int p; // input data pointer + int n; // bytes available there + int q; // output window write pointer + int m; // bytes to end of window or read pointer + + // copy input/output information to locals (UPDATE macro restores) + {p=z.next_in_index;n=z.avail_in;b=bitb;k=bitk;} + {q=write;m=(int)(qThe following code fragment demonstrates a trivial compression + * and decompression of a string using Deflater and + * Inflater. + * + *
+ * + * @see Deflater + * @author David Connelly + * + */ +public +class Inflater extends java.util.zip.Inflater { + private final boolean nowrap; + private JzLibInflater impl; + + /** + * Creates a new decompressor. If the parameter 'nowrap' is true then + * the ZLIB header and checksum fields will not be used. This provides + * compatibility with the compression format used by both GZIP and PKZIP. + *+ * try { + * // Encode a String into bytes + * String inputString = "blahblahblah\u20AC\u20AC"; + * byte[] input = inputString.getBytes("UTF-8"); + * + * // Compress the bytes + * byte[] output = new byte[100]; + * Deflater compresser = new Deflater(); + * compresser.setInput(input); + * compresser.finish(); + * int compressedDataLength = compresser.deflate(output); + * + * // Decompress the bytes + * Inflater decompresser = new Inflater(); + * decompresser.setInput(output, 0, compressedDataLength); + * byte[] result = new byte[100]; + * int resultLength = decompresser.inflate(result); + * decompresser.end(); + * + * // Decode the bytes into a String + * String outputString = new String(result, 0, resultLength, "UTF-8"); + * } catch(java.io.UnsupportedEncodingException ex) { + * // handle + * } catch (java.util.zip.DataFormatException ex) { + * // handle + * } + *
+ * Note: When using the 'nowrap' option it is also necessary to provide + * an extra "dummy" byte as input. This is required by the ZLIB native + * library in order to support certain optimizations. + * + * @param nowrap if true then support GZIP compatible compression + */ + public Inflater(boolean nowrap) { + this.nowrap = nowrap; + reset(); + } + + /** + * Creates a new decompressor. + */ + public Inflater() { + this(false); + } + + /** + * Sets input data for decompression. Should be called whenever + * needsInput() returns true indicating that more input data is + * required. + * @param b the input data bytes + * @param off the start offset of the input data + * @param len the length of the input data + * @see Inflater#needsInput + */ + public void setInput(byte[] b, int off, int len) { + if (b == null) { + throw new NullPointerException(); + } + if (off < 0 || len < 0 || off > b.length - len) { + throw new ArrayIndexOutOfBoundsException(); + } + impl.setInput(b, off, len, false); + } + + /** + * Sets input data for decompression. Should be called whenever + * needsInput() returns true indicating that more input data is + * required. + * @param b the input data bytes + * @see Inflater#needsInput + */ + public void setInput(byte[] b) { + setInput(b, 0, b.length); + } + + /** + * Sets the preset dictionary to the given array of bytes. Should be + * called when inflate() returns 0 and needsDictionary() returns true + * indicating that a preset dictionary is required. The method getAdler() + * can be used to get the Adler-32 value of the dictionary needed. + * @param b the dictionary data bytes + * @param off the start offset of the data + * @param len the length of the data + * @see Inflater#needsDictionary + * @see Inflater#getAdler + */ + public void setDictionary(byte[] b, int off, int len) { + if (b == null) { + throw new NullPointerException(); + } + if (off < 0 || len < 0 || off > b.length - len) { + throw new ArrayIndexOutOfBoundsException(); + } + byte[] arr; + if (off == 0) { + arr = b; + } else { + arr = new byte[len]; + org.apidesign.bck2brwsr.emul.lang.System.arraycopy(b, off, arr, 0, len); + } + impl.setDictionary(arr, len); + } + + /** + * Sets the preset dictionary to the given array of bytes. Should be + * called when inflate() returns 0 and needsDictionary() returns true + * indicating that a preset dictionary is required. The method getAdler() + * can be used to get the Adler-32 value of the dictionary needed. + * @param b the dictionary data bytes + * @see Inflater#needsDictionary + * @see Inflater#getAdler + */ + public void setDictionary(byte[] b) { + impl.setDictionary(b, b.length); + } + + /** + * Returns the total number of bytes remaining in the input buffer. + * This can be used to find out what bytes still remain in the input + * buffer after decompression has finished. + * @return the total number of bytes remaining in the input buffer + */ + public int getRemaining() { + return impl.getAvailIn(); + } + + /** + * Returns true if no data remains in the input buffer. This can + * be used to determine if #setInput should be called in order + * to provide more input. + * @return true if no data remains in the input buffer + */ + public boolean needsInput() { + return getRemaining() <= 0; + } + + /** + * Returns true if a preset dictionary is needed for decompression. + * @return true if a preset dictionary is needed for decompression + * @see Inflater#setDictionary + */ + public boolean needsDictionary() { + return impl.needDict(); + } + + /** + * Returns true if the end of the compressed data stream has been + * reached. + * @return true if the end of the compressed data stream has been + * reached + */ + public boolean finished() { + return impl.finished(); + } + + /** + * Uncompresses bytes into specified buffer. Returns actual number + * of bytes uncompressed. A return value of 0 indicates that + * needsInput() or needsDictionary() should be called in order to + * determine if more input data or a preset dictionary is required. + * In the latter case, getAdler() can be used to get the Adler-32 + * value of the dictionary required. + * @param b the buffer for the uncompressed data + * @param off the start offset of the data + * @param len the maximum number of uncompressed bytes + * @return the actual number of uncompressed bytes + * @exception DataFormatException if the compressed data format is invalid + * @see Inflater#needsInput + * @see Inflater#needsDictionary + */ + public int inflate(byte[] b, int off, int len) + throws DataFormatException + { + if (b == null) { + throw new NullPointerException(); + } + if (off < 0 || len < 0 || off > b.length - len) { + throw new ArrayIndexOutOfBoundsException(); + } + impl.setOutput(b, off, len); + int err = impl.inflate(JzLibInflater.Z_NO_FLUSH); + return impl.next_out_index - off; + } + + /** + * Uncompresses bytes into specified buffer. Returns actual number + * of bytes uncompressed. A return value of 0 indicates that + * needsInput() or needsDictionary() should be called in order to + * determine if more input data or a preset dictionary is required. + * In the latter case, getAdler() can be used to get the Adler-32 + * value of the dictionary required. + * @param b the buffer for the uncompressed data + * @return the actual number of uncompressed bytes + * @exception DataFormatException if the compressed data format is invalid + * @see Inflater#needsInput + * @see Inflater#needsDictionary + */ + public int inflate(byte[] b) throws DataFormatException { + return inflate(b, 0, b.length); + } + + /** + * Returns the ADLER-32 value of the uncompressed data. + * @return the ADLER-32 value of the uncompressed data + */ + public int getAdler() { + return (int) impl.getAdler(); + } + + /** + * Returns the total number of compressed bytes input so far. + * + *
Since the number of bytes may be greater than + * Integer.MAX_VALUE, the {@link #getBytesRead()} method is now + * the preferred means of obtaining this information.
+ * + * @return the total number of compressed bytes input so far + */ + public int getTotalIn() { + return (int) getBytesRead(); + } + + /** + * Returns the total number of compressed bytes input so far. + * + * @return the total (non-negative) number of compressed bytes input so far + * @since 1.5 + */ + public long getBytesRead() { + return impl.total_in; + } + + /** + * Returns the total number of uncompressed bytes output so far. + * + *Since the number of bytes may be greater than + * Integer.MAX_VALUE, the {@link #getBytesWritten()} method is now + * the preferred means of obtaining this information.
+ * + * @return the total number of uncompressed bytes output so far + */ + public int getTotalOut() { + return (int) getBytesWritten(); + } + + /** + * Returns the total number of uncompressed bytes output so far. + * + * @return the total (non-negative) number of uncompressed bytes output so far + * @since 1.5 + */ + public long getBytesWritten() { + return impl.total_out; + } + + /** + * Resets inflater so that a new set of input data can be processed. + */ + public void reset() { + impl = new JzLibInflater(15, nowrap); + } + + /** + * Closes the decompressor and discards any unprocessed input. + * This method should be called when the decompressor is no longer + * being used, but will also be called automatically by the finalize() + * method. Once this method is called, the behavior of the Inflater + * object is undefined. + */ + public void end() { + impl.end(); + } + + /** + * Closes the decompressor when garbage is collected. + */ + protected void finalize() { + end(); + } +} diff -r d088fc482c65 -r 0d277415ed02 emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/zip/JzLibInflater.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/zip/JzLibInflater.java Thu Feb 07 12:58:12 2013 +0100 @@ -0,0 +1,137 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2011 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +package org.apidesign.bck2brwsr.emul.zip; + +final class JzLibInflater extends ZStream{ + + static final private int MAX_WBITS=15; // 32K LZ77 window + static final private int DEF_WBITS=MAX_WBITS; + + public static final int Z_NO_FLUSH=0; + static final private int Z_PARTIAL_FLUSH=1; + static final private int Z_SYNC_FLUSH=2; + static final private int Z_FULL_FLUSH=3; + static final private int Z_FINISH=4; + + static final private int MAX_MEM_LEVEL=9; + + static final private int Z_OK=0; + static final private int Z_STREAM_END=1; + static final private int Z_NEED_DICT=2; + static final private int Z_ERRNO=-1; + static final private int Z_STREAM_ERROR=-2; + static final private int Z_DATA_ERROR=-3; + static final private int Z_MEM_ERROR=-4; + static final private int Z_BUF_ERROR=-5; + static final private int Z_VERSION_ERROR=-6; + + public JzLibInflater() { + super(); + init(); + } + + public JzLibInflater(int w) { + this(w, false); + } + + public JzLibInflater(int w, boolean nowrap) { + super(); + int ret = init(w, nowrap); + if(ret!=Z_OK) + throw new IllegalStateException(ret+": "+msg); + } + + private boolean finished = false; + + public int init(){ + return init(DEF_WBITS); + } + + public int init(boolean nowrap){ + return init(DEF_WBITS, nowrap); + } + + public int init(int w){ + return init(w, false); + } + + public int init(int w, boolean nowrap){ + finished = false; + istate=new Inflate(this); + return istate.inflateInit(nowrap?-w:w); + } + + public int inflate(int f){ + if(istate==null) return Z_STREAM_ERROR; + int ret = istate.inflate(f); + if(ret == Z_STREAM_END) + finished = true; + return ret; + } + + public int end(){ + finished = true; + if(istate==null) return Z_STREAM_ERROR; + int ret=istate.inflateEnd(); +// istate = null; + return ret; + } + + public int sync(){ + if(istate == null) + return Z_STREAM_ERROR; + return istate.inflateSync(); + } + + public int syncPoint(){ + if(istate == null) + return Z_STREAM_ERROR; + return istate.inflateSyncPoint(); + } + + public int setDictionary(byte[] dictionary, int dictLength){ + if(istate == null) + return Z_STREAM_ERROR; + return istate.inflateSetDictionary(dictionary, dictLength); + } + + public boolean finished(){ + return istate.mode==12 /*DONE*/; + } + + public boolean needDict() { + return istate == null ? false : istate.mode == Inflate.DICT0; + } +} diff -r d088fc482c65 -r 0d277415ed02 emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/zip/ZStream.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/zip/ZStream.java Thu Feb 07 12:58:12 2013 +0100 @@ -0,0 +1,253 @@ +/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ +/* +Copyright (c) 2000-2011 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * This program is based on zlib-1.1.3, so all credit should go authors + * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu) + * and contributors of zlib. + */ + +package org.apidesign.bck2brwsr.emul.zip; + +import org.apidesign.bck2brwsr.emul.lang.System; + +/** + * ZStream + * + * @deprecated Not for public use in the future. + */ +@Deprecated +class ZStream{ + + static final private int MAX_WBITS=15; // 32K LZ77 window + static final private int DEF_WBITS=MAX_WBITS; + + static final private int Z_NO_FLUSH=0; + static final private int Z_PARTIAL_FLUSH=1; + static final private int Z_SYNC_FLUSH=2; + static final private int Z_FULL_FLUSH=3; + static final private int Z_FINISH=4; + + static final private int MAX_MEM_LEVEL=9; + + static final private int Z_OK=0; + static final private int Z_STREAM_END=1; + static final private int Z_NEED_DICT=2; + static final private int Z_ERRNO=-1; + static final private int Z_STREAM_ERROR=-2; + static final private int Z_DATA_ERROR=-3; + static final private int Z_MEM_ERROR=-4; + static final private int Z_BUF_ERROR=-5; + static final private int Z_VERSION_ERROR=-6; + + public byte[] next_in; // next input byte + public int next_in_index; + public int avail_in; // number of bytes available at next_in + public long total_in; // total nb of input bytes read so far + + public byte[] next_out; // next output byte should be put there + public int next_out_index; + public int avail_out; // remaining free space at next_out + public long total_out; // total nb of bytes output so far + + public String msg; + + Inflate istate; + + int data_type; // best guess about the data type: ascii or binary + + Checksum adler; + + public ZStream(){ + this(new Adler32()); + } + + public ZStream(Checksum adler){ + this.adler=adler; + } + + public int inflateInit(){ + return inflateInit(DEF_WBITS); + } + public int inflateInit(boolean nowrap){ + return inflateInit(DEF_WBITS, nowrap); + } + public int inflateInit(int w){ + return inflateInit(w, false); + } + + public int inflateInit(int w, boolean nowrap){ + istate=new Inflate(this); + return istate.inflateInit(nowrap?-w:w); + } + + public int inflate(int f){ + if(istate==null) return Z_STREAM_ERROR; + return istate.inflate(f); + } + public int inflateEnd(){ + if(istate==null) return Z_STREAM_ERROR; + int ret=istate.inflateEnd(); +// istate = null; + return ret; + } + + public int inflateSync(){ + if(istate == null) + return Z_STREAM_ERROR; + return istate.inflateSync(); + } + public int inflateSyncPoint(){ + if(istate == null) + return Z_STREAM_ERROR; + return istate.inflateSyncPoint(); + } + public int inflateSetDictionary(byte[] dictionary, int dictLength){ + if(istate == null) + return Z_STREAM_ERROR; + return istate.inflateSetDictionary(dictionary, dictLength); + } + public boolean inflateFinished(){ + return istate.mode==12 /*DONE*/; + } + + + public long getAdler(){ + return adler.getValue(); + } + + public void free(){ + next_in=null; + next_out=null; + msg=null; + } + + public void setOutput(byte[] buf){ + setOutput(buf, 0, buf.length); + } + + public void setOutput(byte[] buf, int off, int len){ + next_out = buf; + next_out_index = off; + avail_out = len; + } + + public void setInput(byte[] buf){ + setInput(buf, 0, buf.length, false); + } + + public void setInput(byte[] buf, boolean append){ + setInput(buf, 0, buf.length, append); + } + + public void setInput(byte[] buf, int off, int len, boolean append){ + if(len<=0 && append && next_in!=null) return; + + if(avail_in>0 && append){ + byte[] tmp = new byte[avail_in+len]; + System.arraycopy(next_in, next_in_index, tmp, 0, avail_in); + System.arraycopy(buf, off, tmp, avail_in, len); + next_in=tmp; + next_in_index=0; + avail_in+=len; + } + else{ + next_in=buf; + next_in_index=off; + avail_in=len; + } + } + + public byte[] getNextIn(){ + return next_in; + } + + public void setNextIn(byte[] next_in){ + this.next_in = next_in; + } + + public int getNextInIndex(){ + return next_in_index; + } + + public void setNextInIndex(int next_in_index){ + this.next_in_index = next_in_index; + } + + public int getAvailIn(){ + return avail_in; + } + + public void setAvailIn(int avail_in){ + this.avail_in = avail_in; + } + + public byte[] getNextOut(){ + return next_out; + } + + public void setNextOut(byte[] next_out){ + this.next_out = next_out; + } + + public int getNextOutIndex(){ + return next_out_index; + } + + public void setNextOutIndex(int next_out_index){ + this.next_out_index = next_out_index; + } + + public int getAvailOut(){ + return avail_out; + + } + + public void setAvailOut(int avail_out){ + this.avail_out = avail_out; + } + + public long getTotalOut(){ + return total_out; + } + + public long getTotalIn(){ + return total_in; + } + + public String getMessage(){ + return msg; + } + + /** + * Those methods are expected to be override by Inflater and Deflater. + * In the future, they will become abstract methods. + */ + public int end(){ return Z_OK; } + public boolean finished(){ return false; } +} diff -r d088fc482c65 -r 0d277415ed02 emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/zip/ZipConstants64.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/zip/ZipConstants64.java Thu Feb 07 12:58:12 2013 +0100 @@ -0,0 +1,84 @@ +/* + * Copyright (c) 1995, 1996, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.apidesign.bck2brwsr.emul.zip; + +/* + * This class defines the constants that are used by the classes + * which manipulate Zip64 files. + */ + +public class ZipConstants64 { + + /* + * ZIP64 constants + */ + static final long ZIP64_ENDSIG = 0x06064b50L; // "PK\006\006" + static final long ZIP64_LOCSIG = 0x07064b50L; // "PK\006\007" + static final int ZIP64_ENDHDR = 56; // ZIP64 end header size + static final int ZIP64_LOCHDR = 20; // ZIP64 end loc header size + static final int ZIP64_EXTHDR = 24; // EXT header size + static final int ZIP64_EXTID = 0x0001; // Extra field Zip64 header ID + + static final int ZIP64_MAGICCOUNT = 0xFFFF; + static final long ZIP64_MAGICVAL = 0xFFFFFFFFL; + + /* + * Zip64 End of central directory (END) header field offsets + */ + static final int ZIP64_ENDLEN = 4; // size of zip64 end of central dir + static final int ZIP64_ENDVEM = 12; // version made by + static final int ZIP64_ENDVER = 14; // version needed to extract + static final int ZIP64_ENDNMD = 16; // number of this disk + static final int ZIP64_ENDDSK = 20; // disk number of start + static final int ZIP64_ENDTOD = 24; // total number of entries on this disk + static final int ZIP64_ENDTOT = 32; // total number of entries + static final int ZIP64_ENDSIZ = 40; // central directory size in bytes + static final int ZIP64_ENDOFF = 48; // offset of first CEN header + static final int ZIP64_ENDEXT = 56; // zip64 extensible data sector + + /* + * Zip64 End of central directory locator field offsets + */ + static final int ZIP64_LOCDSK = 4; // disk number start + static final int ZIP64_LOCOFF = 8; // offset of zip64 end + static final int ZIP64_LOCTOT = 16; // total number of disks + + /* + * Zip64 Extra local (EXT) header field offsets + */ + static final int ZIP64_EXTCRC = 4; // uncompressed file crc-32 value + static final int ZIP64_EXTSIZ = 8; // compressed size, 8-byte + static final int ZIP64_EXTLEN = 16; // uncompressed size, 8-byte + + /* + * Language encoding flag EFS + */ + static final int EFS = 0x800; // If this bit is set the filename and + // comment fields for this file must be + // encoded using UTF-8. + + private ZipConstants64() {} +} diff -r d088fc482c65 -r 0d277415ed02 emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/zip/ZipInputStream.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/zip/ZipInputStream.java Thu Feb 07 12:58:12 2013 +0100 @@ -0,0 +1,468 @@ +/* + * Copyright (c) 1996, 2009, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.apidesign.bck2brwsr.emul.zip; + +import java.util.zip.*; +import java.io.InputStream; +import java.io.IOException; +import java.io.EOFException; +import java.io.PushbackInputStream; +import static org.apidesign.bck2brwsr.emul.zip.ZipConstants64.*; +import static java.util.zip.ZipInputStream.*; + +/** + * This class implements an input stream filter for reading files in the + * ZIP file format. Includes support for both compressed and uncompressed + * entries. + * + * @author David Connelly + */ +public +class ZipInputStream extends InflaterInputStream { + private ZipEntry entry; + private int flag; + private CRC32 crc = new CRC32(); + private long remaining; + private byte[] tmpbuf = new byte[512]; + + private static final int STORED = ZipEntry.STORED; + private static final int DEFLATED = ZipEntry.DEFLATED; + + private boolean closed = false; + // this flag is set to true after EOF has reached for + // one entry + private boolean entryEOF = false; + + /** + * Check to make sure that this stream has not been closed + */ + private void ensureOpen() throws IOException { + if (closed) { + throw new IOException("Stream closed"); + } + } + + /** + * Creates a new ZIP input stream. + * + *The UTF-8 {@link java.nio.charset.Charset charset} is used to + * decode the entry names. + * + * @param in the actual input stream + */ + public ZipInputStream(InputStream in) { +// this(in, "UTF-8"); + super(new PushbackInputStream(in, 512), new Inflater(true), 512); + //usesDefaultInflater = true; + if(in == null) { + throw new NullPointerException("in is null"); + } + } + + /** + * Creates a new ZIP input stream. + * + * @param in the actual input stream + * + * @param charset + * The {@linkplain java.nio.charset.Charset charset} to be + * used to decode the ZIP entry name (ignored if the + * language + * encoding bit of the ZIP entry's general purpose bit + * flag is set). + * + * @since 1.7 + * + public ZipInputStream(InputStream in, Charset charset) { + super(new PushbackInputStream(in, 512), new Inflater(true), 512); + usesDefaultInflater = true; + if(in == null) { + throw new NullPointerException("in is null"); + } + if (charset == null) + throw new NullPointerException("charset is null"); + this.zc = ZipCoder.get(charset); + } + */ + + /** + * Reads the next ZIP file entry and positions the stream at the + * beginning of the entry data. + * @return the next ZIP file entry, or null if there are no more entries + * @exception ZipException if a ZIP file error has occurred + * @exception IOException if an I/O error has occurred + */ + public ZipEntry getNextEntry() throws IOException { + ensureOpen(); + if (entry != null) { + closeEntry(); + } + crc.reset(); + inf.reset(); + if ((entry = readLOC()) == null) { + return null; + } + if (entry.getMethod() == STORED) { + remaining = entry.getSize(); + } + entryEOF = false; + return entry; + } + + /** + * Closes the current ZIP entry and positions the stream for reading the + * next entry. + * @exception ZipException if a ZIP file error has occurred + * @exception IOException if an I/O error has occurred + */ + public void closeEntry() throws IOException { + ensureOpen(); + while (read(tmpbuf, 0, tmpbuf.length) != -1) ; + entryEOF = true; + } + + /** + * Returns 0 after EOF has reached for the current entry data, + * otherwise always return 1. + *
+ * Programs should not count on this method to return the actual number
+ * of bytes that could be read without blocking.
+ *
+ * @return 1 before EOF and 0 after EOF has reached for current entry.
+ * @exception IOException if an I/O error occurs.
+ *
+ */
+ public int available() throws IOException {
+ ensureOpen();
+ if (entryEOF) {
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+
+ /**
+ * Reads from the current ZIP entry into an array of bytes.
+ * If len
is not zero, the method
+ * blocks until some input is available; otherwise, no
+ * bytes are read and 0
is returned.
+ * @param b the buffer into which the data is read
+ * @param off the start offset in the destination array b
+ * @param len the maximum number of bytes read
+ * @return the actual number of bytes read, or -1 if the end of the
+ * entry is reached
+ * @exception NullPointerException if b
is null
.
+ * @exception IndexOutOfBoundsException if off
is negative,
+ * len
is negative, or len
is greater than
+ * b.length - off
+ * @exception ZipException if a ZIP file error has occurred
+ * @exception IOException if an I/O error has occurred
+ */
+ public int read(byte[] b, int off, int len) throws IOException {
+ ensureOpen();
+ if (off < 0 || len < 0 || off > b.length - len) {
+ throw new IndexOutOfBoundsException();
+ } else if (len == 0) {
+ return 0;
+ }
+
+ if (entry == null) {
+ return -1;
+ }
+ switch (entry.getMethod()) {
+ case DEFLATED:
+ len = super.read(b, off, len);
+ if (len == -1) {
+ readEnd(entry);
+ entryEOF = true;
+ entry = null;
+ } else {
+ crc.update(b, off, len);
+ }
+ return len;
+ case STORED:
+ if (remaining <= 0) {
+ entryEOF = true;
+ entry = null;
+ return -1;
+ }
+ if (len > remaining) {
+ len = (int)remaining;
+ }
+ len = in.read(b, off, len);
+ if (len == -1) {
+ throw new ZipException("unexpected EOF");
+ }
+ crc.update(b, off, len);
+ remaining -= len;
+ if (remaining == 0 && entry.getCrc() != crc.getValue()) {
+ throw new ZipException(
+ "invalid entry CRC (expected 0x" + Long.toHexString(entry.getCrc()) +
+ " but got 0x" + Long.toHexString(crc.getValue()) + ")");
+ }
+ return len;
+ default:
+ throw new ZipException("invalid compression method");
+ }
+ }
+
+ /**
+ * Skips specified number of bytes in the current ZIP entry.
+ * @param n the number of bytes to skip
+ * @return the actual number of bytes skipped
+ * @exception ZipException if a ZIP file error has occurred
+ * @exception IOException if an I/O error has occurred
+ * @exception IllegalArgumentException if n < 0
+ */
+ public long skip(long n) throws IOException {
+ if (n < 0) {
+ throw new IllegalArgumentException("negative skip length");
+ }
+ ensureOpen();
+ int max = (int)Math.min(n, Integer.MAX_VALUE);
+ int total = 0;
+ while (total < max) {
+ int len = max - total;
+ if (len > tmpbuf.length) {
+ len = tmpbuf.length;
+ }
+ len = read(tmpbuf, 0, len);
+ if (len == -1) {
+ entryEOF = true;
+ break;
+ }
+ total += len;
+ }
+ return total;
+ }
+
+ /**
+ * Closes this input stream and releases any system resources associated
+ * with the stream.
+ * @exception IOException if an I/O error has occurred
+ */
+ public void close() throws IOException {
+ if (!closed) {
+ super.close();
+ closed = true;
+ }
+ }
+
+ private byte[] b = new byte[256];
+
+ /*
+ * Reads local file (LOC) header for next entry.
+ */
+ private ZipEntry readLOC() throws IOException {
+ try {
+ readFully(tmpbuf, 0, LOCHDR);
+ } catch (EOFException e) {
+ return null;
+ }
+ if (get32(tmpbuf, 0) != LOCSIG) {
+ return null;
+ }
+ // get flag first, we need check EFS.
+ flag = get16(tmpbuf, LOCFLG);
+ // get the entry name and create the ZipEntry first
+ int len = get16(tmpbuf, LOCNAM);
+ int blen = b.length;
+ if (len > blen) {
+ do
+ blen = blen * 2;
+ while (len > blen);
+ b = new byte[blen];
+ }
+ readFully(b, 0, len);
+ // Force to use UTF-8 if the EFS bit is ON, even the cs is NOT UTF-8
+ ZipEntry e = createZipEntry(((flag & EFS) != 0)
+ ? toStringUTF8(b, len)
+ : toString(b, len));
+ // now get the remaining fields for the entry
+ if ((flag & 1) == 1) {
+ throw new ZipException("encrypted ZIP entry not supported");
+ }
+ e.setMethod(get16(tmpbuf, LOCHOW));
+ e.setTime(get32(tmpbuf, LOCTIM));
+ if ((flag & 8) == 8) {
+ /* "Data Descriptor" present */
+ if (e.getMethod() != DEFLATED) {
+ throw new ZipException(
+ "only DEFLATED entries can have EXT descriptor");
+ }
+ } else {
+ e.setCrc(get32(tmpbuf, LOCCRC));
+ e.setCompressedSize(get32(tmpbuf, LOCSIZ));
+ e.setSize(get32(tmpbuf, LOCLEN));
+ }
+ len = get16(tmpbuf, LOCEXT);
+ if (len > 0) {
+ byte[] bb = new byte[len];
+ readFully(bb, 0, len);
+ e.setExtra(bb);
+ // extra fields are in "HeaderID(2)DataSize(2)Data... format
+ if (e.getCompressedSize() == ZIP64_MAGICVAL || e.getCompressedSize() == ZIP64_MAGICVAL) {
+ int off = 0;
+ while (off + 4 < len) {
+ int sz = get16(bb, off + 2);
+ if (get16(bb, off) == ZIP64_EXTID) {
+ off += 4;
+ // LOC extra zip64 entry MUST include BOTH original and
+ // compressed file size fields
+ if (sz < 16 || (off + sz) > len ) {
+ // Invalid zip64 extra fields, simply skip. Even it's
+ // rare, it's possible the entry size happens to be
+ // the magic value and it "accidnetly" has some bytes
+ // in extra match the id.
+ return e;
+ }
+ e.setSize(get64(bb, off));
+ e.setCompressedSize(get64(bb, off + 8));
+ break;
+ }
+ off += (sz + 4);
+ }
+ }
+ }
+ return e;
+ }
+
+ /**
+ * Creates a new ZipEntry
object for the specified
+ * entry name.
+ *
+ * @param name the ZIP file entry name
+ * @return the ZipEntry just created
+ */
+ protected ZipEntry createZipEntry(String name) {
+ return new ZipEntry(name);
+ }
+
+ /*
+ * Reads end of deflated entry as well as EXT descriptor if present.
+ */
+ private void readEnd(ZipEntry e) throws IOException {
+ int n = inf.getRemaining();
+ if (n > 0) {
+ ((PushbackInputStream)in).unread(buf, len - n, n);
+ }
+ if ((flag & 8) == 8) {
+ /* "Data Descriptor" present */
+ if (inf.getBytesWritten() > ZIP64_MAGICVAL ||
+ inf.getBytesRead() > ZIP64_MAGICVAL) {
+ // ZIP64 format
+ readFully(tmpbuf, 0, ZIP64_EXTHDR);
+ long sig = get32(tmpbuf, 0);
+ if (sig != EXTSIG) { // no EXTSIG present
+ e.setCrc(sig);
+ e.setCompressedSize(get64(tmpbuf, ZIP64_EXTSIZ - ZIP64_EXTCRC));
+ e.setSize(get64(tmpbuf, ZIP64_EXTLEN - ZIP64_EXTCRC));
+ ((PushbackInputStream)in).unread(
+ tmpbuf, ZIP64_EXTHDR - ZIP64_EXTCRC - 1, ZIP64_EXTCRC);
+ } else {
+ e.setCrc(get32(tmpbuf, ZIP64_EXTCRC));
+ e.setCompressedSize(get64(tmpbuf, ZIP64_EXTSIZ));
+ e.setSize(get64(tmpbuf, ZIP64_EXTLEN));
+ }
+ } else {
+ readFully(tmpbuf, 0, EXTHDR);
+ long sig = get32(tmpbuf, 0);
+ if (sig != EXTSIG) { // no EXTSIG present
+ e.setCrc(sig);
+ e.setCompressedSize(get32(tmpbuf, EXTSIZ - EXTCRC));
+ e.setSize(get32(tmpbuf, EXTLEN - EXTCRC));
+ ((PushbackInputStream)in).unread(
+ tmpbuf, EXTHDR - EXTCRC - 1, EXTCRC);
+ } else {
+ e.setCrc(get32(tmpbuf, EXTCRC));
+ e.setCompressedSize(get32(tmpbuf, EXTSIZ));
+ e.setSize(get32(tmpbuf, EXTLEN));
+ }
+ }
+ }
+ if (e.getSize() != inf.getBytesWritten()) {
+ throw new ZipException(
+ "invalid entry size (expected " + e.getSize() +
+ " but got " + inf.getBytesWritten() + " bytes)");
+ }
+ if (e.getCompressedSize() != inf.getBytesRead()) {
+ throw new ZipException(
+ "invalid entry compressed size (expected " + e.getCompressedSize() +
+ " but got " + inf.getBytesRead() + " bytes)");
+ }
+ if (e.getCrc() != crc.getValue()) {
+ throw new ZipException(
+ "invalid entry CRC (expected 0x" + Long.toHexString(e.getCrc()) +
+ " but got 0x" + Long.toHexString(crc.getValue()) + ")");
+ }
+ }
+
+ /*
+ * Reads bytes, blocking until all bytes are read.
+ */
+ private void readFully(byte[] b, int off, int len) throws IOException {
+ while (len > 0) {
+ int n = in.read(b, off, len);
+ if (n == -1) {
+ throw new EOFException();
+ }
+ off += n;
+ len -= n;
+ }
+ }
+
+ /*
+ * Fetches unsigned 16-bit value from byte array at specified offset.
+ * The bytes are assumed to be in Intel (little-endian) byte order.
+ */
+ private static final int get16(byte b[], int off) {
+ return (b[off] & 0xff) | ((b[off+1] & 0xff) << 8);
+ }
+
+ /*
+ * Fetches unsigned 32-bit value from byte array at specified offset.
+ * The bytes are assumed to be in Intel (little-endian) byte order.
+ */
+ private static final long get32(byte b[], int off) {
+ return (get16(b, off) | ((long)get16(b, off+2) << 16)) & 0xffffffffL;
+ }
+
+ /*
+ * Fetches signed 64-bit value from byte array at specified offset.
+ * The bytes are assumed to be in Intel (little-endian) byte order.
+ */
+ private static final long get64(byte b[], int off) {
+ return get32(b, off) | (get32(b, off+4) << 32);
+ }
+
+ private static String toStringUTF8(byte[] arr, int len) {
+ return new String(arr, 0, len);
+ }
+
+ private static String toString(byte[] b, int len) {
+ return new String(b, 0, len);
+ }
+}