Skip to content

Commit

Permalink
Fixed sonarcloud warnings
Browse files Browse the repository at this point in the history
  • Loading branch information
depryf committed Jul 24, 2023
1 parent b033efb commit 731edbd
Show file tree
Hide file tree
Showing 8 changed files with 391 additions and 8 deletions.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ repositories {

dependencies {
implementation 'org.apache.commons:commons-lang3:3.12.0'
implementation 'org.apache.commons:commons-compress:1.22'
implementation 'commons-io:commons-io:2.13.0'

testImplementation 'junit:junit:4.13.2'
Expand Down
1 change: 1 addition & 0 deletions src/main/java/com/imsweb/seerutils/SeerLRUCache.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
* @param <A>
* @param <B>
*/
@SuppressWarnings({"java:S2160", "unused"}) // override equals, class not used
public class SeerLRUCache<A, B> extends LinkedHashMap<A, B> {

private static final long serialVersionUID = 4701170688038236784L;
Expand Down
15 changes: 8 additions & 7 deletions src/main/java/com/imsweb/seerutils/SeerUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
package com.imsweb.seerutils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
Expand All @@ -26,13 +25,15 @@
import java.util.zip.GZIPOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;

import com.imsweb.seerutils.zip.ZipSecureFile;

/**
* This class provides shared functionality that can be used by all the other modules in SEER*Utils.
*/
Expand Down Expand Up @@ -727,9 +728,11 @@ public static void unzipFile(File from, File to) throws IOException {
if (!to.isDirectory())
throw new IOException("Target is not a directory.");

try (ZipFile file = new ZipFile(from); FileInputStream fis = new FileInputStream(from); ZipInputStream zipInput = new ZipInputStream(fis)) {
ZipEntry entry = zipInput.getNextEntry();
while (entry != null) {
try (ZipSecureFile file = new ZipSecureFile(from)) {
Enumeration<? extends ZipArchiveEntry> entries = file.getEntries();
while (entries.hasMoreElements()) {
ZipArchiveEntry entry = entries.nextElement();

File target = new File(to, entry.getName());
if (!target.getParentFile().exists())
if (!target.getParentFile().mkdirs())
Expand All @@ -744,8 +747,6 @@ public static void unzipFile(File from, File to) throws IOException {
copyInputStreamToOutputStream(file.getInputStream(entry), fos);
}
}

entry = zipInput.getNextEntry();
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
package com.imsweb.seerutils.zip;

import java.io.EOFException;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.ZipException;

import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import org.apache.commons.compress.utils.InputStreamStatistics;

@SuppressWarnings("unused")
public class ZipArchiveThresholdInputStream extends FilterInputStream {

// don't alert for expanded sizes smaller than 100k
private static final long _GRACE_ENTRY_SIZE = 100 * 1024L;

private static final String _MAX_ENTRY_SIZE_MSG = "The file exceeded the maximum entry size allowed";

private static final String _MIN_INFLATE_RATIO_MSG = "The file exceeded the maximum compression ratio allowed";

private double _minInflateRatio;
private long _maxEntrySize;

/**
* the reference to the current entry is only used for a more detailed log message in case of an error
*/
private ZipArchiveEntry _entry;
private boolean _guardState = true;

public ZipArchiveThresholdInputStream(InputStream is) {
super(is);

if (!(is instanceof InputStreamStatistics))
throw new IllegalArgumentException("InputStream of class " + is.getClass() + " is not implementing InputStreamStatistics.");

// set defaults but they will always be set by ZipSecureFile.getInputStream
_minInflateRatio = 0.01d;
_maxEntrySize = 0xFFFFFFFFL;
}

/**
* Sets the zip entry for a detailed logging
* @param entry the entry
*/
void setEntry(ZipArchiveEntry entry) {
this._entry = entry;
}

void setMaxEntrySize(long maxEntrySize) {
_maxEntrySize = maxEntrySize;
}

void setMinInflateRatio(double ratio) {
_minInflateRatio = ratio;
}

@Override
public int read() throws IOException {
int b = super.read();
if (b > -1)
checkThreshold();
return b;
}

@Override
public int read(byte[] b, int off, int len) throws IOException {
int cnt = super.read(b, off, len);
if (cnt > -1)
checkThreshold();
return cnt;
}

@Override
public long skip(long n) throws IOException {
long cnt = skipFully(super.in, n);
if (cnt > 0)
checkThreshold();
return cnt;
}

/**
* De-/activate threshold check.
* A disabled guard might make sense, when POI is processing its own temporary data (see #59743)
* @param guardState {@code true} (= default) enables the threshold check
*/
public void setGuardState(boolean guardState) {
this._guardState = guardState;
}

private void checkThreshold() throws IOException {
if (!_guardState)
return;

final InputStreamStatistics stats = (InputStreamStatistics)in;
final long payloadSize = stats.getUncompressedCount();

long rawSize;
try {
rawSize = stats.getCompressedCount();
}
catch (NullPointerException e) {
// this can happen with a very specially crafted file (see https://issues.apache.org/jira/browse/COMPRESS-598 for a related bug-report)
// therefore we try to handle this gracefully for now this try/catch can be removed when COMPRESS-598 is fixed
rawSize = 0;
}

final String entryName = _entry == null ? "not set" : _entry.getName();

// check the file size first, in case we are working on uncompressed streams; only check is max entry size is greater than 0
if (_maxEntrySize > 0 && payloadSize > _maxEntrySize)
throw new ZipEntryTooLargeException(_MAX_ENTRY_SIZE_MSG);

// don't alert for small expanded size
if (payloadSize <= _GRACE_ENTRY_SIZE)
return;

// check the inflate ratio if min inflate ratio is greater than zero
double ratio = rawSize / (double)payloadSize;
if (_minInflateRatio > 0.0d && ratio >= _minInflateRatio)
return;

// one of the limits was reached, report it
throw new ZipInvalidCompressionRatioException(_MIN_INFLATE_RATIO_MSG);
}

ZipArchiveEntry getNextEntry() throws IOException {
if (!(in instanceof ZipArchiveInputStream))
throw new IllegalStateException("getNextEntry() is only allowed for stream based zip processing.");

try {
_entry = ((ZipArchiveInputStream)in).getNextZipEntry();
return _entry;
}
catch (ZipException ze) {
if (ze.getMessage().startsWith("Unexpected record signature"))
throw new IllegalStateException("No valid entries or contents found, this is not a valid file", ze);

throw ze;
}
catch (EOFException e) {
return null;
}
}

/**
* Skips bytes from an input byte stream.
* This implementation guarantees that it will read as many bytes
* as possible before giving up; this may not always be the case for
* skip() implementations in subclasses of {@link InputStream}.
* <p>
* Note that the implementation uses {@link InputStream#read(byte[], int, int)} rather
* than delegating to {@link InputStream#skip(long)}.
* This means that the method may be considerably less efficient than using the actual skip implementation,
* this is done to guarantee that the correct number of bytes are skipped.
* <p>
* This mimics POI's readFully(InputStream, byte[]).
* <p>
* If the end of file is reached before any bytes are read, returns {@code -1}. If
* the end of the file is reached after some bytes are read, returns the
* number of bytes read. If the end of the file isn't reached before {@code len}
* bytes have been read, will return {@code len} bytes.
*
* <p>
* Copied nearly verbatim from commons-io 41a3e9c
* @param input byte stream to skip
* @param toSkip number of bytes to skip.
* @return number of bytes actually skipped.
* @throws IOException if there is a problem reading the file
* @throws IllegalArgumentException if toSkip is negative
* @see InputStream#skip(long)
*/
static long skipFully(final InputStream input, final long toSkip) throws IOException {
final int skipBufferSize = 2048;

if (toSkip < 0)
throw new IllegalArgumentException("Skip count must be non-negative, actual: " + toSkip);
if (toSkip == 0)
return 0L;

/*
* N.B. no need to synchronize this because: - we don't care if the buffer is created multiple times (the data
* is ignored) - we always use the same size buffer, so if it it is recreated it will still be OK (if the buffer
* size were variable, we would need to synch. to ensure some other thread did not create a smaller one)
*/
byte[] skipByteBuffer = new byte[skipBufferSize];

long remain = toSkip;
while (remain > 0) {
// See https://issues.apache.org/jira/browse/IO-203 for why we use read() rather than delegating to skip()
final long n = input.read(skipByteBuffer, 0, (int)Math.min(remain, skipBufferSize));
if (n < 0) // EOF
break;

remain -= n;
}

if (toSkip == remain)
return -1L;

return toSkip - remain;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright (C) 2022 Information Management Services, Inc.
*/
package com.imsweb.seerutils.zip;

import java.io.IOException;

public class ZipEntryTooLargeException extends IOException {

/**
* Constructs an {@code ZipEntryTooLargeException} with a given message
* {@code String}. No underlying cause is set;
* {@code getCause} will return {@code null}.
* @param message the error message.
* @see #getMessage
*/
public ZipEntryTooLargeException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright (C) 2022 Information Management Services, Inc.
*/
package com.imsweb.seerutils.zip;

import java.io.IOException;

public class ZipInvalidCompressionRatioException extends IOException {

/**
* Constructs an {@code ZipInvalidCompressionRatioException} with a given message
* {@code String}. No underlying cause is set;
* {@code getCause} will return {@code null}.
* @param message the error message.
* @see #getMessage
*/
public ZipInvalidCompressionRatioException(String message) {
super(message);
}
}
Loading

0 comments on commit 731edbd

Please sign in to comment.