mirror of
https://github.com/xerial/snappy-java.git
synced 2025-07-23 05:54:41 +02:00
Fixes issue 4
This commit is contained in:
parent
4935319db1
commit
41debf9cb6
@ -45,12 +45,12 @@ import java.util.Properties;
|
||||
*/
|
||||
public class LoadSnappy
|
||||
{
|
||||
private static boolean extracted = false;
|
||||
private static boolean isLoaded = false;
|
||||
|
||||
public static boolean initialize() {
|
||||
if (!extracted)
|
||||
public static boolean load() {
|
||||
if (!isLoaded)
|
||||
loadSnappyNativeLibrary();
|
||||
return extracted;
|
||||
return isLoaded;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -164,7 +164,7 @@ public class LoadSnappy
|
||||
}
|
||||
|
||||
private static void loadSnappyNativeLibrary() {
|
||||
if (extracted)
|
||||
if (isLoaded)
|
||||
return;
|
||||
|
||||
// Try loading library from org.sqlite.lib.path library path */
|
||||
@ -177,7 +177,7 @@ public class LoadSnappy
|
||||
|
||||
if (snappyNativeLibraryPath != null) {
|
||||
if (loadNativeLibrary(snappyNativeLibraryPath, snappyNativeLibraryName)) {
|
||||
extracted = true;
|
||||
isLoaded = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -194,11 +194,11 @@ public class LoadSnappy
|
||||
String tempFolder = new File(System.getProperty("java.io.tmpdir")).getAbsolutePath();
|
||||
// Try extracting the library from jar
|
||||
if (extractAndLoadLibraryFile(snappyNativeLibraryPath, snappyNativeLibraryName, tempFolder)) {
|
||||
extracted = true;
|
||||
isLoaded = true;
|
||||
return;
|
||||
}
|
||||
|
||||
extracted = false;
|
||||
isLoaded = false;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,7 @@ package org.xerial.snappy;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Snappy API
|
||||
* Snappy API for data compression/decompression
|
||||
*
|
||||
* @author leo
|
||||
*
|
||||
@ -35,6 +35,11 @@ import java.nio.ByteBuffer;
|
||||
public class Snappy
|
||||
{
|
||||
|
||||
/**
|
||||
* Get the native library version of the snappy
|
||||
*
|
||||
* @return native library version
|
||||
*/
|
||||
public static String getNativeLibraryVersion() {
|
||||
return SnappyNative.nativeLibraryVersion();
|
||||
}
|
||||
@ -53,7 +58,7 @@ public class Snappy
|
||||
* @throws SnappyError
|
||||
* when the input is not a direct buffer
|
||||
*/
|
||||
public static int compress(ByteBuffer uncompressed, ByteBuffer compressed) {
|
||||
public static int compress(ByteBuffer uncompressed, ByteBuffer compressed) throws SnappyException {
|
||||
|
||||
if (!uncompressed.isDirect())
|
||||
throw new SnappyError(SnappyErrorCode.NOT_A_DIRECT_BUFFER, "input is not a direct buffer");
|
||||
@ -73,9 +78,37 @@ public class Snappy
|
||||
return compressedSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compress the input buffer content in [inputOffset,
|
||||
* ...inputOffset+inputLength) then output to the specified output buffer.
|
||||
*
|
||||
* @param input
|
||||
* @param inputOffset
|
||||
* @param inputLength
|
||||
* @param output
|
||||
* @param outputOffset
|
||||
* @return byte size of the compressed data
|
||||
* @throws SnappyException
|
||||
* when failed to access the input/output buffer
|
||||
*/
|
||||
public static int compress(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset)
|
||||
throws SnappyException {
|
||||
if (input == null || output == null)
|
||||
throw new NullPointerException("input or output is null");
|
||||
|
||||
int compressedSize = SnappyNative.rawCompress(input, inputOffset, inputLength, output, outputOffset);
|
||||
return compressedSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uncompress the content in the input buffer. The result is dumped to the
|
||||
* specified output buffer
|
||||
* specified output buffer.
|
||||
*
|
||||
* Note that if you pass the wrong data or the range [pos(), limit()) that
|
||||
* cannot be uncompressed, your JVM might crash due to the access violation
|
||||
* exception issued in the native code written in C++. To avoid this type of
|
||||
* crash, use {@link #isValidCompressedBuffer(ByteBuffer)} first.
|
||||
*
|
||||
*
|
||||
* @param compressed
|
||||
* buffer[pos() ... limit()) containing the input data
|
||||
@ -107,6 +140,32 @@ public class Snappy
|
||||
return decompressedSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uncompress the content in the input buffer. The uncompressed data is
|
||||
* written to the output buffer.
|
||||
*
|
||||
* Note that if you pass the wrong data or the range [inputOffset,
|
||||
* inputOffset + inputLength) that cannot be uncompressed, your JVM might
|
||||
* crash due to the access violation exception issued in the native code
|
||||
* written in C++. To avoid this type of crash, use
|
||||
* {@link #isValidCompressedBuffer(byte[], int, int)} first.
|
||||
*
|
||||
* @param input
|
||||
* @param inputOffset
|
||||
* @param inputLength
|
||||
* @param output
|
||||
* @param outputOffset
|
||||
* @return
|
||||
* @throws SnappyException
|
||||
*/
|
||||
public static int uncompress(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset)
|
||||
throws SnappyException {
|
||||
if (input == null || output == null)
|
||||
throw new NullPointerException("input or output is null");
|
||||
|
||||
return SnappyNative.rawUncompress(input, inputOffset, inputLength, output, outputOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the uncompressed byte size of the given compressed input.
|
||||
*
|
||||
@ -125,6 +184,21 @@ public class Snappy
|
||||
return SnappyNative.uncompressedLength(compressed, compressed.position(), compressed.remaining());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the uncompressed byte size of the given compressed input
|
||||
*
|
||||
* @param input
|
||||
* @param offset
|
||||
* @param length
|
||||
* @return umcompressed byte size of the the given input data
|
||||
* @throws SnappyException
|
||||
*/
|
||||
public static int uncompressedLength(byte[] input, int offset, int length) throws SnappyException {
|
||||
if (input == null)
|
||||
throw new NullPointerException("input is null");
|
||||
return SnappyNative.uncompressedLength(input, offset, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maximum byte size needed for compressing a data of the given byte
|
||||
* size.
|
||||
@ -140,11 +214,23 @@ public class Snappy
|
||||
/**
|
||||
* Returns true iff the contents of compressed buffer [pos() ... limit())
|
||||
* can be uncompressed successfully. Does not return the uncompressed data.
|
||||
* Takes time proportional to compressed_length, but is usually at least a
|
||||
* Takes time proportional to the input length, but is usually at least a
|
||||
* factor of four faster than actual decompression.
|
||||
*/
|
||||
public static boolean isValidCompressedBuffer(ByteBuffer compressed) {
|
||||
public static boolean isValidCompressedBuffer(ByteBuffer compressed) throws SnappyException {
|
||||
return SnappyNative.isValidCompressedBuffer(compressed, compressed.position(), compressed.remaining());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true iff the contents of compressed buffer [offset,
|
||||
* offset+length) can be uncompressed successfully. Does not return the
|
||||
* uncompressed data. Takes time proportional to the input length, but is
|
||||
* usually at least a factor of four faster than actual decompression.
|
||||
*/
|
||||
public static boolean isValidCompressedBuffer(byte[] input, int offset, int length) throws SnappyException {
|
||||
if (input == null)
|
||||
throw new NullPointerException("input is null");
|
||||
return SnappyNative.isValidCompressedBuffer(input, offset, length);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -42,11 +42,15 @@ JNIEXPORT jstring JNICALL Java_org_xerial_snappy_SnappyNative_nativeLibraryVersi
|
||||
JNIEXPORT jint JNICALL Java_org_xerial_snappy_SnappyNative_rawCompress__Ljava_nio_ByteBuffer_2IILjava_nio_ByteBuffer_2I
|
||||
(JNIEnv* env, jclass self, jobject uncompressed, jint upos, jint ulen, jobject compressed, jint cpos)
|
||||
{
|
||||
char* uncompressedBuffer = (char*) env->GetDirectBufferAddress(uncompressed) + upos;
|
||||
char* compressedBuffer = (char*) env->GetDirectBufferAddress(compressed) + cpos;
|
||||
size_t compressedLength;
|
||||
char* uncompressedBuffer = (char*) env->GetDirectBufferAddress(uncompressed);
|
||||
char* compressedBuffer = (char*) env->GetDirectBufferAddress(compressed);
|
||||
if(uncompressedBuffer == 0 || compressedBuffer == 0) {
|
||||
throw_exception(env, self, 3);
|
||||
return (jint) 0;
|
||||
}
|
||||
|
||||
snappy::RawCompress(uncompressedBuffer, (size_t) ulen, compressedBuffer, &compressedLength);
|
||||
size_t compressedLength;
|
||||
snappy::RawCompress(uncompressedBuffer + upos, (size_t) ulen, compressedBuffer + cpos, &compressedLength);
|
||||
return (jint) compressedLength;
|
||||
}
|
||||
|
||||
@ -85,12 +89,16 @@ JNIEXPORT jint JNICALL Java_org_xerial_snappy_SnappyNative_rawCompress___3BII_3B
|
||||
JNIEXPORT jint JNICALL Java_org_xerial_snappy_SnappyNative_rawUncompress__Ljava_nio_ByteBuffer_2IILjava_nio_ByteBuffer_2I
|
||||
(JNIEnv * env, jclass self, jobject compressed, jint cpos, jint clen, jobject decompressed, jint dpos)
|
||||
{
|
||||
char* compressedBuffer = (char*) env->GetDirectBufferAddress(compressed) + cpos;
|
||||
char* decompressedBuffer = (char*) env->GetDirectBufferAddress(decompressed) + dpos;
|
||||
char* compressedBuffer = (char*) env->GetDirectBufferAddress(compressed);
|
||||
char* decompressedBuffer = (char*) env->GetDirectBufferAddress(decompressed);
|
||||
if(compressedBuffer == 0 || decompressedBuffer == 0) {
|
||||
throw_exception(env, self, 3);
|
||||
return (jint) 0;
|
||||
}
|
||||
|
||||
size_t decompressedLength;
|
||||
snappy::GetUncompressedLength(compressedBuffer, (size_t) clen, &decompressedLength);
|
||||
bool ret = snappy::RawUncompress(compressedBuffer, (size_t) clen, decompressedBuffer);
|
||||
snappy::GetUncompressedLength(compressedBuffer + cpos, (size_t) clen, &decompressedLength);
|
||||
bool ret = snappy::RawUncompress(compressedBuffer + cpos, (size_t) clen, decompressedBuffer + dpos);
|
||||
if(!ret) {
|
||||
throw_exception(env, self, 2);
|
||||
return 0;
|
||||
@ -147,9 +155,14 @@ JNIEXPORT jint JNICALL Java_org_xerial_snappy_SnappyNative_maxCompressedLength
|
||||
JNIEXPORT jint JNICALL Java_org_xerial_snappy_SnappyNative_uncompressedLength__Ljava_nio_ByteBuffer_2II
|
||||
(JNIEnv * env, jclass self, jobject compressed, jint cpos, jint clen)
|
||||
{
|
||||
char* compressedBuffer = (char*) env->GetDirectBufferAddress(compressed) + cpos;
|
||||
char* compressedBuffer = (char*) env->GetDirectBufferAddress(compressed);
|
||||
if(compressedBuffer == 0) {
|
||||
throw_exception(env, self, 3);
|
||||
return (jint) 0;
|
||||
}
|
||||
|
||||
size_t result;
|
||||
bool ret = snappy::GetUncompressedLength(compressedBuffer, (size_t) clen, &result);
|
||||
bool ret = snappy::GetUncompressedLength(compressedBuffer + cpos, (size_t) clen, &result);
|
||||
if(!ret) {
|
||||
throw_exception(env, self, 2);
|
||||
return 0;
|
||||
@ -177,8 +190,12 @@ JNIEXPORT jint JNICALL Java_org_xerial_snappy_SnappyNative_uncompressedLength___
|
||||
JNIEXPORT jboolean JNICALL Java_org_xerial_snappy_SnappyNative_isValidCompressedBuffer__Ljava_nio_ByteBuffer_2II
|
||||
(JNIEnv * env, jclass self, jobject compressed, jint cpos, jint clen)
|
||||
{
|
||||
char* compressedBuffer = (char*) env->GetDirectBufferAddress(compressed) + cpos;
|
||||
bool ret = snappy::IsValidCompressedBuffer(compressedBuffer, (size_t) clen);
|
||||
char* compressedBuffer = (char*) env->GetDirectBufferAddress(compressed);
|
||||
if(compressedBuffer == 0) {
|
||||
throw_exception(env, self, 3);
|
||||
return (jint) 0;
|
||||
}
|
||||
bool ret = snappy::IsValidCompressedBuffer(compressedBuffer + cpos, (size_t) clen);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@ import java.nio.ByteBuffer;
|
||||
public class SnappyNative
|
||||
{
|
||||
static {
|
||||
LoadSnappy.initialize();
|
||||
LoadSnappy.load();
|
||||
}
|
||||
|
||||
public native static String nativeLibraryVersion();
|
||||
@ -44,7 +44,7 @@ public class SnappyNative
|
||||
// Generic compression/decompression routines.
|
||||
// ------------------------------------------------------------------------
|
||||
public native static int rawCompress(ByteBuffer input, int inputOffset, int inputLength, ByteBuffer compressed,
|
||||
int outputOffset);
|
||||
int outputOffset) throws SnappyException;
|
||||
|
||||
public native static int rawCompress(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset)
|
||||
throws SnappyException;
|
||||
@ -64,9 +64,10 @@ public class SnappyNative
|
||||
|
||||
public native static int uncompressedLength(byte[] input, int offset, int len) throws SnappyException;
|
||||
|
||||
public native static boolean isValidCompressedBuffer(ByteBuffer compressed, int offset, int len);
|
||||
public native static boolean isValidCompressedBuffer(ByteBuffer compressed, int offset, int len)
|
||||
throws SnappyException;
|
||||
|
||||
public native static boolean isValidCompressedBuffer(byte[] input, int offset, int len);
|
||||
public native static boolean isValidCompressedBuffer(byte[] input, int offset, int len) throws SnappyException;
|
||||
|
||||
public static void throw_error(int errorCode) throws SnappyException {
|
||||
throw new SnappyException(errorCode);
|
||||
|
Binary file not shown.
@ -39,7 +39,7 @@ public class SnappyTest
|
||||
@Test
|
||||
public void getVersion() throws Exception {
|
||||
String version = Snappy.getNativeLibraryVersion();
|
||||
_logger.info("version: " + version);
|
||||
_logger.debug("version: " + version);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -62,7 +62,7 @@ public class SnappyTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void load() throws Exception {
|
||||
public void directBuffer() throws Exception {
|
||||
|
||||
StringBuilder s = new StringBuilder();
|
||||
for (int i = 0; i < 20; ++i) {
|
||||
@ -74,13 +74,13 @@ public class SnappyTest
|
||||
ByteBuffer src = ByteBuffer.allocateDirect(orig.length);
|
||||
src.put(orig);
|
||||
src.flip();
|
||||
_logger.info("input size: " + src.remaining());
|
||||
_logger.debug("input size: " + src.remaining());
|
||||
int maxCompressedLen = Snappy.maxCompressedLength(src.remaining());
|
||||
_logger.info("max compressed length:" + maxCompressedLen);
|
||||
_logger.debug("max compressed length:" + maxCompressedLen);
|
||||
|
||||
ByteBuffer compressed = ByteBuffer.allocateDirect(maxCompressedLen);
|
||||
int compressedSize = Snappy.compress(src, compressed);
|
||||
_logger.info("compressed length: " + compressedSize);
|
||||
_logger.debug("compressed length: " + compressedSize);
|
||||
|
||||
assertTrue(Snappy.isValidCompressedBuffer(compressed));
|
||||
|
||||
@ -93,7 +93,7 @@ public class SnappyTest
|
||||
assertEquals(compressedSize, compressed.remaining());
|
||||
|
||||
int uncompressedLen = Snappy.uncompressedLength(compressed);
|
||||
_logger.info("uncompressed length: " + uncompressedLen);
|
||||
_logger.debug("uncompressed length: " + uncompressedLen);
|
||||
ByteBuffer extract = ByteBuffer.allocateDirect(uncompressedLen);
|
||||
int uncompressedLen2 = Snappy.uncompress(compressed, extract);
|
||||
assertEquals(uncompressedLen, uncompressedLen2);
|
||||
@ -102,13 +102,13 @@ public class SnappyTest
|
||||
byte[] b = new byte[uncompressedLen];
|
||||
extract.get(b);
|
||||
String decompressed = new String(b);
|
||||
_logger.info(decompressed);
|
||||
_logger.debug(decompressed);
|
||||
|
||||
assertEquals(origStr, decompressed);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void intermediateBuffer() throws Exception {
|
||||
public void bufferOffset() throws Exception {
|
||||
|
||||
String m = "ACCAGGGGGGGGGGGGGGGGGGGGATAGATATTTCCCGAGATATTTTATATAAAAAAA";
|
||||
byte[] orig = m.getBytes();
|
||||
@ -146,19 +146,49 @@ public class SnappyTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rawCompress() throws Exception {
|
||||
public void byteArrayCompress() throws Exception {
|
||||
|
||||
String m = "ACCAGGGGGGGGGGGGGGGGGGGGATAGATATTTCCCGAGATATTTTATATAAAAAAA";
|
||||
byte[] input = m.getBytes();
|
||||
byte[] output = new byte[Snappy.maxCompressedLength(input.length)];
|
||||
int compressedSize = SnappyNative.rawCompress(input, 0, input.length, output, 0);
|
||||
int compressedSize = Snappy.compress(input, 0, input.length, output, 0);
|
||||
byte[] uncompressed = new byte[input.length];
|
||||
|
||||
assertTrue(SnappyNative.isValidCompressedBuffer(output, 0, compressedSize));
|
||||
int uncompressedSize = SnappyNative.rawUncompress(output, 0, compressedSize, uncompressed, 0);
|
||||
assertTrue(Snappy.isValidCompressedBuffer(output, 0, compressedSize));
|
||||
int uncompressedSize = Snappy.uncompress(output, 0, compressedSize, uncompressed, 0);
|
||||
String m2 = new String(uncompressed);
|
||||
assertEquals(m, m2);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rangeCheck() throws Exception {
|
||||
String m = "ACCAGGGGGGGGGGGGGGGGGGGGATAGATATTTCCCGAGATATTTTATATAAAAAAA";
|
||||
byte[] input = m.getBytes();
|
||||
byte[] output = new byte[Snappy.maxCompressedLength(input.length)];
|
||||
int compressedSize = Snappy.compress(input, 0, input.length, output, 0);
|
||||
|
||||
assertTrue(Snappy.isValidCompressedBuffer(output, 0, compressedSize));
|
||||
// Intentionally set an invalid range
|
||||
assertFalse(Snappy.isValidCompressedBuffer(output, 0, compressedSize + 1));
|
||||
assertFalse(Snappy.isValidCompressedBuffer(output, 1, compressedSize));
|
||||
|
||||
// Test the ByteBuffer API
|
||||
ByteBuffer bin = ByteBuffer.allocateDirect(input.length);
|
||||
bin.put(input);
|
||||
bin.flip();
|
||||
ByteBuffer bout = ByteBuffer.allocateDirect(Snappy.maxCompressedLength(bin.remaining()));
|
||||
int compressedSize2 = Snappy.compress(bin, bout);
|
||||
assertEquals(compressedSize, compressedSize2);
|
||||
|
||||
assertTrue(Snappy.isValidCompressedBuffer(bout));
|
||||
// Intentionally set an invalid range
|
||||
bout.limit(bout.limit() + 1);
|
||||
assertFalse(Snappy.isValidCompressedBuffer(bout));
|
||||
bout.limit(bout.limit() - 1);
|
||||
bout.position(1);
|
||||
assertFalse(Snappy.isValidCompressedBuffer(bout));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user