de.jarnbjo.jsnappy.SnappyDecompressor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bytecompressor-jsnappy_2.9 Show documentation
Show all versions of bytecompressor-jsnappy_2.9 Show documentation
Java impmenentation of compression algorithm Snappy from Google. This is a Avast a.s. fork of
http://code.google.com/p/jsnappy/ , it adds bytecompressor layer compatibility.
The newest version!
/*
* Copyright 2011 Tor-Einar Jarnbjo
*
* 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 de.jarnbjo.jsnappy;
import java.util.Arrays;
/**
* This class provide utility methods for decompressing
* data blocks using the Snappy algorithm.
*
* @author Tor-Einar Jarnbjo
* @since 1.0
*/
public class SnappyDecompressor {
private SnappyDecompressor() {
}
/**
* Equivalent to decompress(in, 0, in.length, null)
.
* @param in compressed data block
* @return decompressed data block
*/
public static Buffer decompress(byte[] in) {
return decompress(in, 0, in.length, null);
}
/**
* Equivalent to decompress(in, 0, in.length, out)
.
* @param in compressed data block
* @param out Buffer for decompressed data block
* @return reference to out
*/
public static Buffer decompress(byte[] in, Buffer out) {
return decompress(in, 0, in.length, out);
}
/**
* Equivalent to decompress(in, offset, length, null)
.
* @param in byte array containing the compressed data block
* @param offset offset in in, on which decoding is started
* @param length length of compressed data block
* @return decompressed data block
*/
public static Buffer decompress(byte[] in, int offset, int length) {
return decompress(in, offset, length, null);
}
/**
* Equivalent to decompress(in.getData(), 0, in.getLength(), null)
.
* @param in compressed data block
* @return decompressed data block
*/
public static Buffer decompress(Buffer in) {
return decompress(in.getData(), 0, in.getLength());
}
/**
* Equivalent to decompress(in.getData(), 0, in.getLength(), out)
.
* @param in compressed data block
* @param out Buffer for decompressed data block
* @return reference to out
*/
public static Buffer decompress(Buffer in, Buffer out) {
return decompress(in.getData(), 0, in.getLength(), out);
}
/**
* Decompress the data contained in in
from offset
* and length
bytes. If an output buffer is provided, the buffer
* is reused for the decompressed data. If the buffer is too small, its capacity
* is expanded to fit the result. If a null
argument is passed,
* a new buffer is allocated.
* @param in
* @param offset
* @param length
* @param out
* @throws FormatViolationException if the input data is invalid
* @return
*/
public static Buffer decompress(byte[] in, int offset, int length, Buffer out) throws FormatViolationException {
int i=0, l, o, c;
int sourceIndex = offset, targetIndex = 0;
int targetLength = 0;
i = 0;
do {
targetLength += (in[sourceIndex] & 0x7f) << (i++ * 7);
} while ((in[sourceIndex++] & 0x80) == 0x80);
if (out == null) {
out = new Buffer(targetLength);
}
else {
out.ensureCapacity(targetLength);
}
out.setLength(targetLength);
byte[] outBuffer = out.getData();
while(sourceIndex < offset + length) {
if(targetIndex >= targetLength) {
throw new FormatViolationException("Superfluous input data encountered on offset " + sourceIndex, sourceIndex);
}
switch(in[sourceIndex] & 3) {
case 0:
l = (in[sourceIndex++] >> 2) & 0x3f;
switch(l) {
case 60:
l = in[sourceIndex++] & 0xff;
l++;
break;
case 61:
l = in[sourceIndex++] & 0xff;
l |= (in[sourceIndex++] & 0xff) << 8;
l++;
break;
case 62:
l = in[sourceIndex++] & 0xff;
l |= (in[sourceIndex++] & 0xff) << 8;
l |= (in[sourceIndex++] & 0xff) << 16;
l++;
break;
case 63:
l = in[sourceIndex++] & 0xff;
l |= (in[sourceIndex++] & 0xff) << 8;
l |= (in[sourceIndex++] & 0xff) << 16;
l |= (in[sourceIndex++] & 0xff) << 24;
l++;
break;
default:
l++;
break;
}
System.arraycopy(in, sourceIndex, outBuffer, targetIndex, l);
sourceIndex += l;
targetIndex += l;
break;
case 1:
l = 4 + ((in[sourceIndex] >> 2) & 7);
o = (in[sourceIndex++] & 0xe0) << 3;
o |= in[sourceIndex++] & 0xff;
if(l < o) {
System.arraycopy(outBuffer, targetIndex - o, outBuffer, targetIndex, l);
targetIndex += l;
}
else {
if(o == 1) {
Arrays.fill(outBuffer, targetIndex, targetIndex + l, outBuffer[targetIndex-1]);
targetIndex += l;
}
else {
while(l > 0) {
c = l > o ? o : l;
System.arraycopy(outBuffer, targetIndex - o, outBuffer, targetIndex, c);
targetIndex += c;
l -= c;
}
}
}
break;
case 2:
l = ((in[sourceIndex++] >> 2) & 0x3f) + 1;
o = in[sourceIndex++] & 0xff;
o |= (in[sourceIndex++] & 0xff) << 8;
if(l < o) {
System.arraycopy(outBuffer, targetIndex - o, outBuffer, targetIndex, l);
targetIndex += l;
}
else {
while(l > 0) {
c = l > o ? o : l;
System.arraycopy(outBuffer, targetIndex - o, outBuffer, targetIndex, c);
targetIndex += c;
l -= c;
}
}
break;
case 3:
l = ((in[sourceIndex++] >> 2) & 0x3f) + 1;
o = in[sourceIndex++] & 0xff;
o |= (in[sourceIndex++] & 0xff) << 8;
o |= (in[sourceIndex++] & 0xff) << 16;
o |= (in[sourceIndex++] & 0xff) << 24;
if(l < o) {
System.arraycopy(outBuffer, targetIndex - o, outBuffer, targetIndex, l);
targetIndex += l;
}
else {
if(o == 1) {
Arrays.fill(outBuffer, targetIndex, targetIndex + l, outBuffer[targetIndex-1]);
targetIndex += l;
}
else {
while(l > 0) {
c = l > o ? o : l;
System.arraycopy(outBuffer, targetIndex - o, outBuffer, targetIndex, c);
targetIndex += c;
l -= c;
}
}
}
break;
}
}
return out;
}
}