org.osgi
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 a575558bab1..06630b3230d 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
@@ -144,7 +144,7 @@ public int[] decodeInts(final int n, final InputStream in) throws IOException, P
* @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[check(n + 1, in)];
+ final int[] result = new int[check(n, in) + 1];
result[0] = firstValue;
int last = firstValue;
for (int i = 1; i < n + 1; i++) {
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 f70c56ca932..ff39c3142ac 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
@@ -24,7 +24,6 @@
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;
@@ -69,18 +68,15 @@ public class Archive {
* 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.
*
- * @param inputStream TODO
- * @param outputStream TODO
+ * @param inputStream the input stream, preferably a {@link BoundedInputStream}. The bound can the the file size.
+ * @param outputStream the JAR output stream.
+ * @throws IOException if an I/O error occurs
*/
- public Archive(final InputStream inputStream, final JarOutputStream outputStream) {
- this.inputStream = inputStream instanceof BoundedInputStream ? (BoundedInputStream) inputStream : new BoundedInputStream(inputStream);
+ public Archive(final InputStream inputStream, final JarOutputStream outputStream) throws IOException {
+ this.inputStream = Pack200UnpackerAdapter.newBoundedInputStream(inputStream);
this.outputStream = outputStream;
if (inputStream instanceof FileInputStream) {
- try {
- inputPath = Paths.get(((FileInputStream) inputStream).getFD().toString());
- } catch (final IOException e) {
- throw new UncheckedIOException(e);
- }
+ inputPath = Paths.get(Pack200UnpackerAdapter.readPath((FileInputStream) inputStream));
} else {
inputPath = null;
}
@@ -90,18 +86,18 @@ public Archive(final InputStream inputStream, final JarOutputStream outputStream
/**
* Creates an Archive with the given input and output file names.
*
- * @param inputFileName TODO
- * @param outputFileName TODO
+ * @param inputFileName the input file name.
+ * @param outputFileName the output file name
* @throws FileNotFoundException if the input file does not exist
- * @throws FileNotFoundException TODO
- * @throws IOException TODO
+ * @throws IOException if an I/O error occurs
*/
+ @SuppressWarnings("resource")
public Archive(final String inputFileName, final String outputFileName) throws FileNotFoundException, IOException {
this.inputPath = Paths.get(inputFileName);
- this.outputFileName = outputFileName;
this.inputSize = Files.size(this.inputPath);
this.inputStream = new BoundedInputStream(Files.newInputStream(inputPath), inputSize);
this.outputStream = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(outputFileName)));
+ this.outputFileName = outputFileName;
}
private boolean available(final InputStream inputStream) throws IOException {
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 f8038ba71b8..6817f6ca51a 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
@@ -18,8 +18,12 @@
import java.io.BufferedInputStream;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.net.URISyntaxException;
+import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -29,25 +33,124 @@
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;
+import org.apache.commons.lang3.reflect.FieldUtils;
/**
* This class provides the binding between the standard Pack200 interface and the internal interface for (un)packing.
*/
public class Pack200UnpackerAdapter extends Pack200Adapter implements Unpacker {
+ /**
+ * Creates a new BoundedInputStream bound by the size of the given file.
+ *
+ * The new BoundedInputStream wraps a new {@link BufferedInputStream}.
+ *
+ *
+ * @param file The file.
+ * @return a new BoundedInputStream
+ * @throws IOException if an I/O error occurs
+ */
static BoundedInputStream newBoundedInputStream(final File file) throws IOException {
return newBoundedInputStream(file.toPath());
}
+ private static BoundedInputStream newBoundedInputStream(final FileInputStream fileInputStream) throws IOException {
+ return newBoundedInputStream(readPath(fileInputStream));
+ }
+
+ static BoundedInputStream newBoundedInputStream(final InputStream inputStream) throws IOException {
+ if (inputStream instanceof BoundedInputStream) {
+ return (BoundedInputStream) inputStream;
+ }
+ if (inputStream instanceof FilterInputStream) {
+ return newBoundedInputStream(unwrap((FilterInputStream) inputStream));
+ }
+ if (inputStream instanceof FileInputStream) {
+ return newBoundedInputStream((FileInputStream) inputStream);
+ }
+ // No limit
+ return new BoundedInputStream(inputStream);
+ }
+
+ /**
+ * Creates a new BoundedInputStream bound by the size of the given path.
+ *
+ * The new BoundedInputStream wraps a new {@link BufferedInputStream}.
+ *
+ *
+ * @param path The path.
+ * @return a new BoundedInputStream
+ * @throws IOException if an I/O error occurs
+ */
@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 Path path) throws IOException {
+ return new BoundedInputStream(new BufferedInputStream(Files.newInputStream(path)), Files.size(path));
}
+ /**
+ * Creates a new BoundedInputStream bound by the size of the given file.
+ *
+ * The new BoundedInputStream wraps a new {@link BufferedInputStream}.
+ *
+ *
+ * @param first the path string or initial part of the path string.
+ * @param more additional strings to be joined to form the path string.
+ * @return a new BoundedInputStream
+ * @throws IOException if an I/O error occurs
+ */
static BoundedInputStream newBoundedInputStream(final String first, final String... more) throws IOException {
return newBoundedInputStream(Paths.get(first, more));
}
+ /**
+ * Creates a new BoundedInputStream bound by the size of the given URL to a file.
+ *
+ * The new BoundedInputStream wraps a new {@link BufferedInputStream}.
+ *
+ *
+ * @param path The URL.
+ * @return a new BoundedInputStream
+ * @throws IOException if an I/O error occurs
+ * @throws URISyntaxException
+ */
+ static BoundedInputStream newBoundedInputStream(final URL url) throws IOException, URISyntaxException {
+ return newBoundedInputStream(Paths.get(url.toURI()));
+ }
+
+ @SuppressWarnings("unchecked")
+ private static T readField(final Object object, final String fieldName) {
+ try {
+ return (T) FieldUtils.readField(object, fieldName, true);
+ } catch (final IllegalAccessException e) {
+ return null;
+ }
+ }
+
+ static String readPath(final FileInputStream fis) {
+ return readField(fis, "path");
+ }
+
+ /**
+ * Unwraps the given FilterInputStream to return its wrapped InputStream.
+ *
+ * @param filterInputStream The FilterInputStream to unwrap.
+ * @return The wrapped InputStream
+ */
+ static InputStream unwrap(final FilterInputStream filterInputStream) {
+ return readField(filterInputStream, "in");
+ }
+
+ /**
+ * Unwraps the given InputStream if it is an FilterInputStream to return its wrapped InputStream.
+ *
+ * @param filterInputStream The FilterInputStream to unwrap.
+ * @return The wrapped InputStream
+ */
+ @SuppressWarnings("resource")
+ static InputStream unwrap(final InputStream inputStream) {
+ return inputStream instanceof FilterInputStream ? unwrap((FilterInputStream) inputStream) : inputStream;
+ }
+
@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 576fead7513..262cebccdaf 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
@@ -49,6 +49,7 @@
import org.apache.commons.compress.harmony.unpack200.bytecode.ClassFileEntry;
import org.apache.commons.compress.harmony.unpack200.bytecode.InnerClassesAttribute;
import org.apache.commons.compress.harmony.unpack200.bytecode.SourceFileAttribute;
+import org.apache.commons.io.input.BoundedInputStream;
/**
* A Pack200 archive consists of one or more segments. Each segment is stand-alone, in the sense that every segment has the magic number header; thus, every
@@ -462,7 +463,7 @@ public void setPreRead(final boolean value) {
/**
* Unpacks a packed stream (either .pack. or .pack.gz) into a corresponding JarOuputStream.
*
- * @param inputStream a packed input stream.
+ * @param inputStream a packed input stream, preferably a {@link BoundedInputStream}.
* @param out output stream.
* @throws Pack200Exception if there is a problem unpacking
* @throws IOException if there is a problem with I/O during unpacking
@@ -484,7 +485,8 @@ void unpackProcess() throws IOException, Pack200Exception {
* Package-private accessors for unpacking stages
*/
void unpackRead(final InputStream inputStream) throws IOException, Pack200Exception {
- final InputStream in = inputStream.markSupported() ? inputStream : new BufferedInputStream(inputStream);
+ @SuppressWarnings("resource")
+ final InputStream in = Pack200UnpackerAdapter.newBoundedInputStream(inputStream);
header = new SegmentHeader(this);
header.read(in);
diff --git a/src/main/java/org/apache/commons/compress/java/util/jar/Pack200.java b/src/main/java/org/apache/commons/compress/java/util/jar/Pack200.java
index c836b25e694..1055503bc1c 100644
--- a/src/main/java/org/apache/commons/compress/java/util/jar/Pack200.java
+++ b/src/main/java/org/apache/commons/compress/java/util/jar/Pack200.java
@@ -30,6 +30,7 @@
import java.util.jar.JarOutputStream;
import org.apache.commons.compress.harmony.archive.internal.nls.Messages;
+import org.apache.commons.io.input.BoundedInputStream;
/**
* Class factory for {@link Pack200.Packer} and {@link Pack200.Unpacker}.
@@ -230,7 +231,7 @@ public interface Unpacker {
/**
* Unpacks the contents of the specified {@code File} to the specified JAR output stream.
*
- * @param in file to be uncompressed.
+ * @param in file to uncompress.
* @param out JAR output stream of uncompressed data.
* @throws IOException if I/O exception occurs.
*/
@@ -239,7 +240,7 @@ public interface Unpacker {
/**
* Unpacks the specified stream to the specified JAR output stream.
*
- * @param in stream to uncompressed.
+ * @param in stream to uncompress, preferably a {@link BoundedInputStream}.
* @param out JAR output stream of uncompressed data.
* @throws IOException if I/O exception occurs.
*/
diff --git a/src/test/java/org/apache/commons/compress/harmony/unpack200/ArchiveTest.java b/src/test/java/org/apache/commons/compress/harmony/unpack200/ArchiveTest.java
index 9b0d0cc10b0..fc8372b98c3 100644
--- a/src/test/java/org/apache/commons/compress/harmony/unpack200/ArchiveTest.java
+++ b/src/test/java/org/apache/commons/compress/harmony/unpack200/ArchiveTest.java
@@ -33,9 +33,6 @@
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;
@@ -196,18 +193,39 @@ public void testLoggingOptions() throws Exception {
"references_oom.pack",
"segment_header_oom.pack",
"signatures_oom.pack"
- // @formatter:on
+ // @formatter:on
})
// Tests of various files that can cause out of memory errors
- public void testParsingOOM(final String testFileName) throws Exception {
+ public void testParsingOOMBounded(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));
+ try (BoundedInputStream in = Pack200UnpackerAdapter.newBoundedInputStream(url);
JarOutputStream out = new JarOutputStream(NullOutputStream.INSTANCE)) {
assertThrows(IOException.class, () -> new Archive(in, out).unpack());
}
}
+ @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 testParsingOOMUnbounded(final String testFileName) throws Exception {
+ try (InputStream is = Segment.class.getResourceAsStream("/org/apache/commons/compress/pack/" + testFileName);
+ JarOutputStream out = new JarOutputStream(NullOutputStream.INSTANCE)) {
+ assertThrows(IOException.class, () -> new Archive(is, out).unpack());
+ }
+ }
+
@Test
public void testRemovePackFile() throws Exception {
final File original = new File(Archive.class.getResource("/pack200/sql.pack.gz").toURI());
@@ -221,10 +239,10 @@ public void testRemovePackFile() throws Exception {
read = inputStream.read(bytes);
}
}
- final String inputFile = copy.getPath();
+ final String inputFileName = copy.getPath();
final File file = createTempFile("sqlout", ".jar");
- final String outputFile = file.getPath();
- final Archive archive = new Archive(inputFile, outputFile);
+ final String outputFileName = file.getPath();
+ final Archive archive = new Archive(inputFileName, outputFileName);
archive.setRemovePackFile(true);
archive.unpack();
assertFalse(copy.exists());
diff --git a/src/test/java/org/apache/commons/compress/harmony/unpack200/SegmentTest.java b/src/test/java/org/apache/commons/compress/harmony/unpack200/SegmentTest.java
index 5a3b8937a94..f4ba3d67103 100644
--- a/src/test/java/org/apache/commons/compress/harmony/unpack200/SegmentTest.java
+++ b/src/test/java/org/apache/commons/compress/harmony/unpack200/SegmentTest.java
@@ -20,7 +20,6 @@
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;
@@ -28,9 +27,6 @@
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;
@@ -113,10 +109,31 @@ public void testJustResources() throws Exception {
// @formatter:on
})
// Tests of various files that can cause out of memory errors
- public void testParsingOOM(final String testFileName) throws Exception {
+ public void testParsingOOMBounded(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));
+ try (BoundedInputStream in = Pack200UnpackerAdapter.newBoundedInputStream(url);
+ JarOutputStream out = new JarOutputStream(NullOutputStream.INSTANCE)) {
+ assertThrows(IOException.class, () -> new Segment().unpack(in, out));
+ }
+ }
+
+ @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 testParsingOOMUnounded(final String testFileName) throws Exception {
+ try (InputStream in = Segment.class.getResourceAsStream("/org/apache/commons/compress/pack/" + testFileName);
JarOutputStream out = new JarOutputStream(NullOutputStream.INSTANCE)) {
assertThrows(IOException.class, () -> new Segment().unpack(in, out));
}