Fields Summary |
---|
public static final int | DEFLATEDCompression method for deflated entries. |
public static final int | DEFAULT_COMPRESSIONDefault compression level for deflated entries. |
public static final int | STOREDCompression method for stored entries. |
private ZipEntry | entryCurrent entry. |
private String | commentThe file comment. |
private int | levelCompression level for next entry. |
private boolean | hasCompressionLevelChangedHas the compression level changed when compared to the last
entry? |
private int | methodDefault compression method for next entry. |
private Vector | entriesList of ZipEntries written so far. |
private CRC32 | crcCRC instance to avoid parsing DEFLATED data twice. |
private long | writtenCount the bytes written to out. |
private long | dataStartData for local header data |
private long | localDataStartOffset for CRC entry in the local file header data for the
current entry starts here. |
private long | cdOffsetStart of central directory. |
private long | cdLengthLength of central directory. |
private static final byte[] | ZEROHelper, a 0 as ZipShort. |
private static final byte[] | LZEROHelper, a 0 as ZipLong. |
private Hashtable | offsetsHolds the offsets of the LFH starts for each entry. |
private String | encodingThe encoding to use for filenames and the file comment.
For a list of possible values see http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html.
Defaults to the platform's default character encoding. |
protected Deflater | defThis Deflater object is used for output.
This attribute is only protected to provide a level of API
backwards compatibility. This class used to extend {@link
java.util.zip.DeflaterOutputStream DeflaterOutputStream} up to
Revision 1.13. |
protected byte[] | bufThis buffer servers as a Deflater.
This attribute is only protected to provide a level of API
backwards compatibility. This class used to extend {@link
java.util.zip.DeflaterOutputStream DeflaterOutputStream} up to
Revision 1.13. |
private RandomAccessFile | rafOptional random access output. |
protected static final byte[] | LFH_SIGlocal file header signature |
protected static final byte[] | DD_SIGdata descriptor signature |
protected static final byte[] | CFH_SIGcentral file header signature |
protected static final byte[] | EOCD_SIGend of central dir signature |
private static final byte[] | DOS_TIME_MINSmallest date/time ZIP can handle. |
Methods Summary |
---|
protected static long | adjustToLong(int i)Assumes a negative integer really is a positive integer that
has wrapped around and re-creates the original value.
if (i < 0) {
return 2 * ((long) Integer.MAX_VALUE) + 2 + i;
} else {
return i;
}
|
public void | close()Closes this output stream and releases any system resources
associated with the stream.
finish();
if (raf != null) {
raf.close();
}
if (out != null) {
out.close();
}
|
public void | closeEntry()Writes all necessary data for this entry.
if (entry == null) {
return;
}
long realCrc = crc.getValue();
crc.reset();
if (entry.getMethod() == DEFLATED) {
def.finish();
while (!def.finished()) {
deflate();
}
entry.setSize(adjustToLong(def.getTotalIn()));
entry.setCompressedSize(adjustToLong(def.getTotalOut()));
entry.setCrc(realCrc);
def.reset();
written += entry.getCompressedSize();
} else if (raf == null) {
if (entry.getCrc() != realCrc) {
throw new ZipException("bad CRC checksum for entry "
+ entry.getName() + ": "
+ Long.toHexString(entry.getCrc())
+ " instead of "
+ Long.toHexString(realCrc));
}
if (entry.getSize() != written - dataStart) {
throw new ZipException("bad size for entry "
+ entry.getName() + ": "
+ entry.getSize()
+ " instead of "
+ (written - dataStart));
}
} else { /* method is STORED and we used RandomAccessFile */
long size = written - dataStart;
entry.setSize(size);
entry.setCompressedSize(size);
entry.setCrc(realCrc);
}
// If random access output, write the local file header containing
// the correct CRC and compressed/uncompressed sizes
if (raf != null) {
long save = raf.getFilePointer();
raf.seek(localDataStart);
writeOut(ZipLong.getBytes(entry.getCrc()));
writeOut(ZipLong.getBytes(entry.getCompressedSize()));
writeOut(ZipLong.getBytes(entry.getSize()));
raf.seek(save);
}
writeDataDescriptor(entry);
entry = null;
|
protected final void | deflate()Writes next block of compressed data to the output stream.
int len = def.deflate(buf, 0, buf.length);
if (len > 0) {
writeOut(buf, 0, len);
}
|
public void | finish()Finishs writing the contents and closes this as well as the
underlying stream.
closeEntry();
cdOffset = written;
for (int i = 0, entriesSize = entries.size(); i < entriesSize; i++) {
writeCentralFileHeader((ZipEntry) entries.elementAt(i));
}
cdLength = written - cdOffset;
writeCentralDirectoryEnd();
offsets.clear();
entries.removeAllElements();
|
public void | flush()Flushes this output stream and forces any buffered output bytes
to be written out to the stream.
if (out != null) {
out.flush();
}
|
protected byte[] | getBytes(java.lang.String name)Retrieve the bytes for the given String in the encoding set for
this Stream.
if (encoding == null) {
return name.getBytes();
} else {
try {
return name.getBytes(encoding);
} catch (UnsupportedEncodingException uee) {
throw new ZipException(uee.getMessage());
}
}
|
public java.lang.String | getEncoding()The encoding to use for filenames and the file comment.
return encoding;
|
public boolean | isSeekable()This method indicates whether this archive is writing to a seekable stream (i.e., to a random
access file).
For seekable streams, you don't need to calculate the CRC or
uncompressed size for {@link #STORED} entries before
invoking {@link #putNextEntry}.
return raf != null;
|
public void | putNextEntry(ZipEntry ze)Begin writing next entry.
closeEntry();
entry = ze;
entries.addElement(entry);
if (entry.getMethod() == -1) { // not specified
entry.setMethod(method);
}
if (entry.getTime() == -1) { // not specified
entry.setTime(System.currentTimeMillis());
}
// Size/CRC not required if RandomAccessFile is used
if (entry.getMethod() == STORED && raf == null) {
if (entry.getSize() == -1) {
throw new ZipException("uncompressed size is required for"
+ " STORED method when not writing to a"
+ " file");
}
if (entry.getCrc() == -1) {
throw new ZipException("crc checksum is required for STORED"
+ " method when not writing to a file");
}
entry.setCompressedSize(entry.getSize());
}
if (entry.getMethod() == DEFLATED && hasCompressionLevelChanged) {
def.setLevel(level);
hasCompressionLevelChanged = false;
}
writeLocalFileHeader(entry);
|
public void | setComment(java.lang.String comment)Set the file comment.
this.comment = comment;
|
public void | setEncoding(java.lang.String encoding)The encoding to use for filenames and the file comment.
For a list of possible values see http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html.
Defaults to the platform's default character encoding.
this.encoding = encoding;
|
public void | setLevel(int level)Sets the compression level for subsequent entries.
Default is Deflater.DEFAULT_COMPRESSION.
if (level < Deflater.DEFAULT_COMPRESSION
|| level > Deflater.BEST_COMPRESSION) {
throw new IllegalArgumentException(
"Invalid compression level: " + level);
}
hasCompressionLevelChanged = (this.level != level);
this.level = level;
|
public void | setMethod(int method)Sets the default compression method for subsequent entries.
Default is DEFLATED.
this.method = method;
|
protected static ZipLong | toDosTime(java.util.Date time)Convert a Date object to a DOS date/time field.
return new ZipLong(toDosTime(time.getTime()));
|
protected static byte[] | toDosTime(long t)Convert a Date object to a DOS date/time field.
Stolen from InfoZip's fileio.c
Date time = new Date(t);
int year = time.getYear() + 1900;
if (year < 1980) {
return DOS_TIME_MIN;
}
int month = time.getMonth() + 1;
long value = ((year - 1980) << 25)
| (month << 21)
| (time.getDate() << 16)
| (time.getHours() << 11)
| (time.getMinutes() << 5)
| (time.getSeconds() >> 1);
return ZipLong.getBytes(value);
|
public void | write(byte[] b, int offset, int length)Writes bytes to ZIP entry.
if (entry.getMethod() == DEFLATED) {
if (length > 0) {
if (!def.finished()) {
def.setInput(b, offset, length);
while (!def.needsInput()) {
deflate();
}
}
}
} else {
writeOut(b, offset, length);
written += length;
}
crc.update(b, offset, length);
|
public void | write(int b)Writes a single byte to ZIP entry.
Delegates to the three arg method.
byte[] buff = new byte[1];
buff[0] = (byte) (b & 0xff);
write(buff, 0, 1);
|
protected void | writeCentralDirectoryEnd()Writes the "End of central dir record".
writeOut(EOCD_SIG);
// disk numbers
writeOut(ZERO);
writeOut(ZERO);
// number of entries
byte[] num = ZipShort.getBytes(entries.size());
writeOut(num);
writeOut(num);
// length and location of CD
writeOut(ZipLong.getBytes(cdLength));
writeOut(ZipLong.getBytes(cdOffset));
// ZIP file comment
byte[] data = getBytes(comment);
writeOut(ZipShort.getBytes(data.length));
writeOut(data);
|
protected void | writeCentralFileHeader(ZipEntry ze)Writes the central file header entry.
writeOut(CFH_SIG);
written += 4;
// version made by
writeOut(ZipShort.getBytes((ze.getPlatform() << 8) | 20));
written += 2;
// version needed to extract
// general purpose bit flag
if (ze.getMethod() == DEFLATED && raf == null) {
// requires version 2 as we are going to store length info
// in the data descriptor
writeOut(ZipShort.getBytes(20));
// bit3 set to signal, we use a data descriptor
writeOut(ZipShort.getBytes(8));
} else {
writeOut(ZipShort.getBytes(10));
writeOut(ZERO);
}
written += 4;
// compression method
writeOut(ZipShort.getBytes(ze.getMethod()));
written += 2;
// last mod. time and date
writeOut(toDosTime(ze.getTime()));
written += 4;
// CRC
// compressed length
// uncompressed length
writeOut(ZipLong.getBytes(ze.getCrc()));
writeOut(ZipLong.getBytes(ze.getCompressedSize()));
writeOut(ZipLong.getBytes(ze.getSize()));
written += 12;
// file name length
byte[] name = getBytes(ze.getName());
writeOut(ZipShort.getBytes(name.length));
written += 2;
// extra field length
byte[] extra = ze.getCentralDirectoryExtra();
writeOut(ZipShort.getBytes(extra.length));
written += 2;
// file comment length
String comm = ze.getComment();
if (comm == null) {
comm = "";
}
byte[] commentB = getBytes(comm);
writeOut(ZipShort.getBytes(commentB.length));
written += 2;
// disk number start
writeOut(ZERO);
written += 2;
// internal file attributes
writeOut(ZipShort.getBytes(ze.getInternalAttributes()));
written += 2;
// external file attributes
writeOut(ZipLong.getBytes(ze.getExternalAttributes()));
written += 4;
// relative offset of LFH
writeOut((byte[]) offsets.get(ze));
written += 4;
// file name
writeOut(name);
written += name.length;
// extra field
writeOut(extra);
written += extra.length;
// file comment
writeOut(commentB);
written += commentB.length;
|
protected void | writeDataDescriptor(ZipEntry ze)Writes the data descriptor entry.
if (ze.getMethod() != DEFLATED || raf != null) {
return;
}
writeOut(DD_SIG);
writeOut(ZipLong.getBytes(entry.getCrc()));
writeOut(ZipLong.getBytes(entry.getCompressedSize()));
writeOut(ZipLong.getBytes(entry.getSize()));
written += 16;
|
protected void | writeLocalFileHeader(ZipEntry ze)Writes the local file header entry
offsets.put(ze, ZipLong.getBytes(written));
writeOut(LFH_SIG);
written += 4;
//store method in local variable to prevent multiple method calls
final int zipMethod = ze.getMethod();
// version needed to extract
// general purpose bit flag
if (zipMethod == DEFLATED && raf == null) {
// requires version 2 as we are going to store length info
// in the data descriptor
writeOut(ZipShort.getBytes(20));
// bit3 set to signal, we use a data descriptor
writeOut(ZipShort.getBytes(8));
} else {
writeOut(ZipShort.getBytes(10));
writeOut(ZERO);
}
written += 4;
// compression method
writeOut(ZipShort.getBytes(zipMethod));
written += 2;
// last mod. time and date
writeOut(toDosTime(ze.getTime()));
written += 4;
// CRC
// compressed length
// uncompressed length
localDataStart = written;
if (zipMethod == DEFLATED || raf != null) {
writeOut(LZERO);
writeOut(LZERO);
writeOut(LZERO);
} else {
writeOut(ZipLong.getBytes(ze.getCrc()));
writeOut(ZipLong.getBytes(ze.getSize()));
writeOut(ZipLong.getBytes(ze.getSize()));
}
written += 12;
// file name length
byte[] name = getBytes(ze.getName());
writeOut(ZipShort.getBytes(name.length));
written += 2;
// extra field length
byte[] extra = ze.getLocalFileDataExtra();
writeOut(ZipShort.getBytes(extra.length));
written += 2;
// file name
writeOut(name);
written += name.length;
// extra field
writeOut(extra);
written += extra.length;
dataStart = written;
|
protected final void | writeOut(byte[] data)Write bytes to output or random access file.
writeOut(data, 0, data.length);
|
protected final void | writeOut(byte[] data, int offset, int length)Write bytes to output or random access file.
if (raf != null) {
raf.write(data, offset, length);
} else {
out.write(data, offset, length);
}
|