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 b778b64d01811046ae5c69c94012508dde1c58b3
Author: Gary Gregory <garydgreg...@gmail.com>
AuthorDate: Sat Feb 17 14:35:32 2024 -0500

    Internal refactoring
---
 .../commons/compress/harmony/pack200/Codec.java    |  25 ++++++++-
 .../compress/harmony/pack200/PopulationCodec.java  |   2 +-
 .../commons/compress/harmony/pack200/RunCodec.java |   2 +-
 .../compress/harmony/unpack200/Archive.java        |  60 ++++++++++++---------
 .../harmony/unpack200/Pack200UnpackerAdapter.java  |  16 ++++++
 .../compress/harmony/unpack200/Segment.java        |   6 +--
 .../commons/compress/utils/BoundedInputStream.java |   6 +++
 .../harmony/pack200/tests/RunCodecTest.java        |  30 +++++++++++
 .../harmony/unpack200/tests/ArchiveTest.java       |  34 ++++++++++++
 .../harmony/unpack200/tests/SegmentTest.java       |  35 ++++++++++++
 .../apache/commons/compress/pack/bandint_oom.pack  | Bin 0 -> 88 bytes
 .../apache/commons/compress/pack/cpfloat_oom.pack  | Bin 0 -> 178 bytes
 .../apache/commons/compress/pack/cputf8_oom.pack   | Bin 0 -> 427 bytes
 .../apache/commons/compress/pack/favoured_oom.pack | Bin 0 -> 84 bytes
 .../apache/commons/compress/pack/filebits_oom.pack | Bin 0 -> 309 bytes
 .../apache/commons/compress/pack/flags_oom.pack    | Bin 0 -> 1624 bytes
 .../commons/compress/pack/references_oom.pack      | Bin 0 -> 66 bytes
 .../commons/compress/pack/segment_header_oom.pack  | Bin 0 -> 41 bytes
 .../commons/compress/pack/signatures_oom.pack      | Bin 0 -> 121 bytes
 19 files changed, 183 insertions(+), 33 deletions(-)

diff --git 
a/src/main/java/org/apache/commons/compress/harmony/pack200/Codec.java 
b/src/main/java/org/apache/commons/compress/harmony/pack200/Codec.java
index a3f4d43f8..a575558ba 100644
--- a/src/main/java/org/apache/commons/compress/harmony/pack200/Codec.java
+++ b/src/main/java/org/apache/commons/compress/harmony/pack200/Codec.java
@@ -19,6 +19,8 @@ package org.apache.commons.compress.harmony.pack200;
 import java.io.IOException;
 import java.io.InputStream;
 
+import org.apache.commons.io.input.BoundedInputStream;
+
 /**
  * A Codec allows a sequence of bytes to be decoded into integer values (or 
vice versa).
  * <p>
@@ -123,7 +125,7 @@ public abstract class Codec {
      */
     public int[] decodeInts(final int n, final InputStream in) throws 
IOException, Pack200Exception {
         lastBandLength = 0;
-        final int[] result = new int[n];
+        final int[] result = new int[check(n, in)];
         int last = 0;
         for (int i = 0; i < n; i++) {
             result[i] = last = decode(in, last);
@@ -142,7 +144,7 @@ public abstract class Codec {
      * @throws Pack200Exception if there is a problem decoding the value or 
that the value is invalid
      */
     public int[] decodeInts(final int n, final InputStream in, final int 
firstValue) throws IOException, Pack200Exception {
-        final int[] result = new int[n + 1];
+        final int[] result = new int[check(n + 1, in)];
         result[0] = firstValue;
         int last = firstValue;
         for (int i = 1; i < n + 1; i++) {
@@ -151,6 +153,25 @@ public abstract class Codec {
         return result;
     }
 
+    int check(final int n, final InputStream in) throws Pack200Exception {
+        if (in instanceof BoundedInputStream) {
+            final BoundedInputStream bin = (BoundedInputStream) in;
+            final long count = bin.getCount();
+            final long maxLength = bin.getMaxLength();
+            if (maxLength > -1) {
+                final long remaining = maxLength - count;
+                final String format = "Can't read beyond end of stream (n = 
%,d, count = %,d, maxLength = %,d, remaining = %,d)";
+                if (count < -1) {
+                    throw new Pack200Exception(String.format(format, n, count, 
maxLength, remaining));
+                }
+                if (n > remaining) {
+                    throw new Pack200Exception(String.format(format, n, count, 
maxLength, remaining));
+                }
+            }
+        }
+        return n;
+    }
+
     /**
      * Encodes a single value into a sequence of bytes. Note that this method 
can only be used for non-delta encodings.
      *
diff --git 
a/src/main/java/org/apache/commons/compress/harmony/pack200/PopulationCodec.java
 
b/src/main/java/org/apache/commons/compress/harmony/pack200/PopulationCodec.java
index 1ac615995..d32c55701 100644
--- 
a/src/main/java/org/apache/commons/compress/harmony/pack200/PopulationCodec.java
+++ 
b/src/main/java/org/apache/commons/compress/harmony/pack200/PopulationCodec.java
@@ -60,7 +60,7 @@ public class PopulationCodec extends Codec {
     @Override
     public int[] decodeInts(final int n, final InputStream in) throws 
IOException, Pack200Exception {
         lastBandLength = 0;
-        favoured = new int[n]; // there must be <= n values, but probably a lot
+        favoured = new int[check(n, in)]; // there must be <= n values, but 
probably a lot
         // less
         int[] result;
         // read table of favorites first
diff --git 
a/src/main/java/org/apache/commons/compress/harmony/pack200/RunCodec.java 
b/src/main/java/org/apache/commons/compress/harmony/pack200/RunCodec.java
index 1d0902b85..883a3095e 100644
--- a/src/main/java/org/apache/commons/compress/harmony/pack200/RunCodec.java
+++ b/src/main/java/org/apache/commons/compress/harmony/pack200/RunCodec.java
@@ -67,7 +67,7 @@ public class RunCodec extends Codec {
         normalise(aValues, aCodec);
         final int[] bValues = bCodec.decodeInts(n - k, in);
         normalise(bValues, bCodec);
-        final int[] band = new int[n];
+        final int[] band = new int[check(n, in)];
         System.arraycopy(aValues, 0, band, 0, k);
         System.arraycopy(bValues, 0, band, k, n - k);
         lastBandLength = aCodec.lastBandLength + bCodec.lastBandLength;
diff --git 
a/src/main/java/org/apache/commons/compress/harmony/unpack200/Archive.java 
b/src/main/java/org/apache/commons/compress/harmony/unpack200/Archive.java
index 6b41eff9e..f70c56ca9 100644
--- a/src/main/java/org/apache/commons/compress/harmony/unpack200/Archive.java
+++ b/src/main/java/org/apache/commons/compress/harmony/unpack200/Archive.java
@@ -18,13 +18,16 @@ package org.apache.commons.compress.harmony.unpack200;
 
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
-import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.io.UncheckedIOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.jar.JarEntry;
 import java.util.jar.JarInputStream;
 import java.util.jar.JarOutputStream;
@@ -32,6 +35,7 @@ import java.util.zip.GZIPInputStream;
 
 import org.apache.commons.compress.harmony.pack200.Pack200Exception;
 import org.apache.commons.io.IOUtils;
+import org.apache.commons.io.input.BoundedInputStream;
 
 /**
  * Archive is the main entry point to unpack200. An archive is constructed 
with either two file names, a pack file and an output file name or an input 
stream
@@ -39,7 +43,7 @@ import org.apache.commons.io.IOUtils;
  */
 public class Archive {
 
-    private InputStream inputStream;
+    private BoundedInputStream inputStream;
 
     private final JarOutputStream outputStream;
 
@@ -53,10 +57,14 @@ public class Archive {
 
     private boolean deflateHint;
 
-    private String inputFileName;
+    private final Path inputPath;
+
+    private final long inputSize;
 
     private String outputFileName;
 
+    private static final int[] MAGIC = { 0xCA, 0xFE, 0xD0, 0x0D };
+
     /**
      * Creates an Archive with streams for the input and output files. Note: 
If you use this method then calling {@link #setRemovePackFile(boolean)} will 
have
      * no effect.
@@ -65,8 +73,18 @@ public class Archive {
      * @param outputStream TODO
      */
     public Archive(final InputStream inputStream, final JarOutputStream 
outputStream) {
-        this.inputStream = inputStream;
+        this.inputStream = inputStream instanceof BoundedInputStream ? 
(BoundedInputStream) inputStream : new BoundedInputStream(inputStream);
         this.outputStream = outputStream;
+        if (inputStream instanceof FileInputStream) {
+            try {
+                inputPath = Paths.get(((FileInputStream) 
inputStream).getFD().toString());
+            } catch (final IOException e) {
+                throw new UncheckedIOException(e);
+            }
+        } else {
+            inputPath = null;
+        }
+        this.inputSize = -1;
     }
 
     /**
@@ -79,9 +97,10 @@ public class Archive {
      * @throws IOException           TODO
      */
     public Archive(final String inputFileName, final String outputFileName) 
throws FileNotFoundException, IOException {
-        this.inputFileName = inputFileName;
+        this.inputPath = Paths.get(inputFileName);
         this.outputFileName = outputFileName;
-        this.inputStream = new FileInputStream(inputFileName);
+        this.inputSize = Files.size(this.inputPath);
+        this.inputStream = new 
BoundedInputStream(Files.newInputStream(inputPath), inputSize);
         this.outputStream = new JarOutputStream(new BufferedOutputStream(new 
FileOutputStream(outputFileName)));
     }
 
@@ -138,7 +157,7 @@ public class Archive {
         outputStream.setComment("PACK200");
         try {
             if (!inputStream.markSupported()) {
-                inputStream = new BufferedInputStream(inputStream);
+                inputStream = new BoundedInputStream(new 
BufferedInputStream(inputStream));
                 if (!inputStream.markSupported()) {
                     throw new IllegalStateException();
                 }
@@ -146,20 +165,19 @@ public class Archive {
             inputStream.mark(2);
             if ((inputStream.read() & 0xFF | (inputStream.read() & 0xFF) << 8) 
== GZIPInputStream.GZIP_MAGIC) {
                 inputStream.reset();
-                inputStream = new BufferedInputStream(new 
GZIPInputStream(inputStream));
+                inputStream = new BoundedInputStream(new 
BufferedInputStream(new GZIPInputStream(inputStream)));
             } else {
                 inputStream.reset();
             }
-            inputStream.mark(4);
-            final int[] magic = { 0xCA, 0xFE, 0xD0, 0x0D }; // Magic word for
+            inputStream.mark(MAGIC.length);
             // pack200
-            final int[] word = new int[4];
+            final int[] word = new int[MAGIC.length];
             for (int i = 0; i < word.length; i++) {
                 word[i] = inputStream.read();
             }
             boolean compressedWithE0 = false;
-            for (int m = 0; m < magic.length; m++) {
-                if (word[m] != magic[m]) {
+            for (int m = 0; m < MAGIC.length; m++) {
+                if (word[m] != MAGIC[m]) {
                     compressedWithE0 = true;
                 }
             }
@@ -188,7 +206,7 @@ public class Archive {
                     segment.setPreRead(false);
 
                     if (i == 1) {
-                        segment.log(Segment.LOG_LEVEL_VERBOSE, "Unpacking from 
" + inputFileName + " to " + outputFileName);
+                        segment.log(Segment.LOG_LEVEL_VERBOSE, "Unpacking from 
" + inputPath + " to " + outputFileName);
                     }
                     segment.log(Segment.LOG_LEVEL_VERBOSE, "Reading segment " 
+ i);
                     if (overrideDeflateHint) {
@@ -196,10 +214,6 @@ public class Archive {
                     }
                     segment.unpack(inputStream, outputStream);
                     outputStream.flush();
-
-                    if (inputStream instanceof FileInputStream) {
-                        inputFileName = ((FileInputStream) 
inputStream).getFD().toString();
-                    }
                 }
             }
         } finally {
@@ -207,14 +221,8 @@ public class Archive {
             IOUtils.closeQuietly(outputStream);
             IOUtils.closeQuietly(logFile);
         }
-        if (removePackFile) {
-            boolean deleted = false;
-            if (inputFileName != null) {
-                deleted = new File(inputFileName).delete();
-            }
-            if (!deleted) {
-                throw new Pack200Exception("Failed to delete the input file.");
-            }
+        if (removePackFile && inputPath != null) {
+            Files.delete(inputPath);
         }
     }
 
diff --git 
a/src/main/java/org/apache/commons/compress/harmony/unpack200/Pack200UnpackerAdapter.java
 
b/src/main/java/org/apache/commons/compress/harmony/unpack200/Pack200UnpackerAdapter.java
index 2c725fee2..f8038ba71 100644
--- 
a/src/main/java/org/apache/commons/compress/harmony/unpack200/Pack200UnpackerAdapter.java
+++ 
b/src/main/java/org/apache/commons/compress/harmony/unpack200/Pack200UnpackerAdapter.java
@@ -21,17 +21,33 @@ import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.jar.JarOutputStream;
 
 import org.apache.commons.compress.harmony.pack200.Pack200Adapter;
 import org.apache.commons.compress.harmony.pack200.Pack200Exception;
 import org.apache.commons.compress.java.util.jar.Pack200.Unpacker;
+import org.apache.commons.io.input.BoundedInputStream;
 
 /**
  * This class provides the binding between the standard Pack200 interface and 
the internal interface for (un)packing.
  */
 public class Pack200UnpackerAdapter extends Pack200Adapter implements Unpacker 
{
 
+    static BoundedInputStream newBoundedInputStream(final File file) throws 
IOException {
+        return newBoundedInputStream(file.toPath());
+    }
+
+    @SuppressWarnings("resource")
+    static BoundedInputStream newBoundedInputStream(final Path inputPath) 
throws IOException {
+        return new BoundedInputStream(new 
BufferedInputStream(Files.newInputStream(inputPath)), Files.size(inputPath));
+    }
+
+    static BoundedInputStream newBoundedInputStream(final String first, final 
String... more) throws IOException {
+        return newBoundedInputStream(Paths.get(first, more));
+    }
+
     @Override
     public void unpack(final File file, final JarOutputStream out) throws 
IOException {
         if (file == null || out == null) {
diff --git 
a/src/main/java/org/apache/commons/compress/harmony/unpack200/Segment.java 
b/src/main/java/org/apache/commons/compress/harmony/unpack200/Segment.java
index 014db4938..576fead75 100644
--- a/src/main/java/org/apache/commons/compress/harmony/unpack200/Segment.java
+++ b/src/main/java/org/apache/commons/compress/harmony/unpack200/Segment.java
@@ -462,13 +462,13 @@ public class Segment {
     /**
      * Unpacks a packed stream (either .pack. or .pack.gz) into a 
corresponding JarOuputStream.
      *
-     * @param in  a packed stream.
+     * @param inputStream  a packed input stream.
      * @param out output stream.
      * @throws Pack200Exception if there is a problem unpacking
      * @throws IOException      if there is a problem with I/O during unpacking
      */
-    public void unpack(final InputStream in, final JarOutputStream out) throws 
IOException, Pack200Exception {
-        unpackRead(in);
+    public void unpack(final InputStream inputStream, final JarOutputStream 
out) throws IOException, Pack200Exception {
+        unpackRead(inputStream);
         unpackProcess();
         unpackWrite(out);
     }
diff --git 
a/src/main/java/org/apache/commons/compress/utils/BoundedInputStream.java 
b/src/main/java/org/apache/commons/compress/utils/BoundedInputStream.java
index 8da853372..b4622c8b3 100644
--- a/src/main/java/org/apache/commons/compress/utils/BoundedInputStream.java
+++ b/src/main/java/org/apache/commons/compress/utils/BoundedInputStream.java
@@ -49,4 +49,10 @@ public class BoundedInputStream extends 
org.apache.commons.io.input.BoundedInput
         return getMaxLength() - getCount();
     }
 
+//    @Override
+//    protected void onMaxLength(long maxLength, long count) throws 
IOException {
+//        if (count > maxLength) {
+//            throw new IOException("Can't read past EOF.");
+//        }
+//    }
 }
diff --git 
a/src/test/java/org/apache/commons/compress/harmony/pack200/tests/RunCodecTest.java
 
b/src/test/java/org/apache/commons/compress/harmony/pack200/tests/RunCodecTest.java
index 0cb488fdd..cc86a288d 100644
--- 
a/src/test/java/org/apache/commons/compress/harmony/pack200/tests/RunCodecTest.java
+++ 
b/src/test/java/org/apache/commons/compress/harmony/pack200/tests/RunCodecTest.java
@@ -20,12 +20,14 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 
 import java.io.ByteArrayInputStream;
+import java.io.IOException;
 import java.util.stream.Stream;
 
 import org.apache.commons.compress.harmony.pack200.Codec;
 import org.apache.commons.compress.harmony.pack200.Pack200Exception;
 import org.apache.commons.compress.harmony.pack200.PopulationCodec;
 import org.apache.commons.compress.harmony.pack200.RunCodec;
+import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.Arguments;
@@ -76,6 +78,21 @@ public class RunCodecTest {
         }
     }
 
+    @Disabled
+    @Test
+    public void testRunCodecDecodeIntsOverflow() throws Exception {
+        final byte[] bytes1 = Codec.DELTA5.encode(new int[] { 1, -2, -3, 1000, 
55 });
+        final byte[] bytes2 = Codec.UNSIGNED5.encode(new int[] { 5, 10, 20 });
+        final byte[] bandEncoded = new byte[bytes1.length + bytes2.length];
+        System.arraycopy(bytes1, 0, bandEncoded, 0, bytes1.length);
+        System.arraycopy(bytes2, 0, bandEncoded, bytes1.length, bytes2.length);
+        final RunCodec runCodec = new RunCodec(5, Codec.DELTA5, 
Codec.UNSIGNED5);
+
+        // Should only throw an IOException and not an OutOfMemoryError
+        assertThrows(IOException.class, () -> 
runCodec.decodeInts(Integer.MAX_VALUE - 1, new 
ByteArrayInputStream(bandEncoded)));
+        assertThrows(IOException.class, () -> 
runCodec.decodeInts(Integer.MAX_VALUE - 1, new 
ByteArrayInputStream(bandEncoded), 1));
+    }
+
     @Test
     public void testEncodeSingleValue() {
         assertThrows(Pack200Exception.class, () -> new RunCodec(10, 
Codec.SIGNED5, Codec.UDELTA5).encode(5),
@@ -104,6 +121,19 @@ public class RunCodecTest {
         }
     }
 
+    @Disabled
+    @Test
+    public void testPopulationCodecDecodeIntsOverflow() throws Exception {
+        final byte[] bytes1 = Codec.DELTA5.encode(new int[] { 11, 12, 33, 
4000, -555 });
+        final PopulationCodec popCodec = new PopulationCodec(Codec.UNSIGNED5, 
Codec.BYTE1, Codec.UNSIGNED5);
+        final byte[] bytes2 = popCodec.encode(new int[] { 10, 20 }, new int[] 
{ 0, 1, 2, 1, 0, 2, 2, 2, 1, 1, 0, 2, 0, 1, 1, 0, 0 },
+                new int[] { 5, 3, 999, 789, 355, 12345 });
+        final byte[] bandEncoded = new byte[bytes1.length + bytes2.length];
+
+        // Should only throw an IOException and not an OutOfMemoryError
+        assertThrows(IOException.class, () -> 
popCodec.decodeInts(Integer.MAX_VALUE - 1, new 
ByteArrayInputStream(bandEncoded)));
+    }
+
     @Test
     public void testNestedRunCodec() throws Exception {
         final int[] band = { 1, 2, 3, 10, 20, 30, 100, 200, 300 };
diff --git 
a/src/test/java/org/apache/commons/compress/harmony/unpack200/tests/ArchiveTest.java
 
b/src/test/java/org/apache/commons/compress/harmony/unpack200/tests/ArchiveTest.java
index f169af182..98e1b1cd4 100644
--- 
a/src/test/java/org/apache/commons/compress/harmony/unpack200/tests/ArchiveTest.java
+++ 
b/src/test/java/org/apache/commons/compress/harmony/unpack200/tests/ArchiveTest.java
@@ -16,6 +16,7 @@
  */
 package org.apache.commons.compress.harmony.unpack200.tests;
 
+import static org.junit.Assert.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
@@ -31,6 +32,10 @@ import java.io.FileReader;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.Enumeration;
 import java.util.jar.JarEntry;
 import java.util.jar.JarFile;
@@ -39,8 +44,13 @@ import java.util.zip.ZipEntry;
 
 import org.apache.commons.compress.AbstractTempDirTest;
 import org.apache.commons.compress.harmony.unpack200.Archive;
+import org.apache.commons.compress.harmony.unpack200.Segment;
+import org.apache.commons.io.input.BoundedInputStream;
+import org.apache.commons.io.output.NullOutputStream;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
 
 /**
  * Tests for org.apache.commons.compress.harmony.unpack200.Archive, which is 
the main class for unpack200.
@@ -176,6 +186,30 @@ public class ArchiveTest extends AbstractTempDirTest {
         }
     }
 
+    @ParameterizedTest
+    @ValueSource(strings = {
+    // @formatter:off
+            "bandint_oom.pack",
+            "cpfloat_oom.pack",
+            "cputf8_oom.pack",
+            "favoured_oom.pack",
+            "filebits_oom.pack",
+            "flags_oom.pack",
+            "references_oom.pack",
+            "segment_header_oom.pack",
+            "signatures_oom.pack"
+            // @formatter:on
+    })
+    // Tests of various files that can cause out of memory errors
+    public void testParsingOOM(final String testFileName) throws Exception {
+        final URL url = 
Segment.class.getResource("/org/apache/commons/compress/pack/" + testFileName);
+        final Path path = Paths.get(url.toURI());
+        try (InputStream in = new BoundedInputStream(new 
BufferedInputStream(Files.newInputStream(path)), Files.size(path));
+                JarOutputStream out = new 
JarOutputStream(NullOutputStream.INSTANCE)) {
+            assertThrows(IOException.class, () -> new Archive(in, 
out).unpack());
+        }
+    }
+
     @Test
     public void testRemovePackFile() throws Exception {
         final File original = new 
File(Archive.class.getResource("/pack200/sql.pack.gz").toURI());
diff --git 
a/src/test/java/org/apache/commons/compress/harmony/unpack200/tests/SegmentTest.java
 
b/src/test/java/org/apache/commons/compress/harmony/unpack200/tests/SegmentTest.java
index d3dd7f338..76c2dc81b 100644
--- 
a/src/test/java/org/apache/commons/compress/harmony/unpack200/tests/SegmentTest.java
+++ 
b/src/test/java/org/apache/commons/compress/harmony/unpack200/tests/SegmentTest.java
@@ -16,21 +16,32 @@
  */
 package org.apache.commons.compress.harmony.unpack200.tests;
 
+import static org.junit.Assert.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 
+import java.io.BufferedInputStream;
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileOutputStream;
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.jar.JarEntry;
 import java.util.jar.JarFile;
 import java.util.jar.JarOutputStream;
 
 import org.apache.commons.compress.AbstractTempDirTest;
 import org.apache.commons.compress.harmony.unpack200.Segment;
+import org.apache.commons.io.input.BoundedInputStream;
+import org.apache.commons.io.output.NullOutputStream;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
 
 /**
  * Tests for org.apache.commons.compress.harmony.unpack200.Segment.
@@ -88,4 +99,28 @@ public class SegmentTest extends AbstractTempDirTest {
         }
     }
 
+    @ParameterizedTest
+    @ValueSource(strings = {
+    // @formatter:off
+            "bandint_oom.pack",
+            "cpfloat_oom.pack",
+            "cputf8_oom.pack",
+            "favoured_oom.pack",
+            "filebits_oom.pack",
+            "flags_oom.pack",
+            "references_oom.pack",
+            "segment_header_oom.pack",
+            "signatures_oom.pack"
+            // @formatter:on
+    })
+    // Tests of various files that can cause out of memory errors
+    public void testParsingOOM(final String testFileName) throws Exception {
+        final URL url = 
Segment.class.getResource("/org/apache/commons/compress/pack/" + testFileName);
+        final Path path = Paths.get(url.toURI());
+        try (InputStream in = new BoundedInputStream(new 
BufferedInputStream(Files.newInputStream(path)), Files.size(path));
+                JarOutputStream out = new 
JarOutputStream(NullOutputStream.INSTANCE)) {
+            assertThrows(IOException.class, () -> new Segment().unpack(in, 
out));
+        }
+    }
+
 }
diff --git 
a/src/test/resources/org/apache/commons/compress/pack/bandint_oom.pack 
b/src/test/resources/org/apache/commons/compress/pack/bandint_oom.pack
new file mode 100644
index 000000000..ad011e5f2
Binary files /dev/null and 
b/src/test/resources/org/apache/commons/compress/pack/bandint_oom.pack differ
diff --git 
a/src/test/resources/org/apache/commons/compress/pack/cpfloat_oom.pack 
b/src/test/resources/org/apache/commons/compress/pack/cpfloat_oom.pack
new file mode 100644
index 000000000..29255d14f
Binary files /dev/null and 
b/src/test/resources/org/apache/commons/compress/pack/cpfloat_oom.pack differ
diff --git 
a/src/test/resources/org/apache/commons/compress/pack/cputf8_oom.pack 
b/src/test/resources/org/apache/commons/compress/pack/cputf8_oom.pack
new file mode 100644
index 000000000..88632cb9c
Binary files /dev/null and 
b/src/test/resources/org/apache/commons/compress/pack/cputf8_oom.pack differ
diff --git 
a/src/test/resources/org/apache/commons/compress/pack/favoured_oom.pack 
b/src/test/resources/org/apache/commons/compress/pack/favoured_oom.pack
new file mode 100644
index 000000000..658be7f5f
Binary files /dev/null and 
b/src/test/resources/org/apache/commons/compress/pack/favoured_oom.pack differ
diff --git 
a/src/test/resources/org/apache/commons/compress/pack/filebits_oom.pack 
b/src/test/resources/org/apache/commons/compress/pack/filebits_oom.pack
new file mode 100644
index 000000000..282967e47
Binary files /dev/null and 
b/src/test/resources/org/apache/commons/compress/pack/filebits_oom.pack differ
diff --git a/src/test/resources/org/apache/commons/compress/pack/flags_oom.pack 
b/src/test/resources/org/apache/commons/compress/pack/flags_oom.pack
new file mode 100644
index 000000000..2608ee02d
Binary files /dev/null and 
b/src/test/resources/org/apache/commons/compress/pack/flags_oom.pack differ
diff --git 
a/src/test/resources/org/apache/commons/compress/pack/references_oom.pack 
b/src/test/resources/org/apache/commons/compress/pack/references_oom.pack
new file mode 100644
index 000000000..b613eaa4d
Binary files /dev/null and 
b/src/test/resources/org/apache/commons/compress/pack/references_oom.pack differ
diff --git 
a/src/test/resources/org/apache/commons/compress/pack/segment_header_oom.pack 
b/src/test/resources/org/apache/commons/compress/pack/segment_header_oom.pack
new file mode 100644
index 000000000..033967067
Binary files /dev/null and 
b/src/test/resources/org/apache/commons/compress/pack/segment_header_oom.pack 
differ
diff --git 
a/src/test/resources/org/apache/commons/compress/pack/signatures_oom.pack 
b/src/test/resources/org/apache/commons/compress/pack/signatures_oom.pack
new file mode 100644
index 000000000..aa4b2fc79
Binary files /dev/null and 
b/src/test/resources/org/apache/commons/compress/pack/signatures_oom.pack differ

Reply via email to