#89: Add SnappyIOException to distinguish empty input, incompatible format version, etc.
This commit is contained in:
parent
164e51da2e
commit
f0d7f62881
|
@ -38,7 +38,11 @@ public enum SnappyErrorCode {
|
||||||
PARSING_ERROR(2),
|
PARSING_ERROR(2),
|
||||||
NOT_A_DIRECT_BUFFER(3),
|
NOT_A_DIRECT_BUFFER(3),
|
||||||
OUT_OF_MEMORY(4),
|
OUT_OF_MEMORY(4),
|
||||||
FAILED_TO_UNCOMPRESS(5);
|
FAILED_TO_UNCOMPRESS(5),
|
||||||
|
EMPTY_INPUT(6),
|
||||||
|
INCOMPATIBLE_VERSION(7),
|
||||||
|
INVALID_CHUNK_SIZE(8)
|
||||||
|
;
|
||||||
|
|
||||||
public final int id;
|
public final int id;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
package org.xerial.snappy;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enhanced IOException with SnappyErrorCode
|
||||||
|
*/
|
||||||
|
public class SnappyIOException extends IOException {
|
||||||
|
private final SnappyErrorCode errorCode;
|
||||||
|
|
||||||
|
public SnappyIOException(SnappyErrorCode errorCode, String message) {
|
||||||
|
super(message);
|
||||||
|
this.errorCode = errorCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMessage() {
|
||||||
|
return String.format("[%s] %s", errorCode.name(), super.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
public SnappyErrorCode getErrorCode() { return errorCode; }
|
||||||
|
|
||||||
|
}
|
|
@ -83,6 +83,10 @@ public class SnappyInputStream extends InputStream
|
||||||
}
|
}
|
||||||
|
|
||||||
// Quick test of the header
|
// Quick test of the header
|
||||||
|
if(readBytes == 0) {
|
||||||
|
// Snappy produces at least 1-byte result. So the empty input is not a valid input
|
||||||
|
throw new SnappyIOException(SnappyErrorCode.EMPTY_INPUT, "Cannot decompress empty stream");
|
||||||
|
}
|
||||||
if (readBytes < header.length || header[0] != SnappyCodec.MAGIC_HEADER[0]) {
|
if (readBytes < header.length || header[0] != SnappyCodec.MAGIC_HEADER[0]) {
|
||||||
// do the default uncompression
|
// do the default uncompression
|
||||||
readFully(header, readBytes);
|
readFully(header, readBytes);
|
||||||
|
@ -93,8 +97,8 @@ public class SnappyInputStream extends InputStream
|
||||||
if (codec.isValidMagicHeader()) {
|
if (codec.isValidMagicHeader()) {
|
||||||
// The input data is compressed by SnappyOutputStream
|
// The input data is compressed by SnappyOutputStream
|
||||||
if (codec.version < SnappyCodec.MINIMUM_COMPATIBLE_VERSION) {
|
if (codec.version < SnappyCodec.MINIMUM_COMPATIBLE_VERSION) {
|
||||||
throw new IOException(String.format(
|
throw new SnappyIOException(SnappyErrorCode.INCOMPATIBLE_VERSION, String.format(
|
||||||
"compressed with imcompatible codec version %d. At least version %d is required",
|
"Compressed with an incompatible codec version %d. At least version %d is required",
|
||||||
codec.version, SnappyCodec.MINIMUM_COMPATIBLE_VERSION));
|
codec.version, SnappyCodec.MINIMUM_COMPATIBLE_VERSION));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -351,20 +355,15 @@ public class SnappyInputStream extends InputStream
|
||||||
if (readBytes < chunkSize) {
|
if (readBytes < chunkSize) {
|
||||||
throw new IOException("failed to read chunk");
|
throw new IOException("failed to read chunk");
|
||||||
}
|
}
|
||||||
try {
|
|
||||||
int uncompressedLength = Snappy.uncompressedLength(compressed, 0, chunkSize);
|
int uncompressedLength = Snappy.uncompressedLength(compressed, 0, chunkSize);
|
||||||
if (uncompressed == null || uncompressedLength > uncompressed.length) {
|
if (uncompressed == null || uncompressedLength > uncompressed.length) {
|
||||||
uncompressed = new byte[uncompressedLength];
|
uncompressed = new byte[uncompressedLength];
|
||||||
}
|
}
|
||||||
int actualUncompressedLength = Snappy.uncompress(compressed, 0, chunkSize, uncompressed, 0);
|
int actualUncompressedLength = Snappy.uncompress(compressed, 0, chunkSize, uncompressed, 0);
|
||||||
if (uncompressedLength != actualUncompressedLength) {
|
if (uncompressedLength != actualUncompressedLength) {
|
||||||
throw new IOException("invalid uncompressed byte size");
|
throw new SnappyIOException(SnappyErrorCode.INVALID_CHUNK_SIZE, String.format("expected %,d bytes, but decompressed chunk has %,d bytes", uncompressedLength, actualUncompressedLength));
|
||||||
}
|
}
|
||||||
uncompressedLimit = actualUncompressedLength;
|
uncompressedLimit = actualUncompressedLength;
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
throw new IOException("failed to uncompress the chunk: " + e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,11 +135,11 @@ public class SnappyInputStreamTest
|
||||||
SnappyInputStream in = new SnappyInputStream(new ByteArrayInputStream(new byte[0]));
|
SnappyInputStream in = new SnappyInputStream(new ByteArrayInputStream(new byte[0]));
|
||||||
byte[] uncompressed = readFully(in);
|
byte[] uncompressed = readFully(in);
|
||||||
assertEquals(0, uncompressed.length);
|
assertEquals(0, uncompressed.length);
|
||||||
}
|
|
||||||
catch(Exception e) {
|
|
||||||
fail("should not reach here");
|
fail("should not reach here");
|
||||||
}
|
}
|
||||||
|
catch(SnappyIOException e) {
|
||||||
|
assertEquals(SnappyErrorCode.EMPTY_INPUT, e.getErrorCode());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue