2 * 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
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * 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.
19 package org.apache.tools.zip;
21 import java.util.Vector;
22 import java.util.zip.ZipException;
25 * Extension that adds better handling of extra fields and provides
26 * access to the internal and external file attributes.
29 public class ZipEntry extends java.util.zip.ZipEntry implements Cloneable {
31 private static final int PLATFORM_UNIX = 3;
32 private static final int PLATFORM_FAT = 0;
34 private int internalAttributes = 0;
35 private int platform = PLATFORM_FAT;
36 private long externalAttributes = 0;
37 private Vector/*<ZipExtraField>*/ extraFields = null;
38 private String name = null;
41 * Creates a new zip entry with the specified name.
42 * @param name the name of the entry
45 public ZipEntry(String name) {
50 * Creates a new zip entry with fields taken from the specified zip entry.
51 * @param entry the entry to get fields from
53 * @throws ZipException on error
55 public ZipEntry(java.util.zip.ZipEntry entry) throws ZipException {
57 byte[] extra = entry.getExtra();
59 setExtraFields(ExtraFieldUtils.parse(extra));
61 // initializes extra data to an empty byte array
67 * Creates a new zip entry with fields taken from the specified zip entry.
68 * @param entry the entry to get fields from
69 * @throws ZipException on error
72 public ZipEntry(ZipEntry entry) throws ZipException {
73 this((java.util.zip.ZipEntry) entry);
74 setInternalAttributes(entry.getInternalAttributes());
75 setExternalAttributes(entry.getExternalAttributes());
76 setExtraFields(entry.getExtraFields());
82 protected ZipEntry() {
88 * @return a cloned copy of this ZipEntry
91 public Object clone() {
92 ZipEntry e = (ZipEntry) super.clone();
94 e.extraFields = extraFields != null ? (Vector) extraFields.clone() : null;
95 e.setInternalAttributes(getInternalAttributes());
96 e.setExternalAttributes(getExternalAttributes());
97 e.setExtraFields(getExtraFields());
102 * Retrieves the internal file attributes.
104 * @return the internal file attributes
107 public int getInternalAttributes() {
108 return internalAttributes;
112 * Sets the internal file attributes.
113 * @param value an <code>int</code> value
116 public void setInternalAttributes(int value) {
117 internalAttributes = value;
121 * Retrieves the external file attributes.
122 * @return the external file attributes
125 public long getExternalAttributes() {
126 return externalAttributes;
130 * Sets the external file attributes.
131 * @param value an <code>long</code> value
134 public void setExternalAttributes(long value) {
135 externalAttributes = value;
139 * Sets Unix permissions in a way that is understood by Info-Zip's
141 * @param mode an <code>int</code> value
144 public void setUnixMode(int mode) {
145 setExternalAttributes((mode << 16)
146 // MS-DOS read-only attribute
147 | ((mode & 0200) == 0 ? 1 : 0)
148 // MS-DOS directory flag
149 | (isDirectory() ? 0x10 : 0));
150 platform = PLATFORM_UNIX;
155 * @return the unix permissions
158 public int getUnixMode() {
159 return (int) ((getExternalAttributes() >> 16) & 0xFFFF);
163 * Platform specification to put into the "version made
164 * by" part of the central file header.
166 * @return 0 (MS-DOS FAT) unless {@link #setUnixMode setUnixMode}
167 * has been called, in which case 3 (Unix) will be returned.
171 public int getPlatform() {
176 * Set the platform (UNIX or FAT).
177 * @param platform an <code>int</code> value - 0 is FAT, 3 is UNIX
180 protected void setPlatform(int platform) {
181 this.platform = platform;
185 * Replaces all currently attached extra fields with the new array.
186 * @param fields an array of extra fields
189 public void setExtraFields(ZipExtraField[] fields) {
190 extraFields = new Vector();
191 for (int i = 0; i < fields.length; i++) {
192 extraFields.addElement(fields[i]);
198 * Retrieves extra fields.
199 * @return an array of the extra fields
202 public ZipExtraField[] getExtraFields() {
203 if (extraFields == null) {
204 return new ZipExtraField[0];
206 ZipExtraField[] result = new ZipExtraField[extraFields.size()];
207 extraFields.copyInto(result);
212 * Adds an extra fields - replacing an already present extra field
214 * @param ze an extra field
217 public void addExtraField(ZipExtraField ze) {
218 if (extraFields == null) {
219 extraFields = new Vector();
221 ZipShort type = ze.getHeaderId();
222 boolean done = false;
223 for (int i = 0, fieldsSize = extraFields.size(); !done && i < fieldsSize; i++) {
224 if (((ZipExtraField) extraFields.elementAt(i)).getHeaderId().equals(type)) {
225 extraFields.setElementAt(ze, i);
230 extraFields.addElement(ze);
236 * Remove an extra fields.
237 * @param type the type of extra field to remove
240 public void removeExtraField(ZipShort type) {
241 if (extraFields == null) {
242 extraFields = new Vector();
244 boolean done = false;
245 for (int i = 0, fieldsSize = extraFields.size(); !done && i < fieldsSize; i++) {
246 if (((ZipExtraField) extraFields.elementAt(i)).getHeaderId().equals(type)) {
247 extraFields.removeElementAt(i);
252 throw new java.util.NoSuchElementException();
258 * Throws an Exception if extra data cannot be parsed into extra fields.
259 * @param extra an array of bytes to be parsed into extra fields
260 * @throws RuntimeException if the bytes cannot be parsed
262 * @throws RuntimeException on error
264 public void setExtra(byte[] extra) throws RuntimeException {
266 setExtraFields(ExtraFieldUtils.parse(extra));
267 } catch (Exception e) {
268 throw new RuntimeException(e.getMessage());
273 * Unfortunately {@link java.util.zip.ZipOutputStream
274 * java.util.zip.ZipOutputStream} seems to access the extra data
275 * directly, so overriding getExtra doesn't help - we need to
276 * modify super's data directly.
280 protected void setExtra() {
281 super.setExtra(ExtraFieldUtils.mergeLocalFileDataData(getExtraFields()));
285 * Retrieves the extra data for the local file data.
286 * @return the extra data for local file
289 public byte[] getLocalFileDataExtra() {
290 byte[] extra = getExtra();
291 return extra != null ? extra : new byte[0];
295 * Retrieves the extra data for the central directory.
296 * @return the central directory extra data
299 public byte[] getCentralDirectoryExtra() {
300 return ExtraFieldUtils.mergeCentralDirectoryData(getExtraFields());
304 * Make this class work in JDK 1.1 like a 1.2 class.
306 * <p>This either stores the size for later usage or invokes
307 * setCompressedSize via reflection.</p>
308 * @param size the size to use
309 * @deprecated since 1.7.
310 * Use setCompressedSize directly.
313 public void setComprSize(long size) {
314 setCompressedSize(size);
318 * Get the name of the entry.
319 * @return the entry name
322 public String getName() {
323 return name == null ? super.getName() : name;
327 * Is this entry a directory?
328 * @return true if the entry is a directory
331 public boolean isDirectory() {
332 return getName().endsWith("/");
336 * Set the name of the entry.
337 * @param name the name to use
339 protected void setName(String name) {
344 * Get the hashCode of the entry.
345 * This uses the name as the hashcode.
346 * @return a hashcode.
349 public int hashCode() {
350 // this method has severe consequences on performance. We cannot rely
351 // on the super.hashCode() method since super.getName() always return
352 // the empty string in the current implemention (there's no setter)
353 // so it is basically draining the performance of a hashmap lookup
354 return getName().hashCode();
358 * The equality method. In this case, the implementation returns 'this == o'
359 * which is basically the equals method of the Object class.
360 * @param o the object to compare to
361 * @return true if this object is the same as <code>o</code>
364 public boolean equals(Object o) {