| /* ZipEntry.java -- |
| Copyright (C) 2001, 2002, 2004, 2005 Free Software Foundation, Inc. |
| |
| This file is part of GNU Classpath. |
| |
| GNU Classpath is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| GNU Classpath 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 for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU Classpath; see the file COPYING. If not, write to the |
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
| 02111-1307 USA. |
| |
| Linking this library statically or dynamically with other modules is |
| making a combined work based on this library. Thus, the terms and |
| conditions of the GNU General Public License cover the whole |
| combination. |
| |
| As a special exception, the copyright holders of this library give you |
| permission to link this library with independent modules to produce an |
| executable, regardless of the license terms of these independent |
| modules, and to copy and distribute the resulting executable under |
| terms of your choice, provided that you also meet, for each linked |
| independent module, the terms and conditions of the license of that |
| module. An independent module is a module which is not derived from |
| or based on this library. If you modify this library, you may extend |
| this exception to your version of the library, but you are not |
| obligated to do so. If you do not wish to do so, delete this |
| exception statement from your version. */ |
| |
| |
| package java.util.zip; |
| |
| 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, Cloneable |
| { |
| 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 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; /* used by ZipOutputStream */ |
| int offset; /* used by ZipFile and ZipOutputStream */ |
| |
| /** |
| * 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) |
| { |
| name = e.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; |
| } |
| |
| /** |
| * Creates a copy of this zip entry. |
| */ |
| /** |
| * Clones the entry. |
| */ |
| public Object clone() |
| { |
| try |
| { |
| // The JCL says that the `extra' field is also copied. |
| ZipEntry clone = (ZipEntry) super.clone(); |
| if (extra != null) |
| clone.extra = (byte[]) extra.clone(); |
| return clone; |
| } |
| catch (CloneNotSupportedException ex) |
| { |
| throw new InternalError(); |
| } |
| } |
| |
| /** |
| * 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. |
| * @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() |
| { |
| 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; /* since 1900 */ |
| |
| try |
| { |
| cal = getCalendar(); |
| synchronized (cal) |
| { |
| cal.set(year, mon, day, hrs, min, sec); |
| return cal.getTime().getTime(); |
| } |
| } |
| catch (RuntimeException ex) |
| { |
| /* Ignore illegal time stamp */ |
| 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; |
| 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) |
| { |
| /* extended time stamp */ |
| 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) |
| { |
| /* be lenient */ |
| 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(); |
| } |
| } |