This is an automated email from the ASF dual-hosted git repository.
garydgregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-compress.git
The following commit(s) were added to refs/heads/master by this push:
new 65cef25a6 Sort members.
65cef25a6 is described below
commit 65cef25a6e15bb9d644ca107d22cb2a898818259
Author: Gary Gregory <[email protected]>
AuthorDate: Tue Jul 14 13:20:44 2026 -0400
Sort members.
---
.../compress/archivers/tar/SparseFilesTest.java | 172 ++++++++++-----------
.../compressors/deflate64/HuffmanDecoderTest.java | 104 ++++++-------
2 files changed, 138 insertions(+), 138 deletions(-)
diff --git
a/src/test/java/org/apache/commons/compress/archivers/tar/SparseFilesTest.java
b/src/test/java/org/apache/commons/compress/archivers/tar/SparseFilesTest.java
index d503802ba..c68c210f7 100644
---
a/src/test/java/org/apache/commons/compress/archivers/tar/SparseFilesTest.java
+++
b/src/test/java/org/apache/commons/compress/archivers/tar/SparseFilesTest.java
@@ -59,11 +59,60 @@ class SparseFilesTest extends AbstractTest {
@TempDir
private static Path tempDir;
+ private static void appendPadded(final ByteArrayOutputStream out, final
byte[] data) {
+ out.write(data, 0, data.length);
+ final int rem = data.length % TarConstants.DEFAULT_RCDSIZE;
+ if (rem != 0) {
+ out.write(new byte[TarConstants.DEFAULT_RCDSIZE - rem], 0,
TarConstants.DEFAULT_RCDSIZE - rem);
+ }
+ }
+
+ private static String paxRecord(final String key, final String value) {
+ final int size = key.length() + value.length() + 3; // ' ', '=', '\n'
+ int len = size + Integer.toString(size).length();
+ while (len != size + Integer.toString(len).length()) {
+ len = size + Integer.toString(len).length();
+ }
+ return len + " " + key + "=" + value + "\n";
+ }
+
+ private static void putField(final byte[] header, final int offset, final
int length, final String value) {
+ final byte[] bytes =
value.getBytes(java.nio.charset.StandardCharsets.US_ASCII);
+ System.arraycopy(bytes, 0, header, offset, Math.min(length,
bytes.length));
+ }
+
+ private static void putOctal(final byte[] header, final int offset, final
int length, final long value) {
+ putField(header, offset, length, String.format("%0" + (length - 1) +
"o", value));
+ }
+
@BeforeAll
static void setupAll() throws IOException {
TestArchiveGenerator.createSparseFileTestCases(tempDir);
}
+ private static byte[] ustarHeader(final String name, final long size,
final char typeFlag) {
+ final byte[] header = new byte[TarConstants.DEFAULT_RCDSIZE];
+ putField(header, 0, 100, name);
+ putOctal(header, 100, 8, 0644);
+ putOctal(header, 108, 8, 0);
+ putOctal(header, 116, 8, 0);
+ putOctal(header, 124, 12, size);
+ putOctal(header, 136, 12, 0);
+ java.util.Arrays.fill(header, 148, 156, (byte) ' '); // checksum
placeholder
+ header[156] = (byte) typeFlag;
+ putField(header, 257, 6, "ustar");
+ header[263] = '0';
+ header[264] = '0';
+ long checksum = 0;
+ for (final byte b : header) {
+ checksum += b & 0xff;
+ }
+ putField(header, 148, 6, String.format("%06o", checksum));
+ header[154] = 0;
+ header[155] = ' ';
+ return header;
+ }
+
private void assertPaxGNUEntry(final TarArchiveEntry entry, final String
suffix) {
assertEquals("sparsefile-" + suffix, entry.getName());
assertEquals(TarConstants.LF_NORMAL, entry.getLinkFlag());
@@ -133,6 +182,25 @@ private String getTarBinaryHelp() throws IOException {
}
}
+ // Builds a PAX GNU 0.1 sparse entry whose stored size is 4 bytes but
whose sparse map claims a
+ // single 1 MiB data block. realsize equals the block size, so the
existing realSize check passes.
+ // A second entry follows, whose bytes must not be reachable through the
sparse entry.
+ private byte[] sparseArchiveWithNumbytesLargerThanSize() {
+ final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ final String pax = paxRecord("GNU.sparse.size",
String.valueOf(SPARSE_MAP_NUMBYTES)) + paxRecord("GNU.sparse.map", "0," +
SPARSE_MAP_NUMBYTES);
+ final byte[] paxData =
pax.getBytes(java.nio.charset.StandardCharsets.US_ASCII);
+ appendPadded(bos, ustarHeader("PaxHeaders/sparse.bin", paxData.length,
'x'));
+ appendPadded(bos, paxData);
+ appendPadded(bos, ustarHeader("sparse.bin", 4, '0'));
+ appendPadded(bos, new byte[] { 1, 2, 3, 4 });
+ final byte[] payload = "the following
entry".getBytes(java.nio.charset.StandardCharsets.US_ASCII);
+ appendPadded(bos, ustarHeader("next.bin", payload.length, '0'));
+ appendPadded(bos, payload);
+ final int eofLength = 2 * TarConstants.DEFAULT_RCDSIZE; // two zero
EOF records
+ bos.write(new byte[eofLength], 0, eofLength);
+ return bos.toByteArray();
+ }
+
@Test
void testCompareTarArchiveInputStreamWithTarFile() throws IOException {
final Path file = getPath("oldgnu_sparse.tar");
@@ -366,6 +434,24 @@ void testPaxGNU() throws Throwable {
}
}
+ @Test
+ void testRejectsSparseBlocksLargerThanEntrySizeTarArchiveInputStream()
throws IOException {
+ final byte[] archive = sparseArchiveWithNumbytesLargerThanSize();
+ try (TarArchiveInputStream tis = new TarArchiveInputStream(new
ByteArrayInputStream(archive))) {
+ assertThrows(ArchiveException.class, tis::getNextEntry);
+ }
+ }
+
+ @Test
+ void testRejectsSparseBlocksLargerThanEntrySizeTarFile() throws
IOException {
+ final byte[] archive = sparseArchiveWithNumbytesLargerThanSize();
+ assertThrows(ArchiveException.class, () -> {
+ try (TarFile tarFile =
TarFile.builder().setByteArray(archive).get()) {
+ tarFile.getEntries();
+ }
+ });
+ }
+
@Test
@DisabledOnOs(OS.WINDOWS)
void testTarFileExtractExtendedOldGNU() throws IOException,
InterruptedException {
@@ -539,90 +625,4 @@ void testTarFilePaxGNU() throws IOException {
assertPaxGNUEntry(entries.get(2), "1.0");
}
}
-
- private static void appendPadded(final ByteArrayOutputStream out, final
byte[] data) {
- out.write(data, 0, data.length);
- final int rem = data.length % TarConstants.DEFAULT_RCDSIZE;
- if (rem != 0) {
- out.write(new byte[TarConstants.DEFAULT_RCDSIZE - rem], 0,
TarConstants.DEFAULT_RCDSIZE - rem);
- }
- }
-
- private static String paxRecord(final String key, final String value) {
- final int size = key.length() + value.length() + 3; // ' ', '=', '\n'
- int len = size + Integer.toString(size).length();
- while (len != size + Integer.toString(len).length()) {
- len = size + Integer.toString(len).length();
- }
- return len + " " + key + "=" + value + "\n";
- }
-
- private static void putField(final byte[] header, final int offset, final
int length, final String value) {
- final byte[] bytes =
value.getBytes(java.nio.charset.StandardCharsets.US_ASCII);
- System.arraycopy(bytes, 0, header, offset, Math.min(length,
bytes.length));
- }
-
- private static void putOctal(final byte[] header, final int offset, final
int length, final long value) {
- putField(header, offset, length, String.format("%0" + (length - 1) +
"o", value));
- }
-
- private static byte[] ustarHeader(final String name, final long size,
final char typeFlag) {
- final byte[] header = new byte[TarConstants.DEFAULT_RCDSIZE];
- putField(header, 0, 100, name);
- putOctal(header, 100, 8, 0644);
- putOctal(header, 108, 8, 0);
- putOctal(header, 116, 8, 0);
- putOctal(header, 124, 12, size);
- putOctal(header, 136, 12, 0);
- java.util.Arrays.fill(header, 148, 156, (byte) ' '); // checksum
placeholder
- header[156] = (byte) typeFlag;
- putField(header, 257, 6, "ustar");
- header[263] = '0';
- header[264] = '0';
- long checksum = 0;
- for (final byte b : header) {
- checksum += b & 0xff;
- }
- putField(header, 148, 6, String.format("%06o", checksum));
- header[154] = 0;
- header[155] = ' ';
- return header;
- }
-
- // Builds a PAX GNU 0.1 sparse entry whose stored size is 4 bytes but
whose sparse map claims a
- // single 1 MiB data block. realsize equals the block size, so the
existing realSize check passes.
- // A second entry follows, whose bytes must not be reachable through the
sparse entry.
- private byte[] sparseArchiveWithNumbytesLargerThanSize() {
- final ByteArrayOutputStream bos = new ByteArrayOutputStream();
- final String pax = paxRecord("GNU.sparse.size",
String.valueOf(SPARSE_MAP_NUMBYTES)) + paxRecord("GNU.sparse.map", "0," +
SPARSE_MAP_NUMBYTES);
- final byte[] paxData =
pax.getBytes(java.nio.charset.StandardCharsets.US_ASCII);
- appendPadded(bos, ustarHeader("PaxHeaders/sparse.bin", paxData.length,
'x'));
- appendPadded(bos, paxData);
- appendPadded(bos, ustarHeader("sparse.bin", 4, '0'));
- appendPadded(bos, new byte[] { 1, 2, 3, 4 });
- final byte[] payload = "the following
entry".getBytes(java.nio.charset.StandardCharsets.US_ASCII);
- appendPadded(bos, ustarHeader("next.bin", payload.length, '0'));
- appendPadded(bos, payload);
- final int eofLength = 2 * TarConstants.DEFAULT_RCDSIZE; // two zero
EOF records
- bos.write(new byte[eofLength], 0, eofLength);
- return bos.toByteArray();
- }
-
- @Test
- void testRejectsSparseBlocksLargerThanEntrySizeTarArchiveInputStream()
throws IOException {
- final byte[] archive = sparseArchiveWithNumbytesLargerThanSize();
- try (TarArchiveInputStream tis = new TarArchiveInputStream(new
ByteArrayInputStream(archive))) {
- assertThrows(ArchiveException.class, tis::getNextEntry);
- }
- }
-
- @Test
- void testRejectsSparseBlocksLargerThanEntrySizeTarFile() throws
IOException {
- final byte[] archive = sparseArchiveWithNumbytesLargerThanSize();
- assertThrows(ArchiveException.class, () -> {
- try (TarFile tarFile =
TarFile.builder().setByteArray(archive).get()) {
- tarFile.getEntries();
- }
- });
- }
}
diff --git
a/src/test/java/org/apache/commons/compress/compressors/deflate64/HuffmanDecoderTest.java
b/src/test/java/org/apache/commons/compress/compressors/deflate64/HuffmanDecoderTest.java
index cb05bedda..5beac0499 100644
---
a/src/test/java/org/apache/commons/compress/compressors/deflate64/HuffmanDecoderTest.java
+++
b/src/test/java/org/apache/commons/compress/compressors/deflate64/HuffmanDecoderTest.java
@@ -30,6 +30,58 @@
class HuffmanDecoderTest {
+ @Test
+ void testDecodeDynamicHuffmanBlockRejectsInvalidDistanceCode() throws
Exception {
+ // final block + dynamic huffman with HLIT=1, HDIST=0, HCLEN=14. The
code length tree
+ // assigns 1-bit codes to symbols 1 and 18, which encode 1-bit codes
for literal/length
+ // symbols 256 and 257 and a single 1-bit code for distance symbol 0.
The incomplete
+ // distance tree leaves the 1 branch empty, so the block data - length
symbol 257
+ // followed by a 1 bit on the distance side - decodes to distance
symbol -1.
+ final byte[] data = {
+ // |--- binary filling ---|76543210
+ 0b00000000000000000000000000001101, // final block + dynamic
huffman + HLIT 1
+ 0b11111111111111111111111111000000, // HDIST 0 + low 3 bits of
HCLEN 14
+ 0b11111111111111111111111110000001, // high bit of HCLEN +
zero lengths for 16, 17 + low bit of length 1 for 18
+ 0b00000000000000000000000000000000, // high bits of length for
18 + zero lengths for 0, 8
+ 0b00000000000000000000000000000000, // zero lengths for 7, 9 +
low bits of 6
+ 0b00000000000000000000000000000000, // zero lengths for 6, 10,
5
+ 0b00000000000000000000000000000000, // zero lengths for 11, 4,
12
+ 0b00000000000000000000000000000000, // zero lengths for 3, 13,
2
+ 0b11111111111111111111111110010000, // zero length for 14 +
length 1 for symbol 1 + code 18
+ 0b11111111111111111111111111111111, // 7 extra bits (127 ->
138 zero lengths) + code 18
+ 0b00000000000000000000000001101011, // 7 extra bits (107 ->
118 zero lengths) + code 1 (literal 256)
+ 0b00000000000000000000000000001100 // code 1 twice (literal
257, distance 0) + length symbol 257 + invalid distance bit 1
+ };
+ try (HuffmanDecoder decoder = new HuffmanDecoder(new
ByteArrayInputStream(data))) {
+ final byte[] result = new byte[100];
+ final CompressorException e =
assertThrows(CompressorException.class, () -> {
+ final int len = decoder.decode(result);
+ fail("Should have failed but returned " + len + " entries: " +
Arrays.toString(Arrays.copyOf(result, len)));
+ });
+ assertEquals("Invalid Deflate64 distance code -1", e.getMessage());
+ }
+ }
+
+ @Test
+ void testDecodeFixedHuffmanBlockRejectsReservedLiteralLengthCode() throws
Exception {
+ // final block + fixed huffman, followed by the 8-bit fixed code
0b11000110 for
+ // literal/length symbol 286. That symbol is a decodable leaf of the
fixed tree
+ // but is reserved by RFC 1951, so it has no entry in RUN_LENGTH_TABLE.
+ final byte[] data = {
+ // |--- binary filling ---|76543210
+ 0b00000000000000000000000000011011, // final block + fixed
huffman + low 5 bits of code 286
+ 0b00000000000000000000000000000011 // high 3 bits of code 286
+ };
+ try (HuffmanDecoder decoder = new HuffmanDecoder(new
ByteArrayInputStream(data))) {
+ final byte[] result = new byte[100];
+ final CompressorException e =
assertThrows(CompressorException.class, () -> {
+ final int len = decoder.decode(result);
+ fail("Should have failed but returned " + len + " entries: " +
Arrays.toString(Arrays.copyOf(result, len)));
+ });
+ assertEquals("Invalid Deflate64 literal/length code 286",
e.getMessage());
+ }
+ }
+
@Test
void testDecodeFixedHuffmanBlockWithMemoryLookup() throws Exception {
final byte[] data = {
@@ -208,56 +260,4 @@ void testDecodeUncompressedBlockWithInvalidLenNLenValue()
throws Exception {
assertEquals("Illegal LEN / NLEN values", e.getMessage());
}
}
-
- @Test
- void testDecodeDynamicHuffmanBlockRejectsInvalidDistanceCode() throws
Exception {
- // final block + dynamic huffman with HLIT=1, HDIST=0, HCLEN=14. The
code length tree
- // assigns 1-bit codes to symbols 1 and 18, which encode 1-bit codes
for literal/length
- // symbols 256 and 257 and a single 1-bit code for distance symbol 0.
The incomplete
- // distance tree leaves the 1 branch empty, so the block data - length
symbol 257
- // followed by a 1 bit on the distance side - decodes to distance
symbol -1.
- final byte[] data = {
- // |--- binary filling ---|76543210
- 0b00000000000000000000000000001101, // final block + dynamic
huffman + HLIT 1
- 0b11111111111111111111111111000000, // HDIST 0 + low 3 bits of
HCLEN 14
- 0b11111111111111111111111110000001, // high bit of HCLEN +
zero lengths for 16, 17 + low bit of length 1 for 18
- 0b00000000000000000000000000000000, // high bits of length for
18 + zero lengths for 0, 8
- 0b00000000000000000000000000000000, // zero lengths for 7, 9 +
low bits of 6
- 0b00000000000000000000000000000000, // zero lengths for 6, 10,
5
- 0b00000000000000000000000000000000, // zero lengths for 11, 4,
12
- 0b00000000000000000000000000000000, // zero lengths for 3, 13,
2
- 0b11111111111111111111111110010000, // zero length for 14 +
length 1 for symbol 1 + code 18
- 0b11111111111111111111111111111111, // 7 extra bits (127 ->
138 zero lengths) + code 18
- 0b00000000000000000000000001101011, // 7 extra bits (107 ->
118 zero lengths) + code 1 (literal 256)
- 0b00000000000000000000000000001100 // code 1 twice (literal
257, distance 0) + length symbol 257 + invalid distance bit 1
- };
- try (HuffmanDecoder decoder = new HuffmanDecoder(new
ByteArrayInputStream(data))) {
- final byte[] result = new byte[100];
- final CompressorException e =
assertThrows(CompressorException.class, () -> {
- final int len = decoder.decode(result);
- fail("Should have failed but returned " + len + " entries: " +
Arrays.toString(Arrays.copyOf(result, len)));
- });
- assertEquals("Invalid Deflate64 distance code -1", e.getMessage());
- }
- }
-
- @Test
- void testDecodeFixedHuffmanBlockRejectsReservedLiteralLengthCode() throws
Exception {
- // final block + fixed huffman, followed by the 8-bit fixed code
0b11000110 for
- // literal/length symbol 286. That symbol is a decodable leaf of the
fixed tree
- // but is reserved by RFC 1951, so it has no entry in RUN_LENGTH_TABLE.
- final byte[] data = {
- // |--- binary filling ---|76543210
- 0b00000000000000000000000000011011, // final block + fixed
huffman + low 5 bits of code 286
- 0b00000000000000000000000000000011 // high 3 bits of code 286
- };
- try (HuffmanDecoder decoder = new HuffmanDecoder(new
ByteArrayInputStream(data))) {
- final byte[] result = new byte[100];
- final CompressorException e =
assertThrows(CompressorException.class, () -> {
- final int len = decoder.decode(result);
- fail("Should have failed but returned " + len + " entries: " +
Arrays.toString(Arrays.copyOf(result, len)));
- });
- assertEquals("Invalid Deflate64 literal/length code 286",
e.getMessage());
- }
- }
}