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 access to
26 * 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;
33 private static final int PLATFORM_FAT = 0;
35 private int internalAttributes = 0;
37 private int platform = PLATFORM_FAT;
39 private long externalAttributes = 0;
41 private Vector/* <ZipExtraField> */extraFields = null;
43 private String name = null;
46 * Creates a new zip entry with the specified name.
49 * the name of the entry
52 public ZipEntry(String name) {
57 * Creates a new zip entry with fields taken from the specified zip entry.
60 * the entry to get fields from
62 * @throws ZipException
65 public ZipEntry(java.util.zip.ZipEntry entry) throws ZipException {
67 byte[] extra = entry.getExtra();
69 setExtraFields(ExtraFieldUtils.parse(extra));
71 // initializes extra data to an empty byte array
77 * Creates a new zip entry with fields taken from the specified zip entry.
80 * the entry to get fields from
81 * @throws ZipException
85 public ZipEntry(ZipEntry entry) throws ZipException {
86 this((java.util.zip.ZipEntry) entry);
87 setInternalAttributes(entry.getInternalAttributes());
88 setExternalAttributes(entry.getExternalAttributes());
89 setExtraFields(entry.getExtraFields());
95 protected ZipEntry() {
102 * @return a cloned copy of this ZipEntry
105 public Object clone() {
106 ZipEntry e = (ZipEntry) super.clone();
108 e.extraFields = extraFields != null ? (Vector) extraFields.clone() : null;
109 e.setInternalAttributes(getInternalAttributes());
110 e.setExternalAttributes(getExternalAttributes());
111 e.setExtraFields(getExtraFields());
116 * Retrieves the internal file attributes.
118 * @return the internal file attributes
121 public int getInternalAttributes() {
122 return internalAttributes;
126 * Sets the internal file attributes.
129 * an <code>int</code> value
132 public void setInternalAttributes(int value) {
133 internalAttributes = value;
137 * Retrieves the external file attributes.
139 * @return the external file attributes
142 public long getExternalAttributes() {
143 return externalAttributes;
147 * Sets the external file attributes.
150 * an <code>long</code> value
153 public void setExternalAttributes(long value) {
154 externalAttributes = value;
158 * Sets Unix permissions in a way that is understood by Info-Zip's unzip
162 * an <code>int</code> value
165 public void setUnixMode(int mode) {
166 setExternalAttributes((mode << 16)
167 // MS-DOS read-only attribute
168 | ((mode & 0200) == 0 ? 1 : 0)
169 // MS-DOS directory flag
170 | (isDirectory() ? 0x10 : 0));
171 platform = PLATFORM_UNIX;
177 * @return the unix permissions
180 public int getUnixMode() {
181 return (int) ((getExternalAttributes() >> 16) & 0xFFFF);
185 * Platform specification to put into the "version made by" part of
186 * the central file header.
188 * @return 0 (MS-DOS FAT) unless {@link #setUnixMode setUnixMode} has been
189 * called, in which case 3 (Unix) will be returned.
193 public int getPlatform() {
198 * Set the platform (UNIX or FAT).
201 * an <code>int</code> value - 0 is FAT, 3 is UNIX
204 protected void setPlatform(int platform) {
205 this.platform = platform;
209 * Replaces all currently attached extra fields with the new array.
212 * an array of extra fields
215 public void setExtraFields(ZipExtraField[] fields) {
216 extraFields = new Vector();
217 for (int i = 0; i < fields.length; i++) {
218 extraFields.addElement(fields[i]);
224 * Retrieves extra fields.
226 * @return an array of the extra fields
229 public ZipExtraField[] getExtraFields() {
230 if (extraFields == null) {
231 return new ZipExtraField[0];
233 ZipExtraField[] result = new ZipExtraField[extraFields.size()];
234 extraFields.copyInto(result);
239 * Adds an extra fields - replacing an already present extra field of the same
246 public void addExtraField(ZipExtraField ze) {
247 if (extraFields == null) {
248 extraFields = new Vector();
250 ZipShort type = ze.getHeaderId();
251 boolean done = false;
252 for (int i = 0, fieldsSize = extraFields.size(); !done && i < fieldsSize; i++) {
253 if (((ZipExtraField) extraFields.elementAt(i)).getHeaderId().equals(type)) {
254 extraFields.setElementAt(ze, i);
259 extraFields.addElement(ze);
265 * Remove an extra fields.
268 * the type of extra field to remove
271 public void removeExtraField(ZipShort type) {
272 if (extraFields == null) {
273 extraFields = new Vector();
275 boolean done = false;
276 for (int i = 0, fieldsSize = extraFields.size(); !done && i < fieldsSize; i++) {
277 if (((ZipExtraField) extraFields.elementAt(i)).getHeaderId().equals(type)) {
278 extraFields.removeElementAt(i);
283 throw new java.util.NoSuchElementException();
289 * Throws an Exception if extra data cannot be parsed into extra fields.
292 * an array of bytes to be parsed into extra fields
293 * @throws RuntimeException
294 * if the bytes cannot be parsed
296 * @throws RuntimeException
299 public void setExtra(byte[] extra) throws RuntimeException {
301 setExtraFields(ExtraFieldUtils.parse(extra));
302 } catch (Exception e) {
303 throw new RuntimeException(e.getMessage());
308 * Unfortunately {@link java.util.zip.ZipOutputStream
309 * java.util.zip.ZipOutputStream} seems to access the extra data directly, so
310 * overriding getExtra doesn't help - we need to modify super's data directly.
314 protected void setExtra() {
315 super.setExtra(ExtraFieldUtils.mergeLocalFileDataData(getExtraFields()));
319 * Retrieves the extra data for the local file data.
321 * @return the extra data for local file
324 public byte[] getLocalFileDataExtra() {
325 byte[] extra = getExtra();
326 return extra != null ? extra : new byte[0];
330 * Retrieves the extra data for the central directory.
332 * @return the central directory extra data
335 public byte[] getCentralDirectoryExtra() {
336 return ExtraFieldUtils.mergeCentralDirectoryData(getExtraFields());
340 * Make this class work in JDK 1.1 like a 1.2 class.
343 * This either stores the size for later usage or invokes setCompressedSize
349 * @deprecated since 1.7. Use setCompressedSize directly.
352 public void setComprSize(long size) {
353 setCompressedSize(size);
357 * Get the name of the entry.
359 * @return the entry name
362 public String getName() {
363 return name == null ? super.getName() : name;
367 * Is this entry a directory?
369 * @return true if the entry is a directory
372 public boolean isDirectory() {
373 return getName().endsWith("/");
377 * Set the name of the entry.
382 protected void setName(String name) {
387 * Get the hashCode of the entry. This uses the name as the hashcode.
389 * @return a hashcode.
392 public int hashCode() {
393 // this method has severe consequences on performance. We cannot rely
394 // on the super.hashCode() method since super.getName() always return
395 // the empty string in the current implemention (there's no setter)
396 // so it is basically draining the performance of a hashmap lookup
397 return getName().hashCode();
401 * The equality method. In this case, the implementation returns 'this == o'
402 * which is basically the equals method of the Object class.
405 * the object to compare to
406 * @return true if this object is the same as <code>o</code>
409 public boolean equals(Object o) {