/*
* @(#)ZipEntry.java 1.41 06/10/10
*
* Copyright 1990-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program 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.
*
* This program 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 at /legal/license.txt).
*
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*
*/
package java.util.zip;
import java.util.Date;
import java.util.Calendar;
/**
* This class is used to represent a ZIP file entry.
*
* @version 1.32, 05/03/00
* @author David Connelly
*/
public
class ZipEntry implements ZipConstants, Cloneable {
String name; // entry name
long time = -1; // modification time (in DOS time)
long crc = -1; // crc-32 of entry data
long size = -1; // uncompressed size of entry data
long csize = -1; // compressed size of entry data
int method = -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 = 0;
/**
* Compression method for compressed (deflated) entries.
*/
public static final int DEFLATED = 8;
static {
/* load the zip library */
java.security.AccessController.doPrivileged(
new sun.security.action.LoadLibraryAction("zip"));
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 == null) {
throw new NullPointerException();
}
if (name.length() > 0xFFFF) {
throw new IllegalArgumentException("entry name too long");
}
this.name = 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 = e.name;
time = e.time;
crc = e.crc;
size = e.size;
csize = e.csize;
method = e.method;
extra = e.extra;
comment = 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 = 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 = 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 != -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 = 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 = 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 = 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 != STORED && method != DEFLATED) {
throw new IllegalArgumentException("invalid compression method");
}
this.method = 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 != null && extra.length > 0xFFFF) {
throw new IllegalArgumentException("invalid extra field length");
}
this.extra = 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 != null && comment.length() > 0xffff/3
&& getUTF8Length(comment) > 0xffff) {
throw new IllegalArgumentException("invalid entry comment length");
}
this.comment = 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) {
Calendar c = Calendar.getInstance();
c.clear();
c.set((int)(((dtime >> 25) & 0x7f) + 80 + 1900),
(int)(((dtime >> 21) & 0x0f) - 1),
(int)((dtime >> 16) & 0x1f),
(int)((dtime >> 11) & 0x1f),
(int)((dtime >> 5) & 0x3f),
(int)((dtime << 1) & 0x3e));
return c.getTime().getTime();
}
/*
* Converts Java time to DOS time.
*/
private static long javaToDosTime(long time) {
Calendar C = Calendar.getInstance();
C.setTime(new Date(time));
int year = C.get(Calendar.YEAR);
if (year < 1980) {
return (1 << 21) | (1 << 16);
}
return (year - 1980) << 25 | (C.get(Calendar.MONTH) + 1) << 21 |
C.get(Calendar.DAY_OF_MONTH) << 16 | C.get(Calendar.HOUR_OF_DAY) << 11 | C.get(Calendar.MINUTE) << 5 |
C.get(Calendar.SECOND) >> 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 = (ZipEntry)super.clone();
e.extra = (extra == null ? null : (byte[])extra.clone());
return e;
} catch (CloneNotSupportedException e) {
// This should never happen, since we are Cloneable
throw new InternalError();
}
}
/*
* Returns the length of String's UTF8 encoding.
*/
static int getUTF8Length(String s) {
int count = 0;
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
if (ch <= 0x7f) {
count++;
} else if (ch <= 0x7ff) {
count += 2;
} else {
count += 3;
}
}
return count;
}
}