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:26 UTC

[commons-compress] 04/04: COMPRESS-477 mostly cosmetic changes to #84

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 dfa9ed3712097c10765301b15d720f867c4a061d
Author: Stefan Bodewig <bo...@apache.org>
AuthorDate: Sun Dec 8 14:30:40 2019 +0100

    COMPRESS-477 mostly cosmetic changes to #84
---
 .../compress/archivers/zip/ZipArchiveEntry.java    | 12 ++++
 .../archivers/zip/ZipArchiveInputStream.java       | 11 ++-
 .../commons/compress/archivers/zip/ZipFile.java    | 30 ++++-----
 .../zip/ZipSplitReadOnlySeekableByteChannel.java   | 60 ++++++++++++-----
 .../commons/compress/compressors/FileNameUtil.java | 30 ---------
 .../commons/compress/utils/FileNameUtils.java      | 78 ++++++++++++++++++++++
 .../utils/MultiReadOnlySeekableByteChannel.java    |  2 +-
 .../commons/compress/utils/FileNameUtilsTest.java  | 53 +++++++++++++++
 .../ZipSplitReadOnlySeekableByteChannelTest.java   | 18 ++---
 9 files changed, 218 insertions(+), 76 deletions(-)

diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveEntry.java b/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveEntry.java
index a21b478..53af93a 100644
--- a/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveEntry.java
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveEntry.java
@@ -1081,10 +1081,22 @@ public class ZipArchiveEntry extends java.util.zip.ZipEntry
         this.commentSource = commentSource;
     }
 
+    /**
+     * The number of the split segment this entry starts at.
+     *
+     * @return the number of the split segment this entry starts at.
+     * @since 1.20
+     */
     public long getDiskNumberStart() {
         return diskNumberStart;
     }
 
+    /**
+     * The number of the split segment this entry starts at.
+     *
+     * @param diskNumberStart the number of the split segment this entry starts at.
+     * @since 1.20
+     */
     public void setDiskNumberStart(long diskNumberStart) {
         this.diskNumberStart = diskNumberStart;
     }
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 be5a0fd..0f27b14 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
@@ -228,8 +228,9 @@ public class ZipArchiveInputStream extends ArchiveInputStream implements InputSt
      * 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
+     * @param skipSplitSig Whether the stream will try to skip the zip
+     * split signature(08074B50) at the beginning. You will need to
+     * set this to true if you want to read a split archive.
      * @since 1.20
      */
     public ZipArchiveInputStream(final InputStream inputStream,
@@ -393,8 +394,12 @@ public class ZipArchiveInputStream extends ArchiveInputStream implements InputSt
         readFully(lfh);
         final ZipLong sig = new ZipLong(lfh);
 
+        if (!skipSplitSig && sig.equals(ZipLong.DD_SIG)) {
+            throw new UnsupportedZipFeatureException(UnsupportedZipFeatureException.Feature.SPLITTING);
+        }
+
         // 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))) {
+        if (sig.equals(ZipLong.SINGLE_SEGMENT_SPLIT_MARKER) || sig.equals(ZipLong.DD_SIG)) {
             // Just skip over the marker.
             final byte[] missedLfhBytes = new byte[4];
             readFully(missedLfhBytes);
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 ec3a6de..2319456 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
@@ -358,11 +358,7 @@ public class ZipFile implements Closeable {
                     final String encoding, final boolean useUnicodeExtraFields,
                     final boolean closeOnError, final boolean ignoreLocalFileHeader)
         throws IOException {
-        if(channel instanceof ZipSplitReadOnlySeekableByteChannel) {
-            isSplitZipArchive = true;
-        } else {
-            isSplitZipArchive = false;
-        }
+        isSplitZipArchive = (channel instanceof ZipSplitReadOnlySeekableByteChannel);
 
         this.archiveName = archiveName;
         this.encoding = encoding;
@@ -865,7 +861,7 @@ public class ZipFile implements Closeable {
                 ze.setLocalHeaderOffset(z64.getRelativeHeaderOffset().getLongValue());
             }
 
-            if(hasDiskStart) {
+            if (hasDiskStart) {
                 ze.setDiskNumberStart(z64.getDiskStartNumber().getValue());
             }
         }
@@ -1055,7 +1051,7 @@ public class ZipFile implements Closeable {
      */
     private void positionAtCentralDirectory64()
         throws IOException {
-        if(isSplitZipArchive) {
+        if (isSplitZipArchive) {
             wordBbuf.rewind();
             IOUtils.readFully(archive, wordBbuf);
             final long diskNumberOfEOCD = ZipLong.getValue(wordBuf);
@@ -1063,7 +1059,8 @@ 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
                     - WORD /* signature has already been read */);
@@ -1079,7 +1076,7 @@ public class ZipFile implements Closeable {
                                    + "directory locator is corrupt.");
         }
 
-        if(isSplitZipArchive) {
+        if (isSplitZipArchive) {
             skipBytes(ZIP64_EOCD_CFD_DISK_OFFSET
                     - WORD /* signature has already been read */);
             wordBbuf.rewind();
@@ -1091,7 +1088,8 @@ public class ZipFile implements Closeable {
             dwordBbuf.rewind();
             IOUtils.readFully(archive, dwordBbuf);
             final long relativeOffsetOfCFD = ZipEightByteInteger.getLongValue(dwordBuf);
-            ((ZipSplitReadOnlySeekableByteChannel)archive).position(diskNumberOfCFD, relativeOffsetOfCFD);
+            ((ZipSplitReadOnlySeekableByteChannel) archive)
+                .position(diskNumberOfCFD, relativeOffsetOfCFD);
         } else {
             skipBytes(ZIP64_EOCD_CFD_LOCATOR_OFFSET
                     - WORD /* signature has already been read */);
@@ -1110,7 +1108,7 @@ public class ZipFile implements Closeable {
      */
     private void positionAtCentralDirectory32()
         throws IOException {
-        if(isSplitZipArchive) {
+        if (isSplitZipArchive) {
             skipBytes(CFD_DISK_OFFSET);
             shortBbuf.rewind();
             IOUtils.readFully(archive, shortBbuf);
@@ -1121,7 +1119,8 @@ public class ZipFile implements Closeable {
             wordBbuf.rewind();
             IOUtils.readFully(archive, wordBbuf);
             final long relativeOffsetOfCFD = ZipLong.getValue(wordBuf);
-            ((ZipSplitReadOnlySeekableByteChannel)archive).position(diskNumberOfCFD, relativeOffsetOfCFD);
+            ((ZipSplitReadOnlySeekableByteChannel) archive)
+                .position(diskNumberOfCFD, relativeOffsetOfCFD);
         } else {
             skipBytes(CFD_LOCATOR_OFFSET);
             wordBbuf.rewind();
@@ -1261,8 +1260,9 @@ public class ZipFile implements Closeable {
 
     private int[] setDataOffset(ZipArchiveEntry ze) throws IOException {
         long offset = ze.getLocalHeaderOffset();
-        if(isSplitZipArchive) {
-            ((ZipSplitReadOnlySeekableByteChannel)archive).position(ze.getDiskNumberStart(), offset + LFH_OFFSET_FOR_FILENAME_LENGTH);
+        if (isSplitZipArchive) {
+            ((ZipSplitReadOnlySeekableByteChannel) archive)
+                .position(ze.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 {
@@ -1440,7 +1440,7 @@ public class ZipFile implements Closeable {
 
             // disk number is prior to relative offset
             final long diskNumberStartVal = ent1.getDiskNumberStart() - ent2.getDiskNumberStart();
-            if(diskNumberStartVal != 0) {
+            if (diskNumberStartVal != 0) {
                 return diskNumberStartVal < 0 ? -1 : +1;
             }
             final long val = (ent1.getLocalHeaderOffset()
diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/ZipSplitReadOnlySeekableByteChannel.java b/src/main/java/org/apache/commons/compress/archivers/zip/ZipSplitReadOnlySeekableByteChannel.java
index eae00ba..4bb6bf3 100644
--- a/src/main/java/org/apache/commons/compress/archivers/zip/ZipSplitReadOnlySeekableByteChannel.java
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/ZipSplitReadOnlySeekableByteChannel.java
@@ -19,7 +19,7 @@
 package org.apache.commons.compress.archivers.zip;
 
 import org.apache.commons.compress.archivers.ArchiveStreamFactory;
-import org.apache.commons.compress.compressors.FileNameUtil;
+import org.apache.commons.compress.utils.FileNameUtils;
 import org.apache.commons.compress.utils.MultiReadOnlySeekableByteChannel;
 
 import java.io.File;
@@ -36,28 +36,42 @@ import java.util.List;
 import java.util.Objects;
 import java.util.regex.Pattern;
 
+/**
+ * {@link MultiReadOnlySeekableByteChannel} that knows wat a splitted
+ * ZIP archive should look like.
+ *
+ * q<p>If you want to read a splitted archive using {@link ZipFile} then create an instance of this class from the parts of the archive.
+ *
+ * @since 1.20
+ */
 public class ZipSplitReadOnlySeekableByteChannel extends MultiReadOnlySeekableByteChannel {
     private final int ZIP_SPLIT_SIGNATURE_LENGTH = 4;
-    private ByteBuffer zipSplitSignatureByteBuffer = ByteBuffer.allocate(ZIP_SPLIT_SIGNATURE_LENGTH);
+    private final 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
-     * <p>
+     *
+     * <p>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</p>
      *
      * @param channels the channels to concatenate
      * @throws NullPointerException if channels is null
+     * @throws IOException if the first channel doesn't seem to hold
+     * the beginning of a split archive
      */
-    public ZipSplitReadOnlySeekableByteChannel(List<SeekableByteChannel> channels) throws IOException {
+    public ZipSplitReadOnlySeekableByteChannel(List<SeekableByteChannel> channels)
+        throws IOException {
         super(channels);
 
         // the first split zip segment should begin with zip split signature
-        validSplitSignature(channels);
+        assertSplitSignature(channels);
     }
 
     /**
      * 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),
@@ -66,13 +80,15 @@ public class ZipSplitReadOnlySeekableByteChannel extends MultiReadOnlySeekableBy
      * 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 {
+    private void assertSplitSignature(final List<SeekableByteChannel> channels)
+        throws IOException {
         SeekableByteChannel channel = channels.get(0);
         // the zip split file signature is at the beginning of the first split segment
         channel.position(0L);
@@ -82,7 +98,7 @@ public class ZipSplitReadOnlySeekableByteChannel extends MultiReadOnlySeekableBy
         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");
+            throw new IOException("The first zip split segment does not begin with split zip file signature");
         }
 
         channel.position(0L);
@@ -96,7 +112,7 @@ public class ZipSplitReadOnlySeekableByteChannel extends MultiReadOnlySeekableBy
      * @return SeekableByteChannel that concatenates all provided channels
      * @throws NullPointerException if channels is null
      */
-    public static SeekableByteChannel forSeekableByteChannels(SeekableByteChannel... channels) throws IOException {
+    public static SeekableByteChannel forOrderedSeekableByteChannels(SeekableByteChannel... channels) throws IOException {
         if (Objects.requireNonNull(channels, "channels must not be null").length == 1) {
             return channels[0];
         }
@@ -111,8 +127,11 @@ public class ZipSplitReadOnlySeekableByteChannel extends MultiReadOnlySeekableBy
      *                           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
+     * @throws IOException if the first channel doesn't seem to hold
+     * the beginning of a split archive
      */
-    public static SeekableByteChannel forSeekableByteChannels(SeekableByteChannel lastSegmentChannel, Iterable<SeekableByteChannel> channels) throws IOException {
+    public static SeekableByteChannel forOrderedSeekableByteChannels(SeekableByteChannel lastSegmentChannel,
+        Iterable<SeekableByteChannel> channels) throws IOException {
         if (channels == null || lastSegmentChannel == null) {
             throw new NullPointerException("channels must not be null");
         }
@@ -124,7 +143,7 @@ public class ZipSplitReadOnlySeekableByteChannel extends MultiReadOnlySeekableBy
         channelsList.add(lastSegmentChannel);
 
         SeekableByteChannel[] channelArray = new SeekableByteChannel[channelsList.size()];
-        return forSeekableByteChannels(channelsList.toArray(channelArray));
+        return forOrderedSeekableByteChannels(channelsList.toArray(channelArray));
     }
 
     /**
@@ -133,15 +152,17 @@ public class ZipSplitReadOnlySeekableByteChannel extends MultiReadOnlySeekableBy
      * @param lastSegmentFile the last segment of zip split files, note that the extension SHOULD be .zip
      * @return SeekableByteChannel that concatenates all zip split files
      * @throws IllegalArgumentException if the lastSegmentFile's extension is NOT .zip
+     * @throws IOException if the first channel doesn't seem to hold
+     * the beginning of a split archive
      */
     public static SeekableByteChannel buildFromLastSplitSegment(File lastSegmentFile) throws IOException {
-        String extension = FileNameUtil.getExtension(lastSegmentFile.getCanonicalPath());
+        String extension = FileNameUtils.getExtension(lastSegmentFile.getCanonicalPath());
         if (!extension.equalsIgnoreCase(ArchiveStreamFactory.ZIP)) {
-            throw new IllegalArgumentException("The extension of last zip splite segment should be .zip");
+            throw new IllegalArgumentException("The extension of last zip split segment should be .zip");
         }
 
         File parent = lastSegmentFile.getParentFile();
-        String fileBaseName = FileNameUtil.getBaseName(lastSegmentFile.getCanonicalPath());
+        String fileBaseName = FileNameUtils.getBaseName(lastSegmentFile.getCanonicalPath());
         ArrayList<File> splitZipSegments = new ArrayList<>();
 
         // zip split segments should be like z01,z02....z(n-1) based on the zip specification
@@ -166,6 +187,8 @@ public class ZipSplitReadOnlySeekableByteChannel extends MultiReadOnlySeekableBy
      * @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
+     * @throws IOException if the first channel doesn't seem to hold
+     * the beginning of a split archive
      */
     public static SeekableByteChannel forFiles(File... files) throws IOException {
         List<SeekableByteChannel> channels = new ArrayList<>();
@@ -185,7 +208,8 @@ public class ZipSplitReadOnlySeekableByteChannel extends MultiReadOnlySeekableBy
      * @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 IOException if the first channel doesn't seem to hold
+     * the beginning of a split archive
      * @throws NullPointerException if files or lastSegmentFile is null
      */
     public static SeekableByteChannel forFiles(File lastSegmentFile, Iterable<File> files) throws IOException {
@@ -206,8 +230,8 @@ public class ZipSplitReadOnlySeekableByteChannel extends MultiReadOnlySeekableBy
     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());
+            String extension1 = FileNameUtils.getExtension(file1.getPath());
+            String extension2 = FileNameUtils.getExtension(file2.getPath());
 
             if (!extension1.startsWith("z")) {
                 return -1;
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 ec3f0e9..ed94885 100644
--- a/src/main/java/org/apache/commons/compress/compressors/FileNameUtil.java
+++ b/src/main/java/org/apache/commons/compress/compressors/FileNameUtil.java
@@ -18,7 +18,6 @@
  */
 package org.apache.commons.compress.compressors;
 
-import java.io.File;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Locale;
@@ -193,33 +192,4 @@ public class FileNameUtil {
         // No custom suffix found, just append the default
         return fileName + defaultExtension;
     }
-
-
-    public static String getExtension(String filename) {
-        if (filename == null) {
-            return null;
-        }
-
-        int extensionPosition = filename.lastIndexOf('.');
-        int lastSeparatorPosition = Math.max(filename.lastIndexOf('/'), filename.lastIndexOf('\\'));
-        if(lastSeparatorPosition > extensionPosition) {
-            return "";
-        }
-        return filename.substring(extensionPosition + 1);
-    }
-
-    public static String getBaseName(String filename) {
-        if (filename == null) {
-            return null;
-        }
-
-        String name = new File(filename).getName();
-
-        int extensionPosition = name.lastIndexOf('.');
-        if(extensionPosition < 0) {
-            return name;
-        }
-
-        return name.substring(0, extensionPosition);
-    }
 }
diff --git a/src/main/java/org/apache/commons/compress/utils/FileNameUtils.java b/src/main/java/org/apache/commons/compress/utils/FileNameUtils.java
new file mode 100644
index 0000000..80981ca
--- /dev/null
+++ b/src/main/java/org/apache/commons/compress/utils/FileNameUtils.java
@@ -0,0 +1,78 @@
+/*
+ * 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 java.io.File;
+
+/**
+ * Generic file name utilities.
+ * @since 1.20
+ */
+public class FileNameUtils {
+
+    /**
+     * Returns the extension (i.e. the part after the last ".") of a file.
+     *
+     * <p>Will return an empty string if the file name doesn't contain
+     * any dots. Only the last segment of a the file name is consulted
+     * - i.e. all leading directories of the {@code filename}
+     * parameter are skipped.</p>
+     *
+     * @return the extension of filename
+     * @param filename the name of the file to obtain the extension of.
+     */
+    public static String getExtension(String filename) {
+        if (filename == null) {
+            return null;
+        }
+
+        String name = new File(filename).getName();
+        int extensionPosition = name.lastIndexOf('.');
+        if (extensionPosition < 0) {
+            return "";
+        }
+        return name.substring(extensionPosition + 1);
+    }
+
+    /**
+     * Returns the basename (i.e. the part up to and not including the
+     * last ".") of the last path segment of a filename.
+     *
+     * <p>Will return the file name itself if it doesn't contain any
+     * dots. All leading directories of the {@code filename} parameter
+     * are skipped.</p>
+     *
+     * @return the basename of filename
+     * @param filename the name of the file to obtain the basename of.
+     */
+    public static String getBaseName(String filename) {
+        if (filename == null) {
+            return null;
+        }
+
+        String name = new File(filename).getName();
+
+        int extensionPosition = name.lastIndexOf('.');
+        if (extensionPosition < 0) {
+            return name;
+        }
+
+        return name.substring(0, extensionPosition);
+    }
+}
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 5129dbd..21f25ec 100644
--- a/src/main/java/org/apache/commons/compress/utils/MultiReadOnlySeekableByteChannel.java
+++ b/src/main/java/org/apache/commons/compress/utils/MultiReadOnlySeekableByteChannel.java
@@ -212,7 +212,7 @@ public class MultiReadOnlySeekableByteChannel implements SeekableByteChannel {
      * @throws NullPointerException if channels is null
      * @return SeekableByteChannel that concatenates all provided channels
      */
-    public static SeekableByteChannel forSeekableByteChannels(SeekableByteChannel... channels) throws IOException {
+    public static SeekableByteChannel forSeekableByteChannels(SeekableByteChannel... channels) {
         if (Objects.requireNonNull(channels, "channels must not be null").length == 1) {
             return channels[0];
         }
diff --git a/src/test/java/org/apache/commons/compress/utils/FileNameUtilsTest.java b/src/test/java/org/apache/commons/compress/utils/FileNameUtilsTest.java
new file mode 100644
index 0000000..fba87c8
--- /dev/null
+++ b/src/test/java/org/apache/commons/compress/utils/FileNameUtilsTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+public class FileNameUtilsTest {
+
+    @Test
+    public void getExtensionBaseCases() {
+        assertEquals("foo", FileNameUtils.getExtension("a/b/c/bar.foo"));
+        assertEquals("", FileNameUtils.getExtension("foo"));
+    }
+
+    @Test
+    public void getExtensionCornerCases() {
+        assertNull(FileNameUtils.getExtension(null));
+        assertEquals("", FileNameUtils.getExtension("foo."));
+        assertEquals("foo", FileNameUtils.getExtension("bar/.foo"));
+    }
+
+    @Test
+    public void getBaseNameBaseCases() {
+        assertEquals("bar", FileNameUtils.getBaseName("a/b/c/bar.foo"));
+        assertEquals("foo", FileNameUtils.getBaseName("foo"));
+    }
+
+    @Test
+    public void getBaseNameCornerCases() {
+        assertNull(FileNameUtils.getBaseName(null));
+        assertEquals("foo", FileNameUtils.getBaseName("foo."));
+        assertEquals("", FileNameUtils.getBaseName("bar/.foo"));
+    }
+}
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 39c3029..71f7887 100644
--- a/src/test/java/org/apache/commons/compress/utils/ZipSplitReadOnlySeekableByteChannelTest.java
+++ b/src/test/java/org/apache/commons/compress/utils/ZipSplitReadOnlySeekableByteChannelTest.java
@@ -64,19 +64,19 @@ public class ZipSplitReadOnlySeekableByteChannelTest {
     }
 
     @Test
-    public void forSeekableByteChannelsThrowsOnNullArg() throws IOException {
+    public void forOrderedSeekableByteChannelsThrowsOnNullArg() throws IOException {
         thrown.expect(NullPointerException.class);
-        ZipSplitReadOnlySeekableByteChannel.forSeekableByteChannels(null);
+        ZipSplitReadOnlySeekableByteChannel.forOrderedSeekableByteChannels(null);
     }
 
     @Test
-    public void forSeekableByteChannelsOfTwoParametersThrowsOnNullArg() throws IOException {
+    public void forOrderedSeekableByteChannelsOfTwoParametersThrowsOnNullArg() throws IOException {
         thrown.expect(NullPointerException.class);
-        ZipSplitReadOnlySeekableByteChannel.forSeekableByteChannels(null, null);
+        ZipSplitReadOnlySeekableByteChannel.forOrderedSeekableByteChannels(null, null);
     }
 
     @Test
-    public void forSeekableByteChannelsReturnCorrectClass() throws IOException {
+    public void forOrderedSeekableByteChannelsReturnCorrectClass() throws IOException {
         File file1 = getFile("COMPRESS-477/split_zip_created_by_zip/split_zip_created_by_zip.z01");
         SeekableByteChannel firstChannel = Files.newByteChannel(file1.toPath(), StandardOpenOption.READ);
 
@@ -90,17 +90,17 @@ public class ZipSplitReadOnlySeekableByteChannelTest {
         channels.add(firstChannel);
         channels.add(secondChannel);
 
-        SeekableByteChannel channel = ZipSplitReadOnlySeekableByteChannel.forSeekableByteChannels(lastChannel, channels);
+        SeekableByteChannel channel = ZipSplitReadOnlySeekableByteChannel.forOrderedSeekableByteChannels(lastChannel, channels);
         Assert.assertTrue(channel instanceof ZipSplitReadOnlySeekableByteChannel);
 
-        channel = ZipSplitReadOnlySeekableByteChannel.forSeekableByteChannels(firstChannel, secondChannel, lastChannel);
+        channel = ZipSplitReadOnlySeekableByteChannel.forOrderedSeekableByteChannels(firstChannel, secondChannel, lastChannel);
         Assert.assertTrue(channel instanceof ZipSplitReadOnlySeekableByteChannel);
     }
 
     @Test
-    public void forSeekableByteChannelsReturnsIdentityForSingleElement() throws IOException {
+    public void forOrderedSeekableByteChannelsReturnsIdentityForSingleElement() throws IOException {
         SeekableByteChannel emptyChannel = new SeekableInMemoryByteChannel(new byte[0]);
-        final SeekableByteChannel channel = ZipSplitReadOnlySeekableByteChannel.forSeekableByteChannels(emptyChannel);
+        final SeekableByteChannel channel = ZipSplitReadOnlySeekableByteChannel.forOrderedSeekableByteChannels(emptyChannel);
         Assert.assertSame(emptyChannel, channel);
     }