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
The following commit(s) were added to refs/heads/master by this push: new 798e945fe Fix names to reflect kibibytes scale 798e945fe is described below commit 798e945fed58e24a7264c7eef3c5a01df304cf64 Author: Gary D. Gregory <garydgreg...@gmail.com> AuthorDate: Sat Jan 4 09:32:02 2025 -0500 Fix names to reflect kibibytes scale - Add SevenZFile.Builder.setMaxMemoryLimitKiB(int) - Fix Javadoc in org.apache.commons.compress.archivers.sevenz package to specify kibibyte scale in memory limits --- src/changes/changes.xml | 2 + .../archivers/sevenz/AES256SHA256Decoder.java | 2 +- .../compress/archivers/sevenz/AbstractCoder.java | 2 +- .../commons/compress/archivers/sevenz/Coders.java | 14 +++--- .../compress/archivers/sevenz/DeltaDecoder.java | 2 +- .../compress/archivers/sevenz/LZMA2Decoder.java | 6 +-- .../compress/archivers/sevenz/LZMADecoder.java | 8 ++-- .../compress/archivers/sevenz/SevenZFile.java | 53 +++++++++++++++------- .../archivers/sevenz/SevenZFileOptions.java | 14 +++--- .../compress/archivers/sevenz/SevenZFileTest.java | 5 ++ 10 files changed, 68 insertions(+), 40 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 8cd410577..32eaca06a 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -62,6 +62,7 @@ The <action> type attribute can be add,update,fix,remove. <action type="fix" dev="ggregory" due-to="Gary Gregory">CpioArchiveInputStream.read(byte[], int, int) now throws an IOException on a data pad count mismatch.</action> <action type="fix" dev="ggregory" due-to="Gary Gregory">CpioArchiveInputStream.readNewEntry(boolean) now throws an IOException on a header pad count mismatch.</action> <action type="fix" dev="ggregory" due-to="Gary Gregory">CpioArchiveInputStream.readOldBinaryEntry(boolean) now throws an IOException on a header pad count mismatch.</action> + <action type="fix" dev="ggregory" due-to="Gary Gregory">Fix Javadoc in org.apache.commons.compress.archivers.sevenz package to specify kibibyte scale in memory limits.</action> <!-- ADD --> <action type="add" dev="ggregory" due-to="Gary Gregory">Add GzipParameters.getModificationInstant().</action> <action type="add" dev="ggregory" due-to="Gary Gregory">Add GzipParameters.setModificationInstant(Instant).</action> @@ -78,6 +79,7 @@ The <action> type attribute can be add,update,fix,remove. <action type="add" dev="ggregory" due-to="Gary Gregory">Add GzipCompressorInputStream.Builder.setOnMemberStart(IOConsumer) to monitor member parsing.</action> <action type="add" dev="ggregory" due-to="Gary Gregory">Add GzipCompressorInputStream.Builder.setOnMemberEnd(IOConsumer) to monitor member parsing.</action> <action type="add" dev="ggregory" due-to="Gary Gregory">Add PMD check to default Maven goal.</action> + <action type="add" dev="ggregory" due-to="Gary Gregory">Add SevenZFile.Builder.setMaxMemoryLimitKiB(int).</action> <!-- UPDATE --> <action type="update" dev="ggregory" due-to="Dependabot, Gary Gregory">Bump org.apache.commons:commons-parent from 72 to 78 #563, #567, #574, #582, #587, #595.</action> <action type="update" dev="ggregory" due-to="Dependabot, Gary Gregory">Bump com.github.luben:zstd-jni from 1.5.6-4 to 1.5.6-9 #565, #578, #601, #616, #630.</action> diff --git a/src/main/java/org/apache/commons/compress/archivers/sevenz/AES256SHA256Decoder.java b/src/main/java/org/apache/commons/compress/archivers/sevenz/AES256SHA256Decoder.java index 35027c8da..8f2d97571 100644 --- a/src/main/java/org/apache/commons/compress/archivers/sevenz/AES256SHA256Decoder.java +++ b/src/main/java/org/apache/commons/compress/archivers/sevenz/AES256SHA256Decoder.java @@ -238,7 +238,7 @@ final class AES256SHA256Decoder extends AbstractCoder { @Override InputStream decode(final String archiveName, final InputStream in, final long uncompressedLength, final Coder coder, final byte[] passwordBytes, - final int maxMemoryLimitInKb) { + final int maxMemoryLimitKiB) { return new AES256SHA256DecoderInputStream(in, coder, archiveName, passwordBytes); } diff --git a/src/main/java/org/apache/commons/compress/archivers/sevenz/AbstractCoder.java b/src/main/java/org/apache/commons/compress/archivers/sevenz/AbstractCoder.java index d3dcb8bde..6934f717a 100644 --- a/src/main/java/org/apache/commons/compress/archivers/sevenz/AbstractCoder.java +++ b/src/main/java/org/apache/commons/compress/archivers/sevenz/AbstractCoder.java @@ -58,7 +58,7 @@ abstract class AbstractCoder { * * @return a stream that reads from in using the configured coder and password. */ - abstract InputStream decode(String archiveName, InputStream in, long uncompressedLength, Coder coder, byte[] password, int maxMemoryLimitInKb) + abstract InputStream decode(String archiveName, InputStream in, long uncompressedLength, Coder coder, byte[] password, int maxMemoryLimitKiB) throws IOException; /** diff --git a/src/main/java/org/apache/commons/compress/archivers/sevenz/Coders.java b/src/main/java/org/apache/commons/compress/archivers/sevenz/Coders.java index 7c66f3293..4197e98ba 100644 --- a/src/main/java/org/apache/commons/compress/archivers/sevenz/Coders.java +++ b/src/main/java/org/apache/commons/compress/archivers/sevenz/Coders.java @@ -55,7 +55,7 @@ final class Coders { @Override InputStream decode(final String archiveName, final InputStream in, final long uncompressedLength, final Coder coder, final byte[] password, - final int maxMemoryLimitInKb) throws IOException { + final int maxMemoryLimitKiB) throws IOException { try { return opts.getInputStream(in); } catch (final AssertionError e) { @@ -78,7 +78,7 @@ final class Coders { @Override InputStream decode(final String archiveName, final InputStream in, final long uncompressedLength, final Coder coder, final byte[] password, - final int maxMemoryLimitInKb) throws IOException { + final int maxMemoryLimitKiB) throws IOException { return new BZip2CompressorInputStream(in); } @@ -92,7 +92,7 @@ final class Coders { static class CopyDecoder extends AbstractCoder { @Override InputStream decode(final String archiveName, final InputStream in, final long uncompressedLength, final Coder coder, final byte[] password, - final int maxMemoryLimitInKb) throws IOException { + final int maxMemoryLimitKiB) throws IOException { return in; } @@ -109,7 +109,7 @@ final class Coders { @Override InputStream decode(final String archiveName, final InputStream in, final long uncompressedLength, final Coder coder, final byte[] password, - final int maxMemoryLimitInKb) throws IOException { + final int maxMemoryLimitKiB) throws IOException { return new Deflate64CompressorInputStream(in); } } @@ -178,7 +178,7 @@ final class Coders { @Override InputStream decode(final String archiveName, final InputStream in, final long uncompressedLength, final Coder coder, final byte[] password, - final int maxMemoryLimitInKb) throws IOException { + final int maxMemoryLimitKiB) throws IOException { final Inflater inflater = new Inflater(true); // Inflater with nowrap=true has this odd contract for a zero padding // byte following the data stream; this used to be zlib's requirement @@ -222,12 +222,12 @@ final class Coders { }; static InputStream addDecoder(final String archiveName, final InputStream is, final long uncompressedLength, final Coder coder, final byte[] password, - final int maxMemoryLimitInKb) throws IOException { + final int maxMemoryLimitKiB) throws IOException { final AbstractCoder cb = findByMethod(SevenZMethod.byId(coder.decompressionMethodId)); if (cb == null) { throw new IOException("Unsupported compression method " + Arrays.toString(coder.decompressionMethodId) + " used in " + archiveName); } - return cb.decode(archiveName, is, uncompressedLength, coder, password, maxMemoryLimitInKb); + return cb.decode(archiveName, is, uncompressedLength, coder, password, maxMemoryLimitKiB); } static OutputStream addEncoder(final OutputStream out, final SevenZMethod method, final Object options) throws IOException { diff --git a/src/main/java/org/apache/commons/compress/archivers/sevenz/DeltaDecoder.java b/src/main/java/org/apache/commons/compress/archivers/sevenz/DeltaDecoder.java index 365f1cc21..0b12298de 100644 --- a/src/main/java/org/apache/commons/compress/archivers/sevenz/DeltaDecoder.java +++ b/src/main/java/org/apache/commons/compress/archivers/sevenz/DeltaDecoder.java @@ -33,7 +33,7 @@ final class DeltaDecoder extends AbstractCoder { @Override InputStream decode(final String archiveName, final InputStream in, final long uncompressedLength, final Coder coder, final byte[] password, - final int maxMemoryLimitInKb) throws IOException { + final int maxMemoryLimitKiB) throws IOException { return new DeltaOptions(getOptionsFromCoder(coder)).getInputStream(in); } diff --git a/src/main/java/org/apache/commons/compress/archivers/sevenz/LZMA2Decoder.java b/src/main/java/org/apache/commons/compress/archivers/sevenz/LZMA2Decoder.java index 91f237f96..59c595692 100644 --- a/src/main/java/org/apache/commons/compress/archivers/sevenz/LZMA2Decoder.java +++ b/src/main/java/org/apache/commons/compress/archivers/sevenz/LZMA2Decoder.java @@ -35,12 +35,12 @@ final class LZMA2Decoder extends AbstractCoder { @Override InputStream decode(final String archiveName, final InputStream in, final long uncompressedLength, final Coder coder, final byte[] password, - final int maxMemoryLimitInKb) throws IOException { + final int maxMemoryLimitKiB) throws IOException { try { final int dictionarySize = getDictionarySize(coder); final int memoryUsageInKb = LZMA2InputStream.getMemoryUsage(dictionarySize); - if (memoryUsageInKb > maxMemoryLimitInKb) { - throw new MemoryLimitException(memoryUsageInKb, maxMemoryLimitInKb); + if (memoryUsageInKb > maxMemoryLimitKiB) { + throw new MemoryLimitException(memoryUsageInKb, maxMemoryLimitKiB); } return new LZMA2InputStream(in, dictionarySize); } catch (final IllegalArgumentException ex) { // NOSONAR diff --git a/src/main/java/org/apache/commons/compress/archivers/sevenz/LZMADecoder.java b/src/main/java/org/apache/commons/compress/archivers/sevenz/LZMADecoder.java index 0722081d6..2f48c771e 100644 --- a/src/main/java/org/apache/commons/compress/archivers/sevenz/LZMADecoder.java +++ b/src/main/java/org/apache/commons/compress/archivers/sevenz/LZMADecoder.java @@ -37,7 +37,7 @@ final class LZMADecoder extends AbstractCoder { @Override InputStream decode(final String archiveName, final InputStream in, final long uncompressedLength, final Coder coder, final byte[] password, - final int maxMemoryLimitInKb) throws IOException { + final int maxMemoryLimitKiB) throws IOException { if (coder.properties == null) { throw new IOException("Missing LZMA properties"); } @@ -49,9 +49,9 @@ final class LZMADecoder extends AbstractCoder { if (dictSize > LZMAInputStream.DICT_SIZE_MAX) { throw new IOException("Dictionary larger than 4GiB maximum size used in " + archiveName); } - final int memoryUsageInKb = LZMAInputStream.getMemoryUsage(dictSize, propsByte); - if (memoryUsageInKb > maxMemoryLimitInKb) { - throw new MemoryLimitException(memoryUsageInKb, maxMemoryLimitInKb); + final int memoryUsageInKiB = LZMAInputStream.getMemoryUsage(dictSize, propsByte); + if (memoryUsageInKiB > maxMemoryLimitKiB) { + throw new MemoryLimitException(memoryUsageInKiB, maxMemoryLimitKiB); } final LZMAInputStream lzmaIn = new LZMAInputStream(in, uncompressedLength, propsByte, dictSize); lzmaIn.enableRelaxedEndCondition(); diff --git a/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java b/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java index 36f07dad7..ca64c7265 100644 --- a/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java +++ b/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java @@ -95,7 +95,13 @@ public class SevenZFile implements Closeable { private int numberOfEntries; private int numberOfEntriesWithStream; - void assertValidity(final int maxMemoryLimitInKb) throws IOException { + /** + * Asserts the validity of the given input. + * + * @param maxMemoryLimitKiB kibibytes to test. + * @throws IOException Thrown on basic assertion failure. + */ + void assertValidity(final int maxMemoryLimitKiB) throws IOException { if (numberOfEntriesWithStream > 0 && numberOfFolders == 0) { throw new IOException("archive with entries but no folders"); } @@ -103,9 +109,9 @@ public class SevenZFile implements Closeable { throw new IOException("archive doesn't contain enough substreams for entries"); } - final long memoryNeededInKb = estimateSize() / 1024; - if (maxMemoryLimitInKb < memoryNeededInKb) { - throw new MemoryLimitException(memoryNeededInKb, maxMemoryLimitInKb); + final long memoryNeededInKiB = estimateSize() / 1024; + if (maxMemoryLimitKiB < memoryNeededInKiB) { + throw new MemoryLimitException(memoryNeededInKiB, maxMemoryLimitKiB); } } @@ -167,7 +173,7 @@ public class SevenZFile implements Closeable { private SeekableByteChannel seekableByteChannel; private String defaultName = DEFAULT_FILE_NAME; private byte[] password; - private int maxMemoryLimitKb = MEMORY_LIMIT_IN_KB; + private int maxMemoryLimitKiB = MEMORY_LIMIT_IN_KB; private boolean useDefaultNameForUnnamedEntries = USE_DEFAULTNAME_FOR_UNNAMED_ENTRIES; private boolean tryToRecoverBrokenArchives = TRY_TO_RECOVER_BROKEN_ARCHIVES; @@ -192,7 +198,7 @@ public class SevenZFile implements Closeable { actualDescription = path.toAbsolutePath().toString(); } final boolean closeOnError = seekableByteChannel != null; - return new SevenZFile(actualChannel, actualDescription, password, closeOnError, maxMemoryLimitKb, useDefaultNameForUnnamedEntries, + return new SevenZFile(actualChannel, actualDescription, password, closeOnError, maxMemoryLimitKiB, useDefaultNameForUnnamedEntries, tryToRecoverBrokenArchives); } @@ -213,11 +219,26 @@ public class SevenZFile implements Closeable { * Not all codecs honor this setting. Currently only LZMA and LZMA2 are supported. * </p> * - * @param maxMemoryLimitKb the max memory limit in kilobytes. + * @param maxMemoryLimitKiB the max memory limit in kilobytes. + * @return {@code this} instance. + */ + public Builder setMaxMemoryLimitKb(final int maxMemoryLimitKiB) { + this.maxMemoryLimitKiB = maxMemoryLimitKiB / 1024; + return this; + } + + /** + * Sets the maximum amount of memory in kilobytes to use for parsing the archive and during extraction. + * <p> + * Not all codecs honor this setting. Currently only LZMA and LZMA2 are supported. + * </p> + * + * @param maxMemoryLimitKiB the max memory limit in kibibytes. * @return {@code this} instance. + * @since 1.28.0 */ - public Builder setMaxMemoryLimitKb(final int maxMemoryLimitKb) { - this.maxMemoryLimitKb = maxMemoryLimitKb; + public Builder setMaxMemoryLimitKiB(final int maxMemoryLimitKiB) { + this.maxMemoryLimitKiB = maxMemoryLimitKiB; return this; } @@ -413,7 +434,7 @@ public class SevenZFile implements Closeable { private long compressedBytesReadFromCurrentEntry; private long uncompressedBytesReadFromCurrentEntry; private final ArrayList<InputStream> deferredBlockStreams = new ArrayList<>(); - private final int maxMemoryLimitKb; + private final int maxMemoryLimitKiB; private final boolean useDefaultNameForUnnamedEntries; private final boolean tryToRecoverBrokenArchives; @@ -609,12 +630,12 @@ public class SevenZFile implements Closeable { this(channel, fileName, password, false, SevenZFileOptions.DEFAULT); } - private SevenZFile(final SeekableByteChannel channel, final String fileName, final byte[] password, final boolean closeOnError, final int maxMemoryLimitKb, + private SevenZFile(final SeekableByteChannel channel, final String fileName, final byte[] password, final boolean closeOnError, final int maxMemoryLimitKiB, final boolean useDefaultNameForUnnamedEntries, final boolean tryToRecoverBrokenArchives) throws IOException { boolean succeeded = false; this.channel = channel; this.fileName = fileName; - this.maxMemoryLimitKb = maxMemoryLimitKb; + this.maxMemoryLimitKiB = maxMemoryLimitKiB; this.useDefaultNameForUnnamedEntries = useDefaultNameForUnnamedEntries; this.tryToRecoverBrokenArchives = tryToRecoverBrokenArchives; try { @@ -746,7 +767,7 @@ public class SevenZFile implements Closeable { throw new IOException("Multi input/output stream coders are not yet supported"); } final SevenZMethod method = SevenZMethod.byId(coder.decompressionMethodId); - inputStreamStack = Coders.addDecoder(fileName, inputStreamStack, folder.getUnpackSizeForCoder(coder), coder, password, maxMemoryLimitKb); + inputStreamStack = Coders.addDecoder(fileName, inputStreamStack, folder.getUnpackSizeForCoder(coder), coder, password, maxMemoryLimitKiB); methods.addFirst(new SevenZMethodConfiguration(method, Coders.findByMethod(method).getOptionsFromCoder(coder, inputStreamStack))); } entry.setContentMethods(methods); @@ -1190,7 +1211,7 @@ public class SevenZFile implements Closeable { final int pos = header.position(); final ArchiveStatistics stats = new ArchiveStatistics(); sanityCheckStreamsInfo(header, stats); - stats.assertValidity(maxMemoryLimitKb); + stats.assertValidity(maxMemoryLimitKiB); header.position(pos); readStreamsInfo(header, archive); @@ -1214,7 +1235,7 @@ public class SevenZFile implements Closeable { throw new IOException("Multi input/output stream coders are not yet supported"); } inputStreamStack = Coders.addDecoder(fileName, inputStreamStack, // NOSONAR - folder.getUnpackSizeForCoder(coder), coder, password, maxMemoryLimitKb); + folder.getUnpackSizeForCoder(coder), coder, password, maxMemoryLimitKiB); } if (folder.hasCrc) { // @formatter:off @@ -1460,7 +1481,7 @@ public class SevenZFile implements Closeable { private void readHeader(final ByteBuffer header, final Archive archive) throws IOException { final int pos = header.position(); final ArchiveStatistics stats = sanityCheckAndCollectStatistics(header); - stats.assertValidity(maxMemoryLimitKb); + stats.assertValidity(maxMemoryLimitKiB); header.position(pos); int nid = getUnsignedByte(header); diff --git a/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFileOptions.java b/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFileOptions.java index 505792608..66578622e 100644 --- a/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFileOptions.java +++ b/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFileOptions.java @@ -54,11 +54,11 @@ public class SevenZFileOptions { * Not all codecs will honor this setting. Currently only LZMA and LZMA2 are supported. * </p> * - * @param maxMemoryLimitKb limit of the maximum amount of memory to use + * @param maxMemoryLimitKiB limit of the maximum amount of memory to use in kibibytes. * @return the reconfigured builder */ - public Builder withMaxMemoryLimitInKb(final int maxMemoryLimitKb) { - this.maxMemoryLimitKb = maxMemoryLimitKb; + public Builder withMaxMemoryLimitInKb(final int maxMemoryLimitKiB) { + this.maxMemoryLimitKb = maxMemoryLimitKiB; return this; } @@ -110,12 +110,12 @@ public class SevenZFileOptions { return new Builder(); } - private final int maxMemoryLimitKb; + private final int maxMemoryLimitKiB; private final boolean useDefaultNameForUnnamedEntries; private final boolean tryToRecoverBrokenArchives; private SevenZFileOptions(final int maxMemoryLimitKb, final boolean useDefaultNameForUnnamedEntries, final boolean tryToRecoverBrokenArchives) { - this.maxMemoryLimitKb = maxMemoryLimitKb; + this.maxMemoryLimitKiB = maxMemoryLimitKb; this.useDefaultNameForUnnamedEntries = useDefaultNameForUnnamedEntries; this.tryToRecoverBrokenArchives = tryToRecoverBrokenArchives; } @@ -126,10 +126,10 @@ public class SevenZFileOptions { * Not all codecs will honor this setting. Currently only LZMA and LZMA2 are supported. * </p> * - * @return the maximum amount of memory to use for extraction + * @return the maximum amount of memory to use for extraction in kibibytes. */ public int getMaxMemoryLimitInKb() { - return maxMemoryLimitKb; + return maxMemoryLimitKiB; } /** diff --git a/src/test/java/org/apache/commons/compress/archivers/sevenz/SevenZFileTest.java b/src/test/java/org/apache/commons/compress/archivers/sevenz/SevenZFileTest.java index 8e3f32ae9..0608498b8 100644 --- a/src/test/java/org/apache/commons/compress/archivers/sevenz/SevenZFileTest.java +++ b/src/test/java/org/apache/commons/compress/archivers/sevenz/SevenZFileTest.java @@ -441,6 +441,11 @@ public class SevenZFileTest extends AbstractTest { // Do nothing. Exception should be thrown } }); + assertThrows(MemoryLimitException.class, () -> { + try (SevenZFile sevenZFile = SevenZFile.builder().setFile(getFile("bla.7z")).setMaxMemoryLimitKiB(1).get()) { + // Do nothing. Exception should be thrown + } + }); } @Test