/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */
package org.apache.commons.compress.archivers.zip;

import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.EntryStreamOffsets;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.zip.ZipException;

Extension that adds better handling of extra fields and provides access to the internal and external file attributes.

The extra data is expected to follow the recommendation of APPNOTE.TXT:

  • the extra byte array consists of a sequence of extra fields
  • each extra fields starts by a two byte header id followed by a two byte sequence holding the length of the remainder of data.

Any extra data that cannot be parsed by the rules above will be consumed as "unparseable" extra data and treated differently by the methods of this class. Versions prior to Apache Commons Compress 1.1 would have thrown an exception if any attempt was made to read or write extra data not conforming to the recommendation.

@NotThreadSafe
/** * Extension that adds better handling of extra fields and provides * access to the internal and external file attributes. * * <p>The extra data is expected to follow the recommendation of * <a href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">APPNOTE.TXT</a>:</p> * <ul> * <li>the extra byte array consists of a sequence of extra fields</li> * <li>each extra fields starts by a two byte header id followed by * a two byte sequence holding the length of the remainder of * data.</li> * </ul> * * <p>Any extra data that cannot be parsed by the rules above will be * consumed as "unparseable" extra data and treated differently by the * methods of this class. Versions prior to Apache Commons Compress * 1.1 would have thrown an exception if any attempt was made to read * or write extra data not conforming to the recommendation.</p> * * @NotThreadSafe */
public class ZipArchiveEntry extends java.util.zip.ZipEntry implements ArchiveEntry, EntryStreamOffsets { public static final int PLATFORM_UNIX = 3; public static final int PLATFORM_FAT = 0; public static final int CRC_UNKNOWN = -1; private static final int SHORT_MASK = 0xFFFF; private static final int SHORT_SHIFT = 16; private static final byte[] EMPTY = new byte[0];
Indicates how the name of this entry has been determined.
Since:1.16
/** * Indicates how the name of this entry has been determined. * @since 1.16 */
public enum NameSource {
The name has been read from the archive using the encoding of the archive specified when creating the ZipArchiveInputStream or ZipFile (defaults to the platform's default encoding).
/** * The name has been read from the archive using the encoding * of the archive specified when creating the {@link * ZipArchiveInputStream} or {@link ZipFile} (defaults to the * platform's default encoding). */
NAME,
The name has been read from the archive and the archive specified the EFS flag which indicates the name has been encoded as UTF-8.
/** * The name has been read from the archive and the archive * specified the EFS flag which indicates the name has been * encoded as UTF-8. */
NAME_WITH_EFS_FLAG,
The name has been read from an Unicode Extra Field.
/** * The name has been read from an {@link UnicodePathExtraField * Unicode Extra Field}. */
UNICODE_EXTRA_FIELD }
Indicates how the comment of this entry has been determined.
Since:1.16
/** * Indicates how the comment of this entry has been determined. * @since 1.16 */
public enum CommentSource {
The comment has been read from the archive using the encoding of the archive specified when creating the ZipArchiveInputStream or ZipFile (defaults to the platform's default encoding).
/** * The comment has been read from the archive using the encoding * of the archive specified when creating the {@link * ZipArchiveInputStream} or {@link ZipFile} (defaults to the * platform's default encoding). */
COMMENT,
The comment has been read from an Unicode Extra Field.
/** * The comment has been read from an {@link UnicodeCommentExtraField * Unicode Extra Field}. */
UNICODE_EXTRA_FIELD }
The ZipEntry base class only supports the compression methods STORED and DEFLATED. We override the field so that any compression methods can be used.

The default value -1 means that the method has not been specified.

See Also:
/** * The {@link java.util.zip.ZipEntry} base class only supports * the compression methods STORED and DEFLATED. We override the * field so that any compression methods can be used. * <p> * The default value -1 means that the method has not been specified. * * @see <a href="https://issues.apache.org/jira/browse/COMPRESS-93" * >COMPRESS-93</a> */
private int method = ZipMethod.UNKNOWN_CODE;
The ZipEntry.setSize method in the base class throws an IllegalArgumentException if the size is bigger than 2GB for Java versions < 7 and even in Java 7+ if the implementation in java.util.zip doesn't support Zip64 itself (it is an optional feature).

We need to keep our own size information for Zip64 support.

/** * The {@link java.util.zip.ZipEntry#setSize} method in the base * class throws an IllegalArgumentException if the size is bigger * than 2GB for Java versions &lt; 7 and even in Java 7+ if the * implementation in java.util.zip doesn't support Zip64 itself * (it is an optional feature). * * <p>We need to keep our own size information for Zip64 support.</p> */
private long size = SIZE_UNKNOWN; private int internalAttributes = 0; private int versionRequired; private int versionMadeBy; private int platform = PLATFORM_FAT; private int rawFlag; private long externalAttributes = 0; private int alignment = 0; private ZipExtraField[] extraFields; private UnparseableExtraFieldData unparseableExtra = null; private String name = null; private byte[] rawName = null; private GeneralPurposeBit gpb = new GeneralPurposeBit(); private static final ZipExtraField[] noExtraFields = new ZipExtraField[0]; private long localHeaderOffset = OFFSET_UNKNOWN; private long dataOffset = OFFSET_UNKNOWN; private boolean isStreamContiguous = false; private NameSource nameSource = NameSource.NAME; private CommentSource commentSource = CommentSource.COMMENT;
Creates a new zip entry with the specified name.

Assumes the entry represents a directory if and only if the name ends with a forward slash "/".

Params:
  • name – the name of the entry
/** * Creates a new zip entry with the specified name. * * <p>Assumes the entry represents a directory if and only if the * name ends with a forward slash "/".</p> * * @param name the name of the entry */
public ZipArchiveEntry(final String name) { super(name); setName(name); }
Creates a new zip entry with fields taken from the specified zip entry.

Assumes the entry represents a directory if and only if the name ends with a forward slash "/".

Params:
  • entry – the entry to get fields from
Throws:
/** * Creates a new zip entry with fields taken from the specified zip entry. * * <p>Assumes the entry represents a directory if and only if the * name ends with a forward slash "/".</p> * * @param entry the entry to get fields from * @throws ZipException on error */
public ZipArchiveEntry(final java.util.zip.ZipEntry entry) throws ZipException { super(entry); setName(entry.getName()); final byte[] extra = entry.getExtra(); if (extra != null) { setExtraFields(ExtraFieldUtils.parse(extra, true, ExtraFieldUtils .UnparseableExtraField.READ)); } else { // initializes extra data to an empty byte array setExtra(); } setMethod(entry.getMethod()); this.size = entry.getSize(); }
Creates a new zip entry with fields taken from the specified zip entry.

Assumes the entry represents a directory if and only if the name ends with a forward slash "/".

Params:
  • entry – the entry to get fields from
Throws:
/** * Creates a new zip entry with fields taken from the specified zip entry. * * <p>Assumes the entry represents a directory if and only if the * name ends with a forward slash "/".</p> * * @param entry the entry to get fields from * @throws ZipException on error */
public ZipArchiveEntry(final ZipArchiveEntry entry) throws ZipException { this((java.util.zip.ZipEntry) entry); setInternalAttributes(entry.getInternalAttributes()); setExternalAttributes(entry.getExternalAttributes()); setExtraFields(getAllExtraFieldsNoCopy()); setPlatform(entry.getPlatform()); final GeneralPurposeBit other = entry.getGeneralPurposeBit(); setGeneralPurposeBit(other == null ? null : (GeneralPurposeBit) other.clone()); } /** */ protected ZipArchiveEntry() { this(""); }
Creates a new zip entry taking some information from the given file and using the provided name.

The name will be adjusted to end with a forward slash "/" if the file is a directory. If the file is not a directory a potential trailing forward slash will be stripped from the entry name.

Params:
  • inputFile – file to create the entry from
  • entryName – name of the entry
/** * Creates a new zip entry taking some information from the given * file and using the provided name. * * <p>The name will be adjusted to end with a forward slash "/" if * the file is a directory. If the file is not a directory a * potential trailing forward slash will be stripped from the * entry name.</p> * @param inputFile file to create the entry from * @param entryName name of the entry */
public ZipArchiveEntry(final File inputFile, final String entryName) { this(inputFile.isDirectory() && !entryName.endsWith("/") ? entryName + "/" : entryName); if (inputFile.isFile()){ setSize(inputFile.length()); } setTime(inputFile.lastModified()); // TODO are there any other fields we can set here? }
Overwrite clone.
Returns:a cloned copy of this ZipArchiveEntry
/** * Overwrite clone. * @return a cloned copy of this ZipArchiveEntry */
@Override public Object clone() { final ZipArchiveEntry e = (ZipArchiveEntry) super.clone(); e.setInternalAttributes(getInternalAttributes()); e.setExternalAttributes(getExternalAttributes()); e.setExtraFields(getAllExtraFieldsNoCopy()); return e; }
Returns the compression method of this entry, or -1 if the compression method has not been specified.
Returns:compression method
Since:1.1
/** * Returns the compression method of this entry, or -1 if the * compression method has not been specified. * * @return compression method * * @since 1.1 */
@Override public int getMethod() { return method; }
Sets the compression method of this entry.
Params:
  • method – compression method
Since:1.1
/** * Sets the compression method of this entry. * * @param method compression method * * @since 1.1 */
@Override public void setMethod(final int method) { if (method < 0) { throw new IllegalArgumentException( "ZIP compression method can not be negative: " + method); } this.method = method; }
Retrieves the internal file attributes.

Note: ZipArchiveInputStream is unable to fill this field, you must use ZipFile if you want to read entries using this attribute.

Returns:the internal file attributes
/** * Retrieves the internal file attributes. * * <p><b>Note</b>: {@link ZipArchiveInputStream} is unable to fill * this field, you must use {@link ZipFile} if you want to read * entries using this attribute.</p> * * @return the internal file attributes */
public int getInternalAttributes() { return internalAttributes; }
Sets the internal file attributes.
Params:
  • value – an int value
/** * Sets the internal file attributes. * @param value an <code>int</code> value */
public void setInternalAttributes(final int value) { internalAttributes = value; }
Retrieves the external file attributes.

Note: ZipArchiveInputStream is unable to fill this field, you must use ZipFile if you want to read entries using this attribute.

Returns:the external file attributes
/** * Retrieves the external file attributes. * * <p><b>Note</b>: {@link ZipArchiveInputStream} is unable to fill * this field, you must use {@link ZipFile} if you want to read * entries using this attribute.</p> * * @return the external file attributes */
public long getExternalAttributes() { return externalAttributes; }
Sets the external file attributes.
Params:
  • value – an long value
/** * Sets the external file attributes. * @param value an <code>long</code> value */
public void setExternalAttributes(final long value) { externalAttributes = value; }
Sets Unix permissions in a way that is understood by Info-Zip's unzip command.
Params:
  • mode – an int value
/** * Sets Unix permissions in a way that is understood by Info-Zip's * unzip command. * @param mode an <code>int</code> value */
public void setUnixMode(final int mode) { // CheckStyle:MagicNumberCheck OFF - no point setExternalAttributes((mode << SHORT_SHIFT) // MS-DOS read-only attribute | ((mode & 0200) == 0 ? 1 : 0) // MS-DOS directory flag | (isDirectory() ? 0x10 : 0)); // CheckStyle:MagicNumberCheck ON platform = PLATFORM_UNIX; }
Unix permission.
Returns:the unix permissions
/** * Unix permission. * @return the unix permissions */
public int getUnixMode() { return platform != PLATFORM_UNIX ? 0 : (int) ((getExternalAttributes() >> SHORT_SHIFT) & SHORT_MASK); }
Returns true if this entry represents a unix symlink, in which case the entry's content contains the target path for the symlink.
Since:1.5
Returns:true if the entry represents a unix symlink, false otherwise.
/** * Returns true if this entry represents a unix symlink, * in which case the entry's content contains the target path * for the symlink. * * @since 1.5 * @return true if the entry represents a unix symlink, false otherwise. */
public boolean isUnixSymlink() { return (getUnixMode() & UnixStat.FILE_TYPE_FLAG) == UnixStat.LINK_FLAG; }
Platform specification to put into the "version made by" part of the central file header.
Returns:PLATFORM_FAT unless setUnixMode has been called, in which case PLATFORM_UNIX will be returned.
/** * Platform specification to put into the &quot;version made * by&quot; part of the central file header. * * @return PLATFORM_FAT unless {@link #setUnixMode setUnixMode} * has been called, in which case PLATFORM_UNIX will be returned. */
public int getPlatform() { return platform; }
Set the platform (UNIX or FAT).
Params:
  • platform – an int value - 0 is FAT, 3 is UNIX
/** * Set the platform (UNIX or FAT). * @param platform an <code>int</code> value - 0 is FAT, 3 is UNIX */
protected void setPlatform(final int platform) { this.platform = platform; }
Gets currently configured alignment.
Returns: alignment for this entry.
Since:1.14
/** * Gets currently configured alignment. * * @return * alignment for this entry. * @since 1.14 */
protected int getAlignment() { return this.alignment; }
Sets alignment for this entry.
Params:
  • alignment – requested alignment, 0 for default.
Since:1.14
/** * Sets alignment for this entry. * * @param alignment * requested alignment, 0 for default. * @since 1.14 */
public void setAlignment(int alignment) { if ((alignment & (alignment - 1)) != 0 || alignment > 0xffff) { throw new IllegalArgumentException("Invalid value for alignment, must be power of two and no bigger than " + 0xffff + " but is " + alignment); } this.alignment = alignment; }
Replaces all currently attached extra fields with the new array.
Params:
  • fields – an array of extra fields
/** * Replaces all currently attached extra fields with the new array. * @param fields an array of extra fields */
public void setExtraFields(final ZipExtraField[] fields) { final List<ZipExtraField> newFields = new ArrayList<>(); for (final ZipExtraField field : fields) { if (field instanceof UnparseableExtraFieldData) { unparseableExtra = (UnparseableExtraFieldData) field; } else { newFields.add( field); } } extraFields = newFields.toArray(new ZipExtraField[newFields.size()]); setExtra(); }
Retrieves all extra fields that have been parsed successfully.

Note: The set of extra fields may be incomplete when ZipArchiveInputStream has been used as some extra fields use the central directory to store additional information.

Returns:an array of the extra fields
/** * Retrieves all extra fields that have been parsed successfully. * * <p><b>Note</b>: The set of extra fields may be incomplete when * {@link ZipArchiveInputStream} has been used as some extra * fields use the central directory to store additional * information.</p> * * @return an array of the extra fields */
public ZipExtraField[] getExtraFields() { return getParseableExtraFields(); }
Retrieves extra fields.
Params:
Returns:an array of the extra fields
Since:1.1
/** * Retrieves extra fields. * @param includeUnparseable whether to also return unparseable * extra fields as {@link UnparseableExtraFieldData} if such data * exists. * @return an array of the extra fields * * @since 1.1 */
public ZipExtraField[] getExtraFields(final boolean includeUnparseable) { return includeUnparseable ? getAllExtraFields() : getParseableExtraFields(); } private ZipExtraField[] getParseableExtraFieldsNoCopy() { if (extraFields == null) { return noExtraFields; } return extraFields; } private ZipExtraField[] getParseableExtraFields() { final ZipExtraField[] parseableExtraFields = getParseableExtraFieldsNoCopy(); return (parseableExtraFields == extraFields) ? copyOf(parseableExtraFields) : parseableExtraFields; }
Get all extra fields, including unparseable ones.
Returns:An array of all extra fields. Not necessarily a copy of internal data structures, hence private method
/** * Get all extra fields, including unparseable ones. * @return An array of all extra fields. Not necessarily a copy of internal data structures, hence private method */
private ZipExtraField[] getAllExtraFieldsNoCopy() { if (extraFields == null) { return getUnparseableOnly(); } return unparseableExtra != null ? getMergedFields() : extraFields; } private ZipExtraField[] copyOf(final ZipExtraField[] src){ return copyOf(src, src.length); } private ZipExtraField[] copyOf(final ZipExtraField[] src, final int length) { final ZipExtraField[] cpy = new ZipExtraField[length]; System.arraycopy(src, 0, cpy, 0, Math.min(src.length, length)); return cpy; } private ZipExtraField[] getMergedFields() { final ZipExtraField[] zipExtraFields = copyOf(extraFields, extraFields.length + 1); zipExtraFields[extraFields.length] = unparseableExtra; return zipExtraFields; } private ZipExtraField[] getUnparseableOnly() { return unparseableExtra == null ? noExtraFields : new ZipExtraField[] { unparseableExtra }; } private ZipExtraField[] getAllExtraFields() { final ZipExtraField[] allExtraFieldsNoCopy = getAllExtraFieldsNoCopy(); return (allExtraFieldsNoCopy == extraFields) ? copyOf( allExtraFieldsNoCopy) : allExtraFieldsNoCopy; }
Adds an extra field - replacing an already present extra field of the same type.

If no extra field of the same type exists, the field will be added as last field.

Params:
  • ze – an extra field
/** * Adds an extra field - replacing an already present extra field * of the same type. * * <p>If no extra field of the same type exists, the field will be * added as last field.</p> * @param ze an extra field */
public void addExtraField(final ZipExtraField ze) { if (ze instanceof UnparseableExtraFieldData) { unparseableExtra = (UnparseableExtraFieldData) ze; } else { if (extraFields == null) { extraFields = new ZipExtraField[]{ ze}; } else { if (getExtraField(ze.getHeaderId())!= null){ removeExtraField(ze.getHeaderId()); } final ZipExtraField[] zipExtraFields = copyOf(extraFields, extraFields.length + 1); zipExtraFields[zipExtraFields.length -1] = ze; extraFields = zipExtraFields; } } setExtra(); }
Adds an extra field - replacing an already present extra field of the same type.

The new extra field will be the first one.

Params:
  • ze – an extra field
/** * Adds an extra field - replacing an already present extra field * of the same type. * * <p>The new extra field will be the first one.</p> * @param ze an extra field */
public void addAsFirstExtraField(final ZipExtraField ze) { if (ze instanceof UnparseableExtraFieldData) { unparseableExtra = (UnparseableExtraFieldData) ze; } else { if (getExtraField(ze.getHeaderId()) != null){ removeExtraField(ze.getHeaderId()); } final ZipExtraField[] copy = extraFields; final int newLen = extraFields != null ? extraFields.length + 1: 1; extraFields = new ZipExtraField[newLen]; extraFields[0] = ze; if (copy != null){ System.arraycopy(copy, 0, extraFields, 1, extraFields.length - 1); } } setExtra(); }
Remove an extra field.
Params:
  • type – the type of extra field to remove
/** * Remove an extra field. * @param type the type of extra field to remove */
public void removeExtraField(final ZipShort type) { if (extraFields == null) { throw new java.util.NoSuchElementException(); } final List<ZipExtraField> newResult = new ArrayList<>(); for (final ZipExtraField extraField : extraFields) { if (!type.equals(extraField.getHeaderId())){ newResult.add( extraField); } } if (extraFields.length == newResult.size()) { throw new java.util.NoSuchElementException(); } extraFields = newResult.toArray(new ZipExtraField[newResult.size()]); setExtra(); }
Removes unparseable extra field data.
Since:1.1
/** * Removes unparseable extra field data. * * @since 1.1 */
public void removeUnparseableExtraFieldData() { if (unparseableExtra == null) { throw new java.util.NoSuchElementException(); } unparseableExtra = null; setExtra(); }
Looks up an extra field by its header id.
Params:
  • type – the header id
Returns:null if no such field exists.
/** * Looks up an extra field by its header id. * * @param type the header id * @return null if no such field exists. */
public ZipExtraField getExtraField(final ZipShort type) { if (extraFields != null) { for (final ZipExtraField extraField : extraFields) { if (type.equals(extraField.getHeaderId())) { return extraField; } } } return null; }
Looks up extra field data that couldn't be parsed correctly.
Returns:null if no such field exists.
Since:1.1
/** * Looks up extra field data that couldn't be parsed correctly. * * @return null if no such field exists. * * @since 1.1 */
public UnparseableExtraFieldData getUnparseableExtraFieldData() { return unparseableExtra; }
Parses the given bytes as extra field data and consumes any unparseable data as an UnparseableExtraFieldData instance.
Params:
  • extra – an array of bytes to be parsed into extra fields
Throws:
/** * Parses the given bytes as extra field data and consumes any * unparseable data as an {@link UnparseableExtraFieldData} * instance. * @param extra an array of bytes to be parsed into extra fields * @throws RuntimeException if the bytes cannot be parsed * @throws RuntimeException on error */
@Override public void setExtra(final byte[] extra) throws RuntimeException { try { final ZipExtraField[] local = ExtraFieldUtils.parse(extra, true, ExtraFieldUtils.UnparseableExtraField.READ); mergeExtraFields(local, true); } catch (final ZipException e) { // actually this is not possible as of Commons Compress 1.1 throw new RuntimeException("Error parsing extra fields for entry: " //NOSONAR + getName() + " - " + e.getMessage(), e); } }
Unfortunately java.util.zip.ZipOutputStream seems to access the extra data directly, so overriding getExtra doesn't help - we need to modify super's data directly.
/** * Unfortunately {@link java.util.zip.ZipOutputStream * java.util.zip.ZipOutputStream} seems to access the extra data * directly, so overriding getExtra doesn't help - we need to * modify super's data directly. */
protected void setExtra() { super.setExtra(ExtraFieldUtils.mergeLocalFileDataData(getAllExtraFieldsNoCopy())); }
Sets the central directory part of extra fields.
Params:
  • b – an array of bytes to be parsed into extra fields
/** * Sets the central directory part of extra fields. * @param b an array of bytes to be parsed into extra fields */
public void setCentralDirectoryExtra(final byte[] b) { try { final ZipExtraField[] central = ExtraFieldUtils.parse(b, false, ExtraFieldUtils.UnparseableExtraField.READ); mergeExtraFields(central, false); } catch (final ZipException e) { throw new RuntimeException(e.getMessage(), e); //NOSONAR } }
Retrieves the extra data for the local file data.
Returns:the extra data for local file
/** * Retrieves the extra data for the local file data. * @return the extra data for local file */
public byte[] getLocalFileDataExtra() { final byte[] extra = getExtra(); return extra != null ? extra : EMPTY; }
Retrieves the extra data for the central directory.
Returns:the central directory extra data
/** * Retrieves the extra data for the central directory. * @return the central directory extra data */
public byte[] getCentralDirectoryExtra() { return ExtraFieldUtils.mergeCentralDirectoryData(getAllExtraFieldsNoCopy()); }
Get the name of the entry.

This method returns the raw name as it is stored inside of the archive.

Returns:the entry name
/** * Get the name of the entry. * * <p>This method returns the raw name as it is stored inside of the archive.</p> * * @return the entry name */
@Override public String getName() { return name == null ? super.getName() : name; }
Is this entry a directory?
Returns:true if the entry is a directory
/** * Is this entry a directory? * @return true if the entry is a directory */
@Override public boolean isDirectory() { return getName().endsWith("/"); }
Set the name of the entry.
Params:
  • name – the name to use
/** * Set the name of the entry. * @param name the name to use */
protected void setName(String name) { if (name != null && getPlatform() == PLATFORM_FAT && !name.contains("/")) { name = name.replace('\\', '/'); } this.name = name; }
Gets the uncompressed size of the entry data.

Note: ZipArchiveInputStream may create entries that return SIZE_UNKNOWN as long as the entry hasn't been read completely.

Returns:the entry size
/** * Gets the uncompressed size of the entry data. * * <p><b>Note</b>: {@link ZipArchiveInputStream} may create * entries that return {@link #SIZE_UNKNOWN SIZE_UNKNOWN} as long * as the entry hasn't been read completely.</p> * * @return the entry size */
@Override public long getSize() { return size; }
Sets the uncompressed size of the entry data.
Params:
  • size – the uncompressed size in bytes
Throws:
/** * Sets the uncompressed size of the entry data. * @param size the uncompressed size in bytes * @throws IllegalArgumentException if the specified size is less * than 0 */
@Override public void setSize(final long size) { if (size < 0) { throw new IllegalArgumentException("invalid entry size"); } this.size = size; }
Sets the name using the raw bytes and the string created from it by guessing or using the configured encoding.
Params:
  • name – the name to use created from the raw bytes using the guessed or configured encoding
  • rawName – the bytes originally read as name from the archive
Since:1.2
/** * Sets the name using the raw bytes and the string created from * it by guessing or using the configured encoding. * @param name the name to use created from the raw bytes using * the guessed or configured encoding * @param rawName the bytes originally read as name from the * archive * @since 1.2 */
protected void setName(final String name, final byte[] rawName) { setName(name); this.rawName = rawName; }
Returns the raw bytes that made up the name before it has been converted using the configured or guessed encoding.

This method will return null if this instance has not been read from an archive.

Returns:the raw name bytes
Since:1.2
/** * Returns the raw bytes that made up the name before it has been * converted using the configured or guessed encoding. * * <p>This method will return null if this instance has not been * read from an archive.</p> * * @return the raw name bytes * @since 1.2 */
public byte[] getRawName() { if (rawName != null) { final byte[] b = new byte[rawName.length]; System.arraycopy(rawName, 0, b, 0, rawName.length); return b; } return null; } protected long getLocalHeaderOffset() { return this.localHeaderOffset; } protected void setLocalHeaderOffset(long localHeaderOffset) { this.localHeaderOffset = localHeaderOffset; } @Override public long getDataOffset() { return dataOffset; }
Sets the data offset.
Params:
  • dataOffset – new value of data offset.
/** * Sets the data offset. * * @param dataOffset * new value of data offset. */
protected void setDataOffset(long dataOffset) { this.dataOffset = dataOffset; } @Override public boolean isStreamContiguous() { return isStreamContiguous; } protected void setStreamContiguous(boolean isStreamContiguous) { this.isStreamContiguous = isStreamContiguous; }
Get the hashCode of the entry. This uses the name as the hashcode.
Returns:a hashcode.
/** * Get the hashCode of the entry. * This uses the name as the hashcode. * @return a hashcode. */
@Override public int hashCode() { // this method has severe consequences on performance. We cannot rely // on the super.hashCode() method since super.getName() always return // the empty string in the current implemention (there's no setter) // so it is basically draining the performance of a hashmap lookup return getName().hashCode(); }
The "general purpose bit" field.
Returns:the general purpose bit
Since:1.1
/** * The "general purpose bit" field. * @return the general purpose bit * @since 1.1 */
public GeneralPurposeBit getGeneralPurposeBit() { return gpb; }
The "general purpose bit" field.
Params:
  • b – the general purpose bit
Since:1.1
/** * The "general purpose bit" field. * @param b the general purpose bit * @since 1.1 */
public void setGeneralPurposeBit(final GeneralPurposeBit b) { gpb = b; }
If there are no extra fields, use the given fields as new extra data - otherwise merge the fields assuming the existing fields and the new fields stem from different locations inside the archive.
Params:
  • f – the extra fields to merge
  • local – whether the new fields originate from local data
/** * If there are no extra fields, use the given fields as new extra * data - otherwise merge the fields assuming the existing fields * and the new fields stem from different locations inside the * archive. * @param f the extra fields to merge * @param local whether the new fields originate from local data */
private void mergeExtraFields(final ZipExtraField[] f, final boolean local) throws ZipException { if (extraFields == null) { setExtraFields(f); } else { for (final ZipExtraField element : f) { ZipExtraField existing; if (element instanceof UnparseableExtraFieldData) { existing = unparseableExtra; } else { existing = getExtraField(element.getHeaderId()); } if (existing == null) { addExtraField(element); } else { if (local) { final byte[] b = element.getLocalFileDataData(); existing.parseFromLocalFileData(b, 0, b.length); } else { final byte[] b = element.getCentralDirectoryData(); existing.parseFromCentralDirectoryData(b, 0, b.length); } } } setExtra(); } }
Wraps ZipEntry.getTime with a Date as the entry's last modified date.

Changes to the implementation of ZipEntry.getTime leak through and the returned value may depend on your local time zone as well as your version of Java.

/** * Wraps {@link java.util.zip.ZipEntry#getTime} with a {@link Date} as the * entry's last modified date. * * <p>Changes to the implementation of {@link java.util.zip.ZipEntry#getTime} * leak through and the returned value may depend on your local * time zone as well as your version of Java.</p> */
@Override public Date getLastModifiedDate() { return new Date(getTime()); } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(final Object obj) { if (this == obj) { return true; } if (obj == null || getClass() != obj.getClass()) { return false; } final ZipArchiveEntry other = (ZipArchiveEntry) obj; final String myName = getName(); final String otherName = other.getName(); if (myName == null) { if (otherName != null) { return false; } } else if (!myName.equals(otherName)) { return false; } String myComment = getComment(); String otherComment = other.getComment(); if (myComment == null) { myComment = ""; } if (otherComment == null) { otherComment = ""; } return getTime() == other.getTime() && myComment.equals(otherComment) && getInternalAttributes() == other.getInternalAttributes() && getPlatform() == other.getPlatform() && getExternalAttributes() == other.getExternalAttributes() && getMethod() == other.getMethod() && getSize() == other.getSize() && getCrc() == other.getCrc() && getCompressedSize() == other.getCompressedSize() && Arrays.equals(getCentralDirectoryExtra(), other.getCentralDirectoryExtra()) && Arrays.equals(getLocalFileDataExtra(), other.getLocalFileDataExtra()) && localHeaderOffset == other.localHeaderOffset && dataOffset == other.dataOffset && gpb.equals(other.gpb); }
Sets the "version made by" field.
Params:
  • versionMadeBy – "version made by" field
Since:1.11
/** * Sets the "version made by" field. * @param versionMadeBy "version made by" field * @since 1.11 */
public void setVersionMadeBy(final int versionMadeBy) { this.versionMadeBy = versionMadeBy; }
Sets the "version required to expand" field.
Params:
  • versionRequired – "version required to expand" field
Since:1.11
/** * Sets the "version required to expand" field. * @param versionRequired "version required to expand" field * @since 1.11 */
public void setVersionRequired(final int versionRequired) { this.versionRequired = versionRequired; }
The "version required to expand" field.
Returns:"version required to expand" field
Since:1.11
/** * The "version required to expand" field. * @return "version required to expand" field * @since 1.11 */
public int getVersionRequired() { return versionRequired; }
The "version made by" field.
Returns:"version made by" field
Since:1.11
/** * The "version made by" field. * @return "version made by" field * @since 1.11 */
public int getVersionMadeBy() { return versionMadeBy; }
The content of the flags field.
Returns:content of the flags field
Since:1.11
/** * The content of the flags field. * @return content of the flags field * @since 1.11 */
public int getRawFlag() { return rawFlag; }
Sets the content of the flags field.
Params:
  • rawFlag – content of the flags field
Since:1.11
/** * Sets the content of the flags field. * @param rawFlag content of the flags field * @since 1.11 */
public void setRawFlag(final int rawFlag) { this.rawFlag = rawFlag; }
The source of the name field value.
Returns:source of the name field value
Since:1.16
/** * The source of the name field value. * @return source of the name field value * @since 1.16 */
public NameSource getNameSource() { return nameSource; }
Sets the source of the name field value.
Params:
  • nameSource – source of the name field value
Since:1.16
/** * Sets the source of the name field value. * @param nameSource source of the name field value * @since 1.16 */
public void setNameSource(NameSource nameSource) { this.nameSource = nameSource; }
The source of the comment field value.
Returns:source of the comment field value
Since:1.16
/** * The source of the comment field value. * @return source of the comment field value * @since 1.16 */
public CommentSource getCommentSource() { return commentSource; }
Sets the source of the comment field value.
Params:
  • commentSource – source of the comment field value
Since:1.16
/** * Sets the source of the comment field value. * @param commentSource source of the comment field value * @since 1.16 */
public void setCommentSource(CommentSource commentSource) { this.commentSource = commentSource; } }