1 | /* java.util.zip.ZipEntry
|
---|
2 | Copyright (C) 2001, 2002 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., 59 Temple Place, Suite 330, Boston, MA
|
---|
19 | 02111-1307 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 | package java.util.zip;
|
---|
39 | import java.util.Calendar;
|
---|
40 | import java.util.TimeZone;
|
---|
41 | import java.util.Date;
|
---|
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 int KNOWN_SIZE = 1;
|
---|
54 | private static int KNOWN_CSIZE = 2;
|
---|
55 | private static int KNOWN_CRC = 4;
|
---|
56 | private static int KNOWN_TIME = 8;
|
---|
57 |
|
---|
58 | private static Calendar cal;
|
---|
59 |
|
---|
60 | private String name;
|
---|
61 | private int size;
|
---|
62 | private int compressedSize;
|
---|
63 | private int crc;
|
---|
64 | private int dostime;
|
---|
65 | private short known = 0;
|
---|
66 | private short method = -1;
|
---|
67 | private byte[] extra = null;
|
---|
68 | private String comment = null;
|
---|
69 |
|
---|
70 | int flags; /* used by ZipOutputStream */
|
---|
71 | int offset; /* used by ZipFile and ZipOutputStream */
|
---|
72 |
|
---|
73 |
|
---|
74 | /**
|
---|
75 | * Compression method. This method doesn't compress at all.
|
---|
76 | */
|
---|
77 | public final static int STORED = 0;
|
---|
78 | /**
|
---|
79 | * Compression method. This method uses the Deflater.
|
---|
80 | */
|
---|
81 | public final static 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 | name = e.name;
|
---|
106 | known = e.known;
|
---|
107 | size = e.size;
|
---|
108 | compressedSize = e.compressedSize;
|
---|
109 | crc = e.crc;
|
---|
110 | dostime = e.dostime;
|
---|
111 | method = e.method;
|
---|
112 | extra = e.extra;
|
---|
113 | comment = e.comment;
|
---|
114 | }
|
---|
115 |
|
---|
116 | final void setDOSTime(int dostime)
|
---|
117 | {
|
---|
118 | this.dostime = dostime;
|
---|
119 | known |= KNOWN_TIME;
|
---|
120 | }
|
---|
121 |
|
---|
122 | final int getDOSTime()
|
---|
123 | {
|
---|
124 | if ((known & KNOWN_TIME) == 0)
|
---|
125 | return 0;
|
---|
126 | else
|
---|
127 | return dostime;
|
---|
128 | }
|
---|
129 |
|
---|
130 | /**
|
---|
131 | * Creates a copy of this zip entry.
|
---|
132 | */
|
---|
133 | /**
|
---|
134 | * Clones the entry.
|
---|
135 | */
|
---|
136 | public Object clone()
|
---|
137 | {
|
---|
138 | try
|
---|
139 | {
|
---|
140 | // The JCL says that the `extra' field is also copied.
|
---|
141 | ZipEntry clone = (ZipEntry) super.clone();
|
---|
142 | if (extra != null)
|
---|
143 | clone.extra = (byte[]) extra.clone();
|
---|
144 | return clone;
|
---|
145 | }
|
---|
146 | catch (CloneNotSupportedException ex)
|
---|
147 | {
|
---|
148 | throw new InternalError();
|
---|
149 | }
|
---|
150 | }
|
---|
151 |
|
---|
152 | /**
|
---|
153 | * Returns the entry name. The path components in the entry are
|
---|
154 | * always separated by slashes ('/').
|
---|
155 | */
|
---|
156 | public String getName()
|
---|
157 | {
|
---|
158 | return name;
|
---|
159 | }
|
---|
160 |
|
---|
161 | /**
|
---|
162 | * Sets the time of last modification of the entry.
|
---|
163 | * @time the time of last modification of the entry.
|
---|
164 | */
|
---|
165 | public void setTime(long time)
|
---|
166 | {
|
---|
167 | Calendar cal = getCalendar();
|
---|
168 | synchronized (cal)
|
---|
169 | {
|
---|
170 | cal.setTime(new Date(time*1000L));
|
---|
171 | dostime = (cal.get(cal.YEAR) - 1980 & 0x7f) << 25
|
---|
172 | | (cal.get(cal.MONTH) + 1) << 21
|
---|
173 | | (cal.get(cal.DAY_OF_MONTH)) << 16
|
---|
174 | | (cal.get(cal.HOUR_OF_DAY)) << 11
|
---|
175 | | (cal.get(cal.MINUTE)) << 5
|
---|
176 | | (cal.get(cal.SECOND)) >> 1;
|
---|
177 | }
|
---|
178 | dostime = (int) (dostime / 1000L);
|
---|
179 | this.known |= KNOWN_TIME;
|
---|
180 | }
|
---|
181 |
|
---|
182 | /**
|
---|
183 | * Gets the time of last modification of the entry.
|
---|
184 | * @return the time of last modification of the entry, or -1 if unknown.
|
---|
185 | */
|
---|
186 | public long getTime()
|
---|
187 | {
|
---|
188 | if ((known & KNOWN_TIME) == 0)
|
---|
189 | return -1;
|
---|
190 |
|
---|
191 | int sec = 2 * (dostime & 0x1f);
|
---|
192 | int min = (dostime >> 5) & 0x3f;
|
---|
193 | int hrs = (dostime >> 11) & 0x1f;
|
---|
194 | int day = (dostime >> 16) & 0x1f;
|
---|
195 | int mon = ((dostime >> 21) & 0xf) - 1;
|
---|
196 | int year = ((dostime >> 25) & 0x7f) + 1980; /* since 1900 */
|
---|
197 |
|
---|
198 | try
|
---|
199 | {
|
---|
200 | cal = getCalendar();
|
---|
201 | synchronized (cal)
|
---|
202 | {
|
---|
203 | cal.set(year, mon, day, hrs, min, sec);
|
---|
204 | return cal.getTime().getTime();
|
---|
205 | }
|
---|
206 | }
|
---|
207 | catch (RuntimeException ex)
|
---|
208 | {
|
---|
209 | /* Ignore illegal time stamp */
|
---|
210 | known &= ~KNOWN_TIME;
|
---|
211 | return -1;
|
---|
212 | }
|
---|
213 | }
|
---|
214 |
|
---|
215 | private static synchronized Calendar getCalendar()
|
---|
216 | {
|
---|
217 | if (cal == null)
|
---|
218 | cal = Calendar.getInstance();
|
---|
219 |
|
---|
220 | return cal;
|
---|
221 | }
|
---|
222 |
|
---|
223 | /**
|
---|
224 | * Sets the size of the uncompressed data.
|
---|
225 | * @exception IllegalArgumentException if size is not in 0..0xffffffffL
|
---|
226 | */
|
---|
227 | public void setSize(long size)
|
---|
228 | {
|
---|
229 | if ((size & 0xffffffff00000000L) != 0)
|
---|
230 | throw new IllegalArgumentException();
|
---|
231 | this.size = (int) size;
|
---|
232 | this.known |= KNOWN_SIZE;
|
---|
233 | }
|
---|
234 |
|
---|
235 | /**
|
---|
236 | * Gets the size of the uncompressed data.
|
---|
237 | * @return the size or -1 if unknown.
|
---|
238 | */
|
---|
239 | public long getSize()
|
---|
240 | {
|
---|
241 | return (known & KNOWN_SIZE) != 0 ? size & 0xffffffffL : -1L;
|
---|
242 | }
|
---|
243 |
|
---|
244 | /**
|
---|
245 | * Sets the size of the compressed data.
|
---|
246 | * @exception IllegalArgumentException if size is not in 0..0xffffffffL
|
---|
247 | */
|
---|
248 | public void setCompressedSize(long csize)
|
---|
249 | {
|
---|
250 | if ((csize & 0xffffffff00000000L) != 0)
|
---|
251 | throw new IllegalArgumentException();
|
---|
252 | this.compressedSize = (int) csize;
|
---|
253 | this.known |= KNOWN_CSIZE;
|
---|
254 | }
|
---|
255 |
|
---|
256 | /**
|
---|
257 | * Gets the size of the compressed data.
|
---|
258 | * @return the size or -1 if unknown.
|
---|
259 | */
|
---|
260 | public long getCompressedSize()
|
---|
261 | {
|
---|
262 | return (known & KNOWN_CSIZE) != 0 ? compressedSize & 0xffffffffL : -1L;
|
---|
263 | }
|
---|
264 |
|
---|
265 | /**
|
---|
266 | * Sets the crc of the uncompressed data.
|
---|
267 | * @exception IllegalArgumentException if crc is not in 0..0xffffffffL
|
---|
268 | */
|
---|
269 | public void setCrc(long crc)
|
---|
270 | {
|
---|
271 | if ((crc & 0xffffffff00000000L) != 0)
|
---|
272 | throw new IllegalArgumentException();
|
---|
273 | this.crc = (int) crc;
|
---|
274 | this.known |= KNOWN_CRC;
|
---|
275 | }
|
---|
276 |
|
---|
277 | /**
|
---|
278 | * Gets the crc of the uncompressed data.
|
---|
279 | * @return the crc or -1 if unknown.
|
---|
280 | */
|
---|
281 | public long getCrc()
|
---|
282 | {
|
---|
283 | return (known & KNOWN_CRC) != 0 ? crc & 0xffffffffL : -1L;
|
---|
284 | }
|
---|
285 |
|
---|
286 | /**
|
---|
287 | * Sets the compression method. Only DEFLATED and STORED are
|
---|
288 | * supported.
|
---|
289 | * @exception IllegalArgumentException if method is not supported.
|
---|
290 | * @see ZipOutputStream#DEFLATED
|
---|
291 | * @see ZipOutputStream#STORED
|
---|
292 | */
|
---|
293 | public void setMethod(int method)
|
---|
294 | {
|
---|
295 | if (method != ZipOutputStream.STORED
|
---|
296 | && method != ZipOutputStream.DEFLATED)
|
---|
297 | throw new IllegalArgumentException();
|
---|
298 | this.method = (short) method;
|
---|
299 | }
|
---|
300 |
|
---|
301 | /**
|
---|
302 | * Gets the compression method.
|
---|
303 | * @return the compression method or -1 if unknown.
|
---|
304 | */
|
---|
305 | public int getMethod()
|
---|
306 | {
|
---|
307 | return method;
|
---|
308 | }
|
---|
309 |
|
---|
310 | /**
|
---|
311 | * Sets the extra data.
|
---|
312 | * @exception IllegalArgumentException if extra is longer than 0xffff bytes.
|
---|
313 | */
|
---|
314 | public void setExtra(byte[] extra)
|
---|
315 | {
|
---|
316 | if (extra == null)
|
---|
317 | {
|
---|
318 | this.extra = null;
|
---|
319 | return;
|
---|
320 | }
|
---|
321 |
|
---|
322 | if (extra.length > 0xffff)
|
---|
323 | throw new IllegalArgumentException();
|
---|
324 | this.extra = extra;
|
---|
325 | try
|
---|
326 | {
|
---|
327 | int pos = 0;
|
---|
328 | while (pos < extra.length)
|
---|
329 | {
|
---|
330 | int sig = (extra[pos++] & 0xff)
|
---|
331 | | (extra[pos++] & 0xff) << 8;
|
---|
332 | int len = (extra[pos++] & 0xff)
|
---|
333 | | (extra[pos++] & 0xff) << 8;
|
---|
334 | if (sig == 0x5455)
|
---|
335 | {
|
---|
336 | /* extended time stamp */
|
---|
337 | int flags = extra[pos];
|
---|
338 | if ((flags & 1) != 0)
|
---|
339 | {
|
---|
340 | long time = ((extra[pos+1] & 0xff)
|
---|
341 | | (extra[pos+2] & 0xff) << 8
|
---|
342 | | (extra[pos+3] & 0xff) << 16
|
---|
343 | | (extra[pos+4] & 0xff) << 24);
|
---|
344 | setTime(time);
|
---|
345 | }
|
---|
346 | }
|
---|
347 | pos += len;
|
---|
348 | }
|
---|
349 | }
|
---|
350 | catch (ArrayIndexOutOfBoundsException ex)
|
---|
351 | {
|
---|
352 | /* be lenient */
|
---|
353 | return;
|
---|
354 | }
|
---|
355 | }
|
---|
356 |
|
---|
357 | /**
|
---|
358 | * Gets the extra data.
|
---|
359 | * @return the extra data or null if not set.
|
---|
360 | */
|
---|
361 | public byte[] getExtra()
|
---|
362 | {
|
---|
363 | return extra;
|
---|
364 | }
|
---|
365 |
|
---|
366 | /**
|
---|
367 | * Sets the entry comment.
|
---|
368 | * @exception IllegalArgumentException if comment is longer than 0xffff.
|
---|
369 | */
|
---|
370 | public void setComment(String comment)
|
---|
371 | {
|
---|
372 | if (comment != null && comment.length() > 0xffff)
|
---|
373 | throw new IllegalArgumentException();
|
---|
374 | this.comment = comment;
|
---|
375 | }
|
---|
376 |
|
---|
377 | /**
|
---|
378 | * Gets the comment.
|
---|
379 | * @return the comment or null if not set.
|
---|
380 | */
|
---|
381 | public String getComment()
|
---|
382 | {
|
---|
383 | return comment;
|
---|
384 | }
|
---|
385 |
|
---|
386 | /**
|
---|
387 | * Gets true, if the entry is a directory. This is solely
|
---|
388 | * determined by the name, a trailing slash '/' marks a directory.
|
---|
389 | */
|
---|
390 | public boolean isDirectory()
|
---|
391 | {
|
---|
392 | int nlen = name.length();
|
---|
393 | return nlen > 0 && name.charAt(nlen - 1) == '/';
|
---|
394 | }
|
---|
395 |
|
---|
396 | /**
|
---|
397 | * Gets the string representation of this ZipEntry. This is just
|
---|
398 | * the name as returned by getName().
|
---|
399 | */
|
---|
400 | public String toString()
|
---|
401 | {
|
---|
402 | return name;
|
---|
403 | }
|
---|
404 |
|
---|
405 | /**
|
---|
406 | * Gets the hashCode of this ZipEntry. This is just the hashCode
|
---|
407 | * of the name. Note that the equals method isn't changed, though.
|
---|
408 | */
|
---|
409 | public int hashCode()
|
---|
410 | {
|
---|
411 | return name.hashCode();
|
---|
412 | }
|
---|
413 | }
|
---|