This is an automated email from the ASF dual-hosted git repository. ggregory pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-compress.git
commit ba29db349b6c60dc2ce2102e6cec8d69ea0d656e Author: Gary Gregory <garydgreg...@gmail.com> AuthorDate: Thu Nov 2 08:51:43 2023 -0400 Better parameter names - Javadoc link to Java 8 "Supported Encodings" page, not Java 5 page - Format longer lines - Javadoc - private ctor not needed --- .../commons/compress/archivers/zip/ZipFile.java | 863 +++++++++------------ 1 file changed, 375 insertions(+), 488 deletions(-) diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java b/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java index 9569ee46..ebc0d047 100644 --- a/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java +++ b/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java @@ -54,40 +54,33 @@ import org.apache.commons.compress.utils.InputStreamStatistics; /** * Replacement for {@code java.util.ZipFile}. * - * <p>This class adds support for file name encodings other than UTF-8 - * (which is required to work on ZIP files created by native ZIP tools - * and is able to skip a preamble like the one found in self - * extracting archives. Furthermore it returns instances of - * {@code org.apache.commons.compress.archivers.zip.ZipArchiveEntry} - * instead of {@code java.util.zip.ZipEntry}.</p> + * <p> + * This class adds support for file name encodings other than UTF-8 (which is required to work on ZIP files created by native ZIP tools and is able to skip a + * preamble like the one found in self extracting archives. Furthermore it returns instances of + * {@code org.apache.commons.compress.archivers.zip.ZipArchiveEntry} instead of {@code java.util.zip.ZipEntry}. + * </p> * - * <p>It doesn't extend {@code java.util.zip.ZipFile} as it would - * have to reimplement all methods anyway. Like - * {@code java.util.ZipFile}, it uses SeekableByteChannel under the - * covers and supports compressed and uncompressed entries. As of - * Apache Commons Compress 1.3 it also transparently supports Zip64 - * extensions and thus individual entries and archives larger than 4 - * GB or with more than 65536 entries.</p> + * <p> + * It doesn't extend {@code java.util.zip.ZipFile} as it would have to reimplement all methods anyway. Like {@code java.util.ZipFile}, it uses + * SeekableByteChannel under the covers and supports compressed and uncompressed entries. As of Apache Commons Compress 1.3 it also transparently supports Zip64 + * extensions and thus individual entries and archives larger than 4 GB or with more than 65536 entries. + * </p> * - * <p>The method signatures mimic the ones of - * {@code java.util.zip.ZipFile}, with a couple of exceptions: + * <p> + * The method signatures mimic the ones of {@code java.util.zip.ZipFile}, with a couple of exceptions: * * <ul> - * <li>There is no getName method.</li> - * <li>entries has been renamed to getEntries.</li> - * <li>getEntries and getEntry return - * {@code org.apache.commons.compress.archivers.zip.ZipArchiveEntry} - * instances.</li> - * <li>close is allowed to throw IOException.</li> + * <li>There is no getName method.</li> + * <li>entries has been renamed to getEntries.</li> + * <li>getEntries and getEntry return {@code org.apache.commons.compress.archivers.zip.ZipArchiveEntry} instances.</li> + * <li>close is allowed to throw IOException.</li> * </ul> */ public class ZipFile implements Closeable { /** - * Lock-free implementation of BoundedInputStream. The - * implementation uses positioned reads on the underlying archive - * file channel and therefore performs significantly faster in - * concurrent environment. + * Lock-free implementation of BoundedInputStream. The implementation uses positioned reads on the underlying archive file channel and therefore performs + * significantly faster in concurrent environment. */ private static class BoundedFileChannelInputStream extends BoundedArchiveInputStream { private final FileChannel archive; @@ -104,43 +97,39 @@ public class ZipFile implements Closeable { return read; } } + /** * Extends ZipArchiveEntry to store the offset within the archive. */ private static final class Entry extends ZipArchiveEntry { - Entry() { - } - @Override public boolean equals(final Object other) { if (super.equals(other)) { // super.equals would return false if other were not an Entry final Entry otherEntry = (Entry) other; - return getLocalHeaderOffset() - == otherEntry.getLocalHeaderOffset() - && super.getDataOffset() - == otherEntry.getDataOffset() - && super.getDiskNumberStart() - == otherEntry.getDiskNumberStart(); + return getLocalHeaderOffset() == otherEntry.getLocalHeaderOffset() && super.getDataOffset() == otherEntry.getDataOffset() + && super.getDiskNumberStart() == otherEntry.getDiskNumberStart(); } return false; } @Override public int hashCode() { - return 3 * super.hashCode() - + (int) getLocalHeaderOffset()+(int)(getLocalHeaderOffset()>>32); + return 3 * super.hashCode() + (int) getLocalHeaderOffset() + (int) (getLocalHeaderOffset() >> 32); } } + private static final class NameAndComment { private final byte[] name; private final byte[] comment; + private NameAndComment(final byte[] name, final byte[] comment) { this.name = name; this.comment = comment; } } + private static final class StoredStatisticsStream extends CountingInputStream implements InputStreamStatistics { StoredStatisticsStream(final InputStream in) { super(in); @@ -156,24 +145,21 @@ public class ZipFile implements Closeable { return getCompressedCount(); } } + private static final int HASH_SIZE = 509; static final int NIBLET_MASK = 0x0f; static final int BYTE_SHIFT = 8; private static final int POS_0 = 0; - private static final int POS_1 = 1; - private static final int POS_2 = 2; - private static final int POS_3 = 3; - private static final byte[] ONE_ZERO_BYTE = new byte[1]; /** - * Length of a "central directory" entry structure without file - * name, extra fields or comment. + * Length of a "central directory" entry structure without file name, extra fields or comment. */ private static final int CFH_LEN = + // @formatter:off /* version made by */ ZipConstants.SHORT /* version needed to extract */ + ZipConstants.SHORT /* general purpose bit flag */ + ZipConstants.SHORT @@ -190,16 +176,15 @@ public class ZipFile implements Closeable { /* internal file attributes */ + ZipConstants.SHORT /* external file attributes */ + ZipConstants.WORD /* relative offset of local header */ + ZipConstants.WORD; + // @formatter:on - private static final long CFH_SIG = - ZipLong.getValue(ZipArchiveOutputStream.CFH_SIG); + private static final long CFH_SIG = ZipLong.getValue(ZipArchiveOutputStream.CFH_SIG); /** - * Length of the "End of central directory record" - which is - * supposed to be the last structure of the archive - without file - * comment. + * Length of the "End of central directory record" - which is supposed to be the last structure of the archive - without file comment. */ static final int MIN_EOCD_SIZE = + // @formatter:off /* end of central dir signature */ ZipConstants.WORD /* number of this disk */ + ZipConstants.SHORT /* number of the disk with the */ @@ -213,21 +198,22 @@ public class ZipFile implements Closeable { /* directory with respect to */ /* the starting disk number */ + ZipConstants.WORD /* ZIP file comment length */ + ZipConstants.SHORT; + // @formatter:on /** - * Maximum length of the "End of central directory record" with a - * file comment. + * Maximum length of the "End of central directory record" with a file comment. */ private static final int MAX_EOCD_SIZE = MIN_EOCD_SIZE + // @formatter:off /* maximum length of ZIP file comment */ + ZipConstants.ZIP64_MAGIC_SHORT; + // @formatter:on /** - * Offset of the field that holds the location of the length of - * the central directory inside the "End of central directory - * record" relative to the start of the "End of central directory - * record". + * Offset of the field that holds the location of the length of the central directory inside the "End of central directory record" relative to the start of + * the "End of central directory record". */ private static final int CFD_LENGTH_OFFSET = + // @formatter:off /* end of central dir signature */ ZipConstants.WORD /* number of this disk */ + ZipConstants.SHORT /* number of the disk with the */ @@ -236,34 +222,37 @@ public class ZipFile implements Closeable { /* the central dir on this disk */ + ZipConstants.SHORT /* total number of entries in */ /* the central dir */ + ZipConstants.SHORT; + // @formatter:on /** - * Offset of the field that holds the disk number of the first - * central directory entry inside the "End of central directory - * record" relative to the start of the "End of central directory - * record". + * Offset of the field that holds the disk number of the first central directory entry inside the "End of central directory record" relative to the start of + * the "End of central directory record". */ private static final int CFD_DISK_OFFSET = + // @formatter:off /* end of central dir signature */ ZipConstants.WORD /* number of this disk */ + ZipConstants.SHORT; + // @formatter:on + /** - * Offset of the field that holds the location of the first - * central directory entry inside the "End of central directory - * record" relative to the "number of the disk with the start - * of the central directory". + * Offset of the field that holds the location of the first central directory entry inside the "End of central directory record" relative to the "number of + * the disk with the start of the central directory". */ private static final int CFD_LOCATOR_RELATIVE_OFFSET = + // @formatter:off /* total number of entries in */ /* the central dir on this disk */ + ZipConstants.SHORT /* total number of entries in */ /* the central dir */ + ZipConstants.SHORT /* size of the central directory */ + ZipConstants.WORD; + // @formatter:on + /** - * Length of the "Zip64 end of central directory locator" - which - * should be right in front of the "end of central directory - * record" if one is present at all. + * Length of the "Zip64 end of central directory locator" - which should be right in front of the "end of central directory record" if one is present at + * all. */ private static final int ZIP64_EOCDL_LENGTH = + // @formatter:off /* zip64 end of central dir locator sig */ ZipConstants.WORD /* number of the disk with the start */ /* start of the zip64 end of */ @@ -271,24 +260,26 @@ public class ZipFile implements Closeable { /* relative offset of the zip64 */ /* end of central directory record */ + ZipConstants.DWORD /* total number of disks */ + ZipConstants.WORD; + // @formatter:on + /** - * Offset of the field that holds the location of the "Zip64 end - * of central directory record" inside the "Zip64 end of central - * directory locator" relative to the start of the "Zip64 end of - * central directory locator". + * Offset of the field that holds the location of the "Zip64 end of central directory record" inside the "Zip64 end of central directory locator" relative + * to the start of the "Zip64 end of central directory locator". */ private static final int ZIP64_EOCDL_LOCATOR_OFFSET = + // @formatter:off /* zip64 end of central dir locator sig */ ZipConstants.WORD /* number of the disk with the start */ /* start of the zip64 end of */ /* central directory */ + ZipConstants.WORD; + // @formatter:on + /** - * Offset of the field that holds the location of the first - * central directory entry inside the "Zip64 end of central - * directory record" relative to the start of the "Zip64 end of - * central directory record". + * Offset of the field that holds the location of the first central directory entry inside the "Zip64 end of central directory record" relative to the start + * of the "Zip64 end of central directory record". */ private static final int ZIP64_EOCD_CFD_LOCATOR_OFFSET = + // @formatter:off /* zip64 end of central dir */ /* signature */ ZipConstants.WORD /* size of zip64 end of central */ @@ -303,13 +294,14 @@ public class ZipFile implements Closeable { /* total number of entries in the */ /* central directory */ + ZipConstants.DWORD /* size of the central directory */ + ZipConstants.DWORD; + // @formatter:on + /** - * Offset of the field that holds the disk number of the first - * central directory entry inside the "Zip64 end of central - * directory record" relative to the start of the "Zip64 end of - * central directory record". + * Offset of the field that holds the disk number of the first central directory entry inside the "Zip64 end of central directory record" relative to the + * start of the "Zip64 end of central directory record". */ private static final int ZIP64_EOCD_CFD_DISK_OFFSET = + // @formatter:off /* zip64 end of central dir */ /* signature */ ZipConstants.WORD /* size of zip64 end of central */ @@ -317,23 +309,26 @@ public class ZipFile implements Closeable { /* version made by */ + ZipConstants.SHORT /* version needed to extract */ + ZipConstants.SHORT /* number of this disk */ + ZipConstants.WORD; + // @formatter:on + /** - * Offset of the field that holds the location of the first - * central directory entry inside the "Zip64 end of central - * directory record" relative to the "number of the disk - * with the start of the central directory". + * Offset of the field that holds the location of the first central directory entry inside the "Zip64 end of central directory record" relative to the + * "number of the disk with the start of the central directory". */ private static final int ZIP64_EOCD_CFD_LOCATOR_RELATIVE_OFFSET = + // @formatter:off /* total number of entries in the */ /* central directory on this disk */ ZipConstants.DWORD /* total number of entries in the */ /* central directory */ + ZipConstants.DWORD /* size of the central directory */ + ZipConstants.DWORD; + // @formatter:on + /** - * Number of bytes in local file header up to the "length of - * file name" entry. + * Number of bytes in local file header up to the "length of file name" entry. */ private static final long LFH_OFFSET_FOR_FILENAME_LENGTH = + // @formatter:off /* local file header signature */ ZipConstants.WORD /* version needed to extract */ + ZipConstants.SHORT /* general purpose bit flag */ + ZipConstants.SHORT @@ -343,22 +338,23 @@ public class ZipFile implements Closeable { /* crc-32 */ + ZipConstants.WORD /* compressed size */ + ZipConstants.WORD /* uncompressed size */ + (long) ZipConstants.WORD; + // @formatter:on /** * Compares two ZipArchiveEntries based on their offset within the archive. * - * <p>Won't return any meaningful results if one of the entries - * isn't part of the archive at all.</p> + * <p> + * Won't return any meaningful results if one of the entries isn't part of the archive at all. + * </p> * * @since 1.1 */ - private static final Comparator<ZipArchiveEntry> offsetComparator = - Comparator.comparingLong(ZipArchiveEntry::getDiskNumberStart) + private static final Comparator<ZipArchiveEntry> offsetComparator = Comparator.comparingLong(ZipArchiveEntry::getDiskNumberStart) .thenComparingLong(ZipArchiveEntry::getLocalHeaderOffset); /** - * Closes a ZIP file quietly; throwing no IOException, does nothing - * on null input. + * Closes a ZIP file quietly; throwing no IOException, does nothing on null input. + * * @param zipFile file to close, can be null */ public static void closeQuietly(final ZipFile zipFile) { @@ -366,8 +362,7 @@ public class ZipFile implements Closeable { } /** - * List of entries in the order they appear inside the central - * directory. + * List of entries in the order they appear inside the central directory. */ private final List<ZipArchiveEntry> entries = new LinkedList<>(); @@ -379,9 +374,10 @@ public class ZipFile implements Closeable { /** * The encoding to use for file names and the file comment. * - * <p>For a list of possible values see <a - * href="http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html">http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html</a>. - * Defaults to UTF-8.</p> + * <p> + * For a list of possible values see <a href="Supported Encodings">https://docs.oracle.com/javase/8/docs/technotes/guides/intl/encoding.doc.html</a>. + * Defaults to UTF-8. + * </p> */ private final String encoding; @@ -450,12 +446,10 @@ public class ZipFile implements Closeable { } /** - * Opens the given file for reading, assuming the specified - * encoding for file names and scanning for Unicode extra fields. + * Opens the given file for reading, assuming the specified encoding for file names and scanning for Unicode extra fields. * - * @param f the archive. - * @param encoding the encoding to use for file names, use null - * for the platform's default encoding + * @param f the archive. + * @param encoding the encoding to use for file names, use null for the platform's default encoding * * @throws IOException if an error occurs while reading the file. */ @@ -464,49 +458,40 @@ public class ZipFile implements Closeable { } /** - * Opens the given file for reading, assuming the specified - * encoding for file names. + * Opens the given file for reading, assuming the specified encoding for file names. * - * @param f the archive. - * @param encoding the encoding to use for file names, use null - * for the platform's default encoding - * @param useUnicodeExtraFields whether to use InfoZIP Unicode - * Extra Fields (if present) to set the file names. + * @param f the archive. + * @param encoding the encoding to use for file names, use null for the platform's default encoding + * @param useUnicodeExtraFields whether to use InfoZIP Unicode Extra Fields (if present) to set the file names. * * @throws IOException if an error occurs while reading the file. */ - public ZipFile(final File f, final String encoding, final boolean useUnicodeExtraFields) - throws IOException { + public ZipFile(final File f, final String encoding, final boolean useUnicodeExtraFields) throws IOException { this(f.toPath(), encoding, useUnicodeExtraFields, false); } /** - * Opens the given file for reading, assuming the specified - * encoding for file names. + * Opens the given file for reading, assuming the specified encoding for file names. * - * <p>By default the central directory record and all local file headers of the archive will be read immediately - * which may take a considerable amount of time when the archive is big. The {@code ignoreLocalFileHeader} parameter - * can be set to {@code true} which restricts parsing to the central directory. Unfortunately the local file header - * may contain information not present inside of the central directory which will not be available when the argument - * is set to {@code true}. This includes the content of the Unicode extra field, so setting {@code - * ignoreLocalFileHeader} to {@code true} means {@code useUnicodeExtraFields} will be ignored effectively.</p> + * <p> + * By default the central directory record and all local file headers of the archive will be read immediately which may take a considerable amount of time + * when the archive is big. The {@code ignoreLocalFileHeader} parameter can be set to {@code true} which restricts parsing to the central directory. + * Unfortunately the local file header may contain information not present inside of the central directory which will not be available when the argument is + * set to {@code true}. This includes the content of the Unicode extra field, so setting {@code + * ignoreLocalFileHeader} to {@code true} means {@code useUnicodeExtraFields} will be ignored effectively. + * </p> * - * @param f the archive. - * @param encoding the encoding to use for file names, use null - * for the platform's default encoding - * @param useUnicodeExtraFields whether to use InfoZIP Unicode - * Extra Fields (if present) to set the file names. - * @param ignoreLocalFileHeader whether to ignore information - * stored inside the local file header (see the notes in this method's javadoc) + * @param f the archive. + * @param encoding the encoding to use for file names, use null for the platform's default encoding + * @param useUnicodeExtraFields whether to use InfoZIP Unicode Extra Fields (if present) to set the file names. + * @param ignoreLocalFileHeader whether to ignore information stored inside the local file header (see the notes in this method's javadoc) * * @throws IOException if an error occurs while reading the file. * @since 1.19 */ - public ZipFile(final File f, final String encoding, final boolean useUnicodeExtraFields, - final boolean ignoreLocalFileHeader) - throws IOException { - this(Files.newByteChannel(f.toPath(), EnumSet.of(StandardOpenOption.READ)), - f.getAbsolutePath(), encoding, useUnicodeExtraFields, true, ignoreLocalFileHeader); + public ZipFile(final File f, final String encoding, final boolean useUnicodeExtraFields, final boolean ignoreLocalFileHeader) throws IOException { + this(Files.newByteChannel(f.toPath(), EnumSet.of(StandardOpenOption.READ)), f.getAbsolutePath(), encoding, useUnicodeExtraFields, true, + ignoreLocalFileHeader); } /** @@ -521,12 +506,10 @@ public class ZipFile implements Closeable { } /** - * Opens the given path for reading, assuming the specified - * encoding for file names and scanning for Unicode extra fields. + * Opens the given path for reading, assuming the specified encoding for file names and scanning for Unicode extra fields. * - * @param path path to the archive. - * @param encoding the encoding to use for file names, use null - * for the platform's default encoding + * @param path path to the archive. + * @param encoding the encoding to use for file names, use null for the platform's default encoding * @throws IOException if an error occurs while reading the file. * @since 1.22 */ @@ -534,151 +517,124 @@ public class ZipFile implements Closeable { this(path, encoding, true); } - /** - * Opens the given path for reading, assuming the specified - * encoding for file names. + * Opens the given path for reading, assuming the specified encoding for file names. * - * @param path path to the archive. - * @param encoding the encoding to use for file names, use null - * for the platform's default encoding - * @param useUnicodeExtraFields whether to use InfoZIP Unicode - * Extra Fields (if present) to set the file names. + * @param path path to the archive. + * @param encoding the encoding to use for file names, use null for the platform's default encoding + * @param useUnicodeExtraFields whether to use InfoZIP Unicode Extra Fields (if present) to set the file names. * @throws IOException if an error occurs while reading the file. * @since 1.22 */ - public ZipFile(final Path path, final String encoding, final boolean useUnicodeExtraFields) - throws IOException { + public ZipFile(final Path path, final String encoding, final boolean useUnicodeExtraFields) throws IOException { this(path, encoding, useUnicodeExtraFields, false); } /** - * Opens the given path for reading, assuming the specified - * encoding for file names. - * <p>By default the central directory record and all local file headers of the archive will be read immediately - * which may take a considerable amount of time when the archive is big. The {@code ignoreLocalFileHeader} parameter - * can be set to {@code true} which restricts parsing to the central directory. Unfortunately the local file header - * may contain information not present inside of the central directory which will not be available when the argument - * is set to {@code true}. This includes the content of the Unicode extra field, so setting {@code - * ignoreLocalFileHeader} to {@code true} means {@code useUnicodeExtraFields} will be ignored effectively.</p> + * Opens the given path for reading, assuming the specified encoding for file names. + * <p> + * By default the central directory record and all local file headers of the archive will be read immediately which may take a considerable amount of time + * when the archive is big. The {@code ignoreLocalFileHeader} parameter can be set to {@code true} which restricts parsing to the central directory. + * Unfortunately the local file header may contain information not present inside of the central directory which will not be available when the argument is + * set to {@code true}. This includes the content of the Unicode extra field, so setting {@code + * ignoreLocalFileHeader} to {@code true} means {@code useUnicodeExtraFields} will be ignored effectively. + * </p> * - * @param path path to the archive. - * @param encoding the encoding to use for file names, use null - * for the platform's default encoding - * @param useUnicodeExtraFields whether to use InfoZIP Unicode - * Extra Fields (if present) to set the file names. - * @param ignoreLocalFileHeader whether to ignore information - * stored inside the local file header (see the notes in this method's javadoc) + * @param path path to the archive. + * @param encoding the encoding to use for file names, use null for the platform's default encoding + * @param useUnicodeExtraFields whether to use InfoZIP Unicode Extra Fields (if present) to set the file names. + * @param ignoreLocalFileHeader whether to ignore information stored inside the local file header (see the notes in this method's javadoc) * @throws IOException if an error occurs while reading the file. * @since 1.22 */ - public ZipFile(final Path path, final String encoding, final boolean useUnicodeExtraFields, - final boolean ignoreLocalFileHeader) - throws IOException { - this(Files.newByteChannel(path, EnumSet.of(StandardOpenOption.READ)), - path.toAbsolutePath().toString(), encoding, useUnicodeExtraFields, - true, ignoreLocalFileHeader); + public ZipFile(final Path path, final String encoding, final boolean useUnicodeExtraFields, final boolean ignoreLocalFileHeader) throws IOException { + this(Files.newByteChannel(path, EnumSet.of(StandardOpenOption.READ)), path.toAbsolutePath().toString(), encoding, useUnicodeExtraFields, true, + ignoreLocalFileHeader); } /** * Opens the given channel for reading, assuming "UTF8" for file names. * - * <p>{@link - * org.apache.commons.compress.utils.SeekableInMemoryByteChannel} - * allows you to read from an in-memory archive.</p> + * <p> + * {@link org.apache.commons.compress.utils.SeekableInMemoryByteChannel} allows you to read from an in-memory archive. + * </p> * * @param channel the archive. * * @throws IOException if an error occurs while reading the file. * @since 1.13 */ - public ZipFile(final SeekableByteChannel channel) - throws IOException { + public ZipFile(final SeekableByteChannel channel) throws IOException { this(channel, "unknown archive", ZipEncodingHelper.UTF8, true); } /** - * Opens the given channel for reading, assuming the specified - * encoding for file names. + * Opens the given channel for reading, assuming the specified encoding for file names. * - * <p>{@link - * org.apache.commons.compress.utils.SeekableInMemoryByteChannel} - * allows you to read from an in-memory archive.</p> + * <p> + * {@link org.apache.commons.compress.utils.SeekableInMemoryByteChannel} allows you to read from an in-memory archive. + * </p> * - * @param channel the archive. - * @param encoding the encoding to use for file names, use null - * for the platform's default encoding + * @param channel the archive. + * @param encoding the encoding to use for file names, use null for the platform's default encoding * * @throws IOException if an error occurs while reading the file. * @since 1.13 */ - public ZipFile(final SeekableByteChannel channel, final String encoding) - throws IOException { + public ZipFile(final SeekableByteChannel channel, final String encoding) throws IOException { this(channel, "unknown archive", encoding, true); } /** - * Opens the given channel for reading, assuming the specified - * encoding for file names. + * Opens the given channel for reading, assuming the specified encoding for file names. * - * <p>{@link - * org.apache.commons.compress.utils.SeekableInMemoryByteChannel} - * allows you to read from an in-memory archive.</p> + * <p> + * {@link org.apache.commons.compress.utils.SeekableInMemoryByteChannel} allows you to read from an in-memory archive. + * </p> * - * @param channel the archive. - * @param archiveName name of the archive, used for error messages only. - * @param encoding the encoding to use for file names, use null - * for the platform's default encoding - * @param useUnicodeExtraFields whether to use InfoZIP Unicode - * Extra Fields (if present) to set the file names. + * @param channel the archive. + * @param archiveName name of the archive, used for error messages only. + * @param encoding the encoding to use for file names, use null for the platform's default encoding + * @param useUnicodeExtraFields whether to use InfoZIP Unicode Extra Fields (if present) to set the file names. * * @throws IOException if an error occurs while reading the file. * @since 1.13 */ - public ZipFile(final SeekableByteChannel channel, final String archiveName, - final String encoding, final boolean useUnicodeExtraFields) - throws IOException { + public ZipFile(final SeekableByteChannel channel, final String archiveName, final String encoding, final boolean useUnicodeExtraFields) throws IOException { this(channel, archiveName, encoding, useUnicodeExtraFields, false, false); } /** - * Opens the given channel for reading, assuming the specified - * encoding for file names. + * Opens the given channel for reading, assuming the specified encoding for file names. * - * <p>{@link - * org.apache.commons.compress.utils.SeekableInMemoryByteChannel} - * allows you to read from an in-memory archive.</p> + * <p> + * {@link org.apache.commons.compress.utils.SeekableInMemoryByteChannel} allows you to read from an in-memory archive. + * </p> * - * <p>By default the central directory record and all local file headers of the archive will be read immediately - * which may take a considerable amount of time when the archive is big. The {@code ignoreLocalFileHeader} parameter - * can be set to {@code true} which restricts parsing to the central directory. Unfortunately the local file header - * may contain information not present inside of the central directory which will not be available when the argument - * is set to {@code true}. This includes the content of the Unicode extra field, so setting {@code - * ignoreLocalFileHeader} to {@code true} means {@code useUnicodeExtraFields} will be ignored effectively.</p> + * <p> + * By default the central directory record and all local file headers of the archive will be read immediately which may take a considerable amount of time + * when the archive is big. The {@code ignoreLocalFileHeader} parameter can be set to {@code true} which restricts parsing to the central directory. + * Unfortunately the local file header may contain information not present inside of the central directory which will not be available when the argument is + * set to {@code true}. This includes the content of the Unicode extra field, so setting {@code + * ignoreLocalFileHeader} to {@code true} means {@code useUnicodeExtraFields} will be ignored effectively. + * </p> * - * @param channel the archive. - * @param archiveName name of the archive, used for error messages only. - * @param encoding the encoding to use for file names, use null - * for the platform's default encoding - * @param useUnicodeExtraFields whether to use InfoZIP Unicode - * Extra Fields (if present) to set the file names. - * @param ignoreLocalFileHeader whether to ignore information - * stored inside the local file header (see the notes in this method's javadoc) + * @param channel the archive. + * @param archiveName name of the archive, used for error messages only. + * @param encoding the encoding to use for file names, use null for the platform's default encoding + * @param useUnicodeExtraFields whether to use InfoZIP Unicode Extra Fields (if present) to set the file names. + * @param ignoreLocalFileHeader whether to ignore information stored inside the local file header (see the notes in this method's javadoc) * * @throws IOException if an error occurs while reading the file. * @since 1.19 */ - public ZipFile(final SeekableByteChannel channel, final String archiveName, - final String encoding, final boolean useUnicodeExtraFields, - final boolean ignoreLocalFileHeader) - throws IOException { + public ZipFile(final SeekableByteChannel channel, final String archiveName, final String encoding, final boolean useUnicodeExtraFields, + final boolean ignoreLocalFileHeader) throws IOException { this(channel, archiveName, encoding, useUnicodeExtraFields, false, ignoreLocalFileHeader); } - private ZipFile(final SeekableByteChannel channel, final String archiveName, - final String encoding, final boolean useUnicodeExtraFields, - final boolean closeOnError, final boolean ignoreLocalFileHeader) - throws IOException { + private ZipFile(final SeekableByteChannel channel, final String archiveName, final String encoding, final boolean useUnicodeExtraFields, + final boolean closeOnError, final boolean ignoreLocalFileHeader) throws IOException { isSplitZipArchive = channel instanceof ZipSplitReadOnlySeekableByteChannel; this.archiveName = archiveName; @@ -688,8 +644,7 @@ public class ZipFile implements Closeable { archive = channel; boolean success = false; try { - final Map<ZipArchiveEntry, NameAndComment> entriesWithoutUTF8Flag = - populateFromCentralDirectory(); + final Map<ZipArchiveEntry, NameAndComment> entriesWithoutUTF8Flag = populateFromCentralDirectory(); if (!ignoreLocalFileHeader) { resolveLocalFileHeaderData(entriesWithoutUTF8Flag); } @@ -717,12 +672,10 @@ public class ZipFile implements Closeable { } /** - * Opens the given file for reading, assuming the specified - * encoding for file names, scanning unicode extra fields. + * Opens the given file for reading, assuming the specified encoding for file names, scanning unicode extra fields. * - * @param name name of the archive. - * @param encoding the encoding to use for file names, use null - * for the platform's default encoding + * @param name name of the archive. + * @param encoding the encoding to use for file names, use null for the platform's default encoding * * @throws IOException if an error occurs while reading the file. */ @@ -733,18 +686,21 @@ public class ZipFile implements Closeable { /** * Whether this class is able to read the given entry. * - * <p>May return false if it is set up to use encryption or a - * compression method that hasn't been implemented yet.</p> + * <p> + * May return false if it is set up to use encryption or a compression method that hasn't been implemented yet. + * </p> + * * @since 1.1 - * @param ze the entry + * @param entry the entry * @return whether this class is able to read the given entry. */ - public boolean canReadEntryData(final ZipArchiveEntry ze) { - return ZipUtil.canHandleEntryData(ze); + public boolean canReadEntryData(final ZipArchiveEntry entry) { + return ZipUtil.canHandleEntryData(entry); } /** * Closes the archive. + * * @throws IOException if an error occurs closing the archive. */ @Override @@ -753,42 +709,38 @@ public class ZipFile implements Closeable { // can never be run in parallel. // no synchronization needed. closed = true; - archive.close(); } /** - * Transfer selected entries from this ZIP file to a given #ZipArchiveOutputStream. - * Compression and all other attributes will be as in this file. - * <p>This method transfers entries based on the central directory of the ZIP file.</p> + * Transfer selected entries from this ZIP file to a given #ZipArchiveOutputStream. Compression and all other attributes will be as in this file. + * <p> + * This method transfers entries based on the central directory of the ZIP file. + * </p> * - * @param target The zipArchiveOutputStream to write the entries to + * @param target The zipArchiveOutputStream to write the entries to * @param predicate A predicate that selects which entries to write * @throws IOException on error */ - public void copyRawEntries(final ZipArchiveOutputStream target, final ZipArchiveEntryPredicate predicate) - throws IOException { + public void copyRawEntries(final ZipArchiveOutputStream target, final ZipArchiveEntryPredicate predicate) throws IOException { final Enumeration<ZipArchiveEntry> src = getEntriesInPhysicalOrder(); while (src.hasMoreElements()) { final ZipArchiveEntry entry = src.nextElement(); - if (predicate.test( entry)) { + if (predicate.test(entry)) { target.addRawArchiveEntry(entry, getRawInputStream(entry)); } } } /** - * Creates new BoundedInputStream, according to implementation of - * underlying archive channel. + * Creates new BoundedInputStream, according to implementation of underlying archive channel. */ private BoundedArchiveInputStream createBoundedInputStream(final long start, final long remaining) { if (start < 0 || remaining < 0 || start + remaining < start) { - throw new IllegalArgumentException("Corrupted archive, stream boundaries" - + " are out of range"); + throw new IllegalArgumentException("Corrupted archive, stream boundaries" + " are out of range"); } - return archive instanceof FileChannel ? - new BoundedFileChannelInputStream(start, remaining, (FileChannel) archive) : - new BoundedSeekableByteChannelInputStream(start, remaining, archive); + return archive instanceof FileChannel ? new BoundedFileChannelInputStream(start, remaining, (FileChannel) archive) + : new BoundedSeekableByteChannelInputStream(start, remaining, archive); } private void fillNameMap() { @@ -802,8 +754,8 @@ public class ZipFile implements Closeable { } /** - * Ensures that the close method of this ZIP file is called when - * there are no more references to it. + * Ensures that the close method of this ZIP file is called when there are no more references to it. + * * @see #close() */ @Override @@ -820,13 +772,12 @@ public class ZipFile implements Closeable { /** * Gets an InputStream for reading the content before the first local file header. * - * @return null if there is no content before the first local file header. - * Otherwise, returns a stream to read the content before the first local file header. + * @return null if there is no content before the first local file header. Otherwise, returns a stream to read the content before the first local file + * header. * @since 1.23 */ public InputStream getContentBeforeFirstLocalFileHeader() { - return firstLocalFileHeaderOffset == 0 - ? null : createBoundedInputStream(0, firstLocalFileHeaderOffset); + return firstLocalFileHeaderOffset == 0 ? null : createBoundedInputStream(0, firstLocalFileHeaderOffset); } private long getDataOffset(final ZipArchiveEntry ze) throws IOException { @@ -850,8 +801,9 @@ public class ZipFile implements Closeable { /** * Gets all entries. * - * <p>Entries will be returned in the same order they appear - * within the archive's central directory.</p> + * <p> + * Entries will be returned in the same order they appear within the archive's central directory. + * </p> * * @return all entries as {@link ZipArchiveEntry} instances */ @@ -860,12 +812,10 @@ public class ZipFile implements Closeable { } /** - * Gets all named entries in the same order they appear within - * the archive's central directory. + * Gets all named entries in the same order they appear within the archive's central directory. * * @param name name of the entry. - * @return the Iterable<ZipArchiveEntry> corresponding to the - * given name + * @return the Iterable<ZipArchiveEntry> corresponding to the given name * @since 1.6 */ public Iterable<ZipArchiveEntry> getEntries(final String name) { @@ -875,8 +825,9 @@ public class ZipFile implements Closeable { /** * Gets all entries in physical order. * - * <p>Entries will be returned in the same order their contents - * appear within the archive.</p> + * <p> + * Entries will be returned in the same order their contents appear within the archive. + * </p> * * @return all entries as {@link ZipArchiveEntry} instances * @@ -889,12 +840,10 @@ public class ZipFile implements Closeable { } /** - * Gets all named entries in the same order their contents - * appear within the archive. + * Gets all named entries in the same order their contents appear within the archive. * * @param name name of the entry. - * @return the Iterable<ZipArchiveEntry> corresponding to the - * given name + * @return the Iterable<ZipArchiveEntry> corresponding to the given name * @since 1.6 */ public Iterable<ZipArchiveEntry> getEntriesInPhysicalOrder(final String name) { @@ -908,16 +857,14 @@ public class ZipFile implements Closeable { } /** - * Gets a named entry or {@code null} if no entry by - * that name exists. + * Gets a named entry or {@code null} if no entry by that name exists. * - * <p>If multiple entries with the same name exist the first entry - * in the archive's central directory by that name is - * returned.</p> + * <p> + * If multiple entries with the same name exist the first entry in the archive's central directory by that name is returned. + * </p> * * @param name name of the entry. - * @return the ZipArchiveEntry corresponding to the given name - or - * {@code null} if not present. + * @return the ZipArchiveEntry corresponding to the given name - or {@code null} if not present. */ public ZipArchiveEntry getEntry(final String name) { final LinkedList<ZipArchiveEntry> entriesOfThatName = nameMap.get(name); @@ -937,108 +884,105 @@ public class ZipFile implements Closeable { /** * Gets an InputStream for reading the contents of the given entry. * - * @param zipEntry the entry to get the stream for. - * @return a stream to read the entry from. The returned stream - * implements {@link InputStreamStatistics}. + * @param entry the entry to get the stream for. + * @return a stream to read the entry from. The returned stream implements {@link InputStreamStatistics}. * @throws IOException if unable to create an input stream from the zipEntry. */ - public InputStream getInputStream(final ZipArchiveEntry zipEntry) - throws IOException { - if (!(zipEntry instanceof Entry)) { + public InputStream getInputStream(final ZipArchiveEntry entry) throws IOException { + if (!(entry instanceof Entry)) { return null; } // cast validity is checked just above - ZipUtil.checkRequestedFeatures(zipEntry); + ZipUtil.checkRequestedFeatures(entry); // doesn't get closed if the method is not supported - which // should never happen because of the checkRequestedFeatures // call above - final InputStream is = new BufferedInputStream(getRawInputStream(zipEntry)); //NOSONAR - switch (ZipMethod.getMethodByCode(zipEntry.getMethod())) { - case STORED: - return new StoredStatisticsStream(is); - case UNSHRINKING: - return new UnshrinkingInputStream(is); - case IMPLODING: - try { - return new ExplodingInputStream(zipEntry.getGeneralPurposeBit().getSlidingDictionarySize(), - zipEntry.getGeneralPurposeBit().getNumberOfShannonFanoTrees(), is); - } catch (final IllegalArgumentException ex) { - throw new IOException("bad IMPLODE data", ex); - } - case DEFLATED: - final Inflater inflater = new Inflater(true); - // Inflater with nowrap=true has this odd contract for a zero padding - // byte following the data stream; this used to be zlib's requirement - // and has been fixed a long time ago, but the contract persists so - // we comply. - // https://docs.oracle.com/javase/8/docs/api/java/util/zip/Inflater.html#Inflater(boolean) - return new InflaterInputStreamWithStatistics(new SequenceInputStream(is, new ByteArrayInputStream(ONE_ZERO_BYTE)), - inflater) { - @Override - public void close() throws IOException { - try { - super.close(); - } finally { - inflater.end(); - } + final InputStream is = new BufferedInputStream(getRawInputStream(entry)); // NOSONAR + switch (ZipMethod.getMethodByCode(entry.getMethod())) { + case STORED: + return new StoredStatisticsStream(is); + case UNSHRINKING: + return new UnshrinkingInputStream(is); + case IMPLODING: + try { + return new ExplodingInputStream(entry.getGeneralPurposeBit().getSlidingDictionarySize(), + entry.getGeneralPurposeBit().getNumberOfShannonFanoTrees(), is); + } catch (final IllegalArgumentException ex) { + throw new IOException("bad IMPLODE data", ex); + } + case DEFLATED: + final Inflater inflater = new Inflater(true); + // Inflater with nowrap=true has this odd contract for a zero padding + // byte following the data stream; this used to be zlib's requirement + // and has been fixed a long time ago, but the contract persists so + // we comply. + // https://docs.oracle.com/javase/8/docs/api/java/util/zip/Inflater.html#Inflater(boolean) + return new InflaterInputStreamWithStatistics(new SequenceInputStream(is, new ByteArrayInputStream(ONE_ZERO_BYTE)), inflater) { + @Override + public void close() throws IOException { + try { + super.close(); + } finally { + inflater.end(); } - }; - case BZIP2: - return new BZip2CompressorInputStream(is); - case ENHANCED_DEFLATED: - return new Deflate64CompressorInputStream(is); - case AES_ENCRYPTED: - case EXPANDING_LEVEL_1: - case EXPANDING_LEVEL_2: - case EXPANDING_LEVEL_3: - case EXPANDING_LEVEL_4: - case JPEG: - case LZMA: - case PKWARE_IMPLODING: - case PPMD: - case TOKENIZATION: - case UNKNOWN: - case WAVPACK: - case XZ: - default: - throw new UnsupportedZipFeatureException(ZipMethod.getMethodByCode(zipEntry.getMethod()), zipEntry); + } + }; + case BZIP2: + return new BZip2CompressorInputStream(is); + case ENHANCED_DEFLATED: + return new Deflate64CompressorInputStream(is); + case AES_ENCRYPTED: + case EXPANDING_LEVEL_1: + case EXPANDING_LEVEL_2: + case EXPANDING_LEVEL_3: + case EXPANDING_LEVEL_4: + case JPEG: + case LZMA: + case PKWARE_IMPLODING: + case PPMD: + case TOKENIZATION: + case UNKNOWN: + case WAVPACK: + case XZ: + default: + throw new UnsupportedZipFeatureException(ZipMethod.getMethodByCode(entry.getMethod()), entry); } } /** * Gets the raw stream of the archive entry (compressed form). * - * <p>This method does not relate to how/if we understand the payload in the - * stream, since we really only intend to move it on to somewhere else.</p> + * <p> + * This method does not relate to how/if we understand the payload in the stream, since we really only intend to move it on to somewhere else. + * </p> * - * <p>Since version 1.22, this method will make an attempt to read the entry's data - * stream offset, even if the {@code ignoreLocalFileHeader} parameter was {@code true} - * in the constructor. An IOException can also be thrown from the body of the method - * if this lookup fails for some reason.</p> + * <p> + * Since version 1.22, this method will make an attempt to read the entry's data stream offset, even if the {@code ignoreLocalFileHeader} parameter was + * {@code true} in the constructor. An IOException can also be thrown from the body of the method if this lookup fails for some reason. + * </p> * - * @param ze The entry to get the stream for + * @param entry The entry to get the stream for * @return The raw input stream containing (possibly) compressed data. * @since 1.11 * @throws IOException if there is a problem reading data offset (added in version 1.22). */ - public InputStream getRawInputStream(final ZipArchiveEntry ze) throws IOException { - if (!(ze instanceof Entry)) { + public InputStream getRawInputStream(final ZipArchiveEntry entry) throws IOException { + if (!(entry instanceof Entry)) { return null; } - - final long start = getDataOffset(ze); + final long start = getDataOffset(entry); if (start == EntryStreamOffsets.OFFSET_UNKNOWN) { return null; } - return createBoundedInputStream(start, ze.getCompressedSize()); + return createBoundedInputStream(start, entry.getCompressedSize()); } /** - * Gets the entry's content as a String if isUnixSymlink() - * returns true for it, otherwise returns null. - * <p>This method assumes the symbolic link's file name uses the - * same encoding that as been specified for this ZipFile.</p> + * Gets the entry's content as a String if isUnixSymlink() returns true for it, otherwise returns null. + * <p> + * This method assumes the symbolic link's file name uses the same encoding that as been specified for this ZipFile. + * </p> * * @param entry ZipArchiveEntry object that represents the symbolic link * @return entry's content as a String @@ -1055,20 +999,17 @@ public class ZipFile implements Closeable { } /** - * Reads the central directory of the given archive and populates - * the internal tables with ZipArchiveEntry instances. + * Reads the central directory of the given archive and populates the internal tables with ZipArchiveEntry instances. * - * <p>The ZipArchiveEntrys will know all data that can be obtained from - * the central directory alone, but not the data that requires the - * local file header or additional data to be read.</p> + * <p> + * The ZipArchiveEntrys will know all data that can be obtained from the central directory alone, but not the data that requires the local file header or + * additional data to be read. + * </p> * - * @return a map of zip entries that didn't have the language - * encoding flag set when read. + * @return a map of zip entries that didn't have the language encoding flag set when read. */ - private Map<ZipArchiveEntry, NameAndComment> populateFromCentralDirectory() - throws IOException { - final HashMap<ZipArchiveEntry, NameAndComment> noUTF8Flag = - new HashMap<>(); + private Map<ZipArchiveEntry, NameAndComment> populateFromCentralDirectory() throws IOException { + final HashMap<ZipArchiveEntry, NameAndComment> noUTF8Flag = new HashMap<>(); positionAtCentralDirectory(); centralDirectoryStartOffset = archive.position(); @@ -1078,8 +1019,7 @@ public class ZipFile implements Closeable { long sig = ZipLong.getValue(wordBuf); if (sig != CFH_SIG && startsWithLocalFileHeader()) { - throw new IOException("Central directory is empty, can't expand" - + " corrupt archive."); + throw new IOException("Central directory is empty, can't expand" + " corrupt archive."); } while (sig == CFH_SIG) { @@ -1092,23 +1032,18 @@ public class ZipFile implements Closeable { } /** - * Searches for either the "Zip64 end of central directory - * locator" or the "End of central dir record", parses - * it and positions the stream at the first central directory - * record. + * Searches for either the "Zip64 end of central directory locator" or the "End of central dir record", parses it and positions the + * stream at the first central directory record. */ - private void positionAtCentralDirectory() - throws IOException { + private void positionAtCentralDirectory() throws IOException { positionAtEndOfCentralDirectoryRecord(); boolean found = false; - final boolean searchedForZip64EOCD = - archive.position() > ZIP64_EOCDL_LENGTH; + final boolean searchedForZip64EOCD = archive.position() > ZIP64_EOCDL_LENGTH; if (searchedForZip64EOCD) { archive.position(archive.position() - ZIP64_EOCDL_LENGTH); wordBbuf.rewind(); IOUtils.readFully(archive, wordBbuf); - found = Arrays.equals(ZipArchiveOutputStream.ZIP64_EOCD_LOC_SIG, - wordBuf); + found = Arrays.equals(ZipArchiveOutputStream.ZIP64_EOCD_LOC_SIG, wordBuf); } if (!found) { // not a ZIP64 archive @@ -1122,14 +1057,11 @@ public class ZipFile implements Closeable { } /** - * Parses the "End of central dir record" and positions - * the stream at the first central directory record. + * Parses the "End of central dir record" and positions the stream at the first central directory record. * - * Expects stream to be positioned at the beginning of the - * "End of central dir record". + * Expects stream to be positioned at the beginning of the "End of central dir record". */ - private void positionAtCentralDirectory32() - throws IOException { + private void positionAtCentralDirectory32() throws IOException { final long endOfCentralDirectoryRecordOffset = archive.position(); if (isSplitZipArchive) { skipBytes(CFD_DISK_OFFSET); @@ -1142,8 +1074,7 @@ public class ZipFile implements Closeable { wordBbuf.rewind(); IOUtils.readFully(archive, wordBbuf); centralDirectoryStartRelativeOffset = ZipLong.getValue(wordBuf); - ((ZipSplitReadOnlySeekableByteChannel) archive) - .position(centralDirectoryStartDiskNumber, centralDirectoryStartRelativeOffset); + ((ZipSplitReadOnlySeekableByteChannel) archive).position(centralDirectoryStartDiskNumber, centralDirectoryStartRelativeOffset); } else { skipBytes(CFD_LENGTH_OFFSET); wordBbuf.rewind(); @@ -1155,24 +1086,18 @@ public class ZipFile implements Closeable { centralDirectoryStartDiskNumber = 0; centralDirectoryStartRelativeOffset = ZipLong.getValue(wordBuf); - firstLocalFileHeaderOffset = Long.max( - endOfCentralDirectoryRecordOffset - centralDirectoryLength - centralDirectoryStartRelativeOffset, - 0L); + firstLocalFileHeaderOffset = Long.max(endOfCentralDirectoryRecordOffset - centralDirectoryLength - centralDirectoryStartRelativeOffset, 0L); archive.position(centralDirectoryStartRelativeOffset + firstLocalFileHeaderOffset); } } /** - * Parses the "Zip64 end of central directory locator", - * finds the "Zip64 end of central directory record" using the - * parsed information, parses that and positions the stream at the - * first central directory record. + * Parses the "Zip64 end of central directory locator", finds the "Zip64 end of central directory record" using the parsed information, + * parses that and positions the stream at the first central directory record. * - * Expects stream to be positioned right behind the "Zip64 - * end of central directory locator"'s signature. + * Expects stream to be positioned right behind the "Zip64 end of central directory locator"'s signature. */ - private void positionAtCentralDirectory64() - throws IOException { + private void positionAtCentralDirectory64() throws IOException { if (isSplitZipArchive) { wordBbuf.rewind(); IOUtils.readFully(archive, wordBbuf); @@ -1181,11 +1106,9 @@ public class ZipFile implements Closeable { dwordBbuf.rewind(); IOUtils.readFully(archive, dwordBbuf); final long relativeOffsetOfEOCD = ZipEightByteInteger.getLongValue(dwordBuf); - ((ZipSplitReadOnlySeekableByteChannel) archive) - .position(diskNumberOfEOCD, relativeOffsetOfEOCD); + ((ZipSplitReadOnlySeekableByteChannel) archive).position(diskNumberOfEOCD, relativeOffsetOfEOCD); } else { - skipBytes(ZIP64_EOCDL_LOCATOR_OFFSET - - ZipConstants.WORD /* signature has already been read */); + skipBytes(ZIP64_EOCDL_LOCATOR_OFFSET - ZipConstants.WORD /* signature has already been read */); dwordBbuf.rewind(); IOUtils.readFully(archive, dwordBbuf); archive.position(ZipEightByteInteger.getLongValue(dwordBuf)); @@ -1194,13 +1117,11 @@ public class ZipFile implements Closeable { wordBbuf.rewind(); IOUtils.readFully(archive, wordBbuf); if (!Arrays.equals(wordBuf, ZipArchiveOutputStream.ZIP64_EOCD_SIG)) { - throw new ZipException("Archive's ZIP64 end of central " - + "directory locator is corrupt."); + throw new ZipException("Archive's ZIP64 end of central directory locator is corrupt."); } if (isSplitZipArchive) { - skipBytes(ZIP64_EOCD_CFD_DISK_OFFSET - - ZipConstants.WORD /* signature has already been read */); + skipBytes(ZIP64_EOCD_CFD_DISK_OFFSET - ZipConstants.WORD /* signature has already been read */); wordBbuf.rewind(); IOUtils.readFully(archive, wordBbuf); centralDirectoryStartDiskNumber = ZipLong.getValue(wordBuf); @@ -1210,11 +1131,9 @@ public class ZipFile implements Closeable { dwordBbuf.rewind(); IOUtils.readFully(archive, dwordBbuf); centralDirectoryStartRelativeOffset = ZipEightByteInteger.getLongValue(dwordBuf); - ((ZipSplitReadOnlySeekableByteChannel) archive) - .position(centralDirectoryStartDiskNumber, centralDirectoryStartRelativeOffset); + ((ZipSplitReadOnlySeekableByteChannel) archive).position(centralDirectoryStartDiskNumber, centralDirectoryStartRelativeOffset); } else { - skipBytes(ZIP64_EOCD_CFD_LOCATOR_OFFSET - - ZipConstants.WORD /* signature has already been read */); + skipBytes(ZIP64_EOCD_CFD_LOCATOR_OFFSET - ZipConstants.WORD /* signature has already been read */); dwordBbuf.rewind(); IOUtils.readFully(archive, dwordBbuf); centralDirectoryStartDiskNumber = 0; @@ -1224,30 +1143,22 @@ public class ZipFile implements Closeable { } /** - * Searches for the and positions the stream at the start of the - * "End of central dir record". + * Searches for the and positions the stream at the start of the "End of central dir record". */ - private void positionAtEndOfCentralDirectoryRecord() - throws IOException { - final boolean found = tryToLocateSignature(MIN_EOCD_SIZE, MAX_EOCD_SIZE, - ZipArchiveOutputStream.EOCD_SIG); + private void positionAtEndOfCentralDirectoryRecord() throws IOException { + final boolean found = tryToLocateSignature(MIN_EOCD_SIZE, MAX_EOCD_SIZE, ZipArchiveOutputStream.EOCD_SIG); if (!found) { throw new ZipException("Archive is not a ZIP archive"); } } /** - * Reads an individual entry of the central directory, creates an - * ZipArchiveEntry from it and adds it to the global maps. + * Reads an individual entry of the central directory, creates an ZipArchiveEntry from it and adds it to the global maps. * - * @param noUTF8Flag map used to collect entries that don't have - * their UTF-8 flag set and whose name will be set by data read - * from the local file header later. The current entry may be - * added to this map. - */ - private void - readCentralDirectoryEntry(final Map<ZipArchiveEntry, NameAndComment> noUTF8Flag) - throws IOException { + * @param noUTF8Flag map used to collect entries that don't have their UTF-8 flag set and whose name will be set by data read from the local file header + * later. The current entry may be added to this map. + */ + private void readCentralDirectoryEntry(final Map<ZipArchiveEntry, NameAndComment> noUTF8Flag) throws IOException { cfhBbuf.rewind(); IOUtils.readFully(archive, cfhBbuf); int off = 0; @@ -1263,8 +1174,7 @@ public class ZipFile implements Closeable { final GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(cfhBuf, off); final boolean hasUTF8Flag = gpFlag.usesUTF8ForNames(); - final ZipEncoding entryEncoding = - hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding; + final ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding; if (hasUTF8Flag) { ze.setNameSource(ZipArchiveEntry.NameSource.NAME_WITH_EFS_FLAG); } @@ -1273,7 +1183,7 @@ public class ZipFile implements Closeable { off += ZipConstants.SHORT; - //noinspection MagicConstant + // noinspection MagicConstant ze.setMethod(ZipShort.getValue(cfhBuf, off)); off += ZipConstants.SHORT; @@ -1365,18 +1275,15 @@ public class ZipFile implements Closeable { } /** - * Walks through all recorded entries and adds the data available - * from the local file header. + * Walks through all recorded entries and adds the data available from the local file header. * - * <p>Also records the offsets for the data to read from the - * entries.</p> + * <p> + * Also records the offsets for the data to read from the entries. + * </p> */ - private void resolveLocalFileHeaderData(final Map<ZipArchiveEntry, NameAndComment> - entriesWithoutUTF8Flag) - throws IOException { + private void resolveLocalFileHeaderData(final Map<ZipArchiveEntry, NameAndComment> entriesWithoutUTF8Flag) throws IOException { for (final ZipArchiveEntry zipArchiveEntry : entries) { - // entries are filled in populateFromCentralDirectory and - // never modified + // entries are filled in populateFromCentralDirectory and never modified final Entry ze = (Entry) zipArchiveEntry; final int[] lens = setDataOffset(ze); final int fileNameLen = lens[0]; @@ -1396,37 +1303,34 @@ public class ZipFile implements Closeable { if (entriesWithoutUTF8Flag.containsKey(ze)) { final NameAndComment nc = entriesWithoutUTF8Flag.get(ze); - ZipUtil.setNameAndCommentFromExtraFields(ze, nc.name, - nc.comment); + ZipUtil.setNameAndCommentFromExtraFields(ze, nc.name, nc.comment); } } } - private void sanityCheckLFHOffset(final ZipArchiveEntry ze) throws IOException { - if (ze.getDiskNumberStart() < 0) { + private void sanityCheckLFHOffset(final ZipArchiveEntry entry) throws IOException { + if (entry.getDiskNumberStart() < 0) { throw new IOException("broken archive, entry with negative disk number"); } - if (ze.getLocalHeaderOffset() < 0) { + if (entry.getLocalHeaderOffset() < 0) { throw new IOException("broken archive, entry with negative local file header offset"); } if (isSplitZipArchive) { - if (ze.getDiskNumberStart() > centralDirectoryStartDiskNumber) { - throw new IOException("local file header for " + ze.getName() + " starts on a later disk than central directory"); + if (entry.getDiskNumberStart() > centralDirectoryStartDiskNumber) { + throw new IOException("local file header for " + entry.getName() + " starts on a later disk than central directory"); } - if (ze.getDiskNumberStart() == centralDirectoryStartDiskNumber - && ze.getLocalHeaderOffset() > centralDirectoryStartRelativeOffset) { - throw new IOException("local file header for " + ze.getName() + " starts after central directory"); + if (entry.getDiskNumberStart() == centralDirectoryStartDiskNumber && entry.getLocalHeaderOffset() > centralDirectoryStartRelativeOffset) { + throw new IOException("local file header for " + entry.getName() + " starts after central directory"); } - } else if (ze.getLocalHeaderOffset() > centralDirectoryStartOffset) { - throw new IOException("local file header for " + ze.getName() + " starts after central directory"); + } else if (entry.getLocalHeaderOffset() > centralDirectoryStartOffset) { + throw new IOException("local file header for " + entry.getName() + " starts after central directory"); } } - private int[] setDataOffset(final ZipArchiveEntry ze) throws IOException { - long offset = ze.getLocalHeaderOffset(); + private int[] setDataOffset(final ZipArchiveEntry entry) throws IOException { + long offset = entry.getLocalHeaderOffset(); if (isSplitZipArchive) { - ((ZipSplitReadOnlySeekableByteChannel) archive) - .position(ze.getDiskNumberStart(), offset + LFH_OFFSET_FOR_FILENAME_LENGTH); + ((ZipSplitReadOnlySeekableByteChannel) archive).position(entry.getDiskNumberStart(), offset + LFH_OFFSET_FOR_FILENAME_LENGTH); // the offset should be updated to the global offset offset = archive.position() - LFH_OFFSET_FOR_FILENAME_LENGTH; } else { @@ -1439,54 +1343,43 @@ public class ZipFile implements Closeable { final int fileNameLen = ZipShort.getValue(shortBuf); wordBbuf.get(shortBuf); final int extraFieldLen = ZipShort.getValue(shortBuf); - ze.setDataOffset(offset + LFH_OFFSET_FOR_FILENAME_LENGTH - + ZipConstants.SHORT + ZipConstants.SHORT + fileNameLen + extraFieldLen); - if (ze.getDataOffset() + ze.getCompressedSize() > centralDirectoryStartOffset) { - throw new IOException("data for " + ze.getName() + " overlaps with central directory."); + entry.setDataOffset(offset + LFH_OFFSET_FOR_FILENAME_LENGTH + ZipConstants.SHORT + ZipConstants.SHORT + fileNameLen + extraFieldLen); + if (entry.getDataOffset() + entry.getCompressedSize() > centralDirectoryStartOffset) { + throw new IOException("data for " + entry.getName() + " overlaps with central directory."); } return new int[] { fileNameLen, extraFieldLen }; } /** - * If the entry holds a Zip64 extended information extra field, - * read sizes from there if the entry's sizes are set to - * 0xFFFFFFFFF, do the same for the offset of the local file - * header. + * If the entry holds a Zip64 extended information extra field, read sizes from there if the entry's sizes are set to 0xFFFFFFFFF, do the same for the + * offset of the local file header. * - * <p>Ensures the Zip64 extra either knows both compressed and - * uncompressed size or neither of both as the internal logic in - * ExtraFieldUtils forces the field to create local header data - * even if they are never used - and here a field with only one - * size would be invalid.</p> - */ - private void setSizesAndOffsetFromZip64Extra(final ZipArchiveEntry ze) - throws IOException { - final ZipExtraField extra = - ze.getExtraField(Zip64ExtendedInformationExtraField.HEADER_ID); + * <p> + * Ensures the Zip64 extra either knows both compressed and uncompressed size or neither of both as the internal logic in ExtraFieldUtils forces the field + * to create local header data even if they are never used - and here a field with only one size would be invalid. + * </p> + */ + private void setSizesAndOffsetFromZip64Extra(final ZipArchiveEntry entry) throws IOException { + final ZipExtraField extra = entry.getExtraField(Zip64ExtendedInformationExtraField.HEADER_ID); if (extra != null && !(extra instanceof Zip64ExtendedInformationExtraField)) { throw new ZipException("archive contains unparseable zip64 extra field"); } - final Zip64ExtendedInformationExtraField z64 = - (Zip64ExtendedInformationExtraField) extra; + final Zip64ExtendedInformationExtraField z64 = (Zip64ExtendedInformationExtraField) extra; if (z64 != null) { - final boolean hasUncompressedSize = ze.getSize() == ZipConstants.ZIP64_MAGIC; - final boolean hasCompressedSize = ze.getCompressedSize() == ZipConstants.ZIP64_MAGIC; - final boolean hasRelativeHeaderOffset = - ze.getLocalHeaderOffset() == ZipConstants.ZIP64_MAGIC; - final boolean hasDiskStart = ze.getDiskNumberStart() == ZipConstants.ZIP64_MAGIC_SHORT; - z64.reparseCentralDirectoryData(hasUncompressedSize, - hasCompressedSize, - hasRelativeHeaderOffset, - hasDiskStart); + final boolean hasUncompressedSize = entry.getSize() == ZipConstants.ZIP64_MAGIC; + final boolean hasCompressedSize = entry.getCompressedSize() == ZipConstants.ZIP64_MAGIC; + final boolean hasRelativeHeaderOffset = entry.getLocalHeaderOffset() == ZipConstants.ZIP64_MAGIC; + final boolean hasDiskStart = entry.getDiskNumberStart() == ZipConstants.ZIP64_MAGIC_SHORT; + z64.reparseCentralDirectoryData(hasUncompressedSize, hasCompressedSize, hasRelativeHeaderOffset, hasDiskStart); if (hasUncompressedSize) { final long size = z64.getSize().getLongValue(); if (size < 0) { throw new IOException("broken archive, entry with negative size"); } - ze.setSize(size); + entry.setSize(size); } else if (hasCompressedSize) { - z64.setSize(new ZipEightByteInteger(ze.getSize())); + z64.setSize(new ZipEightByteInteger(entry.getSize())); } if (hasCompressedSize) { @@ -1494,24 +1387,23 @@ public class ZipFile implements Closeable { if (size < 0) { throw new IOException("broken archive, entry with negative compressed size"); } - ze.setCompressedSize(size); + entry.setCompressedSize(size); } else if (hasUncompressedSize) { - z64.setCompressedSize(new ZipEightByteInteger(ze.getCompressedSize())); + z64.setCompressedSize(new ZipEightByteInteger(entry.getCompressedSize())); } if (hasRelativeHeaderOffset) { - ze.setLocalHeaderOffset(z64.getRelativeHeaderOffset().getLongValue()); + entry.setLocalHeaderOffset(z64.getRelativeHeaderOffset().getLongValue()); } if (hasDiskStart) { - ze.setDiskNumberStart(z64.getDiskStartNumber().getValue()); + entry.setDiskNumberStart(z64.getDiskStartNumber().getValue()); } } } /** - * Skips the given number of bytes or throws an EOFException if - * skipping failed. + * Skips the given number of bytes or throws an EOFException if skipping failed. */ private void skipBytes(final int count) throws IOException { final long currentPosition = archive.position(); @@ -1523,8 +1415,7 @@ public class ZipFile implements Closeable { } /** - * Checks whether the archive starts with an LFH. If it doesn't, - * it may be an empty archive. + * Checks whether the archive starts with an LFH. If it doesn't, it may be an empty archive. */ private boolean startsWithLocalFileHeader() throws IOException { archive.position(firstLocalFileHeaderOffset); @@ -1534,17 +1425,13 @@ public class ZipFile implements Closeable { } /** - * Searches the archive backwards from minDistance to maxDistance - * for the given signature, positions the RandomaccessFile right - * at the signature if it has been found. + * Searches the archive backwards from minDistance to maxDistance for the given signature, positions the RandomaccessFile right at the signature if it has + * been found. */ - private boolean tryToLocateSignature(final long minDistanceFromEnd, - final long maxDistanceFromEnd, - final byte[] sig) throws IOException { + private boolean tryToLocateSignature(final long minDistanceFromEnd, final long maxDistanceFromEnd, final byte[] sig) throws IOException { boolean found = false; long off = archive.size() - minDistanceFromEnd; - final long stopSearching = - Math.max(0L, archive.size() - maxDistanceFromEnd); + final long stopSearching = Math.max(0L, archive.size() - maxDistanceFromEnd); if (off >= 0) { for (; off >= stopSearching; off--) { archive.position(off);