You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by bo...@apache.org on 2013/11/09 22:36:53 UTC
svn commit: r1540399 - in /commons/proper/compress/trunk/src:
main/java/org/apache/commons/compress/compressors/snappy/
test/java/org/apache/commons/compress/compressors/ test/resources/
Author: bodewig
Date: Sat Nov 9 21:36:52 2013
New Revision: 1540399
URL: http://svn.apache.org/r1540399
Log:
COMPRESS-147 incomplete InputStreams for Snappy
missing (among other things):
* tests with more than 32k of data
* CRC handling
* other chunk types
Added:
commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/snappy/FramedSnappyCompressorInputStream.java (with props)
commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/snappy/SnappyCompressorInputStream.java
- copied, changed from r1540086, commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/snappy/SnappyDecompressor.java
commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/compressors/FramedSnappyTestCase.java (with props)
commons/proper/compress/trunk/src/test/resources/bla.tar.sz (with props)
Added: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/snappy/FramedSnappyCompressorInputStream.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/snappy/FramedSnappyCompressorInputStream.java?rev=1540399&view=auto
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/snappy/FramedSnappyCompressorInputStream.java (added)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/snappy/FramedSnappyCompressorInputStream.java Sat Nov 9 21:36:52 2013
@@ -0,0 +1,226 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.compress.compressors.snappy;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PushbackInputStream;
+import java.util.Arrays;
+
+import org.apache.commons.compress.compressors.CompressorInputStream;
+import org.apache.commons.compress.utils.BoundedInputStream;
+import org.apache.commons.compress.utils.IOUtils;
+
+/**
+ * CompressorInputStream for the framing Snappy format.
+ *
+ * @see "http://code.google.com/p/snappy/source/browse/trunk/framing_format.txt"
+ * @since 1.7
+ */
+public class FramedSnappyCompressorInputStream extends CompressorInputStream {
+ private static final int STREAM_IDENTIFIER_TYPE = 0xff;
+ private static final int COMPRESSED_CHUNK_TYPE = 0;
+ private static final int UNCOMPRESSED_CHUNK_TYPE = 1;
+ private static final int PADDING_CHUNK_TYPE = 0xfe;
+ private static final int MIN_UNSKIPPABLE_TYPE = 2;
+ private static final int MAX_UNSKIPPABLE_TYPE = 0x7f;
+ private static final int MAX_SKIPPABLE_TYPE = 0xfd;
+
+ /** The underlying stream to read compressed data from */
+ private final PushbackInputStream in;
+
+ private SnappyCompressorInputStream currentCompressedChunk;
+
+ // used in no-arg read method
+ private final byte[] oneByte = new byte[1];
+
+ private boolean endReached, inUncompressedChunk;
+
+ private int uncompressedBytesRemaining;
+
+ /**
+ * Constructs a new input stream that decompresses snappy-framed-compressed data
+ * from the specified input stream.
+ * @param in the InputStream from which to read the compressed data
+ */
+ public FramedSnappyCompressorInputStream(InputStream in) throws IOException {
+ this.in = new PushbackInputStream(in, 1);
+ readStreamIdentifier();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int read() throws IOException {
+ return read(oneByte, 0, 1) == -1 ? -1 : (oneByte[0] & 0xFF);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void close() throws IOException {
+ in.close();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ int read = readOnce(b, off, len);
+ if (read == -1) {
+ readNextBlock();
+ if (endReached) {
+ return -1;
+ }
+ read = readOnce(b, off, len);
+ }
+ return read;
+ }
+
+ /**
+ * Read from the current chunk into the given array.
+ *
+ * @return -1 if there is no current chunk or the number of bytes
+ * read from the current chunk (which may be -1 if the end od the
+ * chunk is reached.
+ */
+ private int readOnce(byte[] b, int off, int len) throws IOException {
+ int read = -1;
+ if (inUncompressedChunk) {
+ int amount = Math.min(uncompressedBytesRemaining, len);
+ read = in.read(b, off, amount);
+ if (read != -1) {
+ uncompressedBytesRemaining -= read;
+ count(read);
+ }
+ } else if (currentCompressedChunk != null) {
+ long before = currentCompressedChunk.getBytesRead();
+ read = currentCompressedChunk.read(b, off, len);
+ if (read == -1) {
+ currentCompressedChunk = null;
+ } else {
+ count(currentCompressedChunk.getBytesRead() - before);
+ }
+ }
+ return read;
+ }
+
+ private void readNextBlock() throws IOException {
+ int type = readOneByte();
+ if (type == -1) {
+ endReached = true;
+ } else if (type == STREAM_IDENTIFIER_TYPE) {
+ in.unread(type);
+ count(-1);
+ readStreamIdentifier();
+ readNextBlock();
+ } else if (type == PADDING_CHUNK_TYPE
+ || (type > MAX_UNSKIPPABLE_TYPE && type <= MAX_SKIPPABLE_TYPE)) {
+ skipBlock();
+ readNextBlock();
+ } else if (type >= MIN_UNSKIPPABLE_TYPE && type <= MAX_UNSKIPPABLE_TYPE) {
+ throw new IOException("unskippable chunk with type " + type
+ + " detected.");
+ } else if (type == UNCOMPRESSED_CHUNK_TYPE) {
+ uncompressedBytesRemaining = readSize();
+ readCrc();
+ } else if (type == COMPRESSED_CHUNK_TYPE) {
+ int size = readSize();
+ readCrc();
+ currentCompressedChunk =
+ new SnappyCompressorInputStream(new BoundedInputStream(in, size));
+ } else {
+ // impossible as all potential byte values have been covered
+ throw new IOException("unknown chunk type " + type
+ + " detected.");
+ }
+ }
+
+ private void readCrc() throws IOException {
+ byte[] b = new byte[4];
+ if (IOUtils.readFully(in, b) != 4) {
+ throw new IOException("premature end of stream");
+ }
+ count(4);
+ }
+
+ private int readSize() throws IOException {
+ int b = 0;
+ int sz = 0;
+ for (int i = 0; i < 3; i++) {
+ b = readOneByte();
+ if (b == -1) {
+ throw new IOException("premature end of stream");
+ }
+ sz |= (b << (i * 8));
+ }
+ return sz;
+ }
+
+ private void skipBlock() throws IOException {
+ int size = readSize();
+ if (IOUtils.skip(in, size) != size) {
+ throw new IOException("premature end of stream");
+ }
+ count(size);
+ }
+
+ private void readStreamIdentifier() throws IOException {
+ byte[] b = new byte[10];
+ if (10 != IOUtils.readFully(in, b) || !matches(b, 10)) {
+ throw new IOException("Not a framed Snappy stream");
+ }
+ count(10);
+ }
+
+ private int readOneByte() throws IOException {
+ int b = in.read();
+ if (b != -1) {
+ count(1);
+ return b & 0xFF;
+ }
+ return -1;
+ }
+
+ /**
+ * Checks if the signature matches what is expected for a .sz file.
+ *
+ * <p>.sz files start with a chuck with tag 0xff and content sNaPpY.
+ *
+ * @param signature the bytes to check
+ * @param length the number of bytes to check
+ * @return true if this is a .sz stream, false otherwise
+ */
+ public static boolean matches(byte[] signature, int length) {
+
+ if (length < 10) {
+ return false;
+ }
+
+ byte[] shortenedSig = signature;
+ if (signature.length > 10) {
+ shortenedSig = new byte[10];
+ System.arraycopy(signature, 0, shortenedSig, 0, 10);
+ }
+
+ return Arrays.equals(shortenedSig, new byte[] {
+ (byte) STREAM_IDENTIFIER_TYPE, // tag
+ 6, 0, 0, // length
+ 's', 'N', 'a', 'P', 'p', 'Y'
+ });
+ }
+
+}
Propchange: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/snappy/FramedSnappyCompressorInputStream.java
------------------------------------------------------------------------------
svn:eol-style = native
Copied: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/snappy/SnappyCompressorInputStream.java (from r1540086, commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/snappy/SnappyDecompressor.java)
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/snappy/SnappyCompressorInputStream.java?p2=commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/snappy/SnappyCompressorInputStream.java&p1=commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/snappy/SnappyDecompressor.java&r1=1540086&r2=1540399&rev=1540399&view=diff
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/snappy/SnappyDecompressor.java (original)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/compressors/snappy/SnappyCompressorInputStream.java Sat Nov 9 21:36:52 2013
@@ -18,85 +18,80 @@
*/
package org.apache.commons.compress.compressors.snappy;
-import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.io.OutputStream;
+
+import org.apache.commons.compress.compressors.CompressorInputStream;
/**
- * This class implements Snappy decompression. Snappy is a LZ77-type compressor
- * with a fixed, byte-oriented encoding created by Google(tm). It is originally
- * based on text by Zeev Tarantov. This approach works by allocating a buffer 3x
- * the compression block size. As the stream is decompressed, it is written to
- * the buffer. When the buffer becomes 2/3 full, the first third is flushed to
- * the underlying stream and the following bytes are all shifted down the array.
- * In this way, there is always at least one block-size of buffer available for
- * back-references.
+ * CompressorInputStream for the raw Snappy format.
+ *
+ * <p>This implementation uses an internal buffer in order to handle
+ * the back-references that are at the heart of the LZ77 algorithm.
+ * The size of the buffer must be at least as big as the biggest
+ * offset used in the compressed stream. The current version of the
+ * Snappy algorithm as defined by Google works on 32k blocks and
+ * doesn't contain offsets bigger than 32k which is the default block
+ * size used by this class.</p>
+ *
+ * @see "http://code.google.com/p/snappy/source/browse/trunk/format_description.txt"
+ * @since 1.7
*/
-public class SnappyDecompressor {
+public class SnappyCompressorInputStream extends CompressorInputStream {
/** Mask used to determine the type of "tag" is being processed */
private static final int TAG_MASK = 0x03;
/** Default block size */
- public static final int BLOCK_SIZE = 32768;
+ public static final int DEFAULT_BLOCK_SIZE = 32768;
/** Buffer to write decompressed bytes to for back-references */
private final byte[] decompressBuf;
- /** The index of the next byte in the buffer to write to */
- private int decompressBufIndex;
+ /**
+ * One behind the index of the last byte in the buffer that was
+ * written
+ */
+ private int writeIndex;
+
+ /**
+ * Index of the next byte to be read.
+ */
+ private int readIndex;
/** The actual block size specified */
- protected final int blockSize;
+ private final int blockSize;
/** The underlying stream to read compressed data from */
- protected final InputStream in;
+ private final InputStream in;
/** The size of the uncompressed data */
- protected final int size;
+ private final int size;
/**
- * Constructor
- *
- * @param buf
- * An array of compressed data
- *
- * @throws IOException
+ * Number of uncompressed bytes still to be read.
*/
- public SnappyDecompressor(final byte[] buf) throws IOException {
- this(new ByteArrayInputStream(buf), BLOCK_SIZE);
- }
+ private int uncompressedBytesRemaining;
- /**
- * Constructor
- *
- * @param buf
- * An array of compressed data
- * @param blockSize
- * The block size used in compression
- *
- * @throws IOException
- */
- public SnappyDecompressor(final byte[] buf, int blockSize)
- throws IOException {
- this(new ByteArrayInputStream(buf), blockSize);
- }
+ // used in no-arg read method
+ private final byte[] oneByte = new byte[1];
+
+ private boolean endReached = false;
/**
- * Constructor
+ * Constructor using the default buffer size of 32k.
*
* @param is
* An InputStream to read compressed data from
*
* @throws IOException
*/
- public SnappyDecompressor(final InputStream is) throws IOException {
- this(is, BLOCK_SIZE);
+ public SnappyCompressorInputStream(final InputStream is) throws IOException {
+ this(is, DEFAULT_BLOCK_SIZE);
}
/**
- * Constructor
+ * Constructor using a configurable buffer size.
*
* @param is
* An InputStream to read compressed data from
@@ -105,32 +100,66 @@ public class SnappyDecompressor {
*
* @throws IOException
*/
- public SnappyDecompressor(final InputStream is, final int blockSize)
+ public SnappyCompressorInputStream(final InputStream is, final int blockSize)
throws IOException {
-
this.in = is;
this.blockSize = blockSize;
this.decompressBuf = new byte[blockSize * 3];
- this.decompressBufIndex = 0;
- this.size = (int) readSize();
+ this.writeIndex = readIndex = 0;
+ uncompressedBytesRemaining = size = (int) readSize();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int read() throws IOException {
+ return read(oneByte, 0, 1) == -1 ? -1 : (oneByte[0] & 0xFF);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void close() throws IOException {
+ in.close();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int available() {
+ return writeIndex - readIndex;
}
/**
- * Decompress the stream into an OutputStream
- *
- * @param os
- * The OutputStream to write the decompressed data
- *
- * @throws IOException
- * if an I/O error occurs. In particular, an
- * <code>IOException</code> is thrown if the output stream is
- * closed or the EOF is reached unexpectedly.
+ * {@inheritDoc}
*/
- public void decompress(final OutputStream os) throws IOException {
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ if (endReached) {
+ return -1;
+ }
+ if (len > available()) {
+ fill(len - available());
+ }
- int uncompressedSizeLength = getSize();
+ int readable = Math.min(len, available());
+ System.arraycopy(decompressBuf, readIndex, b, off, readable);
+ readIndex += readable;
+ if (readIndex > blockSize) {
+ slideBuffer();
+ }
+ return readable;
+ }
+
+ /**
+ * Try to fill the buffer with enoug bytes to satisfy the current read request.
+ *
+ * @param len the number of uncompressed bytes to read
+ */
+ private void fill(int len) throws IOException {
+ if (uncompressedBytesRemaining == 0) {
+ endReached = true;
+ }
+ int readNow = Math.min(len, uncompressedBytesRemaining);
- while (uncompressedSizeLength > 0) {
+ while (readNow > 0) {
final int b = readOneByte();
int length = 0;
int offset = 0;
@@ -139,45 +168,10 @@ public class SnappyDecompressor {
case 0x00:
- /*
- * For literals up to and including 60 bytes in length, the
- * upper six bits of the tag byte contain (len-1). The literal
- * follows immediately thereafter in the bytestream. - For
- * longer literals, the (len-1) value is stored after the tag
- * byte, little-endian. The upper six bits of the tag byte
- * describe how many bytes are used for the length; 60, 61, 62
- * or 63 for 1-4 bytes, respectively. The literal itself follows
- * after the length.
- */
-
- switch (b >> 2) {
- case 60:
- length = readOneByte();
- break;
- case 61:
- length = readOneByte();
- length |= (readOneByte() << 8);
- break;
- case 62:
- length = readOneByte();
- length |= (readOneByte() << 8);
- length |= (readOneByte() << 16);
- break;
- case 63:
- length = readOneByte();
- length |= (readOneByte() << 8);
- length |= (readOneByte() << 16);
- length |= (readOneByte() << 24);
- break;
- default:
- length = b >> 2;
- break;
- }
-
- length += 1;
+ length = readLiteralLength(b);
if (expandLiteral(length)) {
- flushDecompressBuffer(os);
+ return;
}
break;
@@ -197,7 +191,7 @@ public class SnappyDecompressor {
offset |= readOneByte();
if (expandCopy(offset, length)) {
- flushDecompressBuffer(os);
+ return;
}
break;
@@ -217,7 +211,7 @@ public class SnappyDecompressor {
offset |= readOneByte() << 8;
if (expandCopy(offset, length)) {
- flushDecompressBuffer(os);
+ return;
}
break;
@@ -238,35 +232,67 @@ public class SnappyDecompressor {
offset |= readOneByte() << 24;
if (expandCopy(offset, length)) {
- flushDecompressBuffer(os);
+ return;
}
break;
}
- uncompressedSizeLength -= length;
+ readNow -= length;
+ uncompressedBytesRemaining -= length;
}
- os.write(decompressBuf, 0, decompressBufIndex);
}
/**
- * Flush the first block of the decompression buffer to the underlying out
- * stream. All subsequent bytes are moved down to the beginning of the
- * buffer.
- *
- * @param os
- * The output stream to write to
- *
- * @throws IOException
- * if an I/O error occurs. In particular, an
- * <code>IOException</code> is thrown if the output stream is
- * closed.
- */
- private void flushDecompressBuffer(final OutputStream os)
- throws IOException {
- os.write(decompressBuf, 0, this.blockSize);
- System.arraycopy(decompressBuf, BLOCK_SIZE, decompressBuf, 0,
- this.blockSize);
- decompressBufIndex -= this.blockSize;
+ * Slide buffer.
+ *
+ * <p>Move all bytes of the buffer after the first block down
+ * tothe beginning of the buffer.</p>
+ */
+ private void slideBuffer() {
+ System.arraycopy(decompressBuf, blockSize, decompressBuf, 0,
+ blockSize);
+ writeIndex -= blockSize;
+ readIndex -= blockSize;
+ }
+
+
+ /*
+ * For literals up to and including 60 bytes in length, the
+ * upper six bits of the tag byte contain (len-1). The literal
+ * follows immediately thereafter in the bytestream. - For
+ * longer literals, the (len-1) value is stored after the tag
+ * byte, little-endian. The upper six bits of the tag byte
+ * describe how many bytes are used for the length; 60, 61, 62
+ * or 63 for 1-4 bytes, respectively. The literal itself follows
+ * after the length.
+ */
+ private int readLiteralLength(int b) throws IOException {
+ int length;
+ switch (b >> 2) {
+ case 60:
+ length = readOneByte();
+ break;
+ case 61:
+ length = readOneByte();
+ length |= (readOneByte() << 8);
+ break;
+ case 62:
+ length = readOneByte();
+ length |= (readOneByte() << 8);
+ length |= (readOneByte() << 16);
+ break;
+ case 63:
+ length = readOneByte();
+ length |= (readOneByte() << 8);
+ length |= (readOneByte() << 16);
+ length |= (readOneByte() << 24);
+ break;
+ default:
+ length = b >> 2;
+ break;
+ }
+
+ return length + 1;
}
/**
@@ -279,16 +305,17 @@ public class SnappyDecompressor {
* If the first byte cannot be read for any reason other than
* end of file, or if the input stream has been closed, or if
* some other I/O error occurs.
- *
* @return True if the decompressed data should be flushed
*/
private boolean expandLiteral(final int length) throws IOException {
- if (length != this.in.read(decompressBuf, decompressBufIndex, length)) {
+ int bytesRead = in.read(decompressBuf, writeIndex, length);
+ count(bytesRead);
+ if (length != bytesRead) {
throw new IOException("Premature end of stream");
}
- decompressBufIndex += length;
- return (decompressBufIndex >= (2 * this.blockSize));
+ writeIndex += length;
+ return (writeIndex >= (2 * this.blockSize));
}
/**
@@ -311,39 +338,37 @@ public class SnappyDecompressor {
* @return True if the decompressed data should be flushed
*/
private boolean expandCopy(final int offset, int length) throws IOException {
-
if (offset > blockSize) {
throw new IOException("Offset is larger than block size");
}
if (offset == 1) {
- byte lastChar = decompressBuf[decompressBufIndex - 1];
+ byte lastChar = decompressBuf[writeIndex - 1];
for (int i = 0; i < length; i++) {
- decompressBuf[decompressBufIndex++] = lastChar;
+ decompressBuf[writeIndex++] = lastChar;
}
} else if (length < offset) {
- System.arraycopy(decompressBuf, decompressBufIndex - offset,
- decompressBuf, decompressBufIndex, length);
- decompressBufIndex += length;
+ System.arraycopy(decompressBuf, writeIndex - offset,
+ decompressBuf, writeIndex, length);
+ writeIndex += length;
} else {
int fullRotations = length / offset;
int pad = length - (offset * fullRotations);
while (fullRotations-- != 0) {
- System.arraycopy(decompressBuf, decompressBufIndex - offset,
- decompressBuf, decompressBufIndex, offset);
- decompressBufIndex += offset;
+ System.arraycopy(decompressBuf, writeIndex - offset,
+ decompressBuf, writeIndex, offset);
+ writeIndex += offset;
}
if (pad > 0) {
- System.arraycopy(decompressBuf, decompressBufIndex - offset,
- decompressBuf, decompressBufIndex, pad);
+ System.arraycopy(decompressBuf, writeIndex - offset,
+ decompressBuf, writeIndex, pad);
- decompressBufIndex += pad;
+ writeIndex += pad;
}
}
-
- return (decompressBufIndex >= (2 * this.blockSize));
+ return (writeIndex >= (2 * this.blockSize));
}
/**
@@ -361,6 +386,7 @@ public class SnappyDecompressor {
if (b == -1) {
throw new IOException("Premature end of stream");
}
+ count(1);
return b & 0xFF;
}
Added: commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/compressors/FramedSnappyTestCase.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/compressors/FramedSnappyTestCase.java?rev=1540399&view=auto
==============================================================================
--- commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/compressors/FramedSnappyTestCase.java (added)
+++ commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/compressors/FramedSnappyTestCase.java Sat Nov 9 21:36:52 2013
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.compress.compressors;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+
+import org.apache.commons.compress.AbstractTestCase;
+import org.apache.commons.compress.compressors.snappy.FramedSnappyCompressorInputStream;
+import org.apache.commons.compress.utils.IOUtils;
+
+public final class FramedSnappyTestCase
+ extends AbstractTestCase {
+
+ public void testMatches() throws IOException {
+ assertFalse(FramedSnappyCompressorInputStream.matches(new byte[10], 10));
+ byte[] b = new byte[12];
+ final File input = getFile("bla.tar.sz");
+ FileInputStream in = new FileInputStream(input);
+ try {
+ IOUtils.readFully(in, b);
+ } finally {
+ in.close();
+ }
+ assertFalse(FramedSnappyCompressorInputStream.matches(b, 9));
+ assertTrue(FramedSnappyCompressorInputStream.matches(b, 10));
+ assertTrue(FramedSnappyCompressorInputStream.matches(b, 12));
+ }
+
+ public void testDefaultExtraction() throws IOException {
+ final File input = getFile("bla.tar.sz");
+ final File output = new File(dir, "bla.tar");
+ final FileInputStream is = new FileInputStream(input);
+ try {
+ final CompressorInputStream in =
+ new FramedSnappyCompressorInputStream(is);
+ FileOutputStream out = null;
+ try {
+ out = new FileOutputStream(output);
+ IOUtils.copy(in, out);
+ } finally {
+ if (out != null) {
+ out.close();
+ }
+ in.close();
+ }
+ } finally {
+ is.close();
+ }
+ final File original = getFile("bla.tar");
+ final FileInputStream written = new FileInputStream(output);
+ try {
+ FileInputStream orig = new FileInputStream(original);
+ try {
+ assertTrue(Arrays.equals(IOUtils.toByteArray(written),
+ IOUtils.toByteArray(orig)));
+ } finally {
+ orig.close();
+ }
+ } finally {
+ written.close();
+ }
+ }
+}
Propchange: commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/compressors/FramedSnappyTestCase.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: commons/proper/compress/trunk/src/test/resources/bla.tar.sz
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/test/resources/bla.tar.sz?rev=1540399&view=auto
==============================================================================
Binary file - no diff available.
Propchange: commons/proper/compress/trunk/src/test/resources/bla.tar.sz
------------------------------------------------------------------------------
svn:mime-type = application/octet-stream