This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-compress.git

commit 2f4bf3c3d09ec50a1543f3ac31867e1ac57a3be2
Author: Gary D. Gregory <[email protected]>
AuthorDate: Tue Aug 19 08:12:31 2025 -0400

    [COMPRESS-707] TAR: TarUtils.verifyCheckSum() throws an Exception when
    checksum could not be parsed
---
 src/changes/changes.xml                            |   1 +
 .../compress/archivers/tar/TarArchiveEntry.java    |   6 +-
 .../commons/compress/archivers/tar/TarUtils.java   | 167 ++++++++++++---------
 .../commons/compress/archivers/ListerTest.java     |   4 +-
 .../archivers/tar/TarArchiveInputStreamTest.java   |  21 +--
 .../compress/archivers/tar/TarUtilsTest.java       |   6 +-
 .../compress/COMPRESS-707/COMPRESS-707-lenient.tar | Bin 0 -> 1024 bytes
 7 files changed, 116 insertions(+), 89 deletions(-)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 91d026d52..b54745184 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -73,6 +73,7 @@ The <action> type attribute can be add,update,fix,remove.
       <!-- FIX tar -->      
       <action type="fix" dev="pkarwasz" due-to="Tyler Nighswander, Piotr P. 
Karwasz, Gary Gregory">>Uniform handling of special tar records in TarFile and 
TarArchiveInputStream.</action>
       <action type="fix" dev="ggregory" due-to="Gary Gregory, Stanislav 
Fort">TarArchiveOutputStream now throws a IllegalArgumentException instead of 
an OutOfMemoryError.</action>
+      <action type="fix" dev="ggregory" issue="COMPRESS-707" due-to="Gary 
Gregory, Roel van Dijk">TarUtils.verifyCheckSum() throws an Exception when 
checksum could not be parsed.</action>
       <!-- FIX ar -->      
       <action type="fix" dev="ggregory" due-to="Gary 
Gregory">org.apache.commons.compress.archivers.ar.ArArchiveInputStream.readGNUStringTable(byte[],
 int, int) now provides a better exception message, wrapping the underlying 
exception.</action>
       <action type="fix" dev="ggregory" due-to="Gary 
Gregory">org.apache.commons.compress.archivers.ar.ArArchiveInputStream.read(byte[],
 int, int) now throws ArchiveException instead of ArithmeticException.</action>
diff --git 
a/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveEntry.java 
b/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveEntry.java
index 70bfcf7d4..6d5b81e98 100644
--- 
a/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveEntry.java
+++ 
b/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveEntry.java
@@ -1132,7 +1132,7 @@ public boolean isCharacterDevice() {
      * Tests whether this entry's checksum status.
      *
      * @return if the header checksum is reasonably correct
-     * @see TarUtils#verifyCheckSum(byte[])
+     * @see TarUtils#verifyCheckSum(byte[], boolean)
      * @since 1.5
      */
     public boolean isCheckSumOK() {
@@ -1498,7 +1498,7 @@ private int parseTarHeaderBlock(final byte[] header, 
final ZipEncoding encoding,
         offset += SIZELEN;
         mTime = FileTimes.fromUnixTime(parseOctalOrBinary(header, offset, 
MODTIMELEN, lenient));
         offset += MODTIMELEN;
-        checkSumOk = TarUtils.verifyCheckSum(header);
+        checkSumOk = TarUtils.verifyCheckSum(header, lenient);
         offset += CHKSUMLEN;
         linkFlag = header[offset++];
         linkName = oldStyle ? TarUtils.parseName(header, offset, NAMELEN) : 
TarUtils.parseName(header, offset, NAMELEN, encoding);
@@ -1563,7 +1563,7 @@ private void parseUstarHeaderBlock(final Map<String, 
String> globalPaxHeaders, f
                 offset += SPARSELEN_GNU;
                 isExtended = TarUtils.parseBoolean(header, offset);
                 offset += ISEXTENDEDLEN_GNU;
-                realSize = TarUtils.parseOctal(header, offset, 
REALSIZELEN_GNU, "parseUstarHeaderBlock()");
+                realSize = TarUtils.parseOctal(header, offset, 
REALSIZELEN_GNU, "parseUstarHeaderBlock()", false);
                 break;
             }
             // Star format (Schily tar)
diff --git 
a/src/main/java/org/apache/commons/compress/archivers/tar/TarUtils.java 
b/src/main/java/org/apache/commons/compress/archivers/tar/TarUtils.java
index 041418353..b5c28ab99 100644
--- a/src/main/java/org/apache/commons/compress/archivers/tar/TarUtils.java
+++ b/src/main/java/org/apache/commons/compress/archivers/tar/TarUtils.java
@@ -86,12 +86,12 @@ public ByteBuffer encode(final String name) {
     /**
      * Applies the PAX headers and sparse headers to the given tar entry.
      *
-     * @param entry               the tar entry to handle
-     * @param paxHeaders          per file PAX headers
-     * @param sparseHeaders       per file sparse headers
-     * @param globalPaxHeaders    global PAX headers
-     * @param globalSparseHeaders global sparse headers
-     * @throws IOException if an I/O error occurs while reading the entry
+     * @param entry               the tar entry to handle.
+     * @param paxHeaders          per file PAX headers.
+     * @param sparseHeaders       per file sparse headers.
+     * @param globalPaxHeaders    global PAX headers.
+     * @param globalSparseHeaders global sparse headers.
+     * @throws IOException if an I/O error occurs while reading the entry.
      */
     static void applyPaxHeadersToEntry(final TarArchiveEntry entry, final 
Map<String, String> paxHeaders, final List<TarArchiveStructSparse> 
sparseHeaders,
             final Map<String, String> globalPaxHeaders, final 
List<TarArchiveStructSparse> globalSparseHeaders) throws IOException {
@@ -156,12 +156,12 @@ private static void formatBigIntegerBinary(final long 
value, final byte[] buf, f
      * Uses {@link #formatUnsignedOctalString} to format the value as an octal 
string with leading zeros. The converted number is followed by NUL and then
      * space.
      *
-     * @param value  The value to convert
-     * @param buf    The destination buffer
+     * @param value  The value to convert.
+     * @param buf    The destination buffer.
      * @param offset The starting offset into the buffer.
      * @param length The size of the buffer.
-     * @return The updated value of offset, i.e. offset+length
-     * @throws IllegalArgumentException if the value (and trailer) will not 
fit in the buffer
+     * @return The updated value of offset, i.e. offset+length.
+     * @throws IllegalArgumentException if the value (and trailer) will not 
fit in the buffer.
      */
     public static int formatCheckSumOctalBytes(final long value, final byte[] 
buf, final int offset, final int length) {
         int idx = length - 2; // for NUL and space
@@ -194,12 +194,12 @@ private static void formatLongBinary(final long value, 
final byte[] buf, final i
      *
      * Uses {@link #formatUnsignedOctalString} to format the value as an octal 
string with leading zeros. The converted number is followed by a space.
      *
-     * @param value  The value to write as octal
+     * @param value  The value to write as octal.
      * @param buf    The destinationbuffer.
      * @param offset The starting offset into the buffer.
-     * @param length The length of the buffer
-     * @return The updated offset
-     * @throws IllegalArgumentException if the value (and trailer) will not 
fit in the buffer
+     * @param length The length of the buffer.
+     * @return The updated offset.
+     * @throws IllegalArgumentException if the value (and trailer) will not 
fit in the buffer.
      */
     public static int formatLongOctalBytes(final long value, final byte[] buf, 
final int offset, final int length) {
         final int idx = length - 1; // For space
@@ -243,9 +243,9 @@ public static int formatLongOctalOrBinaryBytes(final long 
value, final byte[] bu
      *
      * @param name   The header name from which to copy the characters.
      * @param buf    The buffer where the name is to be stored.
-     * @param offset The starting offset into the buffer
+     * @param offset The starting offset into the buffer.
      * @param length The maximum number of header bytes to copy.
-     * @return The updated offset, i.e. offset + length
+     * @return The updated offset, i.e. offset + length.
      */
     public static int formatNameBytes(final String name, final byte[] buf, 
final int offset, final int length) {
         try {
@@ -266,11 +266,11 @@ public static int formatNameBytes(final String name, 
final byte[] buf, final int
      *
      * @param name     The header name from which to copy the characters.
      * @param buf      The buffer where the name is to be stored.
-     * @param offset   The starting offset into the buffer
+     * @param offset   The starting offset into the buffer.
      * @param length   The maximum number of header bytes to copy.
-     * @param encoding name of the encoding to use for file names
-     * @return The updated offset, i.e. offset + length
-     * @throws IOException on error
+     * @param encoding name of the encoding to use for file names.
+     * @return The updated offset, i.e. offset + length.
+     * @throws IOException on error.
      * @since 1.4
      */
     public static int formatNameBytes(final String name, final byte[] buf, 
final int offset, final int length, final ZipEncoding encoding) throws 
IOException {
@@ -291,12 +291,12 @@ public static int formatNameBytes(final String name, 
final byte[] buf, final int
      *
      * Uses {@link #formatUnsignedOctalString} to format the value as an octal 
string with leading zeros. The converted number is followed by space and NUL
      *
-     * @param value  The value to write
-     * @param buf    The buffer to receive the output
-     * @param offset The starting offset into the buffer
-     * @param length The size of the output buffer
-     * @return The updated offset, i.e. offset+length
-     * @throws IllegalArgumentException if the value (and trailer) will not 
fit in the buffer
+     * @param value  The value to write.
+     * @param buf    The buffer to receive the output.
+     * @param offset The starting offset into the buffer.
+     * @param length The size of the output buffer.
+     * @return The updated offset, i.e. offset+length.
+     * @throws IllegalArgumentException if the value (and trailer) will not 
fit in the buffer.
      */
     public static int formatOctalBytes(final long value, final byte[] buf, 
final int offset, final int length) {
         int idx = length - 2; // For space and trailing null
@@ -309,11 +309,11 @@ public static int formatOctalBytes(final long value, 
final byte[] buf, final int
     /**
      * Fills a buffer with unsigned octal number, padded with leading zeroes.
      *
-     * @param value  number to convert to octal - treated as unsigned
-     * @param buffer destination buffer
-     * @param offset starting offset in buffer
-     * @param length length of buffer to fill
-     * @throws IllegalArgumentException if the value will not fit in the buffer
+     * @param value  number to convert to octal - treated as unsigned.
+     * @param buffer destination buffer.
+     * @param offset starting offset in buffer.
+     * @param length length of buffer to fill.
+     * @throws IllegalArgumentException if the value will not fit in the 
buffer.
      */
     public static void formatUnsignedOctalString(final long value, final 
byte[] buffer, final int offset, final int length) {
         int remaining = length;
@@ -347,14 +347,14 @@ public static void formatUnsignedOctalString(final long 
value, final byte[] buff
      *     GNU long file and link names are translated to their equivalent PAX 
headers.
      * </p>
      *
-     * @param input the input stream from which to read the special tar entry 
content
-     * @param encoding the encoding to use for reading names
-     * @param entry the tar entry to handle
-     * @param paxHeaders the map to update with PAX headers
-     * @param sparseHeaders the list to update with sparse headers
-     * @param globalPaxHeaders the map to update with global PAX headers
-     * @param globalSparseHeaders the list to update with global sparse headers
-     * @throws IOException if an I/O error occurs while reading the entry
+     * @param input the input stream from which to read the special tar entry 
content.
+     * @param encoding the encoding to use for reading names.
+     * @param entry the tar entry to handle.
+     * @param paxHeaders the map to update with PAX headers.
+     * @param sparseHeaders the list to update with sparse headers.
+     * @param globalPaxHeaders the map to update with global PAX headers.
+     * @param globalSparseHeaders the list to update with global sparse 
headers.
+     * @throws IOException if an I/O error occurs while reading the entry.
      */
     static void handleSpecialTarRecord(final InputStream input, final 
ZipEncoding encoding, final TarArchiveEntry entry, final Map<String, String> 
paxHeaders,
             final List<TarArchiveStructSparse> sparseHeaders, final 
Map<String, String> globalPaxHeaders,
@@ -398,8 +398,8 @@ static boolean isOctalDigit(final byte b) {
      *     that apply to the entire archive or to the next file entry.
      * </p>
      *
-     * @param entry the tar record to check
-     * @return {@code true} if the entry is a special tar record, {@code 
false} otherwise
+     * @param entry the tar record to check.
+     * @return {@code true} if the entry is a special tar record, {@code 
false} otherwise.
      */
     static boolean isSpecialTarRecord(final TarArchiveEntry entry) {
         return entry.isGNULongLinkEntry() || entry.isGNULongNameEntry() || 
entry.isGlobalPaxHeader() || entry.isPaxHeader();
@@ -451,8 +451,8 @@ public static boolean parseBoolean(final byte[] buffer, 
final int offset) {
      * For PAX Format 0.1, the sparse headers are stored in a single variable 
: GNU.sparse.map GNU.sparse.map Map of non-null data chunks. It is a string
      * consisting of comma-separated values "offset,size[,offset-1,size-1...]"
      *
-     * @param sparseMap the sparse map string consisting of comma-separated 
values "offset,size[,offset-1,size-1...]"
-     * @return unmodifiable list of sparse headers parsed from sparse map
+     * @param sparseMap the sparse map string consisting of comma-separated 
values "offset,size[,offset-1,size-1...]".
+     * @return unmodifiable list of sparse headers parsed from sparse map.
      * @throws IOException Corrupted TAR archive.
      * @since 1.21
      */
@@ -503,9 +503,9 @@ public static String parseName(final byte[] buffer, final 
int offset, final int
      * @param buffer   The buffer from which to parse.
      * @param offset   The offset into the buffer from which to parse.
      * @param length   The maximum number of bytes to parse.
-     * @param encoding name of the encoding to use for file names
+     * @param encoding name of the encoding to use for file names.
      * @return The entry name.
-     * @throws IOException on error
+     * @throws IOException on error.
      * @since 1.4
      */
     public static String parseName(final byte[] buffer, final int offset, 
final int length, final ZipEncoding encoding) throws IOException {
@@ -543,10 +543,10 @@ public static String parseName(final byte[] buffer, final 
int offset, final int
      * @throws IllegalArgumentException if the trailing space/NUL is missing 
or if an invalid byte is detected.
      */
     public static long parseOctal(final byte[] buffer, final int offset, final 
int length) {
-        return parseOctal(buffer, offset, length, "parseOctal()");
+        return parseOctal(buffer, offset, length, "parseOctal()", false);
     }
 
-    static long parseOctal(final byte[] buffer, final int offset, final int 
length, final String context) {
+    static long parseOctal(final byte[] buffer, final int offset, final int 
length, final String context, final boolean lenient) {
         long result = 0;
         int end = offset + length;
         int start = offset;
@@ -574,12 +574,14 @@ static long parseOctal(final byte[] buffer, final int 
offset, final int length,
         }
         for (; start < end; start++) {
             final byte currentByte = buffer[start];
-            // CheckStyle:MagicNumber OFF
             if (!isOctalDigit(currentByte)) {
+                if (currentByte == 0 && lenient) {
+                    // When lenient, an early NUL ends the parsing 
(COMPRESS-707).
+                    return result;
+                }
                 throw new IllegalArgumentException(context + ": " + 
exceptionMessage(buffer, offset, length, start, currentByte));
             }
             result = (result << 3) + (currentByte - '0'); // convert from ASCII
-            // CheckStyle:MagicNumber ON
         }
         return result;
     }
@@ -598,7 +600,7 @@ static long parseOctal(final byte[] buffer, final int 
offset, final int length,
      */
     public static long parseOctalOrBinary(final byte[] buffer, final int 
offset, final int length) {
         if ((buffer[offset] & 0x80) == 0) {
-            return parseOctal(buffer, offset, length, "parseOctalOrBinary()");
+            return parseOctal(buffer, offset, length, "parseOctalOrBinary()", 
false);
         }
         final boolean negative = buffer[offset] == (byte) 0xff;
         if (length < 9) {
@@ -618,9 +620,9 @@ public static long parseOctalOrBinary(final byte[] buffer, 
final int offset, fin
      * {@link #parseFromPAX01SparseHeaders} directly instead.
      * </p>
      *
-     * @param sparseMap the sparse map string consisting of comma-separated 
values "offset,size[,offset-1,size-1...]"
-     * @return sparse headers parsed from sparse map
-     * @deprecated use #parseFromPAX01SparseHeaders instead
+     * @param sparseMap the sparse map string consisting of comma-separated 
values "offset,size[,offset-1,size-1...]".
+     * @return sparse headers parsed from sparse map.
+     * @deprecated use #parseFromPAX01SparseHeaders instead.
      */
     @Deprecated
     protected static List<TarArchiveStructSparse> 
parsePAX01SparseHeaders(final String sparseMap) {
@@ -637,8 +639,8 @@ protected static List<TarArchiveStructSparse> 
parsePAX01SparseHeaders(final Stri
      * map entries, each one consisting of two numbers giving the offset and 
size of the data block it describes.
      *
      * @param inputStream parsing source.
-     * @param recordSize  The size the TAR header
-     * @return sparse headers
+     * @param recordSize  The size the TAR header.
+     * @return sparse headers.
      * @throws IOException if an I/O error occurs.
      */
     protected static List<TarArchiveStructSparse> 
parsePAX1XSparseHeaders(final InputStream inputStream, final int recordSize) 
throws IOException {
@@ -692,12 +694,12 @@ protected static List<TarArchiveStructSparse> 
parsePAX1XSparseHeaders(final Inpu
      * <em>GNU.sparse.map</em>: Map of non-null data chunks. It is a string 
consisting of comma-separated values "offset,size[,offset-1,size-1...]"
      * </p>
      *
-     * @param inputStream      input stream to read keys and values
-     * @param sparseHeaders    used in PAX Format 0.0 &amp; 0.1, as it may 
appear multiple times, the sparse headers need to be stored in an array, not a 
map
-     * @param globalPaxHeaders global PAX headers of the tar archive
+     * @param inputStream      input stream to read keys and values.
+     * @param sparseHeaders    used in PAX Format 0.0 &amp; 0.1, as it may 
appear multiple times, the sparse headers need to be stored in an array, not a 
map.
+     * @param globalPaxHeaders global PAX headers of the tar archive.
      * @return map of PAX headers values found inside the current (local or 
global) PAX headers tar entry.
      * @throws IOException if an I/O error occurs.
-     * @deprecated use the four-arg version instead
+     * @deprecated use the four-arg version instead.
      */
     @Deprecated
     protected static Map<String, String> parsePaxHeaders(final InputStream 
inputStream, final List<TarArchiveStructSparse> sparseHeaders,
@@ -836,7 +838,7 @@ protected static Map<String, String> parsePaxHeaders(final 
InputStream inputStre
      *
      * @param buffer The buffer from which to parse.
      * @param offset The offset into the buffer from which to parse.
-     * @return a parsed sparse struct
+     * @return a parsed sparse struct.
      * @since 1.20
      */
     public static TarArchiveStructSparse parseSparse(final byte[] buffer, 
final int offset) {
@@ -849,8 +851,8 @@ public static TarArchiveStructSparse parseSparse(final 
byte[] buffer, final int
      * For 1.x PAX Format, the sparse headers are stored in the file data 
block, preceding the actual file data. It consists of a series of decimal 
numbers
      * delimited by newlines.
      *
-     * @param inputStream the input stream of the tar file
-     * @return the decimal number delimited by '\n', and the bytes read from 
input stream
+     * @param inputStream the input stream of the tar file.
+     * @return the decimal number delimited by '\n', and the bytes read from 
input stream.
      * @throws IOException if an I/O error occurs.
      */
     private static long[] readLineOfNumberForPax1x(final InputStream 
inputStream) throws IOException {
@@ -874,12 +876,12 @@ private static long[] readLineOfNumberForPax1x(final 
InputStream inputStream) th
     /**
      * Reads a long name (file or link name) from the input stream for a 
special tar record.
      *
-     * @param input the input stream from which to read the long name
-     * @param encoding the encoding to use for reading the name
-     * @param entry the tar entry containing the long name
-     * @return the decoded long name, with trailing NULs removed
-     * @throws IOException if an I/O error occurs or the entry is truncated
-     * @throws ArchiveException if the entry size is invalid
+     * @param input the input stream from which to read the long name.
+     * @param encoding the encoding to use for reading the name.
+     * @param entry the tar entry containing the long name.
+     * @return the decoded long name, with trailing NULs removed.
+     * @throws IOException if an I/O error occurs or the entry is truncated.
+     * @throws ArchiveException if the entry size is invalid.
      */
     private static String readLongName(final InputStream input, final 
ZipEncoding encoding, final TarArchiveEntry entry)
             throws IOException {
@@ -935,14 +937,37 @@ static List<TarArchiveStructSparse> 
readSparseStructs(final byte[] buffer, final
      * well evolve over time as more special cases are encountered.
      * </p>
      *
-     * @param header tar header
-     * @return whether the checksum is reasonably good
+     * @param header tar header.
+     * @return whether the checksum is reasonably good.
      * @see <a 
href="https://en.wikipedia.org/wiki/Tar_(computing)#File_header">TAR header</a>
      * @see <a 
href="https://issues.apache.org/jira/browse/COMPRESS-191";>COMPRESS-191</a>
      * @since 1.5
      */
     public static boolean verifyCheckSum(final byte[] header) {
-        final long storedSum = parseOctal(header, TarConstants.CHKSUM_OFFSET, 
TarConstants.CHKSUMLEN, "verifyCheckSum()");
+        return verifyCheckSum(header, false);
+    }
+
+    /**
+     * Verifies the checksum in the <a 
href="https://en.wikipedia.org/wiki/Tar_(computing)#File_header">TAR 
header</a>: <blockquote>The checksum is calculated
+     * by taking the sum of the unsigned byte values of the header block with 
the eight checksum bytes taken to be ASCII spaces (decimal value 32). It is 
stored
+     * as a six digit octal number with leading zeroes followed by a NUL and 
then a space. Various implementations do not adhere to this format. For better
+     * compatibility, ignore leading and trailing whitespace, and get the 
first six digits. In addition, some historic tar implementations treated bytes 
as
+     * signed. Implementations typically calculate the checksum both ways, and 
treat it as good if either the signed or unsigned sum matches the included
+     * checksum.</blockquote>
+     * <p>
+     * The return value of this method should be treated as a best-effort 
heuristic rather than an absolute and final truth. The checksum verification 
logic may
+     * well evolve over time as more special cases are encountered.
+     * </p>
+     *
+     * @param header tar header.
+     * @param lenient Whether to allow out-of-spec formatting.
+     * @return whether the checksum is reasonably good
+     * @see <a 
href="https://en.wikipedia.org/wiki/Tar_(computing)#File_header">TAR header</a>
+     * @see <a 
href="https://issues.apache.org/jira/browse/COMPRESS-191";>COMPRESS-191</a>
+     * @see <a 
href="https://issues.apache.org/jira/browse/COMPRESS-707";>COMPRESS-707</a>
+     */
+    static boolean verifyCheckSum(final byte[] header, final boolean lenient) {
+        final long storedSum = parseOctal(header, TarConstants.CHKSUM_OFFSET, 
TarConstants.CHKSUMLEN, "verifyCheckSum()", lenient);
         long unsignedSum = 0;
         long signedSum = 0;
         for (int i = 0; i < header.length; i++) {
diff --git 
a/src/test/java/org/apache/commons/compress/archivers/ListerTest.java 
b/src/test/java/org/apache/commons/compress/archivers/ListerTest.java
index baa7799b6..c9ce60a65 100644
--- a/src/test/java/org/apache/commons/compress/archivers/ListerTest.java
+++ b/src/test/java/org/apache/commons/compress/archivers/ListerTest.java
@@ -32,13 +32,13 @@
 class ListerTest {
 
     /**
-     * Creates a stream of paths of test fixtures with file names that don't 
end with {@code "-fail"} for specific file extensions.
+     * Creates a stream of paths of test fixtures with file names that don't 
end with {@code "-fail"} or {@code "-lenient"} for specific file extensions.
      *
      * @return a stream of paths.
      * @throws IOException if an I/O error is thrown.
      */
     public static Stream<Path> getFixtures() throws IOException {
-        return PathUtils.walk(Paths.get("src/test/resources"), new 
RegexFileFilter("^(?!.*(-fail)).*\\.(tar|ar|arj|apk|dump)$"), 10, false);
+        return PathUtils.walk(Paths.get("src/test/resources"), new 
RegexFileFilter("^(?!.*(-fail|-lenient)).*\\.(tar|ar|arj|apk|dump)$"), 10, 
false);
     }
 
     @ParameterizedTest
diff --git 
a/src/test/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStreamTest.java
 
b/src/test/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStreamTest.java
index 0dcaef850..9d51542c8 100644
--- 
a/src/test/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStreamTest.java
+++ 
b/src/test/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStreamTest.java
@@ -63,7 +63,6 @@
 import org.apache.commons.compress.archivers.ArchiveStreamFactory;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.io.function.IOConsumer;
-import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.ValueSource;
@@ -93,6 +92,17 @@ private TarArchiveInputStream getTestStream(final String 
name) {
         return new 
TarArchiveInputStream(TarArchiveInputStreamTest.class.getResourceAsStream(name));
     }
 
+    @Test
+    void testChecksumOnly4Byte() throws IOException {
+        try (InputStream in = 
newInputStream("org/apache/commons/compress/COMPRESS-707/COMPRESS-707-lenient.tar");
+                TarArchiveInputStream archive = 
TarArchiveInputStream.builder().setInputStream(in).setLenient(true).get()) {
+            final TarArchiveEntry nextEntry = archive.getNextEntry();
+            assertNotNull(nextEntry);
+            assertEquals("hi-gary.txt", nextEntry.getName());
+            assertTrue(nextEntry.isCheckSumOK());
+        }
+    }
+
     @Test
     void testCompress197() throws IOException {
         try (TarArchiveInputStream tar = getTestStream("/COMPRESS-197.tar")) {
@@ -390,15 +400,6 @@ void testParseTarWithNonNumberPaxHeaders() throws 
IOException {
         }
     }
 
-    @Test
-    @Disabled
-    void testChecksum() throws IOException {
-        try (InputStream in = 
newInputStream("org/apache/commons/compress/COMPRESS-707/COMPRESS-707.tar");
-                TarArchiveInputStream archive = 
TarArchiveInputStream.builder().setInputStream(in).setLenient(true).get()) {
-            archive.getNextEntry();
-        }
-    }
-
     @Test
     void testParseTarWithSpecialPaxHeaders() throws IOException {
         try (InputStream in = newInputStream("COMPRESS-530-fail.tar");
diff --git 
a/src/test/java/org/apache/commons/compress/archivers/tar/TarUtilsTest.java 
b/src/test/java/org/apache/commons/compress/archivers/tar/TarUtilsTest.java
index a9a128816..f1ac9593f 100644
--- a/src/test/java/org/apache/commons/compress/archivers/tar/TarUtilsTest.java
+++ b/src/test/java/org/apache/commons/compress/archivers/tar/TarUtilsTest.java
@@ -556,7 +556,7 @@ void testVerifyHeaderCheckSum() {
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-        assertTrue(TarUtils.verifyCheckSum(valid));
+        assertTrue(TarUtils.verifyCheckSum(valid, false));
 
         final byte[] compress117 = { // from COMPRESS-117
                 (byte) 0x37, (byte) 0x7a, (byte) 0x43, (byte) 0x2e, (byte) 
0x74, (byte) 0x78, (byte) 0x74, (byte) 0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0,
@@ -575,7 +575,7 @@ void testVerifyHeaderCheckSum() {
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };
-        assertTrue(TarUtils.verifyCheckSum(compress117));
+        assertTrue(TarUtils.verifyCheckSum(compress117, false));
 
         final byte[] invalid = { // from the testAIFF.aif file in Tika
                 70, 79, 82, 77, 0, 0, 15, 46, 65, 73, 70, 70, 67, 79, 77, 77, 
0, 0, 0, 18, 0, 2, 0, 0, 3, -64, 0, 16, 64, 14, -84, 68, 0, 0, 0, 0, 0, 0, 83, 
83,
@@ -590,7 +590,7 @@ void testVerifyHeaderCheckSum() {
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, -2, 0, 1, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 1, -1, -1, 0, 0, 0, 0, -1, -1, 0, 2, -1, -2, 0, 2, -1, -2, 
0,
                 2, -1, -1, 0, 0, 0, 0, -1, -1, 0, 1, -1, -1, 0, 1, -1, -1, 0, 
1, -1, -1, 0, 1, -1, -1, 0, 1, 0, 0, 0, 0, -1, -1, 0, 2, -1, -2, 0, 1, 0, 0, 0, 
0,
                 0, 0, 0, 0, 0, 0, 0, 1, -1, -1, 0, 0, 0, 0, -1, -1, 0, 1, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
-        assertFalse(TarUtils.verifyCheckSum(invalid));
+        assertFalse(TarUtils.verifyCheckSum(invalid, false));
     }
 
     @Test
diff --git 
a/src/test/resources/org/apache/commons/compress/COMPRESS-707/COMPRESS-707-lenient.tar
 
b/src/test/resources/org/apache/commons/compress/COMPRESS-707/COMPRESS-707-lenient.tar
new file mode 100644
index 000000000..560c0012b
Binary files /dev/null and 
b/src/test/resources/org/apache/commons/compress/COMPRESS-707/COMPRESS-707-lenient.tar
 differ

Reply via email to