#89: Add SnappyIOException to distinguish empty input, incompatible format version, etc.

This commit is contained in:
Taro L. Saito 2014-10-23 12:42:12 +09:00
parent 164e51da2e
commit f0d7f62881
4 changed files with 44 additions and 18 deletions

View File

@ -38,7 +38,11 @@ public enum SnappyErrorCode {
PARSING_ERROR(2),
NOT_A_DIRECT_BUFFER(3),
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;

View File

@ -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; }
}

View File

@ -83,6 +83,10 @@ public class SnappyInputStream extends InputStream
}
// 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]) {
// do the default uncompression
readFully(header, readBytes);
@ -93,8 +97,8 @@ public class SnappyInputStream extends InputStream
if (codec.isValidMagicHeader()) {
// The input data is compressed by SnappyOutputStream
if (codec.version < SnappyCodec.MINIMUM_COMPATIBLE_VERSION) {
throw new IOException(String.format(
"compressed with imcompatible codec version %d. At least version %d is required",
throw new SnappyIOException(SnappyErrorCode.INCOMPATIBLE_VERSION, String.format(
"Compressed with an incompatible codec version %d. At least version %d is required",
codec.version, SnappyCodec.MINIMUM_COMPATIBLE_VERSION));
}
}
@ -351,20 +355,15 @@ public class SnappyInputStream extends InputStream
if (readBytes < chunkSize) {
throw new IOException("failed to read chunk");
}
try {
int uncompressedLength = Snappy.uncompressedLength(compressed, 0, chunkSize);
if (uncompressed == null || uncompressedLength > uncompressed.length) {
uncompressed = new byte[uncompressedLength];
}
int actualUncompressedLength = Snappy.uncompress(compressed, 0, chunkSize, uncompressed, 0);
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;
}
catch (IOException e) {
throw new IOException("failed to uncompress the chunk: " + e.getMessage());
}
return true;
}

View File

@ -135,11 +135,11 @@ public class SnappyInputStreamTest
SnappyInputStream in = new SnappyInputStream(new ByteArrayInputStream(new byte[0]));
byte[] uncompressed = readFully(in);
assertEquals(0, uncompressed.length);
}
catch(Exception e) {
fail("should not reach here");
}
catch(SnappyIOException e) {
assertEquals(SnappyErrorCode.EMPTY_INPUT, e.getErrorCode());
}
}
}