• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  * Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved.
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This code is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License version 2 only, as
8  * published by the Free Software Foundation.  Oracle designates this
9  * particular file as subject to the "Classpath" exception as provided
10  * by Oracle in the LICENSE file that accompanied this code.
11  *
12  * This code is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15  * version 2 for more details (a copy is included in the LICENSE file that
16  * accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License version
19  * 2 along with this work; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21  *
22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23  * or visit www.oracle.com if you need additional information or have any
24  * questions.
25  */
26 
27 package java.util.zip;
28 
29 import java.nio.charset.StandardCharsets;
30 import java.util.Date;
31 
32 /**
33  * This class is used to represent a ZIP file entry.
34  *
35  * @author      David Connelly
36  */
37 public
38 class ZipEntry implements ZipConstants, Cloneable {
39     String name;        // entry name
40     long time = -1;     // modification time (in DOS time)
41     long crc = -1;      // crc-32 of entry data
42     long size = -1;     // uncompressed size of entry data
43     long csize = -1;    // compressed size of entry data
44     int method = -1;    // compression method
45     int flag = 0;       // general purpose flag
46     byte[] extra;       // optional extra field data for entry
47     String comment;     // optional comment string for entry
48     // Android-changed: Add dataOffset for internal use.
49     long dataOffset;
50 
51     /**
52      * Compression method for uncompressed entries.
53      */
54     public static final int STORED = 0;
55 
56     /**
57      * Compression method for compressed (deflated) entries.
58      */
59     public static final int DEFLATED = 8;
60 
61 
62     /** @hide - Called from StrictJarFile native code. */
ZipEntry(String name, String comment, long crc, long compressedSize, long size, int compressionMethod, int time, byte[] extra, long dataOffset)63     public ZipEntry(String name, String comment, long crc, long compressedSize,
64             long size, int compressionMethod, int time, byte[] extra,
65             long dataOffset) {
66         this.name = name;
67         this.comment = comment;
68         this.crc = crc;
69         this.csize = compressedSize;
70         this.size = size;
71         this.method = compressionMethod;
72         this.time = time;
73         this.extra = extra;
74         this.dataOffset = dataOffset;
75     }
76 
77     /**
78      * Creates a new zip entry with the specified name.
79      *
80      * @param name the entry name
81      * @exception NullPointerException if the entry name is null
82      * @exception IllegalArgumentException if the entry name is longer than
83      *            0xFFFF bytes
84      */
ZipEntry(String name)85     public ZipEntry(String name) {
86         if (name == null) {
87             throw new NullPointerException();
88         }
89 
90         // Android-changed: Explicitly use UTF_8 instead of the default charset.
91         if (name.getBytes(StandardCharsets.UTF_8).length > 0xffff) {
92             throw new IllegalArgumentException(name + " too long: " +
93                     name.getBytes(StandardCharsets.UTF_8).length);
94         }
95         this.name = name;
96     }
97 
98     /**
99      * Creates a new zip entry with fields taken from the specified
100      * zip entry.
101      * @param e a zip Entry object
102      */
ZipEntry(ZipEntry e)103     public ZipEntry(ZipEntry e) {
104         name = e.name;
105         time = e.time;
106         crc = e.crc;
107         size = e.size;
108         csize = e.csize;
109         method = e.method;
110         flag = e.flag;
111         extra = e.extra;
112         comment = e.comment;
113         dataOffset = e.dataOffset;
114     }
115 
116     /*
117      * Creates a new un-initialized zip entry
118      */
ZipEntry()119     ZipEntry() {}
120 
121     /** @hide */
getDataOffset()122     public long getDataOffset() {
123         return dataOffset;
124     }
125 
126     /**
127      * Returns the name of the entry.
128      * @return the name of the entry
129      */
getName()130     public String getName() {
131         return name;
132     }
133 
134     /**
135      * Sets the modification time of the entry.
136      * @param time the entry modification time in number of milliseconds
137      *             since the epoch
138      * @see #getTime()
139      */
setTime(long time)140     public void setTime(long time) {
141         this.time = javaToDosTime(time);
142     }
143 
144     /**
145      * Returns the modification time of the entry, or -1 if not specified.
146      * @return the modification time of the entry, or -1 if not specified
147      * @see #setTime(long)
148      */
getTime()149     public long getTime() {
150         return time != -1 ? dosToJavaTime(time) : -1;
151     }
152 
153     /**
154      * Sets the uncompressed size of the entry data.
155      * @param size the uncompressed size in bytes
156      * @exception IllegalArgumentException if the specified size is less
157      *            than 0, is greater than 0xFFFFFFFF when
158      *            <a href="package-summary.html#zip64">ZIP64 format</a> is not supported,
159      *            or is less than 0 when ZIP64 is supported
160      * @see #getSize()
161      */
setSize(long size)162     public void setSize(long size) {
163         if (size < 0) {
164             throw new IllegalArgumentException("invalid entry size");
165         }
166         this.size = size;
167     }
168 
169     /**
170      * Returns the uncompressed size of the entry data, or -1 if not known.
171      * @return the uncompressed size of the entry data, or -1 if not known
172      * @see #setSize(long)
173      */
getSize()174     public long getSize() {
175         return size;
176     }
177 
178     /**
179      * Returns the size of the compressed entry data, or -1 if not known.
180      * In the case of a stored entry, the compressed size will be the same
181      * as the uncompressed size of the entry.
182      * @return the size of the compressed entry data, or -1 if not known
183      * @see #setCompressedSize(long)
184      */
getCompressedSize()185     public long getCompressedSize() {
186         return csize;
187     }
188 
189     /**
190      * Sets the size of the compressed entry data.
191      * @param csize the compressed size to set to
192      * @see #getCompressedSize()
193      */
setCompressedSize(long csize)194     public void setCompressedSize(long csize) {
195         this.csize = csize;
196     }
197 
198     /**
199      * Sets the CRC-32 checksum of the uncompressed entry data.
200      * @param crc the CRC-32 value
201      * @exception IllegalArgumentException if the specified CRC-32 value is
202      *            less than 0 or greater than 0xFFFFFFFF
203      * @see #getCrc()
204      */
setCrc(long crc)205     public void setCrc(long crc) {
206         if (crc < 0 || crc > 0xFFFFFFFFL) {
207             throw new IllegalArgumentException("invalid entry crc-32");
208         }
209         this.crc = crc;
210     }
211 
212     /**
213      * Returns the CRC-32 checksum of the uncompressed entry data, or -1 if
214      * not known.
215      * @return the CRC-32 checksum of the uncompressed entry data, or -1 if
216      * not known
217      * @see #setCrc(long)
218      */
getCrc()219     public long getCrc() {
220         return crc;
221     }
222 
223     /**
224      * Sets the compression method for the entry.
225      * @param method the compression method, either STORED or DEFLATED
226      * @exception IllegalArgumentException if the specified compression
227      *            method is invalid
228      * @see #getMethod()
229      */
setMethod(int method)230     public void setMethod(int method) {
231         if (method != STORED && method != DEFLATED) {
232             throw new IllegalArgumentException("invalid compression method");
233         }
234         this.method = method;
235     }
236 
237     /**
238      * Returns the compression method of the entry, or -1 if not specified.
239      * @return the compression method of the entry, or -1 if not specified
240      * @see #setMethod(int)
241      */
getMethod()242     public int getMethod() {
243         return method;
244     }
245 
246     /**
247      * Sets the optional extra field data for the entry.
248      * @param extra the extra field data bytes
249      * @exception IllegalArgumentException if the length of the specified
250      *            extra field data is greater than 0xFFFF bytes
251      * @see #getExtra()
252      */
setExtra(byte[] extra)253     public void setExtra(byte[] extra) {
254         if (extra != null && extra.length > 0xFFFF) {
255             throw new IllegalArgumentException("invalid extra field length");
256         }
257         this.extra = extra;
258     }
259 
260     /**
261      * Returns the extra field data for the entry, or null if none.
262      * @return the extra field data for the entry, or null if none
263      * @see #setExtra(byte[])
264      */
getExtra()265     public byte[] getExtra() {
266         return extra;
267     }
268 
269     /**
270      * Sets the optional comment string for the entry.
271      *
272      * <p>ZIP entry comments have maximum length of 0xffff. If the length of the
273      * specified comment string is greater than 0xFFFF bytes after encoding, only
274      * the first 0xFFFF bytes are output to the ZIP file entry.
275      *
276      * @param comment the comment string
277      *
278      * @see #getComment()
279      */
setComment(String comment)280     public void setComment(String comment) {
281         // Android-changed: Explicitly allow null comments (or allow comments to be
282         // cleared).
283         if (comment == null) {
284             this.comment = null;
285             return;
286         }
287 
288         // Android-changed: Explicitly use UTF-8.
289         if (comment.getBytes(StandardCharsets.UTF_8).length > 0xffff) {
290             throw new IllegalArgumentException(comment + " too long: " +
291                     comment.getBytes(StandardCharsets.UTF_8).length);
292         }
293         this.comment = comment;
294     }
295 
296     /**
297      * Returns the comment string for the entry, or null if none.
298      * @return the comment string for the entry, or null if none
299      * @see #setComment(String)
300      */
getComment()301     public String getComment() {
302         return comment;
303     }
304 
305     /**
306      * Returns true if this is a directory entry. A directory entry is
307      * defined to be one whose name ends with a '/'.
308      * @return true if this is a directory entry
309      */
isDirectory()310     public boolean isDirectory() {
311         return name.endsWith("/");
312     }
313 
314     /**
315      * Returns a string representation of the ZIP entry.
316      */
toString()317     public String toString() {
318         return getName();
319     }
320 
321     /*
322      * Converts DOS time to Java time (number of milliseconds since epoch).
323      */
dosToJavaTime(long dtime)324     private static long dosToJavaTime(long dtime) {
325         Date d = new Date((int)(((dtime >> 25) & 0x7f) + 80),
326                           (int)(((dtime >> 21) & 0x0f) - 1),
327                           (int)((dtime >> 16) & 0x1f),
328                           (int)((dtime >> 11) & 0x1f),
329                           (int)((dtime >> 5) & 0x3f),
330                           (int)((dtime << 1) & 0x3e));
331         return d.getTime();
332     }
333 
334     /*
335      * Converts Java time to DOS time.
336      */
javaToDosTime(long time)337     private static long javaToDosTime(long time) {
338         Date d = new Date(time);
339         int year = d.getYear() + 1900;
340         if (year < 1980) {
341             return (1 << 21) | (1 << 16);
342         }
343         return (year - 1980) << 25 | (d.getMonth() + 1) << 21 |
344                d.getDate() << 16 | d.getHours() << 11 | d.getMinutes() << 5 |
345                d.getSeconds() >> 1;
346     }
347 
348     /**
349      * Returns the hash code value for this entry.
350      */
hashCode()351     public int hashCode() {
352         return name.hashCode();
353     }
354 
355     /**
356      * Returns a copy of this entry.
357      */
clone()358     public Object clone() {
359         try {
360             ZipEntry e = (ZipEntry)super.clone();
361             e.extra = (extra == null) ? null : extra.clone();
362             return e;
363         } catch (CloneNotSupportedException e) {
364             // This should never happen, since we are Cloneable
365             throw new InternalError();
366         }
367     }
368 }
369