blob: 7f2fb32ec88946e650fb6b6b660c039b5144812a [file] [log] [blame]
Torsten Curdtca165392008-07-10 10:17:44 +00001/*
Torsten Curdtab9ebfc2009-01-12 11:15:34 +00002 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
Torsten Curdtca165392008-07-10 10:17:44 +00008 *
Torsten Curdtab9ebfc2009-01-12 11:15:34 +00009 * http://www.apache.org/licenses/LICENSE-2.0
Torsten Curdtca165392008-07-10 10:17:44 +000010 *
Torsten Curdtab9ebfc2009-01-12 11:15:34 +000011 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
Torsten Curdtca165392008-07-10 10:17:44 +000017 */
18package org.apache.commons.compress.archivers.zip;
19
Torsten Curdtab9ebfc2009-01-12 11:15:34 +000020import java.util.Vector;
Torsten Curdtca165392008-07-10 10:17:44 +000021import java.util.zip.ZipException;
22
23/**
Torsten Curdtab9ebfc2009-01-12 11:15:34 +000024 * Extension that adds better handling of extra fields and provides
25 * access to the internal and external file attributes.
26 *
Torsten Curdtca165392008-07-10 10:17:44 +000027 */
Torsten Curdtab9ebfc2009-01-12 11:15:34 +000028public class ZipEntry extends java.util.zip.ZipEntry implements Cloneable {
Torsten Curdtca165392008-07-10 10:17:44 +000029
Torsten Curdtab9ebfc2009-01-12 11:15:34 +000030 public static final int PLATFORM_UNIX = 3;
31 public static final int PLATFORM_FAT = 0;
32 private static final int SHORT_MASK = 0xFFFF;
33 private static final int SHORT_SHIFT = 16;
Torsten Curdtca165392008-07-10 10:17:44 +000034
Torsten Curdtab9ebfc2009-01-12 11:15:34 +000035 private int internalAttributes = 0;
36 private int platform = PLATFORM_FAT;
37 private long externalAttributes = 0;
38 private Vector/*<ZipExtraField>*/ extraFields = null;
39 private String name = null;
Torsten Curdtca165392008-07-10 10:17:44 +000040
41 /**
42 * Creates a new zip entry with the specified name.
Torsten Curdtab9ebfc2009-01-12 11:15:34 +000043 * @param name the name of the entry
Torsten Curdtca165392008-07-10 10:17:44 +000044 * @since 1.1
45 */
Torsten Curdtab9ebfc2009-01-12 11:15:34 +000046 public ZipEntry(String name) {
47 super(name);
Torsten Curdtca165392008-07-10 10:17:44 +000048 }
49
50 /**
51 * Creates a new zip entry with fields taken from the specified zip entry.
Torsten Curdtab9ebfc2009-01-12 11:15:34 +000052 * @param entry the entry to get fields from
Torsten Curdtca165392008-07-10 10:17:44 +000053 * @since 1.1
Torsten Curdtab9ebfc2009-01-12 11:15:34 +000054 * @throws ZipException on error
Torsten Curdtca165392008-07-10 10:17:44 +000055 */
Torsten Curdtab9ebfc2009-01-12 11:15:34 +000056 public ZipEntry(java.util.zip.ZipEntry entry) throws ZipException {
57 super(entry);
58 byte[] extra = entry.getExtra();
59 if (extra != null) {
60 setExtraFields(ExtraFieldUtils.parse(extra));
61 } else {
Torsten Curdtca165392008-07-10 10:17:44 +000062 // initializes extra data to an empty byte array
63 setExtra();
64 }
65 }
66
67 /**
68 * Creates a new zip entry with fields taken from the specified zip entry.
Torsten Curdtab9ebfc2009-01-12 11:15:34 +000069 * @param entry the entry to get fields from
70 * @throws ZipException on error
Torsten Curdtca165392008-07-10 10:17:44 +000071 * @since 1.1
72 */
Torsten Curdtab9ebfc2009-01-12 11:15:34 +000073 public ZipEntry(ZipEntry entry) throws ZipException {
74 this((java.util.zip.ZipEntry) entry);
75 setInternalAttributes(entry.getInternalAttributes());
76 setExternalAttributes(entry.getExternalAttributes());
77 setExtraFields(entry.getExtraFields());
Torsten Curdtca165392008-07-10 10:17:44 +000078 }
79
80 /**
Torsten Curdtab9ebfc2009-01-12 11:15:34 +000081 * @since 1.9
Torsten Curdtca165392008-07-10 10:17:44 +000082 */
Torsten Curdtab9ebfc2009-01-12 11:15:34 +000083 protected ZipEntry() {
84 super("");
Torsten Curdtca165392008-07-10 10:17:44 +000085 }
86
87 /**
Torsten Curdtab9ebfc2009-01-12 11:15:34 +000088 * Overwrite clone.
89 * @return a cloned copy of this ZipEntry
Torsten Curdtca165392008-07-10 10:17:44 +000090 * @since 1.1
91 */
Torsten Curdtab9ebfc2009-01-12 11:15:34 +000092 public Object clone() {
93 ZipEntry e = (ZipEntry) super.clone();
Torsten Curdtca165392008-07-10 10:17:44 +000094
Torsten Curdtab9ebfc2009-01-12 11:15:34 +000095 e.extraFields = extraFields != null ? (Vector) extraFields.clone() : null;
96 e.setInternalAttributes(getInternalAttributes());
97 e.setExternalAttributes(getExternalAttributes());
98 e.setExtraFields(getExtraFields());
99 return e;
Torsten Curdtca165392008-07-10 10:17:44 +0000100 }
101
102 /**
103 * Retrieves the internal file attributes.
104 *
Torsten Curdtab9ebfc2009-01-12 11:15:34 +0000105 * @return the internal file attributes
Torsten Curdtca165392008-07-10 10:17:44 +0000106 * @since 1.1
107 */
Torsten Curdtab9ebfc2009-01-12 11:15:34 +0000108 public int getInternalAttributes() {
109 return internalAttributes;
Torsten Curdtca165392008-07-10 10:17:44 +0000110 }
111
112 /**
Torsten Curdtab9ebfc2009-01-12 11:15:34 +0000113 * Sets the internal file attributes.
114 * @param value an <code>int</code> value
Torsten Curdtca165392008-07-10 10:17:44 +0000115 * @since 1.1
116 */
Torsten Curdtab9ebfc2009-01-12 11:15:34 +0000117 public void setInternalAttributes(int value) {
118 internalAttributes = value;
Torsten Curdtca165392008-07-10 10:17:44 +0000119 }
120
121 /**
Torsten Curdtab9ebfc2009-01-12 11:15:34 +0000122 * Retrieves the external file attributes.
123 * @return the external file attributes
Torsten Curdtca165392008-07-10 10:17:44 +0000124 * @since 1.1
125 */
Torsten Curdtab9ebfc2009-01-12 11:15:34 +0000126 public long getExternalAttributes() {
127 return externalAttributes;
128 }
129
130 /**
131 * Sets the external file attributes.
132 * @param value an <code>long</code> value
133 * @since 1.1
134 */
135 public void setExternalAttributes(long value) {
136 externalAttributes = value;
137 }
138
139 /**
140 * Sets Unix permissions in a way that is understood by Info-Zip's
141 * unzip command.
142 * @param mode an <code>int</code> value
143 * @since Ant 1.5.2
144 */
145 public void setUnixMode(int mode) {
146 // CheckStyle:MagicNumberCheck OFF - no point
147 setExternalAttributes((mode << SHORT_SHIFT)
148 // MS-DOS read-only attribute
149 | ((mode & 0200) == 0 ? 1 : 0)
150 // MS-DOS directory flag
151 | (isDirectory() ? 0x10 : 0));
152 // CheckStyle:MagicNumberCheck ON
153 platform = PLATFORM_UNIX;
154 }
155
156 /**
157 * Unix permission.
158 * @return the unix permissions
159 * @since Ant 1.6
160 */
161 public int getUnixMode() {
162 return platform != PLATFORM_UNIX ? 0 :
163 (int) ((getExternalAttributes() >> SHORT_SHIFT) & SHORT_MASK);
164 }
165
166 /**
167 * Platform specification to put into the &quot;version made
168 * by&quot; part of the central file header.
169 *
170 * @return PLATFORM_FAT unless {@link #setUnixMode setUnixMode}
171 * has been called, in which case PLATORM_UNIX will be returned.
172 *
173 * @since Ant 1.5.2
174 */
175 public int getPlatform() {
176 return platform;
177 }
178
179 /**
180 * Set the platform (UNIX or FAT).
181 * @param platform an <code>int</code> value - 0 is FAT, 3 is UNIX
182 * @since 1.9
183 */
184 protected void setPlatform(int platform) {
185 this.platform = platform;
186 }
187
188 /**
189 * Replaces all currently attached extra fields with the new array.
190 * @param fields an array of extra fields
191 * @since 1.1
192 */
193 public void setExtraFields(ZipExtraField[] fields) {
194 extraFields = new Vector();
195 for (int i = 0; i < fields.length; i++) {
196 extraFields.addElement(fields[i]);
Torsten Curdtca165392008-07-10 10:17:44 +0000197 }
198 setExtra();
199 }
200
201 /**
Torsten Curdtab9ebfc2009-01-12 11:15:34 +0000202 * Retrieves extra fields.
203 * @return an array of the extra fields
Torsten Curdtca165392008-07-10 10:17:44 +0000204 * @since 1.1
205 */
Torsten Curdtab9ebfc2009-01-12 11:15:34 +0000206 public ZipExtraField[] getExtraFields() {
207 if (extraFields == null) {
208 return new ZipExtraField[0];
Torsten Curdtca165392008-07-10 10:17:44 +0000209 }
Torsten Curdtab9ebfc2009-01-12 11:15:34 +0000210 ZipExtraField[] result = new ZipExtraField[extraFields.size()];
211 extraFields.copyInto(result);
212 return result;
213 }
Torsten Curdtca165392008-07-10 10:17:44 +0000214
Torsten Curdtab9ebfc2009-01-12 11:15:34 +0000215 /**
216 * Adds an extra fields - replacing an already present extra field
217 * of the same type.
218 * @param ze an extra field
219 * @since 1.1
220 */
221 public void addExtraField(ZipExtraField ze) {
222 if (extraFields == null) {
223 extraFields = new Vector();
224 }
225 ZipShort type = ze.getHeaderId();
226 boolean done = false;
227 for (int i = 0, fieldsSize = extraFields.size(); !done && i < fieldsSize; i++) {
228 if (((ZipExtraField) extraFields.elementAt(i)).getHeaderId().equals(type)) {
229 extraFields.setElementAt(ze, i);
230 done = true;
231 }
232 }
233 if (!done) {
234 extraFields.addElement(ze);
235 }
236 setExtra();
Torsten Curdtca165392008-07-10 10:17:44 +0000237 }
238
239 /**
240 * Remove an extra fields.
Torsten Curdtab9ebfc2009-01-12 11:15:34 +0000241 * @param type the type of extra field to remove
Torsten Curdtca165392008-07-10 10:17:44 +0000242 * @since 1.1
243 */
Torsten Curdtab9ebfc2009-01-12 11:15:34 +0000244 public void removeExtraField(ZipShort type) {
245 if (extraFields == null) {
246 extraFields = new Vector();
247 }
Torsten Curdtca165392008-07-10 10:17:44 +0000248 boolean done = false;
Torsten Curdtab9ebfc2009-01-12 11:15:34 +0000249 for (int i = 0, fieldsSize = extraFields.size(); !done && i < fieldsSize; i++) {
250 if (((ZipExtraField) extraFields.elementAt(i)).getHeaderId().equals(type)) {
251 extraFields.removeElementAt(i);
Torsten Curdtca165392008-07-10 10:17:44 +0000252 done = true;
253 }
254 }
Torsten Curdtab9ebfc2009-01-12 11:15:34 +0000255 if (!done) {
Torsten Curdtca165392008-07-10 10:17:44 +0000256 throw new java.util.NoSuchElementException();
257 }
258 setExtra();
259 }
260
261 /**
Torsten Curdtab9ebfc2009-01-12 11:15:34 +0000262 * Throws an Exception if extra data cannot be parsed into extra fields.
263 * @param extra an array of bytes to be parsed into extra fields
264 * @throws RuntimeException if the bytes cannot be parsed
265 * @since 1.1
266 * @throws RuntimeException on error
267 */
268 public void setExtra(byte[] extra) throws RuntimeException {
269 try {
270 setExtraFields(ExtraFieldUtils.parse(extra));
271 } catch (Exception e) {
272 throw new RuntimeException(e.getMessage());
273 }
274 }
275
276 /**
Torsten Curdtca165392008-07-10 10:17:44 +0000277 * Unfortunately {@link java.util.zip.ZipOutputStream
Torsten Curdtab9ebfc2009-01-12 11:15:34 +0000278 * java.util.zip.ZipOutputStream} seems to access the extra data
279 * directly, so overriding getExtra doesn't help - we need to
280 * modify super's data directly.
Torsten Curdtca165392008-07-10 10:17:44 +0000281 *
282 * @since 1.1
283 */
Torsten Curdtab9ebfc2009-01-12 11:15:34 +0000284 protected void setExtra() {
285 super.setExtra(ExtraFieldUtils.mergeLocalFileDataData(getExtraFields()));
Torsten Curdtca165392008-07-10 10:17:44 +0000286 }
Torsten Curdtab9ebfc2009-01-12 11:15:34 +0000287
288 /**
289 * Retrieves the extra data for the local file data.
290 * @return the extra data for local file
291 * @since 1.1
292 */
293 public byte[] getLocalFileDataExtra() {
294 byte[] extra = getExtra();
295 return extra != null ? extra : new byte[0];
296 }
297
298 /**
299 * Retrieves the extra data for the central directory.
300 * @return the central directory extra data
301 * @since 1.1
302 */
303 public byte[] getCentralDirectoryExtra() {
304 return ExtraFieldUtils.mergeCentralDirectoryData(getExtraFields());
305 }
306
307 /**
308 * Make this class work in JDK 1.1 like a 1.2 class.
309 *
310 * <p>This either stores the size for later usage or invokes
311 * setCompressedSize via reflection.</p>
312 * @param size the size to use
313 * @deprecated since 1.7.
314 * Use setCompressedSize directly.
315 * @since 1.2
316 */
317 public void setComprSize(long size) {
318 setCompressedSize(size);
319 }
320
321 /**
322 * Get the name of the entry.
323 * @return the entry name
324 * @since 1.9
325 */
326 public String getName() {
327 return name == null ? super.getName() : name;
328 }
329
330 /**
331 * Is this entry a directory?
332 * @return true if the entry is a directory
333 * @since 1.10
334 */
335 public boolean isDirectory() {
336 return getName().endsWith("/");
337 }
338
339 /**
340 * Set the name of the entry.
341 * @param name the name to use
342 */
343 protected void setName(String name) {
344 this.name = name;
345 }
346
347 /**
348 * Get the hashCode of the entry.
349 * This uses the name as the hashcode.
350 * @return a hashcode.
351 * @since Ant 1.7
352 */
353 public int hashCode() {
354 // this method has severe consequences on performance. We cannot rely
355 // on the super.hashCode() method since super.getName() always return
356 // the empty string in the current implemention (there's no setter)
357 // so it is basically draining the performance of a hashmap lookup
358 return getName().hashCode();
359 }
360
361 /**
362 * The equality method. In this case, the implementation returns 'this == o'
363 * which is basically the equals method of the Object class.
364 * @param o the object to compare to
365 * @return true if this object is the same as <code>o</code>
366 * @since Ant 1.7
367 */
368 public boolean equals(Object o) {
369 return (this == o);
370 }
371
Torsten Curdtca165392008-07-10 10:17:44 +0000372}