001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.commons.compress.compressors.snappy;
020
021import java.io.IOException;
022import java.io.InputStream;
023
024import org.apache.commons.compress.compressors.CompressorInputStream;
025import org.apache.commons.compress.utils.IOUtils;
026
027/**
028 * CompressorInputStream for the raw Snappy format.
029 *
030 * <p>This implementation uses an internal buffer in order to handle
031 * the back-references that are at the heart of the LZ77 algorithm.
032 * The size of the buffer must be at least as big as the biggest
033 * offset used in the compressed stream.  The current version of the
034 * Snappy algorithm as defined by Google works on 32k blocks and
035 * doesn't contain offsets bigger than 32k which is the default block
036 * size used by this class.</p>
037 *
038 * @see <a href="http://code.google.com/p/snappy/source/browse/trunk/format_description.txt">Snappy compressed format description</a>
039 * @since 1.7
040 */
041public class SnappyCompressorInputStream extends CompressorInputStream {
042
043    /** Mask used to determine the type of "tag" is being processed */
044    private static final int TAG_MASK = 0x03;
045
046    /** Default block size */
047    public static final int DEFAULT_BLOCK_SIZE = 32768;
048
049    /** Buffer to write decompressed bytes to for back-references */
050    private final byte[] decompressBuf;
051
052    /** One behind the index of the last byte in the buffer that was written */
053    private int writeIndex;
054
055    /** Index of the next byte to be read. */
056    private int readIndex;
057
058    /** The actual block size specified */
059    private final int blockSize;
060
061    /** The underlying stream to read compressed data from */
062    private final InputStream in;
063
064    /** The size of the uncompressed data */
065    private final int size;
066
067    /** Number of uncompressed bytes still to be read. */
068    private int uncompressedBytesRemaining;
069
070    // used in no-arg read method
071    private final byte[] oneByte = new byte[1];
072
073    private boolean endReached = false;
074
075    /**
076     * Constructor using the default buffer size of 32k.
077     * 
078     * @param is
079     *            An InputStream to read compressed data from
080     * 
081     * @throws IOException if reading fails
082     */
083    public SnappyCompressorInputStream(final InputStream is) throws IOException {
084        this(is, DEFAULT_BLOCK_SIZE);
085    }
086
087    /**
088     * Constructor using a configurable buffer size.
089     * 
090     * @param is
091     *            An InputStream to read compressed data from
092     * @param blockSize
093     *            The block size used in compression
094     * 
095     * @throws IOException if reading fails
096     */
097    public SnappyCompressorInputStream(final InputStream is, final int blockSize)
098            throws IOException {
099        this.in = is;
100        this.blockSize = blockSize;
101        this.decompressBuf = new byte[blockSize * 3];
102        this.writeIndex = readIndex = 0;
103        uncompressedBytesRemaining = size = (int) readSize();
104    }
105
106    /** {@inheritDoc} */
107    @Override
108    public int read() throws IOException {
109        return read(oneByte, 0, 1) == -1 ? -1 : oneByte[0] & 0xFF;
110    }
111
112    /** {@inheritDoc} */
113    @Override
114    public void close() throws IOException {
115        in.close();
116    }
117
118    /** {@inheritDoc} */
119    @Override
120    public int available() {
121        return writeIndex - readIndex;
122    }
123
124    /**
125     * {@inheritDoc}
126     */
127    @Override
128    public int read(final byte[] b, final int off, final int len) throws IOException {
129        if (endReached) {
130            return -1;
131        }
132        final int avail = available();
133        if (len > avail) {
134            fill(len - avail);
135        }
136
137        final int readable = Math.min(len, available());
138        if (readable == 0 && len > 0) {
139            return -1;
140        }
141        System.arraycopy(decompressBuf, readIndex, b, off, readable);
142        readIndex += readable;
143        if (readIndex > blockSize) {
144            slideBuffer();
145        }
146        return readable;
147    }
148
149    /**
150     * Try to fill the buffer with enough bytes to satisfy the current
151     * read request.
152     *
153     * @param len the number of uncompressed bytes to read
154     */
155    private void fill(final int len) throws IOException {
156        if (uncompressedBytesRemaining == 0) {
157            endReached = true;
158        }
159        int readNow = Math.min(len, uncompressedBytesRemaining);
160
161        while (readNow > 0) {
162            final int b = readOneByte();
163            int length = 0;
164            long offset = 0;
165
166            switch (b & TAG_MASK) {
167
168            case 0x00:
169
170                length = readLiteralLength(b);
171
172                if (expandLiteral(length)) {
173                    return;
174                }
175                break;
176
177            case 0x01:
178
179                /*
180                 * These elements can encode lengths between [4..11] bytes and
181                 * offsets between [0..2047] bytes. (len-4) occupies three bits
182                 * and is stored in bits [2..4] of the tag byte. The offset
183                 * occupies 11 bits, of which the upper three are stored in the
184                 * upper three bits ([5..7]) of the tag byte, and the lower
185                 * eight are stored in a byte following the tag byte.
186                 */
187
188                length = 4 + ((b >> 2) & 0x07);
189                offset = (b & 0xE0) << 3;
190                offset |= readOneByte();
191
192                if (expandCopy(offset, length)) {
193                    return;
194                }
195                break;
196
197            case 0x02:
198
199                /*
200                 * These elements can encode lengths between [1..64] and offsets
201                 * from [0..65535]. (len-1) occupies six bits and is stored in
202                 * the upper six bits ([2..7]) of the tag byte. The offset is
203                 * stored as a little-endian 16-bit integer in the two bytes
204                 * following the tag byte.
205                 */
206
207                length = (b >> 2) + 1;
208
209                offset = readOneByte();
210                offset |= readOneByte() << 8;
211
212                if (expandCopy(offset, length)) {
213                    return;
214                }
215                break;
216
217            case 0x03:
218
219                /*
220                 * These are like the copies with 2-byte offsets (see previous
221                 * subsection), except that the offset is stored as a 32-bit
222                 * integer instead of a 16-bit integer (and thus will occupy
223                 * four bytes).
224                 */
225
226                length = (b >> 2) + 1;
227
228                offset = readOneByte();
229                offset |= readOneByte() << 8;
230                offset |= readOneByte() << 16;
231                offset |= ((long) readOneByte()) << 24;
232
233                if (expandCopy(offset, length)) {
234                    return;
235                }
236                break;
237            }
238
239            readNow -= length;
240            uncompressedBytesRemaining -= length;
241        }
242    }
243
244    /**
245     * Slide buffer.
246     *
247     * <p>Move all bytes of the buffer after the first block down to
248     * the beginning of the buffer.</p>
249     */
250    private void slideBuffer() {
251        System.arraycopy(decompressBuf, blockSize, decompressBuf, 0,
252                         blockSize * 2);
253        writeIndex -= blockSize;
254        readIndex -= blockSize;
255    }
256
257
258    /*
259     * For literals up to and including 60 bytes in length, the
260     * upper six bits of the tag byte contain (len-1). The literal
261     * follows immediately thereafter in the bytestream. - For
262     * longer literals, the (len-1) value is stored after the tag
263     * byte, little-endian. The upper six bits of the tag byte
264     * describe how many bytes are used for the length; 60, 61, 62
265     * or 63 for 1-4 bytes, respectively. The literal itself follows
266     * after the length.
267     */
268    private int readLiteralLength(final int b) throws IOException {
269        int length;
270        switch (b >> 2) {
271        case 60:
272            length = readOneByte();
273            break;
274        case 61:
275            length = readOneByte();
276            length |= readOneByte() << 8;
277            break;
278        case 62:
279            length = readOneByte();
280            length |= readOneByte() << 8;
281            length |= readOneByte() << 16;
282            break;
283        case 63:
284            length = readOneByte();
285            length |= readOneByte() << 8;
286            length |= readOneByte() << 16;
287            length |= (((long) readOneByte()) << 24);
288            break;
289        default:
290            length = b >> 2;
291            break;
292        }
293
294        return length + 1;
295    }
296
297    /**
298     * Literals are uncompressed data stored directly in the byte stream.
299     * 
300     * @param length
301     *            The number of bytes to read from the underlying stream
302     * 
303     * @throws IOException
304     *             If the first byte cannot be read for any reason other than
305     *             end of file, or if the input stream has been closed, or if
306     *             some other I/O error occurs.
307     * @return True if the decompressed data should be flushed
308     */
309    private boolean expandLiteral(final int length) throws IOException {
310        final int bytesRead = IOUtils.readFully(in, decompressBuf, writeIndex, length);
311        count(bytesRead);
312        if (length != bytesRead) {
313            throw new IOException("Premature end of stream");
314        }
315
316        writeIndex += length;
317        return writeIndex >= 2 * this.blockSize;
318    }
319
320    /**
321     * Copies are references back into previous decompressed data, telling the
322     * decompressor to reuse data it has previously decoded. They encode two
323     * values: The offset, saying how many bytes back from the current position
324     * to read, and the length, how many bytes to copy. Offsets of zero can be
325     * encoded, but are not legal; similarly, it is possible to encode
326     * backreferences that would go past the end of the block (offset > current
327     * decompressed position), which is also nonsensical and thus not allowed.
328     * 
329     * @param off
330     *            The offset from the backward from the end of expanded stream
331     * @param length
332     *            The number of bytes to copy
333     * 
334     * @throws IOException
335     *             An the offset expands past the front of the decompression
336     *             buffer
337     * @return True if the decompressed data should be flushed
338     */
339    private boolean expandCopy(final long off, final int length) throws IOException {
340        if (off > blockSize) {
341            throw new IOException("Offset is larger than block size");
342        }
343        final int offset = (int) off;
344
345        if (offset == 1) {
346            final byte lastChar = decompressBuf[writeIndex - 1];
347            for (int i = 0; i < length; i++) {
348                decompressBuf[writeIndex++] = lastChar;
349            }
350        } else if (length < offset) {
351            System.arraycopy(decompressBuf, writeIndex - offset,
352                    decompressBuf, writeIndex, length);
353            writeIndex += length;
354        } else {
355            int fullRotations = length / offset;
356            final int pad = length - (offset * fullRotations);
357
358            while (fullRotations-- != 0) {
359                System.arraycopy(decompressBuf, writeIndex - offset,
360                        decompressBuf, writeIndex, offset);
361                writeIndex += offset;
362            }
363
364            if (pad > 0) {
365                System.arraycopy(decompressBuf, writeIndex - offset,
366                        decompressBuf, writeIndex, pad);
367
368                writeIndex += pad;
369            }
370        }
371        return writeIndex >= 2 * this.blockSize;
372    }
373
374    /**
375     * This helper method reads the next byte of data from the input stream. The
376     * value byte is returned as an <code>int</code> in the range <code>0</code>
377     * to <code>255</code>. If no byte is available because the end of the
378     * stream has been reached, an Exception is thrown.
379     * 
380     * @return The next byte of data
381     * @throws IOException
382     *             EOF is reached or error reading the stream
383     */
384    private int readOneByte() throws IOException {
385        final int b = in.read();
386        if (b == -1) {
387            throw new IOException("Premature end of stream");
388        }
389        count(1);
390        return b & 0xFF;
391    }
392
393    /**
394     * The stream starts with the uncompressed length (up to a maximum of 2^32 -
395     * 1), stored as a little-endian varint. Varints consist of a series of
396     * bytes, where the lower 7 bits are data and the upper bit is set iff there
397     * are more bytes to be read. In other words, an uncompressed length of 64
398     * would be stored as 0x40, and an uncompressed length of 2097150 (0x1FFFFE)
399     * would be stored as 0xFE 0xFF 0x7F.
400     * 
401     * @return The size of the uncompressed data
402     * 
403     * @throws IOException
404     *             Could not read a byte
405     */
406    private long readSize() throws IOException {
407        int index = 0;
408        long sz = 0;
409        int b = 0;
410
411        do {
412            b = readOneByte();
413            sz |= (b & 0x7f) << (index++ * 7);
414        } while (0 != (b & 0x80));
415        return sz;
416    }
417
418    /**
419     * Get the uncompressed size of the stream
420     * 
421     * @return the uncompressed size
422     */
423    public int getSize() {
424        return size;
425    }
426
427}