| ZipEntry.java |
1 /*
2 * %W% %E%
3 *
4 * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
5 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6 */
7
8 package java.util.zip;
9
10 import java.util.Date;
11
12 /**
13 * This class is used to represent a ZIP file entry.
14 *
15 * @version %I%, %G%
16 * @author David Connelly
17 */
18 public
19 class ZipEntry implements ZipConstants, Cloneable {
20 String name; // entry name
21 long time = -1; // modification time (in DOS time)
22 long crc = -1; // crc-32 of entry data
23 long size = -1; // uncompressed size of entry data
24 long csize = -1; // compressed size of entry data
25 int method = -1; // compression method
26 byte[] extra; // optional extra field data for entry
27 String comment; // optional comment string for entry
28
29 /**
30 * Compression method for uncompressed entries.
31 */
32 public static final int STORED = 0;
33
34 /**
35 * Compression method for compressed (deflated) entries.
36 */
37 public static final int DEFLATED = 8;
38
39 static {
40 /* Zip library is loaded from System.initializeSystemClass */
41 initIDs();
42 }
43
44 private static native void initIDs();
45
46 /**
47 * Creates a new zip entry with the specified name.
48 *
49 * @param name the entry name
50 * @exception NullPointerException if the entry name is null
51 * @exception IllegalArgumentException if the entry name is longer than
52 * 0xFFFF bytes
53 */
54 public ZipEntry(String name) {
55 if (name == null) {
56 throw new NullPointerException();
57 }
58 if (name.length() > 0xFFFF) {
59 throw new IllegalArgumentException("entry name too long");
60 }
61 this.name = name;
62 }
63
64 /**
65 * Creates a new zip entry with fields taken from the specified
66 * zip entry.
67 * @param e a zip Entry object
68 */
69 public ZipEntry(ZipEntry e) {
70 name = e.name;
71 time = e.time;
72 crc = e.crc;
73 size = e.size;
74 csize = e.csize;
75 method = e.method;
76 extra = e.extra;
77 comment = e.comment;
78 }
79
80 /*
81 * Creates a new zip entry for the given name with fields initialized
82 * from the specified jzentry data.
83 */
84 ZipEntry(String name, long jzentry) {
85 this.name = name;
86 initFields(jzentry);
87 }
88
89 private native void initFields(long jzentry);
90
91 /*
92 * Creates a new zip entry with fields initialized from the specified
93 * jzentry data.
94 */
95 ZipEntry(long jzentry) {
96 initFields(jzentry);
97 }
98
99 /**
100 * Returns the name of the entry.
101 * @return the name of the entry
102 */
103 public String getName() {
104 return name;
105 }
106
107 /**
108 * Sets the modification time of the entry.
109 * @param time the entry modification time in number of milliseconds
110 * since the epoch
111 * @see #getTime()
112 */
113 public void setTime(long time) {
114 // fix for bug 6625963: we bypass time calculations while Kernel is
115 // downloading bundles, since they aren't necessary and would cause
116 // the Kernel core to depend upon the (very large) time zone data
117 if (sun.jkernel.DownloadManager.isCurrentThreadDownloading())
118 this.time = sun.jkernel.DownloadManager.KERNEL_STATIC_MODTIME;
119 else
120 this.time = javaToDosTime(time);
121 }
122
123 /**
124 * Returns the modification time of the entry, or -1 if not specified.
125 * @return the modification time of the entry, or -1 if not specified
126 * @see #setTime(long)
127 */
128 public long getTime() {
129 return time != -1 ? dosToJavaTime(time) : -1;
130 }
131
132 /**
133 * Sets the uncompressed size of the entry data.
134 * @param size the uncompressed size in bytes
135 * @exception IllegalArgumentException if the specified size is less
136 * than 0 or greater than 0xFFFFFFFF bytes
137 * @see #getSize()
138 */
139 public void setSize(long size) {
140 if (size < 0 || size > 0xFFFFFFFFL) {
141 throw new IllegalArgumentException("invalid entry size");
142 }
143 this.size = size;
144 }
145
146 /**
147 * Returns the uncompressed size of the entry data, or -1 if not known.
148 * @return the uncompressed size of the entry data, or -1 if not known
149 * @see #setSize(long)
150 */
151 public long getSize() {
152 return size;
153 }
154
155 /**
156 * Returns the size of the compressed entry data, or -1 if not known.
157 * In the case of a stored entry, the compressed size will be the same
158 * as the uncompressed size of the entry.
159 * @return the size of the compressed entry data, or -1 if not known
160 * @see #setCompressedSize(long)
161 */
162 public long getCompressedSize() {
163 return csize;
164 }
165
166 /**
167 * Sets the size of the compressed entry data.
168 * @param csize the compressed size to set to
169 * @see #getCompressedSize()
170 */
171 public void setCompressedSize(long csize) {
172 this.csize = csize;
173 }
174
175 /**
176 * Sets the CRC-32 checksum of the uncompressed entry data.
177 * @param crc the CRC-32 value
178 * @exception IllegalArgumentException if the specified CRC-32 value is
179 * less than 0 or greater than 0xFFFFFFFF
180 * @see #getCrc()
181 */
182 public void setCrc(long crc) {
183 if (crc < 0 || crc > 0xFFFFFFFFL) {
184 throw new IllegalArgumentException("invalid entry crc-32");
185 }
186 this.crc = crc;
187 }
188
189 /**
190 * Returns the CRC-32 checksum of the uncompressed entry data, or -1 if
191 * not known.
192 * @return the CRC-32 checksum of the uncompressed entry data, or -1 if
193 * not known
194 * @see #setCrc(long)
195 */
196 public long getCrc() {
197 return crc;
198 }
199
200 /**
201 * Sets the compression method for the entry.
202 * @param method the compression method, either STORED or DEFLATED
203 * @exception IllegalArgumentException if the specified compression
204 * method is invalid
205 * @see #getMethod()
206 */
207 public void setMethod(int method) {
208 if (method != STORED && method != DEFLATED) {
209 throw new IllegalArgumentException("invalid compression method");
210 }
211 this.method = method;
212 }
213
214 /**
215 * Returns the compression method of the entry, or -1 if not specified.
216 * @return the compression method of the entry, or -1 if not specified
217 * @see #setMethod(int)
218 */
219 public int getMethod() {
220 return method;
221 }
222
223 /**
224 * Sets the optional extra field data for the entry.
225 * @param extra the extra field data bytes
226 * @exception IllegalArgumentException if the length of the specified
227 * extra field data is greater than 0xFFFF bytes
228 * @see #getExtra()
229 */
230 public void setExtra(byte[] extra) {
231 if (extra != null && extra.length > 0xFFFF) {
232 throw new IllegalArgumentException("invalid extra field length");
233 }
234 this.extra = extra;
235 }
236
237 /**
238 * Returns the extra field data for the entry, or null if none.
239 * @return the extra field data for the entry, or null if none
240 * @see #setExtra(byte[])
241 */
242 public byte[] getExtra() {
243 return extra;
244 }
245
246 /**
247 * Sets the optional comment string for the entry.
248 * @param comment the comment string
249 * @exception IllegalArgumentException if the length of the specified
250 * comment string is greater than 0xFFFF bytes
251 * @see #getComment()
252 */
253 public void setComment(String comment) {
254 if (comment != null && comment.length() > 0xffff/3
255 && ZipOutputStream.getUTF8Length(comment) > 0xffff) {
256 throw new IllegalArgumentException("invalid entry comment length");
257 }
258 this.comment = comment;
259 }
260
261 /**
262 * Returns the comment string for the entry, or null if none.
263 * @return the comment string for the entry, or null if none
264 * @see #setComment(String)
265 */
266 public String getComment() {
267 return comment;
268 }
269
270 /**
271 * Returns true if this is a directory entry. A directory entry is
272 * defined to be one whose name ends with a '/'.
273 * @return true if this is a directory entry
274 */
275 public boolean isDirectory() {
276 return name.endsWith("/");
277 }
278
279 /**
280 * Returns a string representation of the ZIP entry.
281 */
282 public String toString() {
283 return getName();
284 }
285
286 /*
287 * Converts DOS time to Java time (number of milliseconds since epoch).
288 */
289 private static long dosToJavaTime(long dtime) {
290 Date d = new Date((int)(((dtime >> 25) & 0x7f) + 80),
291 (int)(((dtime >> 21) & 0x0f) - 1),
292 (int)((dtime >> 16) & 0x1f),
293 (int)((dtime >> 11) & 0x1f),
294 (int)((dtime >> 5) & 0x3f),
295 (int)((dtime << 1) & 0x3e));
296 return d.getTime();
297 }
298
299 /*
300 * Converts Java time to DOS time.
301 */
302 private static long javaToDosTime(long time) {
303 Date d = new Date(time);
304 int year = d.getYear() + 1900;
305 if (year < 1980) {
306 return (1 << 21) | (1 << 16);
307 }
308 return (year - 1980) << 25 | (d.getMonth() + 1) << 21 |
309 d.getDate() << 16 | d.getHours() << 11 | d.getMinutes() << 5 |
310 d.getSeconds() >> 1;
311 }
312
313 /**
314 * Returns the hash code value for this entry.
315 */
316 public int hashCode() {
317 return name.hashCode();
318 }
319
320 /**
321 * Returns a copy of this entry.
322 */
323 public Object clone() {
324 try {
325 ZipEntry e = (ZipEntry)super.clone();
326 e.extra = (extra == null ? null : (byte[])extra.clone());
327 return e;
328 } catch (CloneNotSupportedException e) {
329 // This should never happen, since we are Cloneable
330 throw new InternalError();
331 }
332 }
333 }
334