diff --git a/src/main/java/org/xerial/snappy/SnappyCodec.java b/src/main/java/org/xerial/snappy/SnappyCodec.java index 588236e..ff022b1 100755 --- a/src/main/java/org/xerial/snappy/SnappyCodec.java +++ b/src/main/java/org/xerial/snappy/SnappyCodec.java @@ -120,6 +120,18 @@ public class SnappyCodec return Arrays.equals(MAGIC_HEADER, magic); } + public static boolean hasMagicHeaderPrefix(byte[] b) { + int limit = Math.min(MAGIC_LEN, b.length); + int i = 0; + while(i < limit) { + if(b[i] != MAGIC_HEADER[i]) { + return false; + } + ++i; + } + return true; + } + public static SnappyCodec readHeader(InputStream in) throws IOException { diff --git a/src/main/java/org/xerial/snappy/SnappyInputStream.java b/src/main/java/org/xerial/snappy/SnappyInputStream.java index 19a68c6..24f5976 100755 --- a/src/main/java/org/xerial/snappy/SnappyInputStream.java +++ b/src/main/java/org/xerial/snappy/SnappyInputStream.java @@ -93,7 +93,7 @@ public class SnappyInputStream // 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 || !SnappyCodec.hasMagicHeaderPrefix(header)) { // do the default uncompression // (probably) compressed by Snappy.compress(byte[]) readFully(header, readBytes); diff --git a/src/test/java/org/xerial/snappy/SnappyInputStreamTest.java b/src/test/java/org/xerial/snappy/SnappyInputStreamTest.java index 9af40bf..341a06c 100755 --- a/src/test/java/org/xerial/snappy/SnappyInputStreamTest.java +++ b/src/test/java/org/xerial/snappy/SnappyInputStreamTest.java @@ -204,4 +204,37 @@ public class SnappyInputStreamTest assertArrayEquals(orig, uncompressed); } + + @Test + public void checkMagicHeader() + throws IOException + { + ByteArrayOutputStream b = new ByteArrayOutputStream(); + // Write uncompressed length beginning with -126 (the same with magicheader[0]) + b.write(SnappyCodec.MAGIC_HEADER[0]); + b.write(0x01); + // uncompressed data length = 130 + + ByteArrayOutputStream data = new ByteArrayOutputStream(); + for(int i=0; i<130; ++i) { + data.write('A'); + } + byte[] dataMoreThan8Len = data.toByteArray(); + + // write literal (lower 2-bit of the first tag byte is 00, upper 6-bits represents data size) + b.write(60<<2); // 1-byte data length follows + b.write(dataMoreThan8Len.length-1); // subsequent data length + b.write(dataMoreThan8Len); + + byte[] compressed = b.toByteArray(); + + // This should succeed + assertArrayEquals(dataMoreThan8Len, Snappy.uncompress(compressed)); + + // Reproduce error in #142 + SnappyInputStream in = new SnappyInputStream(new ByteArrayInputStream(b.toByteArray())); + byte[] uncompressed = readFully(in); + + assertArrayEquals(dataMoreThan8Len, uncompressed); + } }