/** * Copyright 2014 BlackBerry, Limited. * * Licensed 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 com.blackberry.bdp.krackle.compression; import java.io.IOException; import org.xerial.snappy.Snappy; import com.blackberry.bdp.krackle.Constants; /** * Decompressor implementation that used the Snappy algorithm. */ public class SnappyDecompressor implements Decompressor { private static final byte[] MAGIC_NUMBER = new byte[]{ // -126, 'S', 'N', 'A', 'P', 'P', 'Y', 0}; private byte[] src; private int pos; private int blockLength; private int decompressedLength; private int uncompressedBlockLength; @Override public byte getAttribute() { return Constants.SNAPPY; } @Override public int decompress(byte[] src, int srcPos, int length, byte[] dest, int destPos, int maxLength) throws IOException { this.src = src; decompressedLength = 0; // Check for magic number if (src[srcPos] == MAGIC_NUMBER[0] // || src[srcPos + 1] == MAGIC_NUMBER[1] // || src[srcPos + 2] == MAGIC_NUMBER[2] // || src[srcPos + 3] == MAGIC_NUMBER[3] // || src[srcPos + 4] == MAGIC_NUMBER[4] // || src[srcPos + 5] == MAGIC_NUMBER[5] // || src[srcPos + 6] == MAGIC_NUMBER[6] // || src[srcPos + 7] == MAGIC_NUMBER[7]) { // advance past the magic number // assume the version (4 bytes), min compatable version (4 bytes) are fine pos = srcPos + 8 + 8; // TODO: limit the decompressed length while (pos < srcPos + length) { blockLength = readInt(); // Check to see if this will exceed maxLength uncompressedBlockLength = Snappy.uncompressedLength(src, pos, blockLength); if (decompressedLength + uncompressedBlockLength > maxLength) { return -1; } decompressedLength += Snappy.uncompress(src, pos, blockLength, dest, destPos + decompressedLength); pos += blockLength; } return decompressedLength; } else { // Assume it's just straight compressed return Snappy.uncompress(src, pos, blockLength, dest, destPos); } } private int readInt() { pos += 4; return src[pos - 4] & 0xFF << 24 // | (src[pos - 3] & 0xFF) << 16 // | (src[pos - 2] & 0xFF) << 8 // | (src[pos - 1] & 0xFF); } }