Author: tdraier
Date: Fri Jul 6 15:01:35 2007
New Revision: 17906
URL: https://svndev.jahia.net/websvn/listing.php?sc=3D1&rev=3D17906&repname=
=3Djahia
Log:
replaced zip implementation by more encoding permissive one ( DOC-112 , DOC=
-111 , DOC-134 ) . If filenames does not appear to be utf8, switch to Cp437=
(which seems to be winzip default) (backport 17352)
Added:
trunk/core/src/java/org/jahia/utils/zip/DeflaterOutputStream.java
trunk/core/src/java/org/jahia/utils/zip/InflaterInputStream.java
trunk/core/src/java/org/jahia/utils/zip/ZipConstants.java
trunk/core/src/java/org/jahia/utils/zip/ZipEntry.java
trunk/core/src/java/org/jahia/utils/zip/ZipInputStream.java
trunk/core/src/java/org/jahia/utils/zip/ZipOutputStream.java
Added: trunk/core/src/java/org/jahia/utils/zip/DeflaterOutputStream.java
URL: https://svndev.jahia.net/websvn/filedetails.php?path=3D/trunk/core/src=
/java/org/jahia/utils/zip/DeflaterOutputStream.java&rev=3D17906&repname=3Dj=
ahia
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- trunk/core/src/java/org/jahia/utils/zip/DeflaterOutputStream.java (adde=
d)
+++ trunk/core/src/java/org/jahia/utils/zip/DeflaterOutputStream.java Fri J=
ul 6 15:01:35 2007
@@ -0,0 +1,164 @@
+/*
+ * @(#)DeflaterOutputStream.java 1.34 06/04/05
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ */
+
+package org.jahia.utils.zip;
+
+import java.io.FilterOutputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+import java.util.zip.Deflater;
+
+/**
+ * This class implements an output stream filter for compressing data in
+ * the "deflate" compression format. It is also used as the basis for other
+ * types of compression filters, such as GZIPOutputStream.
+ *
+ * @see Deflater
+ * @version 1.34, 01/12/04
+ * @author David Connelly
+ */
+public
+class DeflaterOutputStream extends FilterOutputStream {
+ /**
+ * Compressor for this stream.
+ */
+ protected Deflater def;
+
+ /**
+ * Output buffer for writing compressed data.
+ */
+ protected byte[] buf;
+
+ /**
+ * Indicates that the stream has been closed.
+ */
+
+ private boolean closed =3D false;
+
+ /**
+ * Creates a new output stream with the specified compressor and
+ * buffer size.
+ * @param out the output stream
+ * @param def the compressor ("deflater")
+ * @param size the output buffer size
+ * @exception IllegalArgumentException if size is <=3D 0
+ */
+ public DeflaterOutputStream(OutputStream out, Deflater def, int size) {
+ super(out);
+ if (out =3D=3D null || def =3D=3D null) {
+ throw new NullPointerException();
+ } else if (size <=3D 0) {
+ throw new IllegalArgumentException("buffer size <=3D 0");
+ }
+ this.def =3D def;
+ buf =3D new byte[size];
+ }
+
+ /**
+ * Creates a new output stream with the specified compressor and
+ * a default buffer size.
+ * @param out the output stream
+ * @param def the compressor ("deflater")
+ */
+ public DeflaterOutputStream(OutputStream out, Deflater def) {
+ this(out, def, 512);
+ }
+
+ boolean usesDefaultDeflater =3D false;
+
+ /**
+ * Creates a new output stream with a default compressor and buffer si=
ze.
+ * @param out the output stream
+ */
+ public DeflaterOutputStream(OutputStream out) {
+ this(out, new Deflater());
+ usesDefaultDeflater =3D true;
+ }
+
+ /**
+ * Writes a byte to the compressed output stream. This method will
+ * block until the byte can be written.
+ * @param b the byte to be written
+ * @exception IOException if an I/O error has occurred
+ */
+ public void write(int b) throws IOException {
+ byte[] buf =3D new byte[1];
+ buf[0] =3D (byte)(b & 0xff);
+ write(buf, 0, 1);
+ }
+
+ /**
+ * Writes an array of bytes to the compressed output stream. This
+ * method will block until all the bytes are written.
+ * @param b the data to be written
+ * @param off the start offset of the data
+ * @param len the length of the data
+ * @exception IOException if an I/O error has occurred
+ */
+ public void write(byte[] b, int off, int len) throws IOException {
+ if (def.finished()) {
+ throw new IOException("write beyond end of stream");
+ }
+ if ((off | len | (off + len) | (b.length - (off + len))) < 0) {
+ throw new IndexOutOfBoundsException();
+ } else if (len =3D=3D 0) {
+ return;
+ }
+ if (!def.finished()) {
+ // Deflate no more than stride bytes at a time. This avoids
+ // excess copying in deflateBytes (see Deflater.c)
+ int stride =3D buf.length;
+ for (int i =3D 0; i < len; i+=3D stride) {
+ def.setInput(b, off + i, Math.min(stride, len - i));
+ while (!def.needsInput()) {
+ deflate();
+ }
+ }
+ }
+ }
+
+ /**
+ * Finishes writing compressed data to the output stream without closi=
ng
+ * the underlying stream. Use this method when applying multiple filte=
rs
+ * in succession to the same output stream.
+ * @exception IOException if an I/O error has occurred
+ */
+ public void finish() throws IOException {
+ if (!def.finished()) {
+ def.finish();
+ while (!def.finished()) {
+ deflate();
+ }
+ }
+ }
+
+ /**
+ * Writes remaining compressed data to the output stream and closes the
+ * underlying stream.
+ * @exception IOException if an I/O error has occurred
+ */
+ public void close() throws IOException {
+ if (!closed) {
+ finish();
+ if (usesDefaultDeflater)
+ def.end();
+ out.close();
+ closed =3D true;
+ }
+ }
+
+ /**
+ * Writes next block of compressed data to the output stream.
+ * @throws IOException if an I/O error has occurred
+ */
+ protected void deflate() throws IOException {
+ int len =3D def.deflate(buf, 0, buf.length);
+ if (len > 0) {
+ out.write(buf, 0, len);
+ }
+ }
+}
Added: trunk/core/src/java/org/jahia/utils/zip/InflaterInputStream.java
URL: https://svndev.jahia.net/websvn/filedetails.php?path=3D/trunk/core/src=
/java/org/jahia/utils/zip/InflaterInputStream.java&rev=3D17906&repname=3Dja=
hia
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- trunk/core/src/java/org/jahia/utils/zip/InflaterInputStream.java (added)
+++ trunk/core/src/java/org/jahia/utils/zip/InflaterInputStream.java Fri Ju=
l 6 15:01:35 2007
@@ -0,0 +1,222 @@
+/*
+ * @(#)InflaterInputStream.java 1.32 03/01/23
+ *
+ * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ */
+
+package org.jahia.utils.zip;
+
+import java.io.FilterInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.EOFException;
+import java.util.zip.Inflater;
+import java.util.zip.DataFormatException;
+import java.util.zip.ZipException;
+
+/**
+ * This class implements a stream filter for uncompressing data in the
+ * "deflate" compression format. It is also used as the basis for other
+ * decompression filters, such as GZIPInputStream.
+ *
+ * @see Inflater
+ * @version 1.32, 01/23/03
+ * @author David Connelly
+ */
+public
+class InflaterInputStream extends FilterInputStream {
+ /**
+ * Decompressor for this stream.
+ */
+ protected Inflater inf;
+
+ /**
+ * Input buffer for decompression.
+ */
+ protected byte[] buf;
+
+ /**
+ * Length of input buffer.
+ */
+ protected int len;
+
+ private boolean closed =3D false;
+ // this flag is set to true after EOF has reached
+ private boolean reachEOF =3D 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 input stream with the specified decompressor and
+ * buffer size.
+ * @param in the input stream
+ * @param inf the decompressor ("inflater")
+ * @param size the input buffer size
+ * @exception IllegalArgumentException if size is <=3D 0
+ */
+ public InflaterInputStream(InputStream in, Inflater inf, int size) {
+ super(in);
+ if (in =3D=3D null || inf =3D=3D null) {
+ throw new NullPointerException();
+ } else if (size <=3D 0) {
+ throw new IllegalArgumentException("buffer size <=3D 0");
+ }
+ this.inf =3D inf;
+ buf =3D new byte[size];
+ }
+
+ /**
+ * Creates a new input stream with the specified decompressor and a
+ * default buffer size.
+ * @param in the input stream
+ * @param inf the decompressor ("inflater")
+ */
+ public InflaterInputStream(InputStream in, Inflater inf) {
+ this(in, inf, 512);
+ }
+
+ boolean usesDefaultInflater =3D false;
+
+ /**
+ * Creates a new input stream with a default decompressor and buffer s=
ize.
+ * @param in the input stream
+ */
+ public InflaterInputStream(InputStream in) {
+ this(in, new Inflater());
+ usesDefaultInflater =3D true;
+ }
+
+ private byte[] singleByteBuf =3D new byte[1];
+
+ /**
+ * Reads a byte of uncompressed data. This method will block until
+ * enough input is available for decompression.
+ * @return the byte read, or -1 if end of compressed input is reached
+ * @exception IOException if an I/O error has occurred
+ */
+ public int read() throws IOException {
+ ensureOpen();
+ return read(singleByteBuf, 0, 1) =3D=3D -1 ? -1 : singleByteBuf[0] &
0xff;
+ }
+
+ /**
+ * Reads uncompressed data into an array of bytes. This method will
+ * block until some input can be decompressed.
+ * @param b the buffer into which the data is read
+ * @param off the start offset of the data
+ * @param len the maximum number of bytes read
+ * @return the actual number of bytes read, or -1 if the end of the
+ * compressed input is reached or a preset dictionary is needed
+ * @exception java.util.zip.ZipException if a ZIP format error has occ=
urred
+ * @exception IOException if an I/O error has occurred
+ */
+ public int read(byte[] b, int off, int len) throws IOException {
+ ensureOpen();
+ if ((off | len | (off + len) | (b.length - (off + len))) < 0) {
+ throw new IndexOutOfBoundsException();
+ } else if (len =3D=3D 0) {
+ return 0;
+ }
+ try {
+ int n;
+ while ((n =3D inf.inflate(b, off, len)) =3D=3D 0) {
+ if (inf.finished() || inf.needsDictionary()) {
+ reachEOF =3D true;
+ return -1;
+ }
+ if (inf.needsInput()) {
+ fill();
+ }
+ }
+ return n;
+ } catch (DataFormatException e) {
+ String s =3D e.getMessage();
+ throw new ZipException(s !=3D null ? s : "Invalid ZLIB data
format");
+ }
+ }
+
+ /**
+ * Returns 0 after EOF has reached, otherwise always return 1.
+ * <p>
+ * 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.
+ * @exception IOException if an I/O error occurs.
+ *
+ */
+ public int available() throws IOException {
+ ensureOpen();
+ if (reachEOF) {
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+
+ private byte[] b =3D new byte[512];
+
+ /**
+ * Skips specified number of bytes of uncompressed data.
+ * @param n the number of bytes to skip
+ * @return the actual number of bytes skipped.
+ * @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 =3D (int)Math.min(n, Integer.MAX_VALUE);
+ int total =3D 0;
+ while (total < max) {
+ int len =3D max - total;
+ if (len > b.length) {
+ len =3D b.length;
+ }
+ len =3D read(b, 0, len);
+ if (len =3D=3D -1) {
+ reachEOF =3D true;
+ break;
+ }
+ total +=3D len;
+ }
+ return total;
+ }
+
+ /**
+ * Closes the input stream.
+ * @exception IOException if an I/O error has occurred
+ */
+ public void close() throws IOException {
+ if (!closed) {
+ if (usesDefaultInflater)
+ inf.end();
+ in.close();
+ closed =3D true;
+ }
+ }
+
+ /**
+ * Fills input buffer with more data to decompress.
+ * @exception IOException if an I/O error has occurred
+ */
+ protected void fill() throws IOException {
+ ensureOpen();
+ len =3D in.read(buf, 0, buf.length);
+ if (len =3D=3D -1) {
+ throw new EOFException("Unexpected end of ZLIB input stream");
+ }
+ inf.setInput(buf, 0, len);
+ }
+}
Added: trunk/core/src/java/org/jahia/utils/zip/ZipConstants.java
URL: https://svndev.jahia.net/websvn/filedetails.php?path=3D/trunk/core/src=
/java/org/jahia/utils/zip/ZipConstants.java&rev=3D17906&repname=3Djahia
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- trunk/core/src/java/org/jahia/utils/zip/ZipConstants.java (added)
+++ trunk/core/src/java/org/jahia/utils/zip/ZipConstants.java Fri Jul 6 15=
:01:35 2007
@@ -0,0 +1,81 @@
+/*
+ * @(#)ZipConstants.java 1.17 03/01/23
+ *
+ * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ */
+
+package org.jahia.utils.zip;
+
+/*
+ * This interface defines the constants that are used by the classes
+ * which manipulate ZIP files.
+ *
+ * @version 1.17, 01/23/03
+ * @author David Connelly
+ */
+interface ZipConstants {
+ /*
+ * Header signatures
+ */
+ static long LOCSIG =3D 0x04034b50L; // "PK\003\004"
+ static long EXTSIG =3D 0x08074b50L; // "PK\007\008"
+ static long CENSIG =3D 0x02014b50L; // "PK\001\002"
+ static long ENDSIG =3D 0x06054b50L; // "PK\005\006"
+
+ /*
+ * Header sizes in bytes (including signatures)
+ */
+ static final int LOCHDR =3D 30; // LOC header size
+ static final int EXTHDR =3D 16; // EXT header size
+ static final int CENHDR =3D 46; // CEN header size
+ static final int ENDHDR =3D 22; // END header size
+
+ /*
+ * Local file (LOC) header field offsets
+ */
+ static final int LOCVER =3D 4; // version needed to extract
+ static final int LOCFLG =3D 6; // general purpose bit flag
+ static final int LOCHOW =3D 8; // compression method
+ static final int LOCTIM =3D 10; // modification time
+ static final int LOCCRC =3D 14; // uncompressed file crc-32 value
+ static final int LOCSIZ =3D 18; // compressed size
+ static final int LOCLEN =3D 22; // uncompressed size
+ static final int LOCNAM =3D 26; // filename length
+ static final int LOCEXT =3D 28; // extra field length
+
+ /*
+ * Extra local (EXT) header field offsets
+ */
+ static final int EXTCRC =3D 4; // uncompressed file crc-32 value
+ static final int EXTSIZ =3D 8; // compressed size
+ static final int EXTLEN =3D 12; // uncompressed size
+
+ /*
+ * Central directory (CEN) header field offsets
+ */
+ static final int CENVEM =3D 4; // version made by
+ static final int CENVER =3D 6; // version needed to extract
+ static final int CENFLG =3D 8; // encrypt, decrypt flags
+ static final int CENHOW =3D 10; // compression method
+ static final int CENTIM =3D 12; // modification time
+ static final int CENCRC =3D 16; // uncompressed file crc-32 value
+ static final int CENSIZ =3D 20; // compressed size
+ static final int CENLEN =3D 24; // uncompressed size
+ static final int CENNAM =3D 28; // filename length
+ static final int CENEXT =3D 30; // extra field length
+ static final int CENCOM =3D 32; // comment length
+ static final int CENDSK =3D 34; // disk number start
+ static final int CENATT =3D 36; // internal file attributes
+ static final int CENATX =3D 38; // external file attributes
+ static final int CENOFF =3D 42; // LOC header offset
+
+ /*
+ * End of central directory (END) header field offsets
+ */
+ static final int ENDSUB =3D 8; // number of entries on this disk
+ static final int ENDTOT =3D 10; // total number of entries
+ static final int ENDSIZ =3D 12; // central directory size in bytes
+ static final int ENDOFF =3D 16; // offset of first CEN header
+ static final int ENDCOM =3D 20; // zip file comment length
+}
Added: trunk/core/src/java/org/jahia/utils/zip/ZipEntry.java
URL: https://svndev.jahia.net/websvn/filedetails.php?path=3D/trunk/core/src=
/java/org/jahia/utils/zip/ZipEntry.java&rev=3D17906&repname=3Djahia
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- trunk/core/src/java/org/jahia/utils/zip/ZipEntry.java (added)
+++ trunk/core/src/java/org/jahia/utils/zip/ZipEntry.java Fri Jul 6 15:01:=
35 2007
@@ -0,0 +1,331 @@
+/*
+ * @(#)ZipEntry.java 1.37 05/04/29
+ *
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ */
+
+package org.jahia.utils.zip;
+
+import java.util.Date;
+
+/**
+ * This class is used to represent a ZIP file entry.
+ *
+ * @version 1.37, 04/29/05
+ * @author David Connelly
+ */
+public
+class ZipEntry implements ZipConstants, Cloneable {
+ String name; // entry name
+ long time =3D -1; // modification time (in DOS time)
+ long crc =3D -1; // crc-32 of entry data
+ long size =3D -1; // uncompressed size of entry data
+ long csize =3D -1; // compressed size of entry data
+ int method =3D -1; // compression method
+ byte[] extra; // optional extra field data for entry
+ String comment; // optional comment string for entry
+ // The following flags are used only by Zip{Input,Output}Stream
+ int flag; // bit flags
+ int version; // version needed to extract
+ long offset; // offset of loc header
+
+ /**
+ * Compression method for uncompressed entries.
+ */
+ public static final int STORED =3D 0;
+
+ /**
+ * Compression method for compressed (deflated) entries.
+ */
+ public static final int DEFLATED =3D 8;
+
+// static {
+// /* Zip library is loaded from System.initializeSystemClass */
+// initIDs();
+// }
+//
+// private static native void initIDs();
+
+ /**
+ * Creates a new zip entry with the specified name.
+ *
+ * @param name the entry name
+ * @exception NullPointerException if the entry name is null
+ * @exception IllegalArgumentException if the entry name is longer than
+ * 0xFFFF bytes
+ */
+ public ZipEntry(String name) {
+ if (name =3D=3D null) {
+ throw new NullPointerException();
+ }
+ if (name.length() > 0xFFFF) {
+ throw new IllegalArgumentException("entry name too long");
+ }
+ this.name =3D name;
+ }
+
+ /**
+ * Creates a new zip entry with fields taken from the specified
+ * zip entry.
+ * @param e a zip Entry object
+ */
+ public ZipEntry(ZipEntry e) {
+ name =3D e.name;
+ time =3D e.time;
+ crc =3D e.crc;
+ size =3D e.size;
+ csize =3D e.csize;
+ method =3D e.method;
+ extra =3D e.extra;
+ comment =3D e.comment;
+ }
+
+ /*
+ * Creates a new zip entry for the given name with fields initialized
+ * from the specified jzentry data.
+ */
+// ZipEntry(String name, long jzentry) {
+// this.name =3D name;
+// initFields(jzentry);
+// }
+
+// private native void initFields(long jzentry);
+
+ /*
+ * Creates a new zip entry with fields initialized from the specified
+ * jzentry data.
+ */
+// ZipEntry(long jzentry) {
+// initFields(jzentry);
+// }
+
+ /**
+ * Returns the name of the entry.
+ * @return the name of the entry
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets the modification time of the entry.
+ * @param time the entry modification time in number of milliseconds
+ * since the epoch
+ * @see #getTime()
+ */
+ public void setTime(long time) {
+ this.time =3D javaToDosTime(time);
+ }
+
+ /**
+ * Returns the modification time of the entry, or -1 if not specified.
+ * @return the modification time of the entry, or -1 if not specified
+ * @see #setTime(long)
+ */
+ public long getTime() {
+ return time !=3D -1 ? dosToJavaTime(time) : -1;
+ }
+
+ /**
+ * Sets the uncompressed size of the entry data.
+ * @param size the uncompressed size in bytes
+ * @exception IllegalArgumentException if the specified size is less
+ * than 0 or greater than 0xFFFFFFFF bytes
+ * @see #getSize()
+ */
+ public void setSize(long size) {
+ if (size < 0 || size > 0xFFFFFFFFL) {
+ throw new IllegalArgumentException("invalid entry size");
+ }
+ this.size =3D size;
+ }
+
+ /**
+ * Returns the uncompressed size of the entry data, or -1 if not known.
+ * @return the uncompressed size of the entry data, or -1 if not known
+ * @see #setSize(long)
+ */
+ public long getSize() {
+ return size;
+ }
+
+ /**
+ * Returns the size of the compressed entry data, or -1 if not known.
+ * In the case of a stored entry, the compressed size will be the same
+ * as the uncompressed size of the entry.
+ * @return the size of the compressed entry data, or -1 if not known
+ * @see #setCompressedSize(long)
+ */
+ public long getCompressedSize() {
+ return csize;
+ }
+
+ /**
+ * Sets the size of the compressed entry data.
+ * @param csize the compressed size to set to
+ * @see #getCompressedSize()
+ */
+ public void setCompressedSize(long csize) {
+ this.csize =3D csize;
+ }
+
+ /**
+ * Sets the CRC-32 checksum of the uncompressed entry data.
+ * @param crc the CRC-32 value
+ * @exception IllegalArgumentException if the specified CRC-32 value is
+ * less than 0 or greater than 0xFFFFFFFF
+ * @see #setCrc(long)
+ */
+ public void setCrc(long crc) {
+ if (crc < 0 || crc > 0xFFFFFFFFL) {
+ throw new IllegalArgumentException("invalid entry crc-32");
+ }
+ this.crc =3D crc;
+ }
+
+ /**
+ * Returns the CRC-32 checksum of the uncompressed entry data, or -1 if
+ * not known.
+ * @return the CRC-32 checksum of the uncompressed entry data, or -1 if
+ * not known
+ * @see #getCrc()
+ */
+ public long getCrc() {
+ return crc;
+ }
+
+ /**
+ * Sets the compression method for the entry.
+ * @param method the compression method, either STORED or DEFLATED
+ * @exception IllegalArgumentException if the specified compression
+ * method is invalid
+ * @see #getMethod()
+ */
+ public void setMethod(int method) {
+ if (method !=3D STORED && method !=3D DEFLATED) {
+ throw new IllegalArgumentException("invalid compression method");
+ }
+ this.method =3D method;
+ }
+
+ /**
+ * Returns the compression method of the entry, or -1 if not specified.
+ * @return the compression method of the entry, or -1 if not specified
+ * @see #setMethod(int)
+ */
+ public int getMethod() {
+ return method;
+ }
+
+ /**
+ * Sets the optional extra field data for the entry.
+ * @param extra the extra field data bytes
+ * @exception IllegalArgumentException if the length of the specified
+ * extra field data is greater than 0xFFFF bytes
+ * @see #getExtra()
+ */
+ public void setExtra(byte[] extra) {
+ if (extra !=3D null && extra.length > 0xFFFF) {
+ throw new IllegalArgumentException("invalid extra field length");
+ }
+ this.extra =3D extra;
+ }
+
+ /**
+ * Returns the extra field data for the entry, or null if none.
+ * @return the extra field data for the entry, or null if none
+ * @see #setExtra(byte[])
+ */
+ public byte[] getExtra() {
+ return extra;
+ }
+
+ /**
+ * Sets the optional comment string for the entry.
+ * @param comment the comment string
+ * @exception IllegalArgumentException if the length of the specified
+ * comment string is greater than 0xFFFF bytes
+ * @see #getComment()
+ */
+ public void setComment(String comment) {
+ if (comment !=3D null && comment.length() > 0xffff/3
+ && ZipOutputStream.getUTF8Length(comment) > 0xffff) {
+ throw new IllegalArgumentException("invalid entry comment length");
+ }
+ this.comment =3D comment;
+ }
+
+ /**
+ * Returns the comment string for the entry, or null if none.
+ * @return the comment string for the entry, or null if none
+ * @see #setComment(String)
+ */
+ public String getComment() {
+ return comment;
+ }
+
+ /**
+ * Returns true if this is a directory entry. A directory entry is
+ * defined to be one whose name ends with a '/'.
+ * @return true if this is a directory entry
+ */
+ public boolean isDirectory() {
+ return name.endsWith("/");
+ }
+
+ /**
+ * Returns a string representation of the ZIP entry.
+ */
+ public String toString() {
+ return getName();
+ }
+
+ /*
+ * Converts DOS time to Java time (number of milliseconds since epoch).
+ */
+ private static long dosToJavaTime(long dtime) {
+ Date d =3D new Date((int)(((dtime >> 25) & 0x7f) + 80),
+ (int)(((dtime >> 21) & 0x0f) - 1),
+ (int)((dtime >> 16) & 0x1f),
+ (int)((dtime >> 11) & 0x1f),
+ (int)((dtime >> 5) & 0x3f),
+ (int)((dtime << 1) & 0x3e));
+ return d.getTime();
+ }
+
+ /*
+ * Converts Java time to DOS time.
+ */
+ private static long javaToDosTime(long time) {
+ Date d =3D new Date(time);
+ int year =3D d.getYear() + 1900;
+ if (year < 1980) {
+ return (1 << 21) | (1 << 16);
+ }
+ return (year - 1980) << 25 | (d.getMonth() + 1) << 21 |
+ d.getDate() << 16 | d.getHours() << 11 | d.getMinutes() << =
5 |
+ d.getSeconds() >> 1;
+ }
+
+ /**
+ * Returns the hash code value for this entry.
+ */
+ public int hashCode() {
+ return name.hashCode();
+ }
+
+ /**
+ * Returns a copy of this entry.
+ */
+ public Object clone() {
+ try {
+ ZipEntry e =3D (ZipEntry)super.clone();
+ e.extra =3D (extra =3D=3D null ? null : (byte[])extra.clone());
+ return e;
+ } catch (CloneNotSupportedException e) {
+ // This should never happen, since we are Cloneable
+ throw new InternalError();
+ }
+ }
+}
Added: trunk/core/src/java/org/jahia/utils/zip/ZipInputStream.java
URL: https://svndev.jahia.net/websvn/filedetails.php?path=3D/trunk/core/src=
/java/org/jahia/utils/zip/ZipInputStream.java&rev=3D17906&repname=3Djahia
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- trunk/core/src/java/org/jahia/utils/zip/ZipInputStream.java (added)
+++ trunk/core/src/java/org/jahia/utils/zip/ZipInputStream.java Fri Jul 6 =
15:01:35 2007
@@ -0,0 +1,372 @@
+/*
+ * @(#)ZipInputStream.java 1.33 03/02/07
+ *
+ * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ */
+
+package org.jahia.utils.zip;
+
+import org.apache.commons.lang.ArrayUtils;
+
+import java.io.*;
+import java.util.zip.CRC32;
+import java.util.zip.Inflater;
+import java.util.zip.ZipException;
+
+/**
+ * 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
+ * @version 1.33, 02/07/03
+ */
+public
+class ZipInputStream extends InflaterInputStream implements ZipConstants {
+ private ZipEntry entry;
+ private CRC32 crc =3D new CRC32();
+ private long remaining;
+ private byte[] tmpbuf =3D new byte[512];
+
+ private static final int STORED =3D ZipEntry.STORED;
+ private static final int DEFLATED =3D ZipEntry.DEFLATED;
+
+ private boolean closed =3D false;
+ // this flag is set to true after EOF has reached for
+ // one entry
+ private boolean entryEOF =3D 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.
+ * @param in the actual input stream
+ */
+ public ZipInputStream(InputStream in) {
+ super(new PushbackInputStream(in, 512), new Inflater(true), 512);
+ usesDefaultInflater =3D true;
+ if(in =3D=3D null) {
+ throw new NullPointerException("in is null");
+ }
+ }
+
+ /**
+ * Reads the next ZIP file entry and positions stream at the beginning
+ * of the entry data.
+ * @return the ZipEntry just read
+ * @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 !=3D null) {
+ closeEntry();
+ }
+ crc.reset();
+ inf.reset();
+ if ((entry =3D readLOC()) =3D=3D null) {
+ return null;
+ }
+ if (entry.method =3D=3D STORED) {
+ remaining =3D entry.size;
+ }
+ entryEOF =3D false;
+ return entry;
+ }
+
+ /**
+ * Closes the current ZIP entry and positions the stream for reading t=
he
+ * next entry.
+ * @exception java.util.zip.ZipException if a ZIP file error has occur=
red
+ * @exception IOException if an I/O error has occurred
+ */
+ public void closeEntry() throws IOException {
+ ensureOpen();
+ while (read(tmpbuf, 0, tmpbuf.length) !=3D -1) ;
+ entryEOF =3D true;
+ }
+
+ /**
+ * Returns 0 after EOF has reached for the current entry data,
+ * otherwise always return 1.
+ * <p>
+ * 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 en=
try.
+ * @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. Blocks unt=
il
+ * some input is available.
+ * @param b the buffer into which the data is read
+ * @param off the start offset of the data
+ * @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 java.util.zip.ZipException if a ZIP file error has occur=
red
+ * @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 =3D=3D 0) {
+ return 0;
+ }
+
+ if (entry =3D=3D null) {
+ return -1;
+ }
+ switch (entry.method) {
+ case DEFLATED:
+ len =3D super.read(b, off, len);
+ if (len =3D=3D -1) {
+ readEnd(entry);
+ entryEOF =3D true;
+ entry =3D null;
+ } else {
+ crc.update(b, off, len);
+ }
+ return len;
+ case STORED:
+ if (remaining <=3D 0) {
+ entryEOF =3D true;
+ entry =3D null;
+ return -1;
+ }
+ if (len > remaining) {
+ len =3D (int)remaining;
+ }
+ len =3D in.read(b, off, len);
+ if (len =3D=3D -1) {
+ throw new ZipException("unexpected EOF");
+ }
+ crc.update(b, off, len);
+ remaining -=3D len;
+ return len;
+ default:
+ throw new InternalError("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 java.util.zip.ZipException if a ZIP file error has occur=
red
+ * @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 =3D (int)Math.min(n, Integer.MAX_VALUE);
+ int total =3D 0;
+ while (total < max) {
+ int len =3D max - total;
+ if (len > tmpbuf.length) {
+ len =3D tmpbuf.length;
+ }
+ len =3D read(tmpbuf, 0, len);
+ if (len =3D=3D -1) {
+ entryEOF =3D true;
+ break;
+ }
+ total +=3D len;
+ }
+ return total;
+ }
+
+ /**
+ * Closes the ZIP input stream.
+ * @exception IOException if an I/O error has occurred
+ */
+ public void close() throws IOException {
+ if (!closed) {
+ super.close();
+ closed =3D true;
+ }
+ }
+
+ private byte[] b =3D 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) !=3D LOCSIG) {
+ return null;
+ }
+ // get the entry name and create the ZipEntry first
+ int len =3D get16(tmpbuf, LOCNAM);
+ if (len =3D=3D 0) {
+ throw new ZipException("missing entry name");
+ }
+ int blen =3D b.length;
+ if (len > blen) {
+ do
+ blen =3D blen * 2;
+ while (len > blen);
+ b =3D new byte[blen];
+ }
+ readFully(b, 0, len);
+ ZipEntry e =3D createZipEntry(getUTF8String(b, 0, len));
+ // now get the remaining fields for the entry
+ e.version =3D get16(tmpbuf, LOCVER);
+ e.flag =3D get16(tmpbuf, LOCFLG);
+ if ((e.flag & 1) =3D=3D 1) {
+ throw new ZipException("encrypted ZIP entry not supported");
+ }
+ e.method =3D get16(tmpbuf, LOCHOW);
+ e.time =3D get32(tmpbuf, LOCTIM);
+ if ((e.flag & 8) =3D=3D 8) {
+ /* EXT descriptor present */
+ if (e.method !=3D DEFLATED) {
+ throw new ZipException(
+ "only DEFLATED entries can have EXT descriptor");
+ }
+ } else {
+ e.crc =3D get32(tmpbuf, LOCCRC);
+ e.csize =3D get32(tmpbuf, LOCSIZ);
+ e.size =3D get32(tmpbuf, LOCLEN);
+ }
+ len =3D get16(tmpbuf, LOCEXT);
+ if (len > 0) {
+ byte[] bb =3D new byte[len];
+ readFully(bb, 0, len);
+ e.extra =3D bb;
+ }
+ return e;
+ }
+
+ private boolean utfFailed =3D false;
+ private String encoding =3D "Cp437";
+
+ /*
+ * Fetches a UTF8-encoded String from the specified byte array.
+ */
+ private String getUTF8String(byte[] b, int off, int len) {
+ try {
+ if (!utfFailed) {
+ String r =3D new String(b,off,len,"UTF-8");
+ byte[] b2 =3D r.getBytes("UTF-8");
+ if (ArrayUtils.isEquals(b2, ArrayUtils.subarray(b,0,b2.len=
gth))) {
+ return r;
+ } else {
+ utfFailed =3D true;
+ }
+ }
+ return new String(b,off,len,encoding);
+ } catch (UnsupportedEncodingException e) {
+ return new String(b,off,len);
+ }
+ }
+
+ /**
+ * Creates a new <code>ZipEntry</code> 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 =3D inf.getRemaining();
+ if (n > 0) {
+ ((PushbackInputStream)in).unread(buf, len - n, n);
+ }
+ if ((e.flag & 8) =3D=3D 8) {
+ /* EXT descriptor present */
+ readFully(tmpbuf, 0, EXTHDR);
+ long sig =3D get32(tmpbuf, 0);
+ if (sig !=3D EXTSIG) { // no EXTSIG present
+ e.crc =3D sig;
+ e.csize =3D get32(tmpbuf, EXTSIZ - EXTCRC);
+ e.size =3D get32(tmpbuf, EXTLEN - EXTCRC);
+ ((PushbackInputStream)in).unread(
+ tmpbuf, EXTHDR - EXTCRC - 1, EX=
TCRC);
+ } else {
+ e.crc =3D get32(tmpbuf, EXTCRC);
+ e.csize =3D get32(tmpbuf, EXTSIZ);
+ e.size =3D get32(tmpbuf, EXTLEN);
+ }
+ }
+ if (e.size !=3D inf.getTotalOut()) {
+ throw new ZipException(
+ "invalid entry size (expected " + e.size + " but got " +
+ inf.getTotalOut() + " bytes)");
+ }
+ if (e.csize !=3D inf.getTotalIn()) {
+ throw new ZipException(
+ "invalid entry compressed size (expected " + e.csize +
+ " but got " + inf.getTotalIn() + " bytes)");
+ }
+ if (e.crc !=3D crc.getValue()) {
+ throw new ZipException(
+ "invalid entry CRC (expected 0x" + Long.toHexString(e.crc) +
+ " 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 =3D in.read(b, off, len);
+ if (n =3D=3D -1) {
+ throw new EOFException();
+ }
+ off +=3D n;
+ len -=3D 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);
+ }
+}
Added: trunk/core/src/java/org/jahia/utils/zip/ZipOutputStream.java
URL: https://svndev.jahia.net/websvn/filedetails.php?path=3D/trunk/core/src=
/java/org/jahia/utils/zip/ZipOutputStream.java&rev=3D17906&repname=3Djahia
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- trunk/core/src/java/org/jahia/utils/zip/ZipOutputStream.java (added)
+++ trunk/core/src/java/org/jahia/utils/zip/ZipOutputStream.java Fri Jul 6=
15:01:35 2007
@@ -0,0 +1,467 @@
+/*
+ * @(#)ZipOutputStream.java 1.27 03/02/07
+ *
+ * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ */
+
+package org.jahia.utils.zip;
+
+import java.io.OutputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.Vector;
+import java.util.Hashtable;
+import java.util.Enumeration;
+import java.util.zip.CRC32;
+import java.util.zip.Deflater;
+import java.util.zip.ZipException;
+
+/**
+ * This class implements an output stream filter for writing files in the
+ * ZIP file format. Includes support for both compressed and uncompressed
+ * entries.
+ *
+ * @author David Connelly
+ * @version 1.27, 02/07/03
+ */
+public
+class ZipOutputStream extends DeflaterOutputStream implements ZipConstants=
{
+ private ZipEntry entry;
+ private Vector entries =3D new Vector();
+ private Hashtable names =3D new Hashtable();
+ private CRC32 crc =3D new CRC32();
+ private long written;
+ private long locoff =3D 0;
+ private String comment;
+ private int method =3D DEFLATED;
+ private boolean finished;
+
+ private boolean closed =3D false;
+
+ /**
+ * Check to make sure that this stream has not been closed
+ */
+ private void ensureOpen() throws IOException {
+ if (closed) {
+ throw new IOException("Stream closed");
+ }
+ }
+ /**
+ * Compression method for uncompressed (STORED) entries.
+ */
+ public static final int STORED =3D ZipEntry.STORED;
+
+ /**
+ * Compression method for compressed (DEFLATED) entries.
+ */
+ public static final int DEFLATED =3D ZipEntry.DEFLATED;
+
+ /**
+ * Creates a new ZIP output stream.
+ * @param out the actual output stream
+ */
+ public ZipOutputStream(OutputStream out) {
+ super(out, new Deflater(Deflater.DEFAULT_COMPRESSION, true));
+ usesDefaultDeflater =3D true;
+ }
+
+ /**
+ * Sets the ZIP file comment.
+ * @param comment the comment string
+ * @exception IllegalArgumentException if the length of the specified
+ * ZIP file comment is greater than 0xFFFF bytes
+ */
+ public void setComment(String comment) {
+ if (comment !=3D null && comment.length() > 0xffff/3
+ && getUTF8Length(comment) > 0xf=
fff) {
+ throw new IllegalArgumentException("ZIP file comment too long.");
+ }
+ this.comment =3D comment;
+ }
+
+ /**
+ * Sets the default compression method for subsequent entries. This
+ * default will be used whenever the compression method is not specifi=
ed
+ * for an individual ZIP file entry, and is initially set to DEFLATED.
+ * @param method the default compression method
+ * @exception IllegalArgumentException if the specified compression me=
thod
+ * is invalid
+ */
+ public void setMethod(int method) {
+ if (method !=3D DEFLATED && method !=3D STORED) {
+ throw new IllegalArgumentException("invalid compression method");
+ }
+ this.method =3D method;
+ }
+
+ /**
+ * Sets the compression level for subsequent entries which are DEFLATE=
D.
+ * The default setting is DEFAULT_COMPRESSION.
+ * @param level the compression level (0-9)
+ * @exception IllegalArgumentException if the compression level is inv=
alid
+ */
+ public void setLevel(int level) {
+ def.setLevel(level);
+ }
+
+ /**
+ * Begins writing a new ZIP file entry and positions the stream to the
+ * start of the entry data. Closes the current entry if still active.
+ * The default compression method will be used if no compression method
+ * was specified for the entry, and the current time will be used if
+ * the entry has no set modification time.
+ * @param e the ZIP entry to be written
+ * @exception ZipException if a ZIP format error has occurred
+ * @exception IOException if an I/O error has occurred
+ */
+ public void putNextEntry(ZipEntry e) throws IOException {
+ ensureOpen();
+ if (entry !=3D null) {
+ closeEntry(); // close previous entry
+ }
+ if (e.time =3D=3D -1) {
+ e.setTime(System.currentTimeMillis());
+ }
+ if (e.method =3D=3D -1) {
+ e.method =3D method; // use default method
+ }
+ switch (e.method) {
+ case DEFLATED:
+ if (e.size =3D=3D -1 || e.csize =3D=3D -1 || e.crc =3D=3D -1) {
+ // store size, compressed size, and crc-32 in data descriptor
+ // immediately following the compressed entry data
+ e.flag =3D 8;
+ } else if (e.size !=3D -1 && e.csize !=3D -1 && e.crc !=3D -1) {
+ // store size, compressed size, and crc-32 in LOC header
+ e.flag =3D 0;
+ } else {
+ throw new ZipException(
+ "DEFLATED entry missing size, compressed size, or crc-32");
+ }
+ e.version =3D 20;
+ break;
+ case STORED:
+ // compressed size, uncompressed size, and crc-32 must all be
+ // set for entries using STORED compression method
+ if (e.size =3D=3D -1) {
+ e.size =3D e.csize;
+ } else if (e.csize =3D=3D -1) {
+ e.csize =3D e.size;
+ } else if (e.size !=3D e.csize) {
+ throw new ZipException(
+ "STORED entry where compressed !=3D uncompressed size");
+ }
+ if (e.size =3D=3D -1 || e.crc =3D=3D -1) {
+ throw new ZipException(
+ "STORED entry missing size, compressed size, or crc-32");
+ }
+ e.version =3D 10;
+ e.flag =3D 0;
+ break;
+ default:
+ throw new ZipException("unsupported compression method");
+ }
+ e.offset =3D written;
+ if (names.put(e.name, e) !=3D null) {
+ throw new ZipException("duplicate entry: " + e.name);
+ }
+ writeLOC(e);
+ entries.addElement(e);
+ entry =3D e;
+ }
+
+ /**
+ * Closes the current ZIP entry and positions the stream for writing
+ * the next entry.
+ * @exception ZipException if a ZIP format error has occurred
+ * @exception IOException if an I/O error has occurred
+ */
+ public void closeEntry() throws IOException {
+ ensureOpen();
+ ZipEntry e =3D entry;
+ if (e !=3D null) {
+ switch (e.method) {
+ case DEFLATED:
+ def.finish();
+ while (!def.finished()) {
+ deflate();
+ }
+ if ((e.flag & 8) =3D=3D 0) {
+ // verify size, compressed size, and crc-32 settings
+ if (e.size !=3D def.getTotalIn()) {
+ throw new ZipException(
+ "invalid entry size (expected " + e.size +
+ " but got " + def.getTotalIn() + " bytes)");
+ }
+ if (e.csize !=3D def.getTotalOut()) {
+ throw new ZipException(
+ "invalid entry compressed size (expected " +
+ e.csize + " but got " + def.getTotalOut() +
+ " bytes)");
+ }
+ if (e.crc !=3D crc.getValue()) {
+ throw new ZipException(
+ "invalid entry CRC-32 (expected 0x" +
+ Long.toHexString(e.crc) + " but got 0x" +
+ Long.toHexString(crc.getValue()) + ")");
+ }
+ } else {
+ e.size =3D def.getTotalIn();
+ e.csize =3D def.getTotalOut();
+ e.crc =3D crc.getValue();
+ writeEXT(e);
+ }
+ def.reset();
+ written +=3D e.csize;
+ break;
+ case STORED:
+ // we already know that both e.size and e.csize are the same
+ if (e.size !=3D written - locoff) {
+ throw new ZipException(
+ "invalid entry size (expected " + e.size +
+ " but got " + (written - locoff) + " bytes)");
+ }
+ if (e.crc !=3D crc.getValue()) {
+ throw new ZipException(
+ "invalid entry crc-32 (expected 0x" +
+ Long.toHexString(e.crc) + " but got 0x" +
+ Long.toHexString(crc.getValue()) + ")");
+ }
+ break;
+ default:
+ throw new InternalError("invalid compression method");
+ }
+ crc.reset();
+ entry =3D null;
+ }
+ }
+
+ /**
+ * Writes an array of bytes to the current ZIP entry data. This method
+ * will block until all the bytes are written.
+ * @param b the data to be written
+ * @param off the start offset in the data
+ * @param len the number of bytes that are written
+ * @exception ZipException if a ZIP file error has occurred
+ * @exception IOException if an I/O error has occurred
+ */
+ public synchronized void write(byte[] b, int off, int len)
+ throws IOException
+ {
+ ensureOpen();
+ if (off < 0 || len < 0 || off > b.length - len) {
+ throw new IndexOutOfBoundsException();
+ } else if (len =3D=3D 0) {
+ return;
+ }
+
+ if (entry =3D=3D null) {
+ throw new ZipException("no current ZIP entry");
+ }
+ switch (entry.method) {
+ case DEFLATED:
+ super.write(b, off, len);
+ break;
+ case STORED:
+ written +=3D len;
+ if (written - locoff > entry.size) {
+ throw new ZipException(
+ "attempt to write past end of STORED entry");
+ }
+ out.write(b, off, len);
+ break;
+ default:
+ throw new InternalError("invalid compression method");
+ }
+ crc.update(b, off, len);
+ }
+
+ /**
+ * Finishes writing the contents of the ZIP output stream without clos=
ing
+ * the underlying stream. Use this method when applying multiple filte=
rs
+ * in succession to the same output stream.
+ * @exception ZipException if a ZIP file error has occurred
+ * @exception IOException if an I/O exception has occurred
+ */
+ public void finish() throws IOException {
+ ensureOpen();
+ if (finished) {
+ return;
+ }
+ if (entry !=3D null) {
+ closeEntry();
+ }
+ if (entries.size() < 1) {
+ throw new ZipException("ZIP file must have at least one entry");
+ }
+ // write central directory
+ long off =3D written;
+ Enumeration e =3D entries.elements();
+ while (e.hasMoreElements()) {
+ writeCEN((ZipEntry)e.nextElement());
+ }
+ writeEND(off, written - off);
+ finished =3D true;
+ }
+
+ /**
+ * Closes the ZIP output stream as well as the stream being filtered.
+ * @exception ZipException if a ZIP file error has occurred
+ * @exception IOException if an I/O error has occurred
+ */
+ public void close() throws IOException {
+ if (!closed) {
+ super.close();
+ closed =3D true;
+ }
+ }
+
+ /*
+ * Writes local file (LOC) header for specified entry.
+ */
+ private void writeLOC(ZipEntry e) throws IOException {
+ writeInt(LOCSIG); // LOC header signature
+ writeShort(e.version); // version needed to extract
+ writeShort(e.flag); // general purpose bit flag
+ writeShort(e.method); // compression method
+ writeInt(e.time); // last modification time
+ if ((e.flag & 8) =3D=3D 8) {
+ // store size, uncompressed size, and crc-32 in data descriptor
+ // immediately following compressed entry data
+ writeInt(0);
+ writeInt(0);
+ writeInt(0);
+ } else {
+ writeInt(e.crc); // crc-32
+ writeInt(e.csize); // compressed size
+ writeInt(e.size); // uncompressed size
+ }
+ byte[] nameBytes =3D getUTF8Bytes(e.name);
+ writeShort(nameBytes.length);
+ writeShort(e.extra !=3D null ? e.extra.length : 0);
+ writeBytes(nameBytes, 0, nameBytes.length);
+ if (e.extra !=3D null) {
+ writeBytes(e.extra, 0, e.extra.length);
+ }
+ locoff =3D written;
+ }
+
+ /*
+ * Writes extra data descriptor (EXT) for specified entry.
+ */
+ private void writeEXT(ZipEntry e) throws IOException {
+ writeInt(EXTSIG); // EXT header signature
+ writeInt(e.crc); // crc-32
+ writeInt(e.csize); // compressed size
+ writeInt(e.size); // uncompressed size
+ }
+
+ /*
+ * Write central directory (CEN) header for specified entry.
+ * REMIND: add support for file attributes
+ */
+ private void writeCEN(ZipEntry e) throws IOException {
+ writeInt(CENSIG); // CEN header signature
+ writeShort(e.version); // version made by
+ writeShort(e.version); // version needed to extract
+ writeShort(e.flag); // general purpose bit flag
+ writeShort(e.method); // compression method
+ writeInt(e.time); // last modification time
+ writeInt(e.crc); // crc-32
+ writeInt(e.csize); // compressed size
+ writeInt(e.size); // uncompressed size
+ byte[] nameBytes =3D getUTF8Bytes(e.name);
+ writeShort(nameBytes.length);
+ writeShort(e.extra !=3D null ? e.extra.length : 0);
+ byte[] commentBytes;
+ if (e.comment !=3D null) {
+ commentBytes =3D getUTF8Bytes(e.comment);
+ writeShort(commentBytes.length);
+ } else {
+ commentBytes =3D null;
+ writeShort(0);
+ }
+ writeShort(0); // starting disk number
+ writeShort(0); // internal file attributes (unused)
+ writeInt(0); // external file attributes (unused)
+ writeInt(e.offset); // relative offset of local header
+ writeBytes(nameBytes, 0, nameBytes.length);
+ if (e.extra !=3D null) {
+ writeBytes(e.extra, 0, e.extra.length);
+ }
+ if (commentBytes !=3D null) {
+ writeBytes(commentBytes, 0, commentBytes.length);
+ }
+ }
+
+ /*
+ * Writes end of central directory (END) header.
+ */
+ private void writeEND(long off, long len) throws IOException {
+ writeInt(ENDSIG); // END record signature
+ writeShort(0); // number of this disk
+ writeShort(0); // central directory start disk
+ writeShort(entries.size()); // number of directory entries on disk
+ writeShort(entries.size()); // total number of directory entries
+ writeInt(len); // length of central directory
+ writeInt(off); // offset of central directory
+ if (comment !=3D null) { // zip file comment
+ byte[] b =3D getUTF8Bytes(comment);
+ writeShort(b.length);
+ writeBytes(b, 0, b.length);
+ } else {
+ writeShort(0);
+ }
+ }
+
+ /*
+ * Writes a 16-bit short to the output stream in little-endian byte or=
der.
+ */
+ private void writeShort(int v) throws IOException {
+ OutputStream out =3D this.out;
+ out.write((v >>> 0) & 0xff);
+ out.write((v >>> 8) & 0xff);
+ written +=3D 2;
+ }
+
+ /*
+ * Writes a 32-bit int to the output stream in little-endian byte orde=
r.
+ */
+ private void writeInt(long v) throws IOException {
+ OutputStream out =3D this.out;
+ out.write((int)((v >>> 0) & 0xff));
+ out.write((int)((v >>> 8) & 0xff));
+ out.write((int)((v >>> 16) & 0xff));
+ out.write((int)((v >>> 24) & 0xff));
+ written +=3D 4;
+ }
+
+ /*
+ * Writes an array of bytes to the output stream.
+ */
+ private void writeBytes(byte[] b, int off, int len) throws IOException=
{
+ super.out.write(b, off, len);
+ written +=3D len;
+ }
+
+ static private String encoding =3D "UTF-8";
+ /*
+ * Returns the length of String's UTF8 encoding.
+ */
+ static int getUTF8Length(String s) {
+ return getUTF8Bytes(s).length;
+ }
+
+ /*
+ * Returns an array of bytes representing the UTF8 encoding
+ * of the specified String.
+ */
+ private static byte[] getUTF8Bytes(String s) {
+ try {
+ return s.getBytes(encoding);
+ } catch (UnsupportedEncodingException e) {
+ return s.getBytes();
+ }
+ }
+}
_______________________________________________
cvs_list mailing list
[email protected]
http://lists.jahia.org/cgi-bin/mailman/listinfo/cvs_list