OSDN Git Service

Imported Classpath 0.18.
[pf3gnuchains/gcc-fork.git] / libjava / classpath / java / util / zip / ZipEntry.java
1 /* ZipEntry.java --
2    Copyright (C) 2001, 2002, 2004, 2005 Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37
38
39 package java.util.zip;
40
41 import java.util.Calendar;
42
43 /**
44  * This class represents a member of a zip archive.  ZipFile and
45  * ZipInputStream will give you instances of this class as information
46  * about the members in an archive.  On the other hand ZipOutputStream
47  * needs an instance of this class to create a new member.
48  *
49  * @author Jochen Hoenicke 
50  */
51 public class ZipEntry implements ZipConstants, Cloneable
52 {
53   private static final int KNOWN_SIZE   = 1;
54   private static final int KNOWN_CSIZE  = 2;
55   private static final int KNOWN_CRC    = 4;
56   private static final int KNOWN_TIME   = 8;
57   private static final int KNOWN_EXTRA  = 16;
58
59   private static Calendar cal;
60
61   private String name;
62   private int size;
63   private long compressedSize = -1;
64   private int crc;
65   private int dostime;
66   private short known = 0;
67   private short method = -1;
68   private byte[] extra = null;
69   private String comment = null;
70
71   int flags;              /* used by ZipOutputStream */
72   int offset;             /* used by ZipFile and ZipOutputStream */
73
74   /**
75    * Compression method.  This method doesn't compress at all.
76    */
77   public static final int STORED = 0;
78   /**
79    * Compression method.  This method uses the Deflater.
80    */
81   public static final int DEFLATED = 8;
82
83   /**
84    * Creates a zip entry with the given name.
85    * @param name the name. May include directory components separated
86    * by '/'.
87    *
88    * @exception NullPointerException when name is null.
89    * @exception IllegalArgumentException when name is bigger then 65535 chars.
90    */
91   public ZipEntry(String name)
92   {
93     int length = name.length();
94     if (length > 65535)
95       throw new IllegalArgumentException("name length is " + length);
96     this.name = name;
97   }
98
99   /**
100    * Creates a copy of the given zip entry.
101    * @param e the entry to copy.
102    */
103   public ZipEntry(ZipEntry e)
104   {
105     this(e, e.name);
106   }
107
108   ZipEntry(ZipEntry e, String name)
109   {
110     this.name = name;
111     known = e.known;
112     size = e.size;
113     compressedSize = e.compressedSize;
114     crc = e.crc;
115     dostime = e.dostime;
116     method = e.method;
117     extra = e.extra;
118     comment = e.comment;
119   }
120
121   final void setDOSTime(int dostime)
122   {
123     this.dostime = dostime;
124     known |= KNOWN_TIME;
125   }
126
127   final int getDOSTime()
128   {
129     if ((known & KNOWN_TIME) == 0)
130       return 0;
131     else
132       return dostime;
133   }
134
135   /**
136    * Creates a copy of this zip entry.
137    */
138   /**
139    * Clones the entry.
140    */
141   public Object clone()
142   {
143     try
144       {
145         // The JCL says that the `extra' field is also copied.
146         ZipEntry clone = (ZipEntry) super.clone();
147         if (extra != null)
148           clone.extra = (byte[]) extra.clone();
149         return clone;
150       }
151     catch (CloneNotSupportedException ex)
152       {
153         throw new InternalError();
154       }
155   }
156
157   /**
158    * Returns the entry name.  The path components in the entry are
159    * always separated by slashes ('/').  
160    */
161   public String getName()
162   {
163     return name;
164   }
165
166   /**
167    * Sets the time of last modification of the entry.
168    * @time the time of last modification of the entry.
169    */
170   public void setTime(long time)
171   {
172     Calendar cal = getCalendar();
173     synchronized (cal)
174       {
175         cal.setTimeInMillis(time);
176         dostime = (cal.get(Calendar.YEAR) - 1980 & 0x7f) << 25
177           | (cal.get(Calendar.MONTH) + 1) << 21
178           | (cal.get(Calendar.DAY_OF_MONTH)) << 16
179           | (cal.get(Calendar.HOUR_OF_DAY)) << 11
180           | (cal.get(Calendar.MINUTE)) << 5
181           | (cal.get(Calendar.SECOND)) >> 1;
182       }
183     this.known |= KNOWN_TIME;
184   }
185
186   /**
187    * Gets the time of last modification of the entry.
188    * @return the time of last modification of the entry, or -1 if unknown.
189    */
190   public long getTime()
191   {
192     // The extra bytes might contain the time (posix/unix extension)
193     parseExtra();
194
195     if ((known & KNOWN_TIME) == 0)
196       return -1;
197
198     int sec = 2 * (dostime & 0x1f);
199     int min = (dostime >> 5) & 0x3f;
200     int hrs = (dostime >> 11) & 0x1f;
201     int day = (dostime >> 16) & 0x1f;
202     int mon = ((dostime >> 21) & 0xf) - 1;
203     int year = ((dostime >> 25) & 0x7f) + 1980; /* since 1900 */
204    
205     try
206       {
207         cal = getCalendar();
208         synchronized (cal)
209           {
210             cal.set(year, mon, day, hrs, min, sec);
211             return cal.getTimeInMillis();
212           }
213       }
214     catch (RuntimeException ex)
215       {
216         /* Ignore illegal time stamp */
217         known &= ~KNOWN_TIME;
218         return -1;
219       }
220   }
221
222   private static synchronized Calendar getCalendar()
223   {
224     if (cal == null)
225       cal = Calendar.getInstance();
226
227     return cal;
228   }
229
230   /**
231    * Sets the size of the uncompressed data.
232    * @exception IllegalArgumentException if size is not in 0..0xffffffffL
233    */
234   public void setSize(long size)
235   {
236     if ((size & 0xffffffff00000000L) != 0)
237         throw new IllegalArgumentException();
238     this.size = (int) size;
239     this.known |= KNOWN_SIZE;
240   }
241
242   /**
243    * Gets the size of the uncompressed data.
244    * @return the size or -1 if unknown.
245    */
246   public long getSize()
247   {
248     return (known & KNOWN_SIZE) != 0 ? size & 0xffffffffL : -1L;
249   }
250
251   /**
252    * Sets the size of the compressed data.
253    */
254   public void setCompressedSize(long csize)
255   {
256     this.compressedSize = csize;
257   }
258
259   /**
260    * Gets the size of the compressed data.
261    * @return the size or -1 if unknown.
262    */
263   public long getCompressedSize()
264   {
265     return compressedSize;
266   }
267
268   /**
269    * Sets the crc of the uncompressed data.
270    * @exception IllegalArgumentException if crc is not in 0..0xffffffffL
271    */
272   public void setCrc(long crc)
273   {
274     if ((crc & 0xffffffff00000000L) != 0)
275         throw new IllegalArgumentException();
276     this.crc = (int) crc;
277     this.known |= KNOWN_CRC;
278   }
279
280   /**
281    * Gets the crc of the uncompressed data.
282    * @return the crc or -1 if unknown.
283    */
284   public long getCrc()
285   {
286     return (known & KNOWN_CRC) != 0 ? crc & 0xffffffffL : -1L;
287   }
288
289   /**
290    * Sets the compression method.  Only DEFLATED and STORED are
291    * supported.
292    * @exception IllegalArgumentException if method is not supported.
293    * @see ZipOutputStream#DEFLATED
294    * @see ZipOutputStream#STORED 
295    */
296   public void setMethod(int method)
297   {
298     if (method != ZipOutputStream.STORED
299         && method != ZipOutputStream.DEFLATED)
300         throw new IllegalArgumentException();
301     this.method = (short) method;
302   }
303
304   /**
305    * Gets the compression method.  
306    * @return the compression method or -1 if unknown.
307    */
308   public int getMethod()
309   {
310     return method;
311   }
312
313   /**
314    * Sets the extra data.
315    * @exception IllegalArgumentException if extra is longer than 0xffff bytes.
316    */
317   public void setExtra(byte[] extra)
318   {
319     if (extra == null) 
320       {
321         this.extra = null;
322         return;
323       }
324     if (extra.length > 0xffff)
325       throw new IllegalArgumentException();
326     this.extra = extra;
327   }
328
329   private void parseExtra()
330   {
331     // Already parsed?
332     if ((known & KNOWN_EXTRA) != 0)
333       return;
334
335     if (extra == null)
336       {
337         known |= KNOWN_EXTRA;
338         return;
339       }
340
341     try
342       {
343         int pos = 0;
344         while (pos < extra.length) 
345           {
346             int sig = (extra[pos++] & 0xff)
347               | (extra[pos++] & 0xff) << 8;
348             int len = (extra[pos++] & 0xff)
349               | (extra[pos++] & 0xff) << 8;
350             if (sig == 0x5455) 
351               {
352                 /* extended time stamp */
353                 int flags = extra[pos];
354                 if ((flags & 1) != 0)
355                   {
356                     long time = ((extra[pos+1] & 0xff)
357                             | (extra[pos+2] & 0xff) << 8
358                             | (extra[pos+3] & 0xff) << 16
359                             | (extra[pos+4] & 0xff) << 24);
360                     setTime(time);
361                   }
362               }
363             pos += len;
364           }
365       }
366     catch (ArrayIndexOutOfBoundsException ex)
367       {
368         /* be lenient */
369       }
370
371     known |= KNOWN_EXTRA;
372     return;
373   }
374
375   /**
376    * Gets the extra data.
377    * @return the extra data or null if not set.
378    */
379   public byte[] getExtra()
380   {
381     return extra;
382   }
383
384   /**
385    * Sets the entry comment.
386    * @exception IllegalArgumentException if comment is longer than 0xffff.
387    */
388   public void setComment(String comment)
389   {
390     if (comment != null && comment.length() > 0xffff)
391       throw new IllegalArgumentException();
392     this.comment = comment;
393   }
394
395   /**
396    * Gets the comment.
397    * @return the comment or null if not set.
398    */
399   public String getComment()
400   {
401     return comment;
402   }
403
404   /**
405    * Gets true, if the entry is a directory.  This is solely
406    * determined by the name, a trailing slash '/' marks a directory.  
407    */
408   public boolean isDirectory()
409   {
410     int nlen = name.length();
411     return nlen > 0 && name.charAt(nlen - 1) == '/';
412   }
413
414   /**
415    * Gets the string representation of this ZipEntry.  This is just
416    * the name as returned by getName().
417    */
418   public String toString()
419   {
420     return name;
421   }
422
423   /**
424    * Gets the hashCode of this ZipEntry.  This is just the hashCode
425    * of the name.  Note that the equals method isn't changed, though.
426    */
427   public int hashCode()
428   {
429     return name.hashCode();
430   }
431 }