// package net.sf.zipme; import java.util.Calendar; import java.util.Date; /** * This class represents a member of a zip archive. ZipFile and * ZipInputStream will give you instances of this class as information * about the members in an archive. On the other hand ZipOutputStream * needs an instance of this class to create a new member. * @author Jochen Hoenicke */ public class ZipEntry implements ZipConstants { private static final int KNOWN_SIZE=1; private static final int KNOWN_CSIZE=2; private static final int KNOWN_CRC=4; private static final int KNOWN_TIME=8; private static final int KNOWN_EXTRA=16; private static Calendar cal; private String name; private int size; private long compressedSize=-1; private int crc; private int dostime; private short known=0; private short method=-1; private byte[] extra=null; private String comment=null; int flags; public int offset; /** * Compression method. This method doesn't compress at all. */ public static final int STORED=0; /** * Compression method. This method uses the Deflater. */ public static final int DEFLATED=8; /** * Creates a zip entry with the given name. * @param name the name. May include directory components separated * by '/'. * @exception NullPointerException when name is null. * @exception IllegalArgumentException when name is bigger then 65535 chars. */ public ZipEntry( String name){ int length=name.length(); if (length > 65535) throw new IllegalArgumentException("name length is " + length); this.name=name; } /** * Creates a copy of the given zip entry. * @param e the entry to copy. */ public ZipEntry( ZipEntry e){ this(e,e.name); } public ZipEntry( ZipEntry e, String name){ this.name=name; known=e.known; size=e.size; compressedSize=e.compressedSize; crc=e.crc; dostime=e.dostime; method=e.method; extra=e.extra; comment=e.comment; } final void setDOSTime( int dostime){ this.dostime=dostime; known|=KNOWN_TIME; } final int getDOSTime(){ if ((known & KNOWN_TIME) == 0) return 0; else return dostime; } /** * Returns the entry name. The path components in the entry are * always separated by slashes ('/'). */ public String getName(){ return name; } /** * Sets the time of last modification of the entry. * @param time the time of last modification of the entry. */ public void setTime( long time){ Calendar cal=getCalendar(); synchronized (cal) { cal.setTime(new Date(time)); dostime=(cal.get(Calendar.YEAR) - 1980 & 0x7f) << 25 | (cal.get(Calendar.MONTH) + 1) << 21 | (cal.get(Calendar.DAY_OF_MONTH)) << 16 | (cal.get(Calendar.HOUR_OF_DAY)) << 11 | (cal.get(Calendar.MINUTE)) << 5 | (cal.get(Calendar.SECOND)) >> 1; } this.known|=KNOWN_TIME; } /** * Gets the time of last modification of the entry. * @return the time of last modification of the entry, or -1 if unknown. */ public long getTime(){ parseExtra(); if ((known & KNOWN_TIME) == 0) return -1; int sec=2 * (dostime & 0x1f); int min=(dostime >> 5) & 0x3f; int hrs=(dostime >> 11) & 0x1f; int day=(dostime >> 16) & 0x1f; int mon=((dostime >> 21) & 0xf) - 1; int year=((dostime >> 25) & 0x7f) + 1980; try { cal=getCalendar(); synchronized (cal) { cal.set(Calendar.YEAR,year); cal.set(Calendar.MONTH,mon); cal.set(Calendar.DAY_OF_MONTH,day); cal.set(Calendar.HOUR_OF_DAY,hrs); cal.set(Calendar.MINUTE,min); cal.set(Calendar.SECOND,sec); return cal.getTime().getTime(); } } catch ( RuntimeException ex) { known&=~KNOWN_TIME; return -1; } } private static synchronized Calendar getCalendar(){ if (cal == null) cal=Calendar.getInstance(); return cal; } /** * Sets the size of the uncompressed data. * @exception IllegalArgumentException if size is not in 0..0xffffffffL */ public void setSize( long size){ if ((size & 0xffffffff00000000L) != 0) throw new IllegalArgumentException(); this.size=(int)size; this.known|=KNOWN_SIZE; } /** * Gets the size of the uncompressed data. * @return the size or -1 if unknown. */ public long getSize(){ return (known & KNOWN_SIZE) != 0 ? size & 0xffffffffL : -1L; } /** * Sets the size of the compressed data. */ public void setCompressedSize( long csize){ this.compressedSize=csize; } /** * Gets the size of the compressed data. * @return the size or -1 if unknown. */ public long getCompressedSize(){ return compressedSize; } /** * Sets the crc of the uncompressed data. * @exception IllegalArgumentException if crc is not in 0..0xffffffffL */ public void setCrc( long crc){ if ((crc & 0xffffffff00000000L) != 0) throw new IllegalArgumentException(); this.crc=(int)crc; this.known|=KNOWN_CRC; } /** * Gets the crc of the uncompressed data. * @return the crc or -1 if unknown. */ public long getCrc(){ return (known & KNOWN_CRC) != 0 ? crc & 0xffffffffL : -1L; } /** * Sets the compression method. Only DEFLATED and STORED are * supported. * @exception IllegalArgumentException if method is not supported. * @see ZipOutputStream#DEFLATED * @see ZipOutputStream#STORED */ public void setMethod( int method){ if (method != ZipOutputStream.STORED && method != ZipOutputStream.DEFLATED) throw new IllegalArgumentException(); this.method=(short)method; } /** * Gets the compression method. * @return the compression method or -1 if unknown. */ public int getMethod(){ return method; } /** * Sets the extra data. * @exception IllegalArgumentException if extra is longer than 0xffff bytes. */ public void setExtra( byte[] extra){ if (extra == null) { this.extra=null; return; } if (extra.length > 0xffff) throw new IllegalArgumentException(); this.extra=extra; } private void parseExtra(){ if ((known & KNOWN_EXTRA) != 0) return; if (extra == null) { known|=KNOWN_EXTRA; return; } try { int pos=0; while (pos < extra.length) { int sig=(extra[pos++] & 0xff) | (extra[pos++] & 0xff) << 8; int len=(extra[pos++] & 0xff) | (extra[pos++] & 0xff) << 8; if (sig == 0x5455) { int flags=extra[pos]; if ((flags & 1) != 0) { long time=((extra[pos + 1] & 0xff) | (extra[pos + 2] & 0xff) << 8 | (extra[pos + 3] & 0xff) << 16 | (extra[pos + 4] & 0xff) << 24); setTime(time); } } pos+=len; } } catch ( ArrayIndexOutOfBoundsException ex) { } known|=KNOWN_EXTRA; return; } /** * Gets the extra data. * @return the extra data or null if not set. */ public byte[] getExtra(){ return extra; } /** * Sets the entry comment. * @exception IllegalArgumentException if comment is longer than 0xffff. */ public void setComment( String comment){ if (comment != null && comment.length() > 0xffff) throw new IllegalArgumentException(); this.comment=comment; } /** * Gets the comment. * @return the comment or null if not set. */ public String getComment(){ return comment; } /** * Gets true, if the entry is a directory. This is solely * determined by the name, a trailing slash '/' marks a directory. */ public boolean isDirectory(){ int nlen=name.length(); return nlen > 0 && name.charAt(nlen - 1) == '/'; } /** * Gets the string representation of this ZipEntry. This is just * the name as returned by getName(). */ public String toString(){ return name; } /** * Gets the hashCode of this ZipEntry. This is just the hashCode * of the name. Note that the equals method isn't changed, though. */ public int hashCode(){ return name.hashCode(); } }