This is an automated email from the ASF dual-hosted git repository. bodewig pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-compress.git
commit 0df4d084182c2c2662b777ee2c3b04a1c42bbc66 Author: Lee <[email protected]> AuthorDate: Mon Oct 28 16:04:35 2019 +0800 COMPRESS-477:add support for splitted zip file add support for splitted zip file for ZipArchiveInputStream --- .../archivers/zip/ZipArchiveInputStream.java | 34 ++++-- .../commons/compress/archivers/zip/ZipFile.java | 5 +- .../zip}/ZipSplitReadOnlySeekableByteChannel.java | 114 ++++++++++++--------- .../commons/compress/compressors/FileNameUtil.java | 4 +- .../utils/MultiReadOnlySeekableByteChannel.java | 23 ++++- .../compress/utils/ZipSplitSegmentComparator.java | 45 -------- .../archivers/zip/ZipArchiveInputStreamTest.java | 72 +++++++++++++ .../compress/archivers/zip/ZipFileTest.java | 17 ++- .../ZipSplitReadOnlySeekableByteChannelTest.java | 13 +-- .../split_zip_created_by_winrar.z01 | Bin 262144 -> 262144 bytes .../split_zip_created_by_winrar.z02 | Bin 262044 -> 262144 bytes .../split_zip_created_by_winrar.zip | Bin 41809 -> 50536 bytes .../zip_to_compare_created_by_winrar.zip | Bin 0 -> 574820 bytes .../zip_to_compare_created_by_zip.zip | Bin 0 -> 582047 bytes .../zip_to_compare_created_by_zip_zip64.zip | Bin 0 -> 584681 bytes 15 files changed, 202 insertions(+), 125 deletions(-) diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java b/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java index 48ad5d5..be5a0fd 100644 --- a/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java +++ b/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java @@ -120,6 +120,9 @@ public class ZipArchiveInputStream extends ArchiveInputStream implements InputSt /** Count decompressed bytes for current entry */ private long uncompressedCount = 0; + /** Whether the stream will try to skip the zip split signature(08074B50) at the beginning **/ + private final boolean skipSplitSig; + private static final int LFH_LEN = 30; /* local file header signature WORD @@ -213,12 +216,34 @@ public class ZipArchiveInputStream extends ArchiveInputStream implements InputSt final String encoding, final boolean useUnicodeExtraFields, final boolean allowStoredEntriesWithDataDescriptor) { + this(inputStream, encoding, useUnicodeExtraFields, allowStoredEntriesWithDataDescriptor, false); + } + + /** + * Create an instance using the specified encoding + * @param inputStream the stream to wrap + * @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 allowStoredEntriesWithDataDescriptor whether the stream + * will try to read STORED entries that use a data descriptor + * @param skipSplitSig Whether the stream will try to skip the + * zip split signature(08074B50) at the beginning + * @since 1.20 + */ + public ZipArchiveInputStream(final InputStream inputStream, + final String encoding, + final boolean useUnicodeExtraFields, + final boolean allowStoredEntriesWithDataDescriptor, + final boolean skipSplitSig) { this.encoding = encoding; zipEncoding = ZipEncodingHelper.getZipEncoding(encoding); this.useUnicodeExtraFields = useUnicodeExtraFields; in = new PushbackInputStream(inputStream, buf.capacity()); this.allowStoredEntriesWithDataDescriptor = allowStoredEntriesWithDataDescriptor; + this.skipSplitSig = skipSplitSig; // haven't read anything so far buf.limit(0); } @@ -367,13 +392,10 @@ public class ZipArchiveInputStream extends ArchiveInputStream implements InputSt private void readFirstLocalFileHeader(final byte[] lfh) throws IOException { readFully(lfh); final ZipLong sig = new ZipLong(lfh); - if (sig.equals(ZipLong.DD_SIG)) { - throw new UnsupportedZipFeatureException(UnsupportedZipFeatureException.Feature.SPLITTING); - } - if (sig.equals(ZipLong.SINGLE_SEGMENT_SPLIT_MARKER)) { - // The archive is not really split as only one segment was - // needed in the end. Just skip over the marker. + // the split zip signature(08074B50) should only be skipped when the skipSplitSig is set + if (sig.equals(ZipLong.SINGLE_SEGMENT_SPLIT_MARKER) || (skipSplitSig && sig.equals(ZipLong.DD_SIG))) { + // Just skip over the marker. final byte[] missedLfhBytes = new byte[4]; readFully(missedLfhBytes); System.arraycopy(lfh, 4, lfh, 0, LFH_LEN - 4); 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 e89fe96..ec3a6de 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 @@ -48,7 +48,6 @@ import org.apache.commons.compress.compressors.deflate64.Deflate64CompressorInpu import org.apache.commons.compress.utils.CountingInputStream; import org.apache.commons.compress.utils.IOUtils; import org.apache.commons.compress.utils.InputStreamStatistics; -import org.apache.commons.compress.utils.ZipSplitReadOnlySeekableByteChannel; import static org.apache.commons.compress.archivers.zip.ZipConstants.DWORD; import static org.apache.commons.compress.archivers.zip.ZipConstants.SHORT; @@ -147,7 +146,7 @@ public class ZipFile implements Closeable { /** * Whether the zip archive is a splite zip archive */ - private boolean isSplitZipArchive = false; + private final boolean isSplitZipArchive; // cached buffers - must only be used locally in the class (COMPRESS-172 - reduce garbage collection) private final byte[] dwordBuf = new byte[DWORD]; @@ -361,6 +360,8 @@ public class ZipFile implements Closeable { throws IOException { if(channel instanceof ZipSplitReadOnlySeekableByteChannel) { isSplitZipArchive = true; + } else { + isSplitZipArchive = false; } this.archiveName = archiveName; diff --git a/src/main/java/org/apache/commons/compress/utils/ZipSplitReadOnlySeekableByteChannel.java b/src/main/java/org/apache/commons/compress/archivers/zip/ZipSplitReadOnlySeekableByteChannel.java similarity index 68% rename from src/main/java/org/apache/commons/compress/utils/ZipSplitReadOnlySeekableByteChannel.java rename to src/main/java/org/apache/commons/compress/archivers/zip/ZipSplitReadOnlySeekableByteChannel.java index f483eda..eae00ba 100644 --- a/src/main/java/org/apache/commons/compress/utils/ZipSplitReadOnlySeekableByteChannel.java +++ b/src/main/java/org/apache/commons/compress/archivers/zip/ZipSplitReadOnlySeekableByteChannel.java @@ -16,11 +16,11 @@ * */ -package org.apache.commons.compress.utils; +package org.apache.commons.compress.archivers.zip; import org.apache.commons.compress.archivers.ArchiveStreamFactory; -import org.apache.commons.compress.archivers.zip.ZipLong; import org.apache.commons.compress.compressors.FileNameUtil; +import org.apache.commons.compress.utils.MultiReadOnlySeekableByteChannel; import java.io.File; import java.io.IOException; @@ -31,21 +31,20 @@ import java.nio.file.StandardOpenOption; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.Comparator; import java.util.List; import java.util.Objects; import java.util.regex.Pattern; public class ZipSplitReadOnlySeekableByteChannel extends MultiReadOnlySeekableByteChannel { - protected final int ZIP_SPLIT_SIGNATURE_LENGTH = 4; - protected ByteBuffer zipSplitSignatureByteBuffer = ByteBuffer.allocate(ZIP_SPLIT_SIGNATURE_LENGTH); + private final int ZIP_SPLIT_SIGNATURE_LENGTH = 4; + private ByteBuffer zipSplitSignatureByteBuffer = ByteBuffer.allocate(ZIP_SPLIT_SIGNATURE_LENGTH); /** * Concatenates the given channels. * the channels should be add in ascending order, e.g. z01, z02, ... z99, zip * please note that the .zip file is the last segment and should be added as the last one in the channels - * - * The first 4 bytes of split zip signature will be taken into consideration by Inflator, - * so we don't need to skip them + * <p> * * @param channels the channels to concatenate * @throws NullPointerException if channels is null @@ -53,48 +52,40 @@ public class ZipSplitReadOnlySeekableByteChannel extends MultiReadOnlySeekableBy public ZipSplitReadOnlySeekableByteChannel(List<SeekableByteChannel> channels) throws IOException { super(channels); - // each split zip segment should begin with zip split signature + // the first split zip segment should begin with zip split signature validSplitSignature(channels); } /** - * the first 4 bytes of zip split segments should be the zip split signature(0x08074B50) + * Based on the zip specification: + * <p> + * 8.5.3 Spanned/Split archives created using PKZIP for Windows + * (V2.50 or greater), PKZIP Command Line (V2.50 or greater), + * or PKZIP Explorer will include a special spanning + * signature as the first 4 bytes of the first segment of + * the archive. This signature (0x08074b50) will be + * followed immediately by the local header signature for + * the first file in the archive. + * <p> + * the first 4 bytes of the first zip split segment should be the zip split signature(0x08074B50) * * @param channels channels to be valided * @throws IOException */ private void validSplitSignature(final List<SeekableByteChannel> channels) throws IOException { - for(int i = 0;i < channels.size();i++) { - SeekableByteChannel channel = channels.get(i); - // the zip split file signature is always at the beginning of the segment - channel.position(0L); - - channel.read(zipSplitSignatureByteBuffer); - final ZipLong signature = new ZipLong(zipSplitSignatureByteBuffer.array()); - if(!signature.equals(ZipLong.DD_SIG)) { - channel.position(0L); - throw new IOException("No." + (i + 1) + " split zip file is not begin with split zip file signature"); - } - + SeekableByteChannel channel = channels.get(0); + // the zip split file signature is at the beginning of the first split segment + channel.position(0L); + + zipSplitSignatureByteBuffer.rewind(); + channel.read(zipSplitSignatureByteBuffer); + final ZipLong signature = new ZipLong(zipSplitSignatureByteBuffer.array()); + if (!signature.equals(ZipLong.DD_SIG)) { channel.position(0L); + throw new IOException("The first zip split segment is not begin with split zip file signature"); } - } - /** - * set the position based on the given disk number and relative offset - * - * @param diskNumber the disk number of split zip files - * @param relativeOffset the offset in the split zip segment with given disk number - * @return global position of all split zip files as if they are a single channel - * @throws IOException - */ - public synchronized SeekableByteChannel position(long diskNumber, long relativeOffset) throws IOException { - long globalPosition = relativeOffset; - for(int i = 0; i < diskNumber;i++) { - globalPosition += channels.get(i).size(); - } - - return position(globalPosition); + channel.position(0L); } /** @@ -102,8 +93,8 @@ public class ZipSplitReadOnlySeekableByteChannel extends MultiReadOnlySeekableBy * * @param channels the channels to concatenate, note that the LAST CHANNEL of channels should be the LAST SEGMENT(.zip) * and theses channels should be added in correct order (e.g. .z01, .z02... .z99, .zip) - * @throws NullPointerException if channels is null * @return SeekableByteChannel that concatenates all provided channels + * @throws NullPointerException if channels is null */ public static SeekableByteChannel forSeekableByteChannels(SeekableByteChannel... channels) throws IOException { if (Objects.requireNonNull(channels, "channels must not be null").length == 1) { @@ -116,18 +107,18 @@ public class ZipSplitReadOnlySeekableByteChannel extends MultiReadOnlySeekableBy * Concatenates the given channels. * * @param lastSegmentChannel channel of the last segment of split zip segments, its extension should be .zip - * @param channels the channels to concatenate except for the last segment, - * note theses channels should be added in correct order (e.g. .z01, .z02... .z99) + * @param channels the channels to concatenate except for the last segment, + * note theses channels should be added in correct order (e.g. .z01, .z02... .z99) * @return SeekableByteChannel that concatenates all provided channels * @throws NullPointerException if lastSegmentChannel or channels is null */ public static SeekableByteChannel forSeekableByteChannels(SeekableByteChannel lastSegmentChannel, Iterable<SeekableByteChannel> channels) throws IOException { - if(channels == null || lastSegmentChannel == null) { + if (channels == null || lastSegmentChannel == null) { throw new NullPointerException("channels must not be null"); } List<SeekableByteChannel> channelsList = new ArrayList<>(); - for(SeekableByteChannel channel : channels) { + for (SeekableByteChannel channel : channels) { channelsList.add(channel); } channelsList.add(lastSegmentChannel); @@ -145,7 +136,7 @@ public class ZipSplitReadOnlySeekableByteChannel extends MultiReadOnlySeekableBy */ public static SeekableByteChannel buildFromLastSplitSegment(File lastSegmentFile) throws IOException { String extension = FileNameUtil.getExtension(lastSegmentFile.getCanonicalPath()); - if(!extension.equals(ArchiveStreamFactory.ZIP)) { + if (!extension.equalsIgnoreCase(ArchiveStreamFactory.ZIP)) { throw new IllegalArgumentException("The extension of last zip splite segment should be .zip"); } @@ -154,9 +145,9 @@ public class ZipSplitReadOnlySeekableByteChannel extends MultiReadOnlySeekableBy ArrayList<File> splitZipSegments = new ArrayList<>(); // zip split segments should be like z01,z02....z(n-1) based on the zip specification - String pattern = fileBaseName + ".z[0-9]+"; - for(File file : parent.listFiles()) { - if(!Pattern.matches(pattern, file.getName())) { + Pattern pattern = Pattern.compile(Pattern.quote(fileBaseName) + ".[zZ][0-9]+"); + for (File file : parent.listFiles()) { + if (!pattern.matcher(file.getName()).matches()) { continue; } @@ -172,9 +163,9 @@ public class ZipSplitReadOnlySeekableByteChannel extends MultiReadOnlySeekableBy * * @param files the files to concatenate, note that the LAST FILE of files should be the LAST SEGMENT(.zip) * and theses files should be added in correct order (e.g. .z01, .z02... .z99, .zip) - * @throws NullPointerException if files is null - * @throws IOException if opening a channel for one of the files fails * @return SeekableByteChannel that concatenates all provided files + * @throws NullPointerException if files is null + * @throws IOException if opening a channel for one of the files fails */ public static SeekableByteChannel forFiles(File... files) throws IOException { List<SeekableByteChannel> channels = new ArrayList<>(); @@ -191,14 +182,14 @@ public class ZipSplitReadOnlySeekableByteChannel extends MultiReadOnlySeekableBy * Concatenates the given files. * * @param lastSegmentFile the last segment of split zip segments, its extension should be .zip - * @param files the files to concatenate except for the last segment, - * note theses files should be added in correct order (e.g. .z01, .z02... .z99) + * @param files the files to concatenate except for the last segment, + * note theses files should be added in correct order (e.g. .z01, .z02... .z99) * @return SeekableByteChannel that concatenates all provided files * @throws IOException * @throws NullPointerException if files or lastSegmentFile is null */ public static SeekableByteChannel forFiles(File lastSegmentFile, Iterable<File> files) throws IOException { - if(files == null || lastSegmentFile == null) { + if (files == null || lastSegmentFile == null) { throw new NullPointerException("files must not be null"); } @@ -211,4 +202,25 @@ public class ZipSplitReadOnlySeekableByteChannel extends MultiReadOnlySeekableBy File[] filesArray = new File[filesList.size()]; return forFiles(filesList.toArray(filesArray)); } + + public static class ZipSplitSegmentComparator implements Comparator<File> { + @Override + public int compare(File file1, File file2) { + String extension1 = FileNameUtil.getExtension(file1.getPath()); + String extension2 = FileNameUtil.getExtension(file2.getPath()); + + if (!extension1.startsWith("z")) { + return -1; + } + + if (!extension2.startsWith("z")) { + return 1; + } + + Integer splitSegmentNumber1 = Integer.parseInt(extension1.substring(1)); + Integer splitSegmentNumber2 = Integer.parseInt(extension2.substring(1)); + + return splitSegmentNumber1.compareTo(splitSegmentNumber2); + } + } } diff --git a/src/main/java/org/apache/commons/compress/compressors/FileNameUtil.java b/src/main/java/org/apache/commons/compress/compressors/FileNameUtil.java index 3b9d76c..ec3f0e9 100644 --- a/src/main/java/org/apache/commons/compress/compressors/FileNameUtil.java +++ b/src/main/java/org/apache/commons/compress/compressors/FileNameUtil.java @@ -18,6 +18,7 @@ */ package org.apache.commons.compress.compressors; +import java.io.File; import java.util.Collections; import java.util.HashMap; import java.util.Locale; @@ -212,8 +213,7 @@ public class FileNameUtil { return null; } - int lastSeparatorPosition = Math.max(filename.lastIndexOf('/'), filename.lastIndexOf('\\')); - String name = filename.substring(lastSeparatorPosition + 1); + String name = new File(filename).getName(); int extensionPosition = name.lastIndexOf('.'); if(extensionPosition < 0) { diff --git a/src/main/java/org/apache/commons/compress/utils/MultiReadOnlySeekableByteChannel.java b/src/main/java/org/apache/commons/compress/utils/MultiReadOnlySeekableByteChannel.java index b9eee89..5129dbd 100644 --- a/src/main/java/org/apache/commons/compress/utils/MultiReadOnlySeekableByteChannel.java +++ b/src/main/java/org/apache/commons/compress/utils/MultiReadOnlySeekableByteChannel.java @@ -44,9 +44,9 @@ import java.util.Objects; */ public class MultiReadOnlySeekableByteChannel implements SeekableByteChannel { - protected final List<SeekableByteChannel> channels; - protected long globalPosition; - protected int currentChannelIdx; + private final List<SeekableByteChannel> channels; + private long globalPosition; + private int currentChannelIdx; /** * Concatenates the given channels. @@ -122,6 +122,23 @@ public class MultiReadOnlySeekableByteChannel implements SeekableByteChannel { return globalPosition; } + /** + * set the position based on the given channel number and relative offset + * + * @param channelNumber the channel number + * @param relativeOffset the relative offset in the corresponding channel + * @return global position of all channels as if they are a single channel + * @throws IOException + */ + public synchronized SeekableByteChannel position(long channelNumber, long relativeOffset) throws IOException { + long globalPosition = relativeOffset; + for (int i = 0; i < channelNumber; i++) { + globalPosition += channels.get(i).size(); + } + + return position(globalPosition); + } + @Override public long size() throws IOException { long acc = 0; diff --git a/src/main/java/org/apache/commons/compress/utils/ZipSplitSegmentComparator.java b/src/main/java/org/apache/commons/compress/utils/ZipSplitSegmentComparator.java deleted file mode 100644 index 3b0a9e8..0000000 --- a/src/main/java/org/apache/commons/compress/utils/ZipSplitSegmentComparator.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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.utils; - -import org.apache.commons.compress.compressors.FileNameUtil; - -import java.io.File; -import java.util.Comparator; - -public class ZipSplitSegmentComparator implements Comparator<File> { - @Override - public int compare(File file1, File file2) { - String extension1 = FileNameUtil.getExtension(file1.getPath()); - String extension2 = FileNameUtil.getExtension(file2.getPath()); - - if(!extension1.startsWith("z")) { - return -1; - } - - if(!extension2.startsWith("z")) { - return 1; - } - - Integer splitSegmentNumber1 = Integer.parseInt(extension1.substring(1)); - Integer splitSegmentNumber2 = Integer.parseInt(extension2.substring(1)); - - return splitSegmentNumber1.compareTo(splitSegmentNumber2); - } -} diff --git a/src/test/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStreamTest.java b/src/test/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStreamTest.java index 43a509e..f108878 100644 --- a/src/test/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStreamTest.java +++ b/src/test/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStreamTest.java @@ -34,6 +34,8 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.nio.channels.Channels; +import java.nio.channels.SeekableByteChannel; import java.util.Arrays; import java.util.zip.ZipException; @@ -596,6 +598,76 @@ public class ZipArchiveInputStreamTest { } } + @Test + public void testSplitZipCreatedByZip() throws IOException { + File lastFile = getFile("COMPRESS-477/split_zip_created_by_zip/split_zip_created_by_zip.zip"); + SeekableByteChannel channel = ZipSplitReadOnlySeekableByteChannel.buildFromLastSplitSegment(lastFile); + InputStream inputStream = Channels.newInputStream(channel); + ZipArchiveInputStream splitInputStream = new ZipArchiveInputStream(inputStream, ZipEncodingHelper.UTF8, true, false, true); + + File fileToCompare = getFile("COMPRESS-477/split_zip_created_by_zip/zip_to_compare_created_by_zip.zip"); + ZipArchiveInputStream inputStreamToCompare = new ZipArchiveInputStream(new FileInputStream(fileToCompare), ZipEncodingHelper.UTF8, true, false, true); + + ArchiveEntry entry; + while((entry = splitInputStream.getNextEntry()) != null && inputStreamToCompare.getNextEntry() != null) { + if(entry.isDirectory()) { + continue; + } + Assert.assertTrue(shaded.org.apache.commons.io.IOUtils.contentEquals(splitInputStream, inputStreamToCompare)); + } + } + + @Test + public void testSplitZipCreatedByZipOfZip64() throws IOException { + File lastFile = getFile("COMPRESS-477/split_zip_created_by_zip/split_zip_created_by_zip_zip64.zip"); + SeekableByteChannel channel = ZipSplitReadOnlySeekableByteChannel.buildFromLastSplitSegment(lastFile); + InputStream inputStream = Channels.newInputStream(channel); + ZipArchiveInputStream splitInputStream = new ZipArchiveInputStream(inputStream, ZipEncodingHelper.UTF8, true, false, true); + + File fileToCompare = getFile("COMPRESS-477/split_zip_created_by_zip/zip_to_compare_created_by_zip_zip64.zip"); + ZipArchiveInputStream inputStreamToCompare = new ZipArchiveInputStream(new FileInputStream(fileToCompare), ZipEncodingHelper.UTF8, true, false, true); + + ArchiveEntry entry; + while((entry = splitInputStream.getNextEntry()) != null && inputStreamToCompare.getNextEntry() != null) { + if(entry.isDirectory()) { + continue; + } + Assert.assertTrue(shaded.org.apache.commons.io.IOUtils.contentEquals(splitInputStream, inputStreamToCompare)); + } + } + + @Test + public void testSplitZipCreatedByWinrar() throws IOException { + File lastFile = getFile("COMPRESS-477/split_zip_created_by_winrar/split_zip_created_by_winrar.zip"); + SeekableByteChannel channel = ZipSplitReadOnlySeekableByteChannel.buildFromLastSplitSegment(lastFile); + InputStream inputStream = Channels.newInputStream(channel); + ZipArchiveInputStream splitInputStream = new ZipArchiveInputStream(inputStream, ZipEncodingHelper.UTF8, true, false, true); + + File fileToCompare = getFile("COMPRESS-477/split_zip_created_by_winrar/zip_to_compare_created_by_winrar.zip"); + ZipArchiveInputStream inputStreamToCompare = new ZipArchiveInputStream(new FileInputStream(fileToCompare), ZipEncodingHelper.UTF8, true, false, true); + + ArchiveEntry entry; + while((entry = splitInputStream.getNextEntry()) != null && inputStreamToCompare.getNextEntry() != null) { + if(entry.isDirectory()) { + continue; + } + Assert.assertTrue(shaded.org.apache.commons.io.IOUtils.contentEquals(splitInputStream, inputStreamToCompare)); + } + } + + @Test + public void testSplitZipCreatedByZipThrowsException() throws IOException { + thrown.expect(EOFException.class); + File zipSplitFile = getFile("COMPRESS-477/split_zip_created_by_zip/split_zip_created_by_zip.z01"); + InputStream fileInputStream = new FileInputStream(zipSplitFile); + ZipArchiveInputStream inputStream = new ZipArchiveInputStream(fileInputStream, ZipEncodingHelper.UTF8, true, false, true); + + ArchiveEntry entry = inputStream.getNextEntry(); + while(entry != null){ + entry = inputStream.getNextEntry(); + } + } + private static byte[] readEntry(ZipArchiveInputStream zip, ZipArchiveEntry zae) throws IOException { final int len = (int)zae.getSize(); final byte[] buff = new byte[len]; diff --git a/src/test/java/org/apache/commons/compress/archivers/zip/ZipFileTest.java b/src/test/java/org/apache/commons/compress/archivers/zip/ZipFileTest.java index ba75bbf..bb34632 100644 --- a/src/test/java/org/apache/commons/compress/archivers/zip/ZipFileTest.java +++ b/src/test/java/org/apache/commons/compress/archivers/zip/ZipFileTest.java @@ -46,12 +46,9 @@ import java.util.zip.ZipEntry; import org.apache.commons.compress.utils.IOUtils; import org.apache.commons.compress.utils.SeekableInMemoryByteChannel; -import org.apache.commons.compress.utils.ZipSplitReadOnlySeekableByteChannel; import org.junit.After; import org.junit.Assert; import org.junit.Test; -import shaded.org.apache.commons.io.FileUtils; -import shaded.org.apache.commons.io.FilenameUtils; public class ZipFileTest { private ZipFile zf = null; @@ -697,8 +694,8 @@ public class ZipFileTest { @Test public void extractFileLiesAcrossSplitZipSegmentsCreatedByZip() throws Exception { File lastFile = getFile("COMPRESS-477/split_zip_created_by_zip/split_zip_created_by_zip.zip"); - SeekableByteChannel splitInputStream = ZipSplitReadOnlySeekableByteChannel.buildFromLastSplitSegment(lastFile); - zf = new ZipFile(splitInputStream); + SeekableByteChannel channel = ZipSplitReadOnlySeekableByteChannel.buildFromLastSplitSegment(lastFile); + zf = new ZipFile(channel); // the compressed content of UnsupportedCompressionAlgorithmException.java lies between .z01 and .z02 ZipArchiveEntry zipEntry = zf.getEntry("commons-compress/src/main/java/org/apache/commons/compress/archivers/dump/UnsupportedCompressionAlgorithmException.java"); @@ -714,8 +711,8 @@ public class ZipFileTest { @Test public void extractFileLiesAcrossSplitZipSegmentsCreatedByZipOfZip64() throws Exception { File lastFile = getFile("COMPRESS-477/split_zip_created_by_zip/split_zip_created_by_zip_zip64.zip"); - SeekableByteChannel splitInputStream = ZipSplitReadOnlySeekableByteChannel.buildFromLastSplitSegment(lastFile); - zf = new ZipFile(splitInputStream); + SeekableByteChannel channel = ZipSplitReadOnlySeekableByteChannel.buildFromLastSplitSegment(lastFile); + zf = new ZipFile(channel); // the compressed content of UnsupportedCompressionAlgorithmException.java lies between .z01 and .z02 ZipArchiveEntry zipEntry = zf.getEntry("commons-compress/src/main/java/org/apache/commons/compress/archivers/dump/UnsupportedCompressionAlgorithmException.java"); @@ -731,11 +728,11 @@ public class ZipFileTest { @Test public void extractFileLiesAcrossSplitZipSegmentsCreatedByWinrar() throws Exception { File lastFile = getFile("COMPRESS-477/split_zip_created_by_winrar/split_zip_created_by_winrar.zip"); - SeekableByteChannel splitInputStream = ZipSplitReadOnlySeekableByteChannel.buildFromLastSplitSegment(lastFile); - zf = new ZipFile(splitInputStream); + SeekableByteChannel channel = ZipSplitReadOnlySeekableByteChannel.buildFromLastSplitSegment(lastFile); + zf = new ZipFile(channel); // the compressed content of ZipArchiveInputStream.java lies between .z01 and .z02 - ZipArchiveEntry zipEntry = zf.getEntry("main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java"); + ZipArchiveEntry zipEntry = zf.getEntry("commons-compress/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java"); File fileToCompare = getFile("COMPRESS-477/split_zip_created_by_winrar/file_to_compare_1"); assertFileEqualsToEntry(fileToCompare, zipEntry, zf); } diff --git a/src/test/java/org/apache/commons/compress/utils/ZipSplitReadOnlySeekableByteChannelTest.java b/src/test/java/org/apache/commons/compress/utils/ZipSplitReadOnlySeekableByteChannelTest.java index 4a36951..39c3029 100644 --- a/src/test/java/org/apache/commons/compress/utils/ZipSplitReadOnlySeekableByteChannelTest.java +++ b/src/test/java/org/apache/commons/compress/utils/ZipSplitReadOnlySeekableByteChannelTest.java @@ -18,6 +18,7 @@ package org.apache.commons.compress.utils; +import org.apache.commons.compress.archivers.zip.ZipSplitReadOnlySeekableByteChannel; import org.junit.Assert; import org.junit.Rule; import org.junit.Test; @@ -57,7 +58,7 @@ public class ZipSplitReadOnlySeekableByteChannelTest { public void channelsPositionIsZeroAfterConstructor() throws IOException { List<SeekableByteChannel> channels = getSplitZipChannels(); new ZipSplitReadOnlySeekableByteChannel(channels); - for(SeekableByteChannel channel : channels) { + for (SeekableByteChannel channel : channels) { Assert.assertEquals(0, channel.position()); } } @@ -142,19 +143,19 @@ public class ZipSplitReadOnlySeekableByteChannelTest { @Test public void positionToSomeZipSplitSegment() throws IOException { File firstFile = getFile("COMPRESS-477/split_zip_created_by_zip/split_zip_created_by_zip.z01"); - int firstFileSize = (int)firstFile.length(); + int firstFileSize = (int) firstFile.length(); File secondFile = getFile("COMPRESS-477/split_zip_created_by_zip/split_zip_created_by_zip.z02"); - int secondFileSize = (int)secondFile.length(); + int secondFileSize = (int) secondFile.length(); File lastFile = getFile("COMPRESS-477/split_zip_created_by_zip/split_zip_created_by_zip.zip"); - int lastFileSize = (int)lastFile.length(); + int lastFileSize = (int) lastFile.length(); Random random = new Random(); int randomDiskNumber = random.nextInt(3); - int randomOffset = randomDiskNumber < 2 ? random.nextInt(firstFileSize):random.nextInt(lastFileSize); + int randomOffset = randomDiskNumber < 2 ? random.nextInt(firstFileSize) : random.nextInt(lastFileSize); - ZipSplitReadOnlySeekableByteChannel channel = (ZipSplitReadOnlySeekableByteChannel)ZipSplitReadOnlySeekableByteChannel.buildFromLastSplitSegment(lastFile); + ZipSplitReadOnlySeekableByteChannel channel = (ZipSplitReadOnlySeekableByteChannel) ZipSplitReadOnlySeekableByteChannel.buildFromLastSplitSegment(lastFile); channel.position(randomDiskNumber, randomOffset); long expectedPosition = randomOffset; diff --git a/src/test/resources/COMPRESS-477/split_zip_created_by_winrar/split_zip_created_by_winrar.z01 b/src/test/resources/COMPRESS-477/split_zip_created_by_winrar/split_zip_created_by_winrar.z01 index dc87d52..da153f7 100644 Binary files a/src/test/resources/COMPRESS-477/split_zip_created_by_winrar/split_zip_created_by_winrar.z01 and b/src/test/resources/COMPRESS-477/split_zip_created_by_winrar/split_zip_created_by_winrar.z01 differ diff --git a/src/test/resources/COMPRESS-477/split_zip_created_by_winrar/split_zip_created_by_winrar.z02 b/src/test/resources/COMPRESS-477/split_zip_created_by_winrar/split_zip_created_by_winrar.z02 index 4fedb2f..e2047f4 100644 Binary files a/src/test/resources/COMPRESS-477/split_zip_created_by_winrar/split_zip_created_by_winrar.z02 and b/src/test/resources/COMPRESS-477/split_zip_created_by_winrar/split_zip_created_by_winrar.z02 differ diff --git a/src/test/resources/COMPRESS-477/split_zip_created_by_winrar/split_zip_created_by_winrar.zip b/src/test/resources/COMPRESS-477/split_zip_created_by_winrar/split_zip_created_by_winrar.zip index 6f10459..5937de8 100644 Binary files a/src/test/resources/COMPRESS-477/split_zip_created_by_winrar/split_zip_created_by_winrar.zip and b/src/test/resources/COMPRESS-477/split_zip_created_by_winrar/split_zip_created_by_winrar.zip differ diff --git a/src/test/resources/COMPRESS-477/split_zip_created_by_winrar/zip_to_compare_created_by_winrar.zip b/src/test/resources/COMPRESS-477/split_zip_created_by_winrar/zip_to_compare_created_by_winrar.zip new file mode 100644 index 0000000..a79bd67 Binary files /dev/null and b/src/test/resources/COMPRESS-477/split_zip_created_by_winrar/zip_to_compare_created_by_winrar.zip differ diff --git a/src/test/resources/COMPRESS-477/split_zip_created_by_zip/zip_to_compare_created_by_zip.zip b/src/test/resources/COMPRESS-477/split_zip_created_by_zip/zip_to_compare_created_by_zip.zip new file mode 100644 index 0000000..b7326ec Binary files /dev/null and b/src/test/resources/COMPRESS-477/split_zip_created_by_zip/zip_to_compare_created_by_zip.zip differ diff --git a/src/test/resources/COMPRESS-477/split_zip_created_by_zip/zip_to_compare_created_by_zip_zip64.zip b/src/test/resources/COMPRESS-477/split_zip_created_by_zip/zip_to_compare_created_by_zip_zip64.zip new file mode 100644 index 0000000..f6cc080 Binary files /dev/null and b/src/test/resources/COMPRESS-477/split_zip_created_by_zip/zip_to_compare_created_by_zip_zip64.zip differ
