You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by bo...@apache.org on 2019/12/08 13:31:23 UTC

[commons-compress] 01/04: COMPRESS-477:add support for splitted zip file

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 <pe...@gmail.com>
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