diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d7d1371 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +SOURCES/1.7.1.tar.gz +SOURCES/v1.9.2.tar.gz diff --git a/.lz4-java.metadata b/.lz4-java.metadata new file mode 100644 index 0000000..d8eb543 --- /dev/null +++ b/.lz4-java.metadata @@ -0,0 +1,2 @@ +c0935ff2f1de0eb2c1762632af9c28b409cc5ff8 SOURCES/1.7.1.tar.gz +4dc36f29d7b4e5b45b114be2674068200714abb3 SOURCES/v1.9.2.tar.gz diff --git a/SOURCES/0-remove-unsafe.patch b/SOURCES/0-remove-unsafe.patch new file mode 100644 index 0000000..416658f --- /dev/null +++ b/SOURCES/0-remove-unsafe.patch @@ -0,0 +1,797 @@ +diff --git a/.classpath b/.classpath +index 5ee3f97..058b340 100644 +--- a/.classpath ++++ b/.classpath +@@ -2,7 +2,6 @@ + + + +- + + + +diff --git a/CHANGES.md b/CHANGES.md +index c7eed89..b71dc35 100644 +--- a/CHANGES.md ++++ b/CHANGES.md +@@ -140,12 +140,6 @@ + - [#99](https://github.com/lz4/lz4-java/pull/99) + LZ4FrameInputStream allows EndMark to be incompressible. (Charles Allen) + +- - [#95](https://github.com/lz4/lz4-java/pull/95) +- Added unsafe instance support for aarch64. (Yuqi Gu) +- +- - [#93](https://github.com/lz4/lz4-java/pull/93) +- Added unsafe instance support for ppc64le. (Madhusudanan Kandasamy) +- + - [#90](https://github.com/lz4/lz4-java/issues/90) + LZ4 Java now supports 64-bit JNI build on Solaris. (cndcourt) + +@@ -207,11 +201,6 @@ + - [#39](https://github.com/jpountz/lz4-java/pull/39) + The JAR is now a valid OSGI bundle. (Simon Chemouil) + +- - [#33](https://github.com/jpountz/lz4-java/pull/33) +- The implementation based on Java's sun.misc.Unsafe relies on unaligned +- memory access and is now only used on platforms that support it. +- (Dmitry Shohov) +- + + ## 1.2.0 + +diff --git a/README.md b/README.md +index 9a34ea6..b966d9a 100644 +--- a/README.md ++++ b/README.md +@@ -24,12 +24,10 @@ decompressor instance. + + ## Implementations + +-For LZ4 compressors, LZ4 HC compressors and decompressors, 3 implementations are ++For LZ4 compressors, LZ4 HC compressors and decompressors, 2 implementations are + available: + - JNI bindings to the original C implementation by Yann Collet, + - a pure Java port of the compression and decompression algorithms, +- - a Java port that uses the sun.misc.Unsafe API in order to achieve compression +- and decompression speeds close to the C implementation. + + Have a look at LZ4Factory for more information. + +@@ -94,8 +92,7 @@ score of 10) hash function. + + ## Implementations + +-Similarly to LZ4, 3 implementations are available: JNI bindings, pure Java port +-and pure Java port that uses sun.misc.Unsafe. ++Unsimilarly to LZ4, 2 implementations are available: JNI bindings, pure Java port + + Have a look at XXHashFactory for more information. + +@@ -131,7 +128,7 @@ int hash = hash32.getValue(); + + You can download released artifacts from [Maven Central](https://search.maven.org/search?q=g:org.lz4%20a:lz4-java). + +-You can download pure-Java lz4-java from [Maven Central](https://search.maven.org/search?q=g:org.lz4%20a:lz4-pure-java). These artifacts include the Safe and Unsafe Java versions but not JNI bindings. (Experimental) ++You can download pure-Java lz4-java from [Maven Central](https://search.maven.org/search?q=g:org.lz4%20a:lz4-pure-java). These artifacts include the Safe Java versions but not JNI bindings. (Experimental) + + # Documentation + +@@ -172,10 +169,8 @@ Then run `ant`. It will: + located under `src/build`, + - compile the lz4 and xxhash libraries and their JNI (Java Native Interface) + bindings, +- - compile Java sources in `src/java` (normal sources), `src/java-unsafe` +- (sources that make use of `sun.misc.Unsafe`) and `build/java` +- (auto-generated sources) to `build/classes`, `build/unsafe-classes` and +- `build/generated-classes`, ++ - compile Java sources in `src/java` (normal sources) and `build/java` ++ (auto-generated sources) to `build/classes` and `build/generated-classes`, + - generate a JAR file called lz4-${version}.jar under the `dist` directory. + + The JAR file that is generated contains Java class files, the native library +diff --git a/build.xml b/build.xml +index 2a08ad8..1d4cff5 100644 +--- a/build.xml ++++ b/build.xml +@@ -148,16 +148,6 @@ + debug="true" + destdir="${build}/classes" + nativeHeaderDir="${build}/jni-headers"/> +- +- + + + + +- + + + +@@ -234,7 +223,6 @@ + + + +- + + + +@@ -249,7 +237,6 @@ + + + +- + + + +@@ -317,7 +304,6 @@ + + +- + + + +@@ -351,7 +337,6 @@ + destfile="${dist}/${ivy.module}.jar"> + + +- + + + +@@ -365,7 +350,6 @@ + + +- + + + +@@ -411,15 +395,12 @@ + + + +- + + + + +- + + +- + + + +diff --git a/src/build/gen_sources.mvel b/src/build/gen_sources.mvel +index 0f32671..43ebb78 100644 +--- a/src/build/gen_sources.mvel ++++ b/src/build/gen_sources.mvel +@@ -24,7 +24,7 @@ def dest_file(path) { + + def generate_decompressors() { + compiledTemplate = get_template("decompressor.template"); +- for (type : ["Safe", "Unsafe"]) { ++ for (type : ["Safe"]) { + for (size : ["Fast", "Safe"]) { + dest = dest_file("lz4/LZ4Java" + type + size + "Decompressor.java"); + args = new HashMap(); +@@ -37,7 +37,7 @@ def generate_decompressors() { + + def generate_compressors() { + compiledTemplate = get_template("compressor.template"); +- for (type : ["Safe", "Unsafe"]) { ++ for (type : ["Safe"]) { + dest = dest_file("lz4/LZ4Java" + type + "Compressor.java"); + args = new HashMap(); + args.put("type", type); +@@ -47,7 +47,7 @@ def generate_compressors() { + + def generate_hc_compressors() { + compiledTemplate = get_template("compressor_hc.template"); +- for (type : ["Safe", "Unsafe"]) { ++ for (type : ["Safe"]) { + dest = dest_file("lz4/LZ4HCJava" + type + "Compressor.java"); + args = new HashMap(); + args.put("type", type); +@@ -58,7 +58,7 @@ def generate_hc_compressors() { + def generate_xxhash() { + for (bitness : ["32", "64"]) { + compiledTemplate = get_template("xxhash" + bitness + ".template"); +- for (type : ["Safe", "Unsafe"]) { ++ for (type : ["Safe"]) { + dest = dest_file("xxhash/XXHash" + bitness + "Java" + type + ".java"); + args = new HashMap(); + args.put("type", type); +@@ -70,7 +70,7 @@ def generate_xxhash() { + def generate_streaming_xxhash() { + for (bitness : ["32", "64"]) { + compiledTemplate = get_template("xxhash" + bitness + "_streaming.template"); +- for (type : ["Safe", "Unsafe"]) { ++ for (type : ["Safe"]) { + dest = dest_file("xxhash/StreamingXXHash" + bitness + "Java" + type + ".java"); + args = new HashMap(); + args.put("type", type); +diff --git a/src/java-unsafe/net/jpountz/lz4/LZ4UnsafeUtils.java b/src/java-unsafe/net/jpountz/lz4/LZ4UnsafeUtils.java +deleted file mode 100644 +index a5ad783..0000000 +--- a/src/java-unsafe/net/jpountz/lz4/LZ4UnsafeUtils.java ++++ /dev/null +@@ -1,206 +0,0 @@ +-package net.jpountz.lz4; +- +-/* +- * 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. +- */ +- +-import static net.jpountz.lz4.LZ4Constants.COPY_LENGTH; +-import static net.jpountz.lz4.LZ4Constants.LAST_LITERALS; +-import static net.jpountz.lz4.LZ4Constants.ML_BITS; +-import static net.jpountz.lz4.LZ4Constants.ML_MASK; +-import static net.jpountz.lz4.LZ4Constants.RUN_MASK; +-import static net.jpountz.util.UnsafeUtils.readByte; +-import static net.jpountz.util.UnsafeUtils.readInt; +-import static net.jpountz.util.UnsafeUtils.readLong; +-import static net.jpountz.util.UnsafeUtils.readShort; +-import static net.jpountz.util.UnsafeUtils.writeByte; +-import static net.jpountz.util.UnsafeUtils.writeInt; +-import static net.jpountz.util.UnsafeUtils.writeLong; +-import static net.jpountz.util.UnsafeUtils.writeShort; +-import static net.jpountz.util.Utils.NATIVE_BYTE_ORDER; +- +-import java.nio.ByteOrder; +- +-enum LZ4UnsafeUtils { +- ; +- +- static void safeArraycopy(byte[] src, int srcOff, byte[] dest, int destOff, int len) { +- final int fastLen = len & 0xFFFFFFF8; +- wildArraycopy(src, srcOff, dest, destOff, fastLen); +- for (int i = 0, slowLen = len & 0x7; i < slowLen; i += 1) { +- writeByte(dest, destOff + fastLen + i, readByte(src, srcOff + fastLen + i)); +- } +- } +- +- static void wildArraycopy(byte[] src, int srcOff, byte[] dest, int destOff, int len) { +- for (int i = 0; i < len; i += 8) { +- writeLong(dest, destOff + i, readLong(src, srcOff + i)); +- } +- } +- +- static void wildIncrementalCopy(byte[] dest, int matchOff, int dOff, int matchCopyEnd) { +- if (dOff - matchOff < 4) { +- for (int i = 0; i < 4; ++i) { +- writeByte(dest, dOff+i, readByte(dest, matchOff+i)); +- } +- dOff += 4; +- matchOff += 4; +- int dec = 0; +- assert dOff >= matchOff && dOff - matchOff < 8; +- switch (dOff - matchOff) { +- case 1: +- matchOff -= 3; +- break; +- case 2: +- matchOff -= 2; +- break; +- case 3: +- matchOff -= 3; +- dec = -1; +- break; +- case 5: +- dec = 1; +- break; +- case 6: +- dec = 2; +- break; +- case 7: +- dec = 3; +- break; +- default: +- break; +- } +- writeInt(dest, dOff, readInt(dest, matchOff)); +- dOff += 4; +- matchOff -= dec; +- } else if (dOff - matchOff < COPY_LENGTH) { +- writeLong(dest, dOff, readLong(dest, matchOff)); +- dOff += dOff - matchOff; +- } +- while (dOff < matchCopyEnd) { +- writeLong(dest, dOff, readLong(dest, matchOff)); +- dOff += 8; +- matchOff += 8; +- } +- } +- +- static void safeIncrementalCopy(byte[] dest, int matchOff, int dOff, int matchLen) { +- for (int i = 0; i < matchLen; ++i) { +- dest[dOff + i] = dest[matchOff + i]; +- writeByte(dest, dOff + i, readByte(dest, matchOff + i)); +- } +- } +- +- static int readShortLittleEndian(byte[] src, int srcOff) { +- short s = readShort(src, srcOff); +- if (NATIVE_BYTE_ORDER == ByteOrder.BIG_ENDIAN) { +- s = Short.reverseBytes(s); +- } +- return s & 0xFFFF; +- } +- +- static void writeShortLittleEndian(byte[] dest, int destOff, int value) { +- short s = (short) value; +- if (NATIVE_BYTE_ORDER == ByteOrder.BIG_ENDIAN) { +- s = Short.reverseBytes(s); +- } +- writeShort(dest, destOff, s); +- } +- +- static boolean readIntEquals(byte[] src, int ref, int sOff) { +- return readInt(src, ref) == readInt(src, sOff); +- } +- +- static int commonBytes(byte[] src, int ref, int sOff, int srcLimit) { +- int matchLen = 0; +- while (sOff <= srcLimit - 8) { +- if (readLong(src, sOff) == readLong(src, ref)) { +- matchLen += 8; +- ref += 8; +- sOff += 8; +- } else { +- final int zeroBits; +- if (NATIVE_BYTE_ORDER == ByteOrder.BIG_ENDIAN) { +- zeroBits = Long.numberOfLeadingZeros(readLong(src, sOff) ^ readLong(src, ref)); +- } else { +- zeroBits = Long.numberOfTrailingZeros(readLong(src, sOff) ^ readLong(src, ref)); +- } +- return matchLen + (zeroBits >>> 3); +- } +- } +- while (sOff < srcLimit && readByte(src, ref++) == readByte(src, sOff++)) { +- ++matchLen; +- } +- return matchLen; +- } +- +- static int writeLen(int len, byte[] dest, int dOff) { +- while (len >= 0xFF) { +- writeByte(dest, dOff++, 0xFF); +- len -= 0xFF; +- } +- writeByte(dest, dOff++, len); +- return dOff; +- } +- +- static int encodeSequence(byte[] src, int anchor, int matchOff, int matchRef, int matchLen, byte[] dest, int dOff, int destEnd) { +- final int runLen = matchOff - anchor; +- final int tokenOff = dOff++; +- int token; +- +- if (runLen >= RUN_MASK) { +- token = (byte) (RUN_MASK << ML_BITS); +- dOff = writeLen(runLen - RUN_MASK, dest, dOff); +- } else { +- token = runLen << ML_BITS; +- } +- +- // copy literals +- wildArraycopy(src, anchor, dest, dOff, runLen); +- dOff += runLen; +- +- // encode offset +- final int matchDec = matchOff - matchRef; +- dest[dOff++] = (byte) matchDec; +- dest[dOff++] = (byte) (matchDec >>> 8); +- +- // encode match len +- matchLen -= 4; +- if (dOff + (1 + LAST_LITERALS) + (matchLen >>> 8) > destEnd) { +- throw new LZ4Exception("maxDestLen is too small"); +- } +- if (matchLen >= ML_MASK) { +- token |= ML_MASK; +- dOff = writeLen(matchLen - RUN_MASK, dest, dOff); +- } else { +- token |= matchLen; +- } +- +- dest[tokenOff] = (byte) token; +- +- return dOff; +- } +- +- static int commonBytesBackward(byte[] b, int o1, int o2, int l1, int l2) { +- int count = 0; +- while (o1 > l1 && o2 > l2 && readByte(b, --o1) == readByte(b, --o2)) { +- ++count; +- } +- return count; +- } +- +- static int lastLiterals(byte[] src, int sOff, int srcLen, byte[] dest, int dOff, int destEnd) { +- return LZ4SafeUtils.lastLiterals(src, sOff, srcLen, dest, dOff, destEnd); +- } +- +-} +diff --git a/src/java-unsafe/net/jpountz/util/UnsafeUtils.java b/src/java-unsafe/net/jpountz/util/UnsafeUtils.java +deleted file mode 100644 +index 30231ef..0000000 +--- a/src/java-unsafe/net/jpountz/util/UnsafeUtils.java ++++ /dev/null +@@ -1,147 +0,0 @@ +-package net.jpountz.util; +- +-/* +- * 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. +- */ +- +-import static net.jpountz.util.Utils.NATIVE_BYTE_ORDER; +- +-import java.lang.reflect.Field; +-import java.nio.ByteOrder; +- +-import sun.misc.Unsafe; +- +-public enum UnsafeUtils { +- ; +- +- private static final Unsafe UNSAFE; +- private static final long BYTE_ARRAY_OFFSET; +- private static final int BYTE_ARRAY_SCALE; +- private static final long INT_ARRAY_OFFSET; +- private static final int INT_ARRAY_SCALE; +- private static final long SHORT_ARRAY_OFFSET; +- private static final int SHORT_ARRAY_SCALE; +- +- static { +- try { +- Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); +- theUnsafe.setAccessible(true); +- UNSAFE = (Unsafe) theUnsafe.get(null); +- BYTE_ARRAY_OFFSET = UNSAFE.arrayBaseOffset(byte[].class); +- BYTE_ARRAY_SCALE = UNSAFE.arrayIndexScale(byte[].class); +- INT_ARRAY_OFFSET = UNSAFE.arrayBaseOffset(int[].class); +- INT_ARRAY_SCALE = UNSAFE.arrayIndexScale(int[].class); +- SHORT_ARRAY_OFFSET = UNSAFE.arrayBaseOffset(short[].class); +- SHORT_ARRAY_SCALE = UNSAFE.arrayIndexScale(short[].class); +- } catch (IllegalAccessException e) { +- throw new ExceptionInInitializerError("Cannot access Unsafe"); +- } catch (NoSuchFieldException e) { +- throw new ExceptionInInitializerError("Cannot access Unsafe"); +- } catch (SecurityException e) { +- throw new ExceptionInInitializerError("Cannot access Unsafe"); +- } +- } +- +- public static void checkRange(byte[] buf, int off) { +- SafeUtils.checkRange(buf, off); +- } +- +- public static void checkRange(byte[] buf, int off, int len) { +- SafeUtils.checkRange(buf, off, len); +- } +- +- public static void checkLength(int len) { +- SafeUtils.checkLength(len); +- } +- +- public static byte readByte(byte[] src, int srcOff) { +- return UNSAFE.getByte(src, BYTE_ARRAY_OFFSET + BYTE_ARRAY_SCALE * srcOff); +- } +- +- public static void writeByte(byte[] src, int srcOff, byte value) { +- UNSAFE.putByte(src, BYTE_ARRAY_OFFSET + BYTE_ARRAY_SCALE * srcOff, (byte) value); +- } +- +- public static void writeByte(byte[] src, int srcOff, int value) { +- writeByte(src, srcOff, (byte) value); +- } +- +- public static long readLong(byte[] src, int srcOff) { +- return UNSAFE.getLong(src, BYTE_ARRAY_OFFSET + srcOff); +- } +- +- public static long readLongLE(byte[] src, int srcOff) { +- long i = readLong(src, srcOff); +- if (NATIVE_BYTE_ORDER == ByteOrder.BIG_ENDIAN) { +- i = Long.reverseBytes(i); +- } +- return i; +- } +- +- public static void writeLong(byte[] dest, int destOff, long value) { +- UNSAFE.putLong(dest, BYTE_ARRAY_OFFSET + destOff, value); +- } +- +- public static int readInt(byte[] src, int srcOff) { +- return UNSAFE.getInt(src, BYTE_ARRAY_OFFSET + srcOff); +- } +- +- public static int readIntLE(byte[] src, int srcOff) { +- int i = readInt(src, srcOff); +- if (NATIVE_BYTE_ORDER == ByteOrder.BIG_ENDIAN) { +- i = Integer.reverseBytes(i); +- } +- return i; +- } +- +- public static void writeInt(byte[] dest, int destOff, int value) { +- UNSAFE.putInt(dest, BYTE_ARRAY_OFFSET + destOff, value); +- } +- +- public static short readShort(byte[] src, int srcOff) { +- return UNSAFE.getShort(src, BYTE_ARRAY_OFFSET + srcOff); +- } +- +- public static int readShortLE(byte[] src, int srcOff) { +- short s = readShort(src, srcOff); +- if (NATIVE_BYTE_ORDER == ByteOrder.BIG_ENDIAN) { +- s = Short.reverseBytes(s); +- } +- return s & 0xFFFF; +- } +- +- public static void writeShort(byte[] dest, int destOff, short value) { +- UNSAFE.putShort(dest, BYTE_ARRAY_OFFSET + destOff, value); +- } +- +- public static void writeShortLE(byte[] buf, int off, int v) { +- writeByte(buf, off, (byte) v); +- writeByte(buf, off + 1, (byte) (v >>> 8)); +- } +- +- public static int readInt(int[] src, int srcOff) { +- return UNSAFE.getInt(src, INT_ARRAY_OFFSET + INT_ARRAY_SCALE * srcOff); +- } +- +- public static void writeInt(int[] dest, int destOff, int value) { +- UNSAFE.putInt(dest, INT_ARRAY_OFFSET + INT_ARRAY_SCALE * destOff, value); +- } +- +- public static int readShort(short[] src, int srcOff) { +- return UNSAFE.getShort(src, SHORT_ARRAY_OFFSET + SHORT_ARRAY_SCALE * srcOff) & 0xFFFF; +- } +- +- public static void writeShort(short[] dest, int destOff, int value) { +- UNSAFE.putShort(dest, SHORT_ARRAY_OFFSET + SHORT_ARRAY_SCALE * destOff, (short) value); +- } +-} +diff --git a/src/java/net/jpountz/lz4/LZ4Factory.java b/src/java/net/jpountz/lz4/LZ4Factory.java +index e04867b..69f81fa 100644 +--- a/src/java/net/jpountz/lz4/LZ4Factory.java ++++ b/src/java/net/jpountz/lz4/LZ4Factory.java +@@ -32,8 +32,6 @@ import static net.jpountz.lz4.LZ4Constants.MAX_COMPRESSION_LEVEL; + * the original LZ4 C implementation. + *
  • a {@link #safeInstance() safe Java} instance which is a pure Java port + * of the original C library,
  • +- *
  • an {@link #unsafeInstance() unsafe Java} instance which is a Java port +- * using the unofficial {@link sun.misc.Unsafe} API. + * + *

    + * Only the {@link #safeInstance() safe instance} is guaranteed to work on your +@@ -55,7 +53,6 @@ public final class LZ4Factory { + } + + private static LZ4Factory NATIVE_INSTANCE, +- JAVA_UNSAFE_INSTANCE, + JAVA_SAFE_INSTANCE; + + /** +@@ -107,42 +104,15 @@ public final class LZ4Factory { + return JAVA_SAFE_INSTANCE; + } + +- /** +- * Returns a {@link LZ4Factory} instance that returns compressors and +- * decompressors that may use {@link sun.misc.Unsafe} to speed up compression +- * and decompression. +- * +- * @return a {@link LZ4Factory} instance that returns compressors and +- * decompressors that may use {@link sun.misc.Unsafe} to speed up compression +- * and decompression. +- */ +- public static synchronized LZ4Factory unsafeInstance() { +- if (JAVA_UNSAFE_INSTANCE == null) { +- JAVA_UNSAFE_INSTANCE = instance("JavaUnsafe"); +- } +- return JAVA_UNSAFE_INSTANCE; +- } +- + /** + * Returns the fastest available {@link LZ4Factory} instance which does not +- * rely on JNI bindings. It first tries to load the +- * {@link #unsafeInstance() unsafe instance}, and then the +- * {@link #safeInstance() safe Java instance} if the JVM doesn't have a +- * working {@link sun.misc.Unsafe}. ++ * rely on JNI bindings. It loads {@link #safeInstance() safe Java instance} + * + * @return the fastest available {@link LZ4Factory} instance which does not + * rely on JNI bindings. + */ + public static LZ4Factory fastestJavaInstance() { +- if (Utils.isUnalignedAccessAllowed()) { +- try { +- return unsafeInstance(); +- } catch (Throwable t) { +- return safeInstance(); +- } +- } else { + return safeInstance(); +- } + } + + /** +@@ -249,9 +219,9 @@ public final class LZ4Factory { + *

  • A compression level lower than 1 would be treated as 9.
  • + * + * Note that compression levels from different implementations +- * (native, unsafe Java, and safe Java) cannot be compared with one another. ++ * (native, and safe Java) cannot be compared with one another. + * Specifically, the native implementation of a high compression level +- * is not necessarily faster than the safe/unsafe Java implementation ++ * is not necessarily faster than the safe Java implementation + * of the same compression level. + * + * @param compressionLevel the compression level between [1, 17]; the higher the level, the higher the compression ratio +diff --git a/src/java/net/jpountz/xxhash/XXHashFactory.java b/src/java/net/jpountz/xxhash/XXHashFactory.java +index 9a9b4d1..9ccdf76 100644 +--- a/src/java/net/jpountz/xxhash/XXHashFactory.java ++++ b/src/java/net/jpountz/xxhash/XXHashFactory.java +@@ -28,8 +28,6 @@ import net.jpountz.util.Utils; + * the original LZ4 C implementation. + *
  • a {@link #safeInstance() safe Java} instance which is a pure Java port + * of the original C library,
  • +- *
  • an {@link #unsafeInstance() unsafe Java} instance which is a Java port +- * using the unofficial {@link sun.misc.Unsafe} API. + * + *

    + * Only the {@link #safeInstance() safe instance} is guaranteed to work on your +@@ -51,7 +49,6 @@ public final class XXHashFactory { + } + + private static XXHashFactory NATIVE_INSTANCE, +- JAVA_UNSAFE_INSTANCE, + JAVA_SAFE_INSTANCE; + + /** +@@ -96,40 +93,15 @@ public final class XXHashFactory { + return JAVA_SAFE_INSTANCE; + } + +- /** +- * Returns a {@link XXHashFactory} that returns {@link XXHash32} instances that +- * may use {@link sun.misc.Unsafe} to speed up hashing. +- * +- * @return a {@link XXHashFactory} that returns {@link XXHash32} instances that +- * may use {@link sun.misc.Unsafe} to speed up hashing. +- */ +- public static synchronized XXHashFactory unsafeInstance() { +- if (JAVA_UNSAFE_INSTANCE == null) { +- JAVA_UNSAFE_INSTANCE = instance("JavaUnsafe"); +- } +- return JAVA_UNSAFE_INSTANCE; +- } +- + /** + * Returns the fastest available {@link XXHashFactory} instance which does not +- * rely on JNI bindings. It first tries to load the +- * {@link #unsafeInstance() unsafe instance}, and then the +- * {@link #safeInstance() safe Java instance} if the JVM doesn't have a +- * working {@link sun.misc.Unsafe}. ++ * rely on JNI bindings. It loads {@link #safeInstance() safe instance} + * + * @return the fastest available {@link XXHashFactory} instance which does not + * rely on JNI bindings. + */ + public static XXHashFactory fastestJavaInstance() { +- if (Utils.isUnalignedAccessAllowed()) { +- try { +- return unsafeInstance(); +- } catch (Throwable t) { +- return safeInstance(); +- } +- } else { + return safeInstance(); +- } + } + + /** +diff --git a/src/test/net/jpountz/lz4/Instances.java b/src/test/net/jpountz/lz4/Instances.java +index b9caae5..44f7809 100644 +--- a/src/test/net/jpountz/lz4/Instances.java ++++ b/src/test/net/jpountz/lz4/Instances.java +@@ -21,21 +21,17 @@ enum Instances { + static LZ4Compressor[] COMPRESSORS = new LZ4Compressor[] { + LZ4Factory.nativeInstance().fastCompressor(), + LZ4Factory.nativeInstance().highCompressor(), +- LZ4Factory.unsafeInstance().fastCompressor(), +- LZ4Factory.unsafeInstance().highCompressor(), + LZ4Factory.safeInstance().fastCompressor(), + LZ4Factory.safeInstance().highCompressor() + }; + + static LZ4FastDecompressor[] FAST_DECOMPRESSORS = new LZ4FastDecompressor[] { + LZ4Factory.nativeInstance().fastDecompressor(), +- LZ4Factory.unsafeInstance().fastDecompressor(), + LZ4Factory.safeInstance().fastDecompressor() + }; + + static LZ4SafeDecompressor[] SAFE_DECOMPRESSORS = new LZ4SafeDecompressor[] { + LZ4Factory.nativeInstance().safeDecompressor(), +- LZ4Factory.unsafeInstance().safeDecompressor(), + LZ4Factory.safeInstance().safeDecompressor() + }; + +diff --git a/src/test/net/jpountz/lz4/LZ4FactoryTest.java b/src/test/net/jpountz/lz4/LZ4FactoryTest.java +index c4ef05e..b8b33d7 100644 +--- a/src/test/net/jpountz/lz4/LZ4FactoryTest.java ++++ b/src/test/net/jpountz/lz4/LZ4FactoryTest.java +@@ -21,17 +21,13 @@ public class LZ4FactoryTest extends TestCase { + public void test() { + assertEquals(LZ4JNICompressor.INSTANCE, LZ4Factory.nativeInstance().fastCompressor()); + assertEquals(LZ4HCJNICompressor.INSTANCE, LZ4Factory.nativeInstance().highCompressor()); +- assertEquals(LZ4JavaUnsafeCompressor.INSTANCE, LZ4Factory.unsafeInstance().fastCompressor()); +- assertEquals(LZ4HCJavaUnsafeCompressor.INSTANCE, LZ4Factory.unsafeInstance().highCompressor()); + assertEquals(LZ4JavaSafeCompressor.INSTANCE, LZ4Factory.safeInstance().fastCompressor()); + assertEquals(LZ4HCJavaSafeCompressor.INSTANCE, LZ4Factory.safeInstance().highCompressor()); + + assertEquals(LZ4JNIFastDecompressor.INSTANCE, LZ4Factory.nativeInstance().fastDecompressor()); +- assertEquals(LZ4JavaUnsafeFastDecompressor.INSTANCE, LZ4Factory.unsafeInstance().fastDecompressor()); + assertEquals(LZ4JavaSafeFastDecompressor.INSTANCE, LZ4Factory.safeInstance().fastDecompressor()); + + assertEquals(LZ4JNISafeDecompressor.INSTANCE, LZ4Factory.nativeInstance().safeDecompressor()); +- assertEquals(LZ4JavaUnsafeSafeDecompressor.INSTANCE, LZ4Factory.unsafeInstance().safeDecompressor()); + assertEquals(LZ4JavaSafeSafeDecompressor.INSTANCE, LZ4Factory.safeInstance().safeDecompressor()); + } + +diff --git a/src/test/net/jpountz/xxhash/XXHashFactoryTest.java b/src/test/net/jpountz/xxhash/XXHashFactoryTest.java +index c410220..2aae562 100644 +--- a/src/test/net/jpountz/xxhash/XXHashFactoryTest.java ++++ b/src/test/net/jpountz/xxhash/XXHashFactoryTest.java +@@ -21,14 +21,10 @@ public class XXHashFactoryTest extends TestCase { + public void test() { + assertEquals(XXHash32JNI.INSTANCE, XXHashFactory.nativeInstance().hash32()); + assertTrue(XXHashFactory.nativeInstance().newStreamingHash32(0) instanceof StreamingXXHash32JNI); +- assertEquals(XXHash32JavaUnsafe.INSTANCE, XXHashFactory.unsafeInstance().hash32()); +- assertTrue(XXHashFactory.unsafeInstance().newStreamingHash32(0) instanceof StreamingXXHash32JavaUnsafe); + assertEquals(XXHash32JavaSafe.INSTANCE, XXHashFactory.safeInstance().hash32()); + assertTrue(XXHashFactory.safeInstance().newStreamingHash32(0) instanceof StreamingXXHash32JavaSafe); + assertEquals(XXHash64JNI.INSTANCE, XXHashFactory.nativeInstance().hash64()); + assertTrue(XXHashFactory.nativeInstance().newStreamingHash64(0) instanceof StreamingXXHash64JNI); +- assertEquals(XXHash64JavaUnsafe.INSTANCE, XXHashFactory.unsafeInstance().hash64()); +- assertTrue(XXHashFactory.unsafeInstance().newStreamingHash64(0) instanceof StreamingXXHash64JavaUnsafe); + assertEquals(XXHash64JavaSafe.INSTANCE, XXHashFactory.safeInstance().hash64()); + assertTrue(XXHashFactory.safeInstance().newStreamingHash64(0) instanceof StreamingXXHash64JavaSafe); + } diff --git a/SOURCES/1-remove-comments-from-templates.patch b/SOURCES/1-remove-comments-from-templates.patch new file mode 100644 index 0000000..83fb640 --- /dev/null +++ b/SOURCES/1-remove-comments-from-templates.patch @@ -0,0 +1,311 @@ +diff --git a/src/build/source_templates/compress.template b/src/build/source_templates/compress.template +index 32008e9..09a5df4 100644 +--- a/src/build/source_templates/compress.template ++++ b/src/build/source_templates/compress.template +@@ -31,7 +31,6 @@ + main: + while (true) { + +- // find a match + int forwardOff = sOff; + + int ref; +@@ -51,15 +50,12 @@ + ${type}Utils.writeShort(hashTable, h, sOff - srcOff); + } while (!LZ4${utils}.readIntEquals(src, ref, sOff)); + +- // catch up + final int excess = LZ4${utils}.commonBytesBackward(src, ref, sOff, srcOff, anchor); + sOff -= excess; + ref -= excess; + +- // sequence == refsequence + final int runLen = sOff - anchor; + +- // encode literal length + int tokenOff = dOff++; + + if (dOff + runLen + (2 + 1 + LAST_LITERALS) + (runLen >>> 8) > destEnd) { +@@ -73,16 +69,13 @@ + ${utils}.writeByte(dest, tokenOff, runLen << ML_BITS); + } + +- // copy literals + LZ4${utils}.wildArraycopy(src, anchor, dest, dOff, runLen); + dOff += runLen; + + while (true) { +- // encode offset + ${utils}.writeShortLE(dest, dOff, (short) (sOff - ref)); + dOff += 2; + +- // count nb matches + sOff += MIN_MATCH; + ref += MIN_MATCH; + final int matchLen = LZ4${utils}.commonBytes(src, ref, sOff, srcLimit); +@@ -91,7 +84,6 @@ + } + sOff += matchLen; + +- // encode match len + if (matchLen >= ML_MASK) { + ${utils}.writeByte(dest, tokenOff, ${utils}.readByte(dest, tokenOff) | ML_MASK); + dOff = LZ4${utils}.writeLen(matchLen - ML_MASK, dest, dOff); +@@ -99,16 +91,13 @@ + ${utils}.writeByte(dest, tokenOff, ${utils}.readByte(dest, tokenOff) | matchLen); + } + +- // test end of chunk + if (sOff > mflimit) { + anchor = sOff; + break main; + } + +- // fill table + ${type}Utils.writeShort(hashTable, hash64k(${utils}.readInt(src, sOff - 2)), sOff - 2 - srcOff); + +- // test next position + final int h = hash64k(${utils}.readInt(src, sOff)); + ref = srcOff + ${type}Utils.readShort(hashTable, h); + ${type}Utils.writeShort(hashTable, h, sOff - srcOff); +@@ -121,7 +110,6 @@ + ${utils}.writeByte(dest, tokenOff, 0); + } + +- // prepare next loop + anchor = sOff++; + } + } +@@ -160,7 +148,6 @@ + main: + while (true) { + +- // find a match + int forwardOff = sOff; + + int ref; +@@ -187,10 +174,8 @@ + sOff -= excess; + ref -= excess; + +- // sequence == refsequence + final int runLen = sOff - anchor; + +- // encode literal length + int tokenOff = dOff++; + + if (dOff + runLen + (2 + 1 + LAST_LITERALS) + (runLen >>> 8) > destEnd) { +@@ -204,16 +189,13 @@ + ${utils}.writeByte(dest, tokenOff, runLen << ML_BITS); + } + +- // copy literals + LZ4${utils}.wildArraycopy(src, anchor, dest, dOff, runLen); + dOff += runLen; + + while (true) { +- // encode offset + ${utils}.writeShortLE(dest, dOff, back); + dOff += 2; + +- // count nb matches + sOff += MIN_MATCH; + final int matchLen = LZ4${utils}.commonBytes(src, ref + MIN_MATCH, sOff, srcLimit); + if (dOff + (1 + LAST_LITERALS) + (matchLen >>> 8) > destEnd) { +@@ -221,7 +203,6 @@ + } + sOff += matchLen; + +- // encode match len + if (matchLen >= ML_MASK) { + ${utils}.writeByte(dest, tokenOff, ${utils}.readByte(dest, tokenOff) | ML_MASK); + dOff = LZ4${utils}.writeLen(matchLen - ML_MASK, dest, dOff); +@@ -229,16 +210,13 @@ + ${utils}.writeByte(dest, tokenOff, ${utils}.readByte(dest, tokenOff) | matchLen); + } + +- // test end of chunk + if (sOff > mflimit) { + anchor = sOff; + break main; + } + +- // fill table + ${type}Utils.writeInt(hashTable, hash(${utils}.readInt(src, sOff - 2)), sOff - 2); + +- // test next position + final int h = hash(${utils}.readInt(src, sOff)); + ref = ${type}Utils.readInt(hashTable, h); + ${type}Utils.writeInt(hashTable, h, sOff); +@@ -252,7 +230,6 @@ + ${utils}.writeByte(dest, tokenOff, 0); + } + +- // prepare next loop + anchor = sOff++; + } + +diff --git a/src/build/source_templates/compress_hc.template b/src/build/source_templates/compress_hc.template +index 7179db3..7976ad1 100644 +--- a/src/build/source_templates/compress_hc.template ++++ b/src/build/source_templates/compress_hc.template +@@ -47,7 +47,6 @@ + continue; + } + +- // saved, in case we would skip too much + copyTo(match1, match0); + + search2: +@@ -55,20 +54,19 @@ + assert match1.start >= anchor; + if (match1.end() >= mfLimit + || !ht.insertAndFindWiderMatch(src, match1.end() - 2, match1.start + 1, matchLimit, match1.len, match2)) { +- // no better match + dOff = LZ4${utils}.encodeSequence(src, anchor, match1.start, match1.ref, match1.len, dest, dOff, destEnd); + anchor = sOff = match1.end(); + continue main; + } + + if (match0.start < match1.start) { +- if (match2.start < match1.start + match0.len) { // empirical ++ if (match2.start < match1.start + match0.len) { + copyTo(match0, match1); + } + } + assert match2.start > match1.start; + +- if (match2.start - match1.start < 3) { // First Match too small : removed ++ if (match2.start - match1.start < 3) { + copyTo(match2, match1); + continue search2; + } +@@ -91,21 +89,18 @@ + + if (match2.start + match2.len >= mfLimit + || !ht.insertAndFindWiderMatch(src, match2.end() - 3, match2.start, matchLimit, match2.len, match3)) { +- // no better match -> 2 sequences to encode + if (match2.start < match1.end()) { + match1.len = match2.start - match1.start; + } +- // encode seq 1 + dOff = LZ4${utils}.encodeSequence(src, anchor, match1.start, match1.ref, match1.len, dest, dOff, destEnd); + anchor = sOff = match1.end(); +- // encode seq 2 + dOff = LZ4${utils}.encodeSequence(src, anchor, match2.start, match2.ref, match2.len, dest, dOff, destEnd); + anchor = sOff = match2.end(); + continue main; + } + +- if (match3.start < match1.end() + 3) { // Not enough space for match 2 : remove it +- if (match3.start >= match1.end()) { // // can write Seq1 immediately ==> Seq2 is removed, so Seq3 becomes Seq1 ++ if (match3.start < match1.end() + 3) { ++ if (match3.start >= match1.end()) { + if (match2.start < match1.end()) { + final int correction = match1.end() - match2.start; + match2.fix(correction); +@@ -127,7 +122,6 @@ + continue search3; + } + +- // OK, now we have 3 ascending matches; let's write at least the first one + if (match2.start < match1.end()) { + if (match2.start - match1.start < ML_MASK) { + if (match1.len > OPTIMAL_ML) { +diff --git a/src/build/source_templates/decompress.template b/src/build/source_templates/decompress.template +index f1c2890..1e2aa23 100644 +--- a/src/build/source_templates/decompress.template ++++ b/src/build/source_templates/decompress.template +@@ -55,7 +55,6 @@ + final int token = ${utils}.readByte(src, sOff) & 0xFF; + ++sOff; + +- // literals + int literalLen = token >>> ML_BITS; + if (literalLen == RUN_MASK) { + byte len = (byte) 0xFF; +@@ -81,7 +80,7 @@ + LZ4${utils}.safeArraycopy(src, sOff, dest, dOff, literalLen); + sOff += literalLen; + dOff = literalCopyEnd; +- break; // EOF ++ break; + } + } + +@@ -89,7 +88,6 @@ + sOff += literalLen; + dOff = literalCopyEnd; + +- // matchs + final int matchDec = ${utils}.readShortLE(src, sOff); + sOff += 2; + int matchOff = dOff - matchDec; +diff --git a/src/build/source_templates/hashtable.template b/src/build/source_templates/hashtable.template +index 174f8e8..91935f5 100644 +--- a/src/build/source_templates/hashtable.template ++++ b/src/build/source_templates/hashtable.template +@@ -92,8 +92,8 @@ + + int ref = hashPointer(buf, off); + +- if (ref >= off - 4 && ref <= off && ref >= base) { // potential repetition +- if (LZ4${utils}.readIntEquals(buf, ref, off)) { // confirmed ++ if (ref >= off - 4 && ref <= off && ref >= base) { ++ if (LZ4${utils}.readIntEquals(buf, ref, off)) { + delta = off - ref; + repl = match.len = MIN_MATCH + LZ4${utils}.commonBytes(buf, ref + MIN_MATCH, off + MIN_MATCH, matchLimit); + match.ref = ref; +@@ -119,7 +119,7 @@ + int ptr = off; + final int end = off + repl - (MIN_MATCH - 1); + while (ptr < end - delta) { +- chainTable[ptr & MASK] = (short) delta; // pre load ++ chainTable[ptr & MASK] = (short) delta; + ++ptr; + } + do { +diff --git a/src/build/source_templates/xxhash32_streaming.template b/src/build/source_templates/xxhash32_streaming.template +index 6166758..9fa55e8 100644 +--- a/src/build/source_templates/xxhash32_streaming.template ++++ b/src/build/source_templates/xxhash32_streaming.template +@@ -66,7 +66,7 @@ final class StreamingXXHash32Java${type} extends AbstractStreamingXXHash32Java { + + totalLen += len; + +- if (memSize + len < 16) { // fill in tmp buffer ++ if (memSize + len < 16) { + System.arraycopy(buf, off, memory, memSize, len); + memSize += len; + return; +@@ -74,7 +74,7 @@ final class StreamingXXHash32Java${type} extends AbstractStreamingXXHash32Java { + + final int end = off + len; + +- if (memSize > 0) { // data left from previous update ++ if (memSize > 0) { + System.arraycopy(buf, off, memory, memSize, 16 - memSize); + + v1 += readIntLE(memory, 0) * PRIME2; +diff --git a/src/build/source_templates/xxhash64_streaming.template b/src/build/source_templates/xxhash64_streaming.template +index 2789ae0..e781746 100644 +--- a/src/build/source_templates/xxhash64_streaming.template ++++ b/src/build/source_templates/xxhash64_streaming.template +@@ -90,7 +90,7 @@ final class StreamingXXHash64Java${type} extends AbstractStreamingXXHash64Java { + + totalLen += len; + +- if (memSize + len < 32) { // fill in tmp buffer ++ if (memSize + len < 32) { + System.arraycopy(buf, off, memory, memSize, len); + memSize += len; + return; +@@ -98,7 +98,7 @@ final class StreamingXXHash64Java${type} extends AbstractStreamingXXHash64Java { + + final int end = off + len; + +- if (memSize > 0) { // data left from previous update ++ if (memSize > 0) { + System.arraycopy(buf, off, memory, memSize, 32 - memSize); + + v1 += readLongLE(memory, 0) * PRIME64_2; diff --git a/SOURCES/2-remove-cpptasks.patch b/SOURCES/2-remove-cpptasks.patch new file mode 100644 index 0000000..f896d55 --- /dev/null +++ b/SOURCES/2-remove-cpptasks.patch @@ -0,0 +1,98 @@ +diff --git a/Makefile b/Makefile +new file mode 100644 +index 0000000..01934f1 +--- /dev/null ++++ b/Makefile +@@ -0,0 +1,33 @@ ++CC = gcc ++ ++BUILD_DIR = build ++OBJECTS_DIR = $(BUILD_DIR)/objects ++JNI_HEADERS_DIR = $(BUILD_DIR)/jni-headers ++JNI_SOURCES_DIR = src/jni ++INCLUDE = -I $(JAVA_HOME)/include -I $(JAVA_HOME)/include/linux ++ ++LIBS = -llz4 -lxxhash ++JNI_PREFIX = net_jpountz_ ++ ++default: all move_objects generate_so ++ ++all: ++ $(CC) -fPIC -I $(JNI_HEADERS_DIR) \ ++ $(INCLUDE) \ ++ $(LIBS) \ ++ -c $(JNI_SOURCES_DIR)/$(JNI_PREFIX)lz4_LZ4JNI.c ++ ++ $(CC) -fPIC -I $(JNI_HEADERS_DIR) \ ++ $(INCLUDE) \ ++ $(LIBS) \ ++ -c $(JNI_SOURCES_DIR)/$(JNI_PREFIX)xxhash_XXHashJNI.c ++ ++move_objects: ++ mv *.o $(OBJECTS_DIR) ++ ++generate_so: ++ gcc -fPIC -shared \ ++ $(OBJECTS_DIR)/*.o \ ++ $(LIB_DIR)/liblz4.so \ ++ $(LIB_DIR)/libxxhash.so \ ++ -o $(BUILD_DIR)/jni/net/jpountz/util/$(PLATFORM)/$(ARCH)/liblz4-java.so +diff --git a/build.xml b/build.xml +index 1d4cff5..13d8ce3 100644 +--- a/build.xml ++++ b/build.xml +@@ -13,7 +13,6 @@ + --> + + +@@ -78,13 +77,6 @@ + + + +- +- +- +- +- +- + + +@@ -184,27 +176,13 @@ + + + +- ++ + + +- +- +- +- +- +- +- +- +- +- +- +- +- ++ ++ ++ ++ + + + diff --git a/SOURCES/3-remove-randomizedtesting-tests.patch b/SOURCES/3-remove-randomizedtesting-tests.patch new file mode 100644 index 0000000..c7d2282 --- /dev/null +++ b/SOURCES/3-remove-randomizedtesting-tests.patch @@ -0,0 +1,1689 @@ +diff --git a/.classpath b/.classpath +index 058b340..c48898b 100644 +--- a/.classpath ++++ b/.classpath +@@ -7,7 +7,5 @@ + + + +- +- + + + +diff --git a/build.xml b/build.xml +index 1bdc702..919386f 100644 +--- a/build.xml ++++ b/build.xml +@@ -14,7 +14,6 @@ + + + + +@@ -105,15 +104,6 @@ + + + +- +- +- +- +- +- +- +- +- + + +@@ -236,37 +226,14 @@ + + + +- +- +- +- +- +- ++ ++ + +- +- +- +- +- +- +- +- +- +- +- ++ ++ ++ ++ ++ + + + +diff --git a/ivy-pure-java.xml b/ivy-pure-java.xml +index 6e99e19..9c1c99b 100644 +--- a/ivy-pure-java.xml ++++ b/ivy-pure-java.xml +@@ -21,6 +21,6 @@ + + + +- ++ + + +diff --git a/ivy.xml b/ivy.xml +index 6643da7..e5a9620 100644 +--- a/ivy.xml ++++ b/ivy.xml +@@ -21,6 +21,6 @@ + + + +- ++ + + +diff --git a/src/test/net/jpountz/lz4/AbstractLZ4Test.java b/src/test/net/jpountz/lz4/AbstractLZ4Test.java +deleted file mode 100644 +index 8c5cd38..0000000 +--- a/src/test/net/jpountz/lz4/AbstractLZ4Test.java ++++ /dev/null +@@ -1,257 +0,0 @@ +-package net.jpountz.lz4; +- +-/* +- * 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. +- */ +- +-import java.io.ByteArrayOutputStream; +-import java.io.IOException; +-import java.io.InputStream; +-import java.nio.ByteBuffer; +-import java.nio.ByteOrder; +-import java.util.Arrays; +- +-import com.carrotsearch.randomizedtesting.RandomizedTest; +- +-public abstract class AbstractLZ4Test extends RandomizedTest { +- +- public interface Tester { +- +- T allocate(int length); +- T copyOf(byte[] array); +- byte[] copyOf(T data, int off, int len); +- int maxCompressedLength(int len); +- int compress(LZ4Compressor compressor, T src, int srcOff, int srcLen, T dest, int destOff, int maxDestLen); +- int decompress(LZ4FastDecompressor decompressor, T src, int srcOff, T dest, int destOff, int destLen); +- int decompress(LZ4SafeDecompressor decompressor, T src, int srcOff, int srcLen, T dest, int destOff, int maxDestLen); +- void fill(T instance, byte b); +- +- public static class ByteArrayTester implements Tester { +- +- @Override +- public byte[] allocate(int length) { +- return new byte[length]; +- } +- +- @Override +- public byte[] copyOf(byte[] array) { +- return Arrays.copyOf(array, array.length); +- } +- +- @Override +- public byte[] copyOf(byte[] data, int off, int len) { +- return Arrays.copyOfRange(data, off, off + len); +- } +- +- @Override +- public int maxCompressedLength(int len) { +- return LZ4Utils.maxCompressedLength(len); +- } +- +- @Override +- public int compress(LZ4Compressor compressor, byte[] src, int srcOff, +- int srcLen, byte[] dest, int destOff, int maxDestLen) { +- return compressor.compress(src, srcOff, srcLen, dest, destOff, maxDestLen); +- } +- +- @Override +- public int decompress(LZ4FastDecompressor decompressor, +- byte[] src, int srcOff, byte[] dest, int destOff, int destLen) { +- return decompressor.decompress(src, srcOff, dest, destOff, destLen); +- } +- +- @Override +- public int decompress(LZ4SafeDecompressor decompressor, +- byte[] src, int srcOff, int srcLen, byte[] dest, int destOff, int maxDestLen) { +- return decompressor.decompress(src, srcOff, srcLen, dest, destOff, maxDestLen); +- } +- +- @Override +- public void fill(byte[] instance, byte b) { +- Arrays.fill(instance, b); +- } +- } +- public static final Tester BYTE_ARRAY = new ByteArrayTester(); +- public static final Tester BYTE_ARRAY_WITH_LENGTH = new ByteArrayTester() { +- @Override +- public int compress(LZ4Compressor compressor, byte[] src, int srcOff, +- int srcLen, byte[] dest, int destOff, int maxDestLen) { +- return new LZ4CompressorWithLength(compressor).compress(src, srcOff, srcLen, dest, destOff, maxDestLen); +- } +- +- @Override +- public int decompress(LZ4FastDecompressor decompressor, +- byte[] src, int srcOff, byte[] dest, int destOff, int destLen) { +- return new LZ4DecompressorWithLength(decompressor).decompress(src, srcOff, dest, destOff); +- } +- +- @Override +- public int decompress(LZ4SafeDecompressor decompressor, +- byte[] src, int srcOff, int srcLen, byte[] dest, int destOff, int maxDestLen) { +- return -1; +- } +- }; +- +- public static class ByteBufferTester implements Tester { +- +- @Override +- public ByteBuffer allocate(int length) { +- ByteBuffer bb; +- int slice = randomInt(5); +- if (randomBoolean()) { +- bb = ByteBuffer.allocate(length + slice); +- } else { +- bb = ByteBuffer.allocateDirect(length + slice); +- } +- bb.position(slice); +- bb = bb.slice(); +- if (randomBoolean()) { +- bb.order(ByteOrder.LITTLE_ENDIAN); +- } else { +- bb.order(ByteOrder.BIG_ENDIAN); +- } +- return bb; +- } +- +- @Override +- public ByteBuffer copyOf(byte[] array) { +- ByteBuffer bb = allocate(array.length).put(array); +- if (randomBoolean()) { +- bb = bb.asReadOnlyBuffer(); +- } +- bb.position(0); +- return bb; +- } +- +- @Override +- public byte[] copyOf(ByteBuffer data, int off, int len) { +- byte[] copy = new byte[len]; +- data.position(off); +- data.get(copy); +- return copy; +- } +- +- @Override +- public int maxCompressedLength(int len) { +- return LZ4Utils.maxCompressedLength(len); +- } +- +- @Override +- public int compress(LZ4Compressor compressor, ByteBuffer src, int srcOff, +- int srcLen, ByteBuffer dest, int destOff, int maxDestLen) { +- return compressor.compress(src, srcOff, srcLen, dest, destOff, maxDestLen); +- } +- +- @Override +- public int decompress(LZ4FastDecompressor decompressor, ByteBuffer src, +- int srcOff, ByteBuffer dest, int destOff, int destLen) { +- return decompressor.decompress(src, srcOff, dest, destOff, destLen); +- } +- +- @Override +- public int decompress(LZ4SafeDecompressor decompressor, ByteBuffer src, +- int srcOff, int srcLen, ByteBuffer dest, int destOff, int maxDestLen) { +- return decompressor.decompress(src, srcOff, srcLen, dest, destOff, maxDestLen); +- } +- +- @Override +- public void fill(ByteBuffer instance, byte b) { +- for (int i = 0; i < instance.capacity(); ++i) { +- instance.put(i, b); +- } +- } +- } +- public static final Tester BYTE_BUFFER = new ByteBufferTester(); +- public static final Tester BYTE_BUFFER_WITH_LENGTH = new ByteBufferTester() { +- @Override +- public int compress(LZ4Compressor compressor, ByteBuffer src, int srcOff, +- int srcLen, ByteBuffer dest, int destOff, int maxDestLen) { +- return new LZ4CompressorWithLength(compressor).compress(src, srcOff, srcLen, dest, destOff, maxDestLen); +- } +- +- @Override +- public int decompress(LZ4FastDecompressor decompressor, ByteBuffer src, +- int srcOff, ByteBuffer dest, int destOff, int destLen) { +- return new LZ4DecompressorWithLength(decompressor).decompress(src, srcOff, dest, destOff); +- } +- +- @Override +- public int decompress(LZ4SafeDecompressor decompressor, ByteBuffer src, +- int srcOff, int srcLen, ByteBuffer dest, int destOff, int maxDestLen) { +- return -1; +- } +- }; +- } +- +- protected class RandomBytes { +- private final byte[] bytes; +- RandomBytes(int n) { +- assert n > 0 && n <= 256; +- bytes = new byte[n]; +- for (int i = 0; i < n; ++i) { +- bytes[i] = (byte) randomInt(255); +- } +- } +- byte next() { +- final int i = randomInt(bytes.length - 1); +- return bytes[i]; +- } +- } +- +- protected static byte[] readResource(String resource) throws IOException { +- InputStream is = LZ4Test.class.getResourceAsStream(resource); +- if (is == null) { +- throw new IllegalStateException("Cannot find " + resource); +- } +- byte[] buf = new byte[4096]; +- ByteArrayOutputStream baos = new ByteArrayOutputStream(); +- try { +- while (true) { +- final int read = is.read(buf); +- if (read == -1) { +- break; +- } +- baos.write(buf, 0, read); +- } +- } finally { +- is.close(); +- } +- return baos.toByteArray(); +- } +- +- protected byte[] randomArray(int len, int n) { +- byte[] result = new byte[len]; +- RandomBytes randomBytes = new RandomBytes(n); +- for (int i = 0; i < result.length; ++i) { +- result[i] = randomBytes.next(); +- } +- return result; +- } +- +- protected ByteBuffer copyOf(byte[] bytes, int offset, int len) { +- ByteBuffer buffer; +- if (randomBoolean()) { +- buffer = ByteBuffer.allocate(bytes.length); +- } else { +- buffer = ByteBuffer.allocateDirect(bytes.length); +- } +- buffer.put(bytes); +- buffer.position(offset); +- buffer.limit(offset + len); +- if (randomBoolean()) { +- buffer = buffer.asReadOnlyBuffer(); +- } +- return buffer; +- } +- +-} +diff --git a/src/test/net/jpountz/lz4/LZ4BlockStreamingTest.java b/src/test/net/jpountz/lz4/LZ4BlockStreamingTest.java +deleted file mode 100644 +index 9d6fc5b..0000000 +--- a/src/test/net/jpountz/lz4/LZ4BlockStreamingTest.java ++++ /dev/null +@@ -1,347 +0,0 @@ +-package net.jpountz.lz4; +- +-/* +- * 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. +- */ +- +-import java.io.ByteArrayInputStream; +-import java.io.ByteArrayOutputStream; +-import java.io.FilterInputStream; +-import java.io.FilterOutputStream; +-import java.io.IOException; +-import java.io.InputStream; +-import java.io.OutputStream; +-import java.nio.charset.Charset; +-import java.util.Arrays; +-import java.util.zip.Adler32; +-import java.util.zip.CRC32; +-import java.util.zip.Checksum; +- +-import net.jpountz.xxhash.XXHashFactory; +- +-import org.junit.Test; +-import static org.junit.Assert.*; +- +-import com.carrotsearch.randomizedtesting.annotations.Repeat; +- +-public class LZ4BlockStreamingTest extends AbstractLZ4Test { +- +- // An input stream that might read less data than it is able to +- class MockInputStream extends FilterInputStream { +- +- MockInputStream(InputStream in) { +- super(in); +- } +- +- @Override +- public int read(byte[] b, int off, int len) throws IOException { +- return super.read(b, off, randomIntBetween(0, len)); +- } +- +- @Override +- public long skip(long n) throws IOException { +- return super.skip(randomInt((int) Math.min(n, Integer.MAX_VALUE))); +- } +- +- } +- +- // an output stream that delays the actual writes +- class MockOutputStream extends FilterOutputStream { +- +- private final byte[] buffer; +- private int delayedBytes; +- +- MockOutputStream(OutputStream out) { +- super(out); +- buffer = new byte[randomIntBetween(10, 1000)]; +- delayedBytes = 0; +- } +- +- private void flushIfNecessary() throws IOException { +- if (delayedBytes == buffer.length) { +- flushPendingData(); +- } +- } +- +- private void flushPendingData() throws IOException { +- out.write(buffer, 0, delayedBytes); +- delayedBytes = 0; +- } +- +- @Override +- public void write(int b) throws IOException { +- if (rarely()) { +- flushPendingData(); +- } else { +- flushIfNecessary(); +- } +- buffer[delayedBytes++] = (byte) b; +- } +- +- @Override +- public void write(byte[] b, int off, int len) throws IOException { +- if (rarely()) { +- flushPendingData(); +- } +- if (len + delayedBytes > buffer.length) { +- flushPendingData(); +- delayedBytes = randomInt(Math.min(len, buffer.length)); +- out.write(b, off, len - delayedBytes); +- System.arraycopy(b, off + len - delayedBytes, buffer, 0, delayedBytes); +- } else { +- System.arraycopy(b, off, buffer, delayedBytes, len); +- delayedBytes += len; +- } +- } +- +- @Override +- public void write(byte[] b) throws IOException { +- write(b, 0, b.length); +- } +- +- @Override +- public void flush() throws IOException { +- // no-op +- } +- +- @Override +- public void close() throws IOException { +- flushPendingData(); +- out.close(); +- } +- +- } +- +- private InputStream open(byte[] data) { +- return new MockInputStream(new ByteArrayInputStream(data)); +- } +- +- private OutputStream wrap(OutputStream other) { +- return new MockOutputStream(other); +- } +- +- @Test +- @Repeat(iterations=5) +- public void testRoundtripGeo() throws IOException { +- testRoundTrip("/calgary/geo"); +- } +- +- @Test +- @Repeat(iterations=5) +- public void testRoundtripBook1() throws IOException { +- testRoundTrip("/calgary/book1"); +- } +- +- @Test +- @Repeat(iterations=5) +- public void testRoundtripPic() throws IOException { +- testRoundTrip("/calgary/pic"); +- } +- +- public void testRoundTrip(String resource) throws IOException { +- testRoundTrip(readResource(resource)); +- } +- +- public void testRoundTrip(byte[] data) throws IOException { +- final ByteArrayOutputStream compressed = new ByteArrayOutputStream(); +- final int blockSize; +- switch (randomInt(2)) { +- case 0: +- blockSize = LZ4BlockOutputStream.MIN_BLOCK_SIZE; +- break; +- case 1: +- blockSize = LZ4BlockOutputStream.MAX_BLOCK_SIZE; +- break; +- default: +- blockSize = randomIntBetween(LZ4BlockOutputStream.MIN_BLOCK_SIZE, LZ4BlockOutputStream.MAX_BLOCK_SIZE); +- break; +- } +- final LZ4Compressor compressor = randomBoolean() +- ? LZ4Factory.fastestInstance().fastCompressor() +- : LZ4Factory.fastestInstance().highCompressor(); +- final Checksum checksum; +- switch (randomInt(2)) { +- case 0: +- checksum = new Adler32(); +- break; +- case 1: +- checksum = new CRC32(); +- break; +- default: +- checksum = XXHashFactory.fastestInstance().newStreamingHash32(randomInt()).asChecksum(); +- break; +- } +- final boolean syncFlush = randomBoolean(); +- final LZ4BlockOutputStream os = new LZ4BlockOutputStream(wrap(compressed), blockSize, compressor, checksum, syncFlush); +- final int half = data.length / 2; +- switch (randomInt(2)) { +- case 0: +- os.write(data, 0, half); +- for (int i = half; i < data.length; ++i) { +- os.write(data[i]); +- } +- break; +- case 1: +- for (int i = 0; i < half; ++i) { +- os.write(data[i]); +- } +- os.write(data, half, data.length - half); +- break; +- case 2: +- os.write(data, 0, data.length); +- break; +- } +- os.close(); +- +- final LZ4FastDecompressor decompressor = LZ4Factory.fastestInstance().fastDecompressor(); +- InputStream is = new LZ4BlockInputStream(open(compressed.toByteArray()), decompressor, checksum); +- assertFalse(is.markSupported()); +- try { +- is.mark(1); +- is.reset(); +- assertFalse(true); +- } catch (IOException e) { +- // OK +- } +- byte[] restored = new byte[data.length + 1000]; +- int read = 0; +- while (true) { +- if (randomFloat() < 0.01f) { +- final int r = is.read(restored, read, restored.length - read); +- if (r == -1) { +- break; +- } else { +- read += r; +- } +- } else { +- final int b = is.read(); +- if (b == -1) { +- break; +- } else { +- restored[read++] = (byte) b; +- } +- } +- } +- is.close(); +- assertEquals(data.length, read); +- assertArrayEquals(data, Arrays.copyOf(restored, read)); +- +- // test skip +- final int offset = data.length <= 1 ? 0 : randomInt(data.length - 1); +- final int length = randomInt(data.length - offset); +- is = new LZ4BlockInputStream(open(compressed.toByteArray()), decompressor, checksum); +- restored = new byte[length + 1000]; +- read = 0; +- while (read < offset) { +- final long skipped = is.skip(offset - read); +- assertTrue(skipped >= 0); +- read += skipped; +- } +- read = 0; +- while (read < length) { +- final int r = is.read(restored, read, length - read); +- assertTrue(r >= 0); +- read += r; +- } +- is.close(); +- assertArrayEquals(Arrays.copyOfRange(data, offset, offset + length), Arrays.copyOfRange(restored, 0, length)); +- } +- +- @Test +- @Repeat(iterations=20) +- public void testRoundtripRandom() throws IOException { +- final int size = randomFloat() < 0.1f ? randomInt(5) : randomInt(1 << 20); +- final byte[] data = randomArray(size, randomBoolean() ? randomIntBetween(1, 5) : randomIntBetween(6, 100)); +- testRoundTrip(data); +- } +- +- @Test +- public void testRoundtripEmpty() throws IOException { +- testRoundTrip(new byte[0]); +- } +- +- @Test +- public void testDoubleClose() throws IOException { +- final byte[] testBytes = "Testing!".getBytes(Charset.forName("UTF-8")); +- +- ByteArrayOutputStream bytes = new ByteArrayOutputStream(); +- LZ4BlockOutputStream out = new LZ4BlockOutputStream(bytes); +- +- out.write(testBytes); +- +- out.close(); +- out.close(); +- +- LZ4BlockInputStream in = new LZ4BlockInputStream(new ByteArrayInputStream(bytes.toByteArray())); +- byte[] actual = new byte[testBytes.length]; +- in.read(actual); +- +- assertArrayEquals(testBytes, actual); +- +- in.close(); +- in.close(); +- } +- +- private static int readFully(InputStream in, byte[] b) throws IOException { +- int total; +- int result; +- for (total = 0; total < b.length; total += result) { +- result = in.read(b, total, b.length - total); +- if(result == -1) { +- break; +- } +- } +- return total; +- } +- +- @Test +- public void testConcatenationOfSerializedStreams() throws IOException { +- final byte[] testBytes1 = randomArray(64, 256); +- final byte[] testBytes2 = randomArray(64, 256); +- byte[] expected = new byte[128]; +- System.arraycopy(testBytes1, 0, expected, 0, 64); +- System.arraycopy(testBytes2, 0, expected, 64, 64); +- +- ByteArrayOutputStream bytes1os = new ByteArrayOutputStream(); +- LZ4BlockOutputStream out1 = new LZ4BlockOutputStream(bytes1os); +- out1.write(testBytes1); +- out1.close(); +- +- ByteArrayOutputStream bytes2os = new ByteArrayOutputStream(); +- LZ4BlockOutputStream out2 = new LZ4BlockOutputStream(bytes2os); +- out2.write(testBytes2); +- out2.close(); +- +- byte[] bytes1 = bytes1os.toByteArray(); +- byte[] bytes2 = bytes2os.toByteArray(); +- byte[] concatenatedBytes = new byte[bytes1.length + bytes2.length]; +- System.arraycopy(bytes1, 0, concatenatedBytes, 0, bytes1.length); +- System.arraycopy(bytes2, 0, concatenatedBytes, bytes1.length, bytes2.length); +- +- // In a default behaviour, we can read the first block of the concatenated bytes only +- LZ4BlockInputStream in1 = new LZ4BlockInputStream(new ByteArrayInputStream(concatenatedBytes)); +- byte[] actual1 = new byte[128]; +- assertEquals(64, readFully(in1, actual1)); +- assertEquals(-1, in1.read()); +- in1.close(); +- +- // Check if we can read concatenated byte stream +- LZ4BlockInputStream in2 = new LZ4BlockInputStream(new ByteArrayInputStream(concatenatedBytes), false); +- byte[] actual2 = new byte[128]; +- assertEquals(128, readFully(in2, actual2)); +- assertEquals(-1, in2.read()); +- in2.close(); +- +- assertArrayEquals(expected, actual2); +- } +-} +diff --git a/src/test/net/jpountz/lz4/LZ4Test.java b/src/test/net/jpountz/lz4/LZ4Test.java +deleted file mode 100644 +index 161899c..0000000 +--- a/src/test/net/jpountz/lz4/LZ4Test.java ++++ /dev/null +@@ -1,562 +0,0 @@ +-package net.jpountz.lz4; +- +-/* +- * 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. +- */ +- +-import static net.jpountz.lz4.Instances.COMPRESSORS; +-import static net.jpountz.lz4.Instances.FAST_DECOMPRESSORS; +-import static net.jpountz.lz4.Instances.SAFE_DECOMPRESSORS; +- +-import java.io.ByteArrayOutputStream; +-import java.io.IOException; +-import java.nio.ByteBuffer; +-import java.nio.ReadOnlyBufferException; +-import java.util.Arrays; +-import java.io.File; +-import java.io.FilenameFilter; +- +-import org.junit.Test; +-import static org.junit.Assert.*; +- +-import com.carrotsearch.randomizedtesting.annotations.Repeat; +- +-public class LZ4Test extends AbstractLZ4Test { +- +- @Test +- public void testLockFileOfTemporaryNativeLibrary() { +- // Load the native library +- LZ4JNI.LZ4_compressBound(100); +- String tempFolder = new File(System.getProperty("java.io.tmpdir")).getAbsolutePath(); +- File tempDir = new File(new File(System.getProperty("java.io.tmpdir")).getAbsolutePath()); +- if (!System.getProperty("os.name").contains("Windows")) { +- // A temporary library must be accompanied by a lock file. +- // On Windows, JVM does not remove a temporary library on exit. +- // This means on Windows, there might be a temporary library +- // that is not accompanied by a lock file when there was +- // a Java process using lz4-java that was running concurrently +- // to this test process. +- File[] tempLibFiles = tempDir.listFiles(new FilenameFilter() { +- public boolean accept(File dir, String name) { +- return name.startsWith("liblz4-java-") && !name.endsWith(".lck"); +- } +- }); +- if (tempLibFiles != null) { +- for (File tempLibFile : tempLibFiles) { +- File lckFile = new File(tempLibFile.getAbsolutePath() + ".lck"); +- assertTrue(tempLibFile.getAbsolutePath(), lckFile.exists()); +- } +- } +- } +- // A lock file must be accompanied by a temporary library. +- File[] tempLockFiles = tempDir.listFiles(new FilenameFilter() { +- public boolean accept(File dir, String name) { +- return name.startsWith("liblz4-java-") && name.endsWith(".lck"); +- } +- }); +- if (tempLockFiles != null) { +- for (File tempLockFile : tempLockFiles) { +- String tempLockFilePath = tempLockFile.getAbsolutePath(); +- File libFile = new File(tempLockFilePath.substring(0, tempLockFilePath.length() - 4)); +- assertTrue(tempLockFilePath, libFile.exists()); +- } +- } +- } +- +- @Test +- @Repeat(iterations=50) +- public void testMaxCompressedLength() { +- final int len = randomBoolean() ? randomInt(16) : randomInt(1 << 30); +- for (LZ4Compressor compressor : COMPRESSORS) { +- assertEquals(LZ4JNI.LZ4_compressBound(len), compressor.maxCompressedLength(len)); +- } +- } +- +- private static byte[] getCompressedWorstCase(byte[] decompressed) { +- ByteArrayOutputStream baos = new ByteArrayOutputStream(); +- int len = decompressed.length; +- if (len >= LZ4Constants.RUN_MASK) { +- baos.write(LZ4Constants.RUN_MASK << LZ4Constants.ML_BITS); +- len -= LZ4Constants.RUN_MASK; +- } +- while (len >= 255) { +- baos.write(255); +- len -= 255; +- } +- baos.write(len); +- try { +- baos.write(decompressed); +- } catch (IOException e) { +- throw new AssertionError(); +- } +- return baos.toByteArray(); +- } +- +- @Test +- public void testEmpty() { +- testRoundTrip(new byte[0]); +- } +- +- public void testUncompressWorstCase(LZ4FastDecompressor decompressor) { +- final int len = randomInt(100 * 1024); +- final int max = randomIntBetween(1, 255); +- byte[] decompressed = randomArray(len, max); +- byte[] compressed = getCompressedWorstCase(decompressed); +- byte[] restored = new byte[decompressed.length]; +- int cpLen = decompressor.decompress(compressed, 0, restored, 0, decompressed.length); +- assertEquals(compressed.length, cpLen); +- assertArrayEquals(decompressed, restored); +- } +- +- @Test +- public void testUncompressWorstCase() { +- for (LZ4FastDecompressor decompressor : FAST_DECOMPRESSORS) { +- testUncompressWorstCase(decompressor); +- } +- } +- +- public void testUncompressWorstCase(LZ4SafeDecompressor decompressor) { +- final int len = randomInt(100 * 1024); +- final int max = randomIntBetween(1, 256); +- byte[] decompressed = randomArray(len, max); +- byte[] compressed = getCompressedWorstCase(decompressed); +- byte[] restored = new byte[decompressed.length]; +- int uncpLen = decompressor.decompress(compressed, 0, compressed.length, restored, 0); +- assertEquals(decompressed.length, uncpLen); +- assertArrayEquals(decompressed, restored); +- } +- +- @Test +- public void testUncompressSafeWorstCase() { +- for (LZ4SafeDecompressor decompressor : SAFE_DECOMPRESSORS) { +- testUncompressWorstCase(decompressor); +- } +- } +- +- public void testRoundTrip(byte[] data, int off, int len, +- LZ4Compressor compressor, +- LZ4FastDecompressor decompressor, +- LZ4SafeDecompressor decompressor2) { +- for (Tester tester : Arrays.asList(Tester.BYTE_ARRAY, Tester.BYTE_BUFFER, Tester.BYTE_ARRAY_WITH_LENGTH, Tester.BYTE_BUFFER_WITH_LENGTH)) { +- testRoundTrip(tester, data, off, len, compressor, decompressor, decompressor2); +- } +- } +- +- public void testRoundTrip( +- Tester tester, +- byte[] data, int off, int len, +- LZ4Compressor compressor, +- LZ4FastDecompressor decompressor, +- LZ4SafeDecompressor decompressor2) { +- final int maxCompressedLength = tester.maxCompressedLength(len); +- // "maxCompressedLength + 1" for the over-estimated compressed length test below +- final T compressed = tester.allocate(maxCompressedLength + 1); +- final int compressedLen = tester.compress(compressor, +- tester.copyOf(data), off, len, +- compressed, 0, maxCompressedLength); +- +- // test decompression +- final T restored = tester.allocate(len); +- assertEquals(compressedLen, tester.decompress(decompressor, compressed, 0, restored, 0, len)); +- assertArrayEquals(Arrays.copyOfRange(data, off, off + len), tester.copyOf(restored, 0, len)); +- +- // make sure it fails if the compression dest is not large enough +- tester.fill(restored, randomByte()); +- final T compressed2 = tester.allocate(compressedLen-1); +- try { +- final int compressedLen2 = tester.compress(compressor, +- tester.copyOf(data), off, len, +- compressed2, 0, compressedLen - 1); +- // Compression can succeed even with the smaller dest +- // because the compressor is allowed to return different compression results +- // even when it is invoked with the same input data. +- // In this case, just make sure the compressed data can be successfully decompressed. +- assertEquals(compressedLen2, tester.decompress(decompressor, compressed2, 0, restored, 0, len)); +- assertArrayEquals(Arrays.copyOfRange(data, off, off + len), tester.copyOf(restored, 0, len)); +- } catch (LZ4Exception e) { +- // OK +- } +- +- if (tester != Tester.BYTE_ARRAY_WITH_LENGTH && tester != Tester.BYTE_BUFFER_WITH_LENGTH) { +- if (len > 0) { +- // decompression dest is too small +- try { +- tester.decompress(decompressor, compressed, 0, restored, 0, len - 1); +- fail(); +- } catch (LZ4Exception e) { +- // OK +- } +- } +- +- // decompression dest is too large +- final T restored2 = tester.allocate(len+1); +- try { +- final int cpLen = tester.decompress(decompressor, compressed, 0, restored2, 0, len + 1); +- fail("compressedLen=" + cpLen); +- } catch (LZ4Exception e) { +- // OK +- } +- +- // try decompression when only the size of the compressed buffer is known +- if (len > 0) { +- tester.fill(restored, randomByte()); +- assertEquals(len, tester.decompress(decompressor2, compressed, 0, compressedLen, restored, 0, len)); +- assertArrayEquals(Arrays.copyOfRange(data, off, off + len), tester.copyOf(restored, 0, len)); +- tester.fill(restored, randomByte()); +- } else { +- assertEquals(0, tester.decompress(decompressor2, compressed, 0, compressedLen, tester.allocate(1), 0, 1)); +- } +- +- // over-estimated compressed length +- try { +- final int decompressedLen = tester.decompress(decompressor2, compressed, 0, compressedLen + 1, tester.allocate(len + 100), 0, len + 100); +- fail("decompressedLen=" + decompressedLen); +- } catch (LZ4Exception e) { +- // OK +- } +- +- // under-estimated compressed length +- try { +- final int decompressedLen = tester.decompress(decompressor2, compressed, 0, compressedLen - 1, tester.allocate(len + 100), 0, len + 100); +- if (!(decompressor2 instanceof LZ4JNISafeDecompressor)) { +- fail("decompressedLen=" + decompressedLen); +- } +- } catch (LZ4Exception e) { +- // OK +- } +- } +- } +- +- public void testRoundTrip(byte[] data, int off, int len, LZ4Factory compressorFactory, LZ4Factory decompressorFactory) { +- for (LZ4Compressor compressor : Arrays.asList( +- compressorFactory.fastCompressor(), compressorFactory.highCompressor())) { +- testRoundTrip(data, off, len, compressor, decompressorFactory.fastDecompressor(), decompressorFactory.safeDecompressor()); +- } +- } +- +- public void testRoundTrip(byte[] data, int off, int len) { +- for (LZ4Factory compressorFactory : Arrays.asList( +- LZ4Factory.nativeInstance(), +- LZ4Factory.unsafeInstance(), +- LZ4Factory.safeInstance())) { +- for (LZ4Factory decompressorFactory : Arrays.asList( +- LZ4Factory.nativeInstance(), +- LZ4Factory.unsafeInstance(), +- LZ4Factory.safeInstance())) { +- testRoundTrip(data, off, len, compressorFactory, decompressorFactory); +- } +- } +- } +- +- public void testRoundTrip(byte[] data) { +- testRoundTrip(data, 0, data.length); +- } +- +- public void testRoundTrip(String resource) throws IOException { +- final byte[] data = readResource(resource); +- testRoundTrip(data); +- } +- +- @Test +- public void testRoundtripGeo() throws IOException { +- testRoundTrip("/calgary/geo"); +- } +- +- @Test +- public void testRoundtripBook1() throws IOException { +- testRoundTrip("/calgary/book1"); +- } +- +- @Test +- public void testRoundtripPic() throws IOException { +- testRoundTrip("/calgary/pic"); +- } +- +- @Test +- public void testNullMatchDec() { +- // 1 literal, 4 matchs with matchDec=0, 8 literals +- final byte[] invalid = new byte[] { 16, 42, 0, 0, (byte) 128, 42, 42, 42, 42, 42, 42, 42, 42 }; +- // decompression should neither throw an exception nor loop indefinitely +- for (LZ4FastDecompressor decompressor : FAST_DECOMPRESSORS) { +- decompressor.decompress(invalid, 0, new byte[13], 0, 13); +- } +- for (LZ4SafeDecompressor decompressor : SAFE_DECOMPRESSORS) { +- decompressor.decompress(invalid, 0, invalid.length, new byte[20], 0); +- } +- } +- +- @Test +- public void testEndsWithMatch() { +- // 6 literals, 4 matchs +- final byte[] invalid = new byte[] { 96, 42, 43, 44, 45, 46, 47, 5, 0 }; +- final int decompressedLength = 10; +- +- for (LZ4FastDecompressor decompressor : FAST_DECOMPRESSORS) { +- try { +- // it is invalid to end with a match, should be at least 5 literals +- decompressor.decompress(invalid, 0, new byte[decompressedLength], 0, decompressedLength); +- assertTrue(decompressor.toString(), false); +- } catch (LZ4Exception e) { +- // OK +- } +- } +- +- for (LZ4SafeDecompressor decompressor : SAFE_DECOMPRESSORS) { +- try { +- // it is invalid to end with a match, should be at least 5 literals +- decompressor.decompress(invalid, 0, invalid.length, new byte[20], 0); +- assertTrue(false); +- } catch (LZ4Exception e) { +- // OK +- } +- } +- } +- +- @Test +- public void testEndsWithLessThan5Literals() { +- // 6 literals, 4 matchs +- final byte[] invalidBase = new byte[] { 96, 42, 43, 44, 45, 46, 47, 5, 0 }; +- +- for (int i = 1; i < 5; ++i) { +- final byte[] invalid = Arrays.copyOf(invalidBase, invalidBase.length + 1 + i); +- invalid[invalidBase.length] = (byte) (i << 4); // i literals at the end +- +- for (LZ4FastDecompressor decompressor : FAST_DECOMPRESSORS) { +- try { +- // it is invalid to end with a match, should be at least 5 literals +- decompressor.decompress(invalid, 0, new byte[20], 0, 20); +- assertTrue(decompressor.toString(), false); +- } catch (LZ4Exception e) { +- // OK +- } +- } +- +- for (LZ4SafeDecompressor decompressor : SAFE_DECOMPRESSORS) { +- try { +- // it is invalid to end with a match, should be at least 5 literals +- decompressor.decompress(invalid, 0, invalid.length, new byte[20], 0); +- assertTrue(false); +- } catch (LZ4Exception e) { +- // OK +- } +- } +- } +- } +- +- @Test +- public void testWriteToReadOnlyBuffer() { +- for (LZ4Compressor compressor : COMPRESSORS) { +- ByteBuffer in = Tester.BYTE_BUFFER.copyOf(new byte[] {2, 3}); +- ByteBuffer out = Tester.BYTE_BUFFER.allocate(100).asReadOnlyBuffer(); +- try { +- compressor.compress(in, out); +- fail(); +- } catch (ReadOnlyBufferException e) { +- // ok +- } +- } +- for (LZ4SafeDecompressor decompressor : SAFE_DECOMPRESSORS) { +- ByteBuffer in = Tester.BYTE_BUFFER.copyOf(COMPRESSORS[0].compress(new byte[] {2, 3})); +- ByteBuffer out = Tester.BYTE_BUFFER.allocate(100).asReadOnlyBuffer(); +- try { +- decompressor.decompress(in, out); +- fail(); +- } catch (ReadOnlyBufferException e) { +- // ok +- } +- } +- for (LZ4FastDecompressor decompressor : FAST_DECOMPRESSORS) { +- ByteBuffer in = Tester.BYTE_BUFFER.copyOf(COMPRESSORS[0].compress(new byte[] {2, 3})); +- ByteBuffer out = Tester.BYTE_BUFFER.allocate(100).asReadOnlyBuffer(); +- out.limit(2); +- try { +- decompressor.decompress(in, out); +- fail(); +- } catch (ReadOnlyBufferException e) { +- // ok +- } +- } +- } +- +- @Test +- @Repeat(iterations=5) +- public void testAllEqual() { +- final int len = randomBoolean() ? randomInt(20) : randomInt(100000); +- final byte[] buf = new byte[len]; +- Arrays.fill(buf, randomByte()); +- testRoundTrip(buf); +- } +- +- @Test +- public void testMaxDistance() { +- final int len = randomIntBetween(1 << 17, 1 << 18); +- final int off = randomInt(len - (1 << 16) - (1 << 15)); +- final byte[] buf = new byte[len]; +- for (int i = 0; i < (1 << 15); ++i) { +- buf[off + i] = randomByte(); +- } +- System.arraycopy(buf, off, buf, off + 65535, 1 << 15); +- testRoundTrip(buf); +- } +- +- @Test +- @Repeat(iterations=10) +- public void testRandomData() { +- final int n = randomIntBetween(1, 15); +- final int off = randomInt(1000); +- final int len = randomBoolean() ? randomInt(1 << 16) : randomInt(1 << 20); +- final byte[] data = randomArray(off + len + randomInt(100), n); +- testRoundTrip(data, off, len); +- } +- +- @Test +- // https://github.com/jpountz/lz4-java/issues/12 +- public void testRoundtripIssue12() { +- byte[] data = new byte[]{ +- 14, 72, 14, 85, 3, 72, 14, 85, 3, 72, 14, 72, 14, 72, 14, 85, 3, 72, 14, 72, 14, 72, 14, 72, 14, 72, 14, 72, 14, 85, 3, 72, +- 14, 85, 3, 72, 14, 85, 3, 72, 14, 85, 3, 72, 14, 85, 3, 72, 14, 85, 3, 72, 14, 50, 64, 0, 46, -1, 0, 0, 0, 29, 3, 85, +- 8, -113, 0, 68, -97, 3, 0, 2, 3, -97, 6, 0, 68, -113, 0, 2, 3, -97, 6, 0, 68, -113, 0, 2, 3, 85, 8, -113, 0, 68, -97, 3, +- 0, 2, 3, -97, 6, 0, 68, -113, 0, 2, 3, -97, 6, 0, 68, -113, 0, 2, 3, -97, 6, 0, 68, -113, 0, 2, 3, -97, 6, 0, 68, -113, +- 0, 2, 3, -97, 6, 0, 68, -113, 0, 2, 3, -97, 6, 0, 68, -113, 0, 2, 3, -97, 6, 0, 68, -113, 0, 2, 3, -97, 6, 0, 68, -113, +- 0, 2, 3, -97, 6, 0, 68, -113, 0, 2, 3, -97, 6, 0, 68, -113, 0, 50, 64, 0, 47, -105, 0, 0, 0, 30, 3, -97, 6, 0, 68, -113, +- 0, 2, 3, -97, 6, 0, 68, -113, 0, 2, 3, 85, 8, -113, 0, 68, -97, 3, 0, 2, 3, 85, 8, -113, 0, 68, -97, 3, 0, 2, 3, 85, +- 8, -113, 0, 68, -97, 3, 0, 2, -97, 6, 0, 2, 3, 85, 8, -113, 0, 68, -97, 3, 0, 2, 3, -97, 6, 0, 68, -113, 0, 2, 3, -97, +- 6, 0, 68, -113, 0, 120, 64, 0, 48, 4, 0, 0, 0, 31, 34, 72, 29, 72, 37, 72, 35, 72, 45, 72, 23, 72, 46, 72, 20, 72, 40, 72, +- 33, 72, 25, 72, 39, 72, 38, 72, 26, 72, 28, 72, 42, 72, 24, 72, 27, 72, 36, 72, 41, 72, 32, 72, 18, 72, 30, 72, 22, 72, 31, 72, +- 43, 72, 19, 72, 34, 72, 29, 72, 37, 72, 35, 72, 45, 72, 23, 72, 46, 72, 20, 72, 40, 72, 33, 72, 25, 72, 39, 72, 38, 72, 26, 72, +- 28, 72, 42, 72, 24, 72, 27, 72, 36, 72, 41, 72, 32, 72, 18, 72, 30, 72, 22, 72, 31, 72, 43, 72, 19, 72, 34, 72, 29, 72, 37, 72, +- 35, 72, 45, 72, 23, 72, 46, 72, 20, 72, 40, 72, 33, 72, 25, 72, 39, 72, 38, 72, 26, 72, 28, 72, 42, 72, 24, 72, 27, 72, 36, 72, +- 41, 72, 32, 72, 18, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +- 0, 39, 24, 32, 34, 124, 0, 120, 64, 0, 48, 80, 0, 0, 0, 31, 30, 72, 22, 72, 31, 72, 43, 72, 19, 72, 34, 72, 29, 72, 37, 72, +- 35, 72, 45, 72, 23, 72, 46, 72, 20, 72, 40, 72, 33, 72, 25, 72, 39, 72, 38, 72, 26, 72, 28, 72, 42, 72, 24, 72, 27, 72, 36, 72, +- 41, 72, 32, 72, 18, 72, 30, 72, 22, 72, 31, 72, 43, 72, 19, 72, 34, 72, 29, 72, 37, 72, 35, 72, 45, 72, 23, 72, 46, 72, 20, 72, +- 40, 72, 33, 72, 25, 72, 39, 72, 38, 72, 26, 72, 28, 72, 42, 72, 24, 72, 27, 72, 36, 72, 41, 72, 32, 72, 18, 72, 30, 72, 22, 72, +- 31, 72, 43, 72, 19, 72, 34, 72, 29, 72, 37, 72, 35, 72, 45, 72, 23, 72, 46, 72, 20, 72, 40, 72, 33, 72, 25, 72, 39, 72, 38, 72, +- 26, 72, 28, 72, 42, 72, 24, 72, 27, 72, 36, 72, 41, 72, 32, 72, 18, 72, 30, 72, 22, 72, 31, 72, 43, 72, 19, 72, 34, 72, 29, 72, +- 37, 72, 35, 72, 45, 72, 23, 72, 46, 72, 20, 72, 40, 72, 33, 72, 25, 72, 39, 72, 38, 72, 26, 72, 28, 72, 42, 72, 24, 72, 27, 72, +- 36, 72, 41, 72, 32, 72, 18, 72, 30, 72, 22, 72, 31, 72, 43, 72, 19, 72, 34, 72, 29, 72, 37, 72, 35, 72, 45, 72, 23, 72, 46, 72, +- 20, 72, 40, 72, 33, 72, 25, 72, 39, 72, 38, 72, 26, 72, 28, 72, 42, 72, 24, 72, 27, 72, 36, 72, 41, 72, 32, 72, 18, 72, 30, 72, +- 22, 72, 31, 72, 43, 72, 19, 72, 34, 72, 29, 72, 37, 72, 35, 72, 45, 72, 23, 72, 46, 72, 20, 72, 40, 72, 33, 72, 25, 72, 39, 72, +- 38, 72, 26, 72, 28, 72, 42, 72, 24, 72, 27, 72, 36, 72, 41, 72, 32, 72, 18, 72, 30, 72, 22, 72, 31, 72, 43, 72, 19, 72, 34, 72, +- 29, 72, 37, 72, 35, 72, 45, 72, 23, 72, 46, 72, 20, 72, 40, 72, 33, 72, 25, 72, 39, 72, 38, 72, 26, 72, 28, 72, 42, 72, 24, 72, +- 27, 72, 36, 72, 41, 72, 32, 72, 18, 72, 30, 72, 22, 72, 31, 72, 43, 72, 19, 50, 64, 0, 49, 20, 0, 0, 0, 32, 3, -97, 6, 0, +- 68, -113, 0, 2, 3, 85, 8, -113, 0, 68, -97, 3, 0, 2, 3, -97, 6, 0, 68, -113, 0, 2, 3, -97, 6, 0, 68, -113, 0, 2, 3, -97, +- 6, 0, 68, -113, 0, 2, 3, 85, 8, -113, 0, 68, -97, 3, 0, 2, 3, -97, 6, 0, 68, -113, 0, 2, 3, -97, 6, 0, 68, -113, 0, 2, +- 3, -97, 6, 0, 68, -113, 0, 2, 3, -97, 6, 0, 68, -113, 0, 2, 3, -97, 6, 0, 68, -113, 0, 2, 3, -97, 6, 0, 68, -113, 0, 2, +- 3, -97, 6, 0, 50, 64, 0, 50, 53, 0, 0, 0, 34, 3, -97, 6, 0, 68, -113, 0, 2, 3, 85, 8, -113, 0, 68, -113, 0, 2, 3, -97, +- 6, 0, 68, -113, 0, 2, 3, 85, 8, -113, 0, 68, -113, 0, 2, 3, -97, 6, 0, 68, -113, 0, 2, 3, -97, 6, 0, 68, -113, 0, 2, 3, +- -97, 6, 0, 68, -113, 0, 2, 3, 85, 8, -113, 0, 68, -97, 3, 0, 2, 3, -97, 6, 0, 68, -113, 0, 2, 3, 85, 8, -113, 0, 68, -97, +- 3, 0, 2, 3, 85, 8, -113, 0, 68, -97, 3, 0, 2, 3, -97, 6, 0, 68, -113, 0, 2, 3, 85, 8, -113, 0, 68, -97, 3, 0, 2, 3, +- 85, 8, -113, 0, 68, -97, 3, 0, 2, 3, -97, 6, 0, 68, -113, 0, 2, 3, -97, 6, 0, 68, -113, 0, 2, 3, -97, 6, 0, 68, -113, 0, +- 2, 3, 85, 8, -113, 0, 68, -97, 3, 0, 2, 3, 85, 8, -113, 0, 68, -97, 3, 0, 2, 3, 85, 8, -113, 0, 68, -97, 3, 0, 2, 3, +- -97, 6, 0, 50, 64, 0, 51, 85, 0, 0, 0, 36, 3, 85, 8, -113, 0, 68, -97, 3, 0, 2, 3, -97, 6, 0, 68, -113, 0, 2, 3, -97, +- 6, 0, 68, -113, 0, 2, 3, -97, 6, 0, 68, -113, 0, 2, 3, -97, 6, 0, 68, -113, 0, 2, -97, 5, 0, 2, 3, 85, 8, -113, 0, 68, +- -97, 3, 0, 2, 3, -97, 6, 0, 68, -113, 0, 2, 3, -97, 6, 0, 68, -113, 0, 2, 3, -97, 6, 0, 68, -113, 0, 2, 3, -97, 6, 0, +- 68, -113, 0, 2, 3, -97, 6, 0, 50, -64, 0, 51, -45, 0, 0, 0, 37, 68, -113, 0, 2, 3, -97, 6, 0, 68, -113, 0, 2, 3, -97, 6, +- 0, 68, -113, 0, 2, 3, -97, 6, 0, 68, -113, 0, 2, 3, -97, 6, 0, 68, -113, 0, 2, 3, 85, 8, -113, 0, 68, -113, 0, 2, 3, -97, +- 6, 0, 68, -113, 0, 2, 3, 85, 8, -113, 0, 68, -97, 3, 0, 2, 3, 85, 8, -113, 0, 68, -97, 3, 0, 120, 64, 0, 52, -88, 0, 0, +- 0, 39, 13, 85, 5, 72, 13, 85, 5, 72, 13, 85, 5, 72, 13, 72, 13, 85, 5, 72, 13, 85, 5, 72, 13, 85, 5, 72, 13, 85, 5, 72, +- 13, 72, 13, 85, 5, 72, 13, 85, 5, 72, 13, 72, 13, 72, 13, 85, 5, 72, 13, 85, 5, 72, 13, 85, 5, 72, 13, 85, 5, 72, 13, 85, +- 5, 72, 13, 85, 5, 72, 13, 72, 13, 72, 13, 72, 13, 85, 5, 72, 13, 85, 5, 72, 13, 72, 13, 85, 5, 72, 13, 85, 5, 72, 13, 85, +- 5, 72, 13, 85, 5, 72, 13, 85, 5, 72, 13, 85, 5, 72, 13, 85, 5, 72, 13, 85, 5, 72, 13, 85, 5, 72, 13, 85, 5, 72, 13, 85, +- 5, 72, 13, 85, 5, 72, 13, 72, 13, 72, 13, 72, 13, 85, 5, 72, 13, 85, 5, 72, 13, 85, 5, 72, 13, 72, 13, 85, 5, 72, 13, 72, +- 13, 85, 5, 72, 13, 72, 13, 85, 5, 72, 13, -19, -24, -101, -35 +- }; +- testRoundTrip(data, 9, data.length - 9); +- } +- +- private static void assertCompressedArrayEquals(String message, byte[] expected, byte[] actual) { +- int off = 0; +- int decompressedOff = 0; +- while (true) { +- if (off == expected.length) { +- break; +- } +- final Sequence sequence1 = readSequence(expected, off); +- final Sequence sequence2 = readSequence(actual, off); +- assertEquals(message + ", off=" + off + ", decompressedOff=" + decompressedOff, sequence1, sequence2); +- off += sequence1.length; +- decompressedOff += sequence1.literalLen + sequence1.matchLen; +- } +- } +- +- private static Sequence readSequence(byte[] buf, int off) { +- final int start = off; +- final int token = buf[off++] & 0xFF; +- int literalLen = token >>> 4; +- if (literalLen >= 0x0F) { +- int len; +- while ((len = buf[off++] & 0xFF) == 0xFF) { +- literalLen += 0xFF; +- } +- literalLen += len; +- } +- off += literalLen; +- if (off == buf.length) { +- return new Sequence(literalLen, -1, -1, off - start); +- } +- int matchDec = (buf[off++] & 0xFF) | ((buf[off++] & 0xFF) << 8); +- int matchLen = token & 0x0F; +- if (matchLen >= 0x0F) { +- int len; +- while ((len = buf[off++] & 0xFF) == 0xFF) { +- matchLen += 0xFF; +- } +- matchLen += len; +- } +- matchLen += 4; +- return new Sequence(literalLen, matchDec, matchLen, off - start); +- } +- +- private static class Sequence { +- final int literalLen, matchDec, matchLen, length; +- +- public Sequence(int literalLen, int matchDec, int matchLen, int length) { +- this.literalLen = literalLen; +- this.matchDec = matchDec; +- this.matchLen = matchLen; +- this.length = length; +- } +- +- @Override +- public String toString() { +- return "Sequence [literalLen=" + literalLen + ", matchDec=" + matchDec +- + ", matchLen=" + matchLen + "]"; +- } +- +- @Override +- public int hashCode() { +- return 42; +- } +- +- @Override +- public boolean equals(Object obj) { +- if (this == obj) +- return true; +- if (obj == null) +- return false; +- if (getClass() != obj.getClass()) +- return false; +- Sequence other = (Sequence) obj; +- if (literalLen != other.literalLen) +- return false; +- if (matchDec != other.matchDec) +- return false; +- if (matchLen != other.matchLen) +- return false; +- return true; +- } +- +- } +- +-} +diff --git a/src/test/net/jpountz/xxhash/XXHash32Test.java b/src/test/net/jpountz/xxhash/XXHash32Test.java +deleted file mode 100644 +index 98c9436..0000000 +--- a/src/test/net/jpountz/xxhash/XXHash32Test.java ++++ /dev/null +@@ -1,189 +0,0 @@ +-package net.jpountz.xxhash; +- +-/* +- * 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. +- */ +- +-import java.nio.ByteBuffer; +- +-import net.jpountz.lz4.AbstractLZ4Test; +-import net.jpountz.util.SafeUtils; +- +-import org.junit.Test; +-import static org.junit.Assert.*; +- +-import com.carrotsearch.randomizedtesting.annotations.Repeat; +- +-public class XXHash32Test extends AbstractLZ4Test { +- +- private static abstract class StreamingXXHash32Adapter extends XXHash32 { +- +- protected abstract StreamingXXHash32 streamingHash(int seed); +- +- @Override +- public int hash(byte[] buf, int off, int len, int seed) { +- SafeUtils.checkRange(buf, off, len); +- int originalOff = off; +- int remainingPasses = randomInt(5); +- StreamingXXHash32 h = streamingHash(seed); +- final int end = off + len; +- while (off < end) { +- final int l = randomIntBetween(off, end) - off; +- h.update(buf, off, l); +- off += l; +- if (remainingPasses > 0 && randomInt(5) == 0) { +- h.reset(); +- --remainingPasses; +- off = originalOff; +- } +- if (randomBoolean()) { +- h.getValue(); +- } +- } +- return h.getValue(); +- } +- +- @Override +- public int hash(ByteBuffer buf, int off, int len, int seed) { +- byte[] bytes = new byte[len]; +- int originalPosition = buf.position(); +- try { +- buf.position(off); +- buf.get(bytes, 0, len); +- return hash(bytes, 0, len, seed); +- } finally { +- buf.position(originalPosition); +- } +- } +- +- public String toString() { +- return streamingHash(0).toString(); +- } +- +- } +- +- private static XXHash32[] INSTANCES = new XXHash32[] { +- XXHashFactory.nativeInstance().hash32(), +- XXHashFactory.unsafeInstance().hash32(), +- XXHashFactory.safeInstance().hash32(), +- new StreamingXXHash32Adapter() { +- protected StreamingXXHash32 streamingHash(int seed) { +- return XXHashFactory.nativeInstance().newStreamingHash32(seed); +- } +- }, +- new StreamingXXHash32Adapter() { +- protected StreamingXXHash32 streamingHash(int seed) { +- return XXHashFactory.unsafeInstance().newStreamingHash32(seed); +- } +- }, +- new StreamingXXHash32Adapter() { +- protected StreamingXXHash32 streamingHash(int seed) { +- return XXHashFactory.safeInstance().newStreamingHash32(seed); +- } +- } +- }; +- +- @Test +- public void testEmpty() { +- final int seed = randomInt(); +- for (XXHash32 xxHash : INSTANCES) { +- xxHash.hash(new byte[0], 0, 0, seed); +- xxHash.hash(copyOf(new byte[0], 0, 0), 0, 0, seed); +- } +- } +- +- @Test +- @Repeat(iterations = 20) +- public void testAIOOBE() { +- final int seed = randomInt(); +- final int max = randomBoolean() ? 32 : 1000; +- final int bufLen = randomIntBetween(1, max); +- final byte[] buf = randomArray(bufLen, 256); +- final int off = randomInt(buf.length - 1); +- final int len = randomInt(buf.length - off); +- for (XXHash32 xxHash : INSTANCES) { +- xxHash.hash(buf, off, len, seed); +- xxHash.hash(copyOf(buf, off, len), off, len, seed); +- } +- } +- +- @Test +- @Repeat(iterations=40) +- public void testInstances() { +- final int maxLenLog = randomInt(20); +- final int bufLen = randomInt(1 << maxLenLog); +- byte[] buf = randomArray(bufLen, 256); +- final int seed = randomInt(); +- final int off = randomIntBetween(0, Math.max(0, bufLen - 1)); +- final int len = randomIntBetween(0, bufLen - off); +- +- final int ref = XXHashFactory.nativeInstance().hash32().hash(buf, off, len, seed); +- for (XXHash32 hash : INSTANCES) { +- final int h = hash.hash(buf, off, len, seed); +- assertEquals(hash.toString(), ref, h); +- final ByteBuffer copy = copyOf(buf, off, len); +- final int h2 = hash.hash(copy, off, len, seed); +- assertEquals(off, copy.position()); +- assertEquals(len, copy.remaining()); +- assertEquals(hash.toString(), ref, h2); +- } +- } +- +- @Test +- public void test4GB() { +- byte[] bytes = new byte[randomIntBetween(1 << 22, 1 << 26)]; +- for (int i = 0; i < bytes.length; ++i) { +- bytes[i] = randomByte(); +- } +- final int off = randomInt(5); +- final int len = randomIntBetween(bytes.length - off - 1024, bytes.length - off); +- long totalLen = 0; +- final int seed = randomInt(); +- StreamingXXHash32 hash1 = XXHashFactory.nativeInstance().newStreamingHash32(seed); +- StreamingXXHash32 hash2 = XXHashFactory.unsafeInstance().newStreamingHash32(seed); +- StreamingXXHash32 hash3 = XXHashFactory.safeInstance().newStreamingHash32(seed); +- while (totalLen < (1L << 33)) { +- hash1.update(bytes, off, len); +- hash2.update(bytes, off, len); +- hash3.update(bytes, off, len); +- assertEquals(hash2.toString() + " " + totalLen, hash1.getValue(), hash2.getValue()); +- assertEquals(hash3.toString() + " " + totalLen, hash1.getValue(), hash3.getValue()); +- totalLen += len; +- } +- } +- +- @Test +- public void testClose() { +- StreamingXXHash32 hash = XXHashFactory.nativeInstance().newStreamingHash32(randomInt()); +- hash.close(); +- hash.close(); +- try { +- hash.getValue(); +- assertTrue(hash.toString(), false); +- } catch (AssertionError e) { +- // OK +- } +- try { +- hash.update(null, 0, 0); +- assertTrue(hash.toString(), false); +- } catch (AssertionError e) { +- // OK +- } +- try { +- hash.reset(); +- assertTrue(hash.toString(), false); +- } catch (AssertionError e) { +- // OK +- } +- } +-} +diff --git a/src/test/net/jpountz/xxhash/XXHash64Test.java b/src/test/net/jpountz/xxhash/XXHash64Test.java +deleted file mode 100644 +index dadbeda..0000000 +--- a/src/test/net/jpountz/xxhash/XXHash64Test.java ++++ /dev/null +@@ -1,194 +0,0 @@ +-package net.jpountz.xxhash; +- +-/* +- * 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. +- */ +- +-import java.nio.ByteBuffer; +- +-import net.jpountz.lz4.AbstractLZ4Test; +-import net.jpountz.util.SafeUtils; +- +-import org.junit.Test; +-import static org.junit.Assert.*; +- +-import com.carrotsearch.randomizedtesting.annotations.Repeat; +- +-public class XXHash64Test extends AbstractLZ4Test { +- +- private static abstract class StreamingXXHash64Adapter extends XXHash64 { +- +- protected abstract StreamingXXHash64 streamingHash(long seed); +- +- @Override +- public long hash(byte[] buf, int off, int len, long seed) { +- SafeUtils.checkRange(buf, off, len); +- int originalOff = off; +- int remainingPasses = randomInt(5); +- StreamingXXHash64 h = streamingHash(seed); +- final int end = off + len; +- while (off < end) { +- final int l = randomIntBetween(off, end) - off; +- h.update(buf, off, l); +- off += l; +- if (remainingPasses > 0 && randomInt(5) == 0) { +- h.reset(); +- --remainingPasses; +- off = originalOff; +- } +- if (randomBoolean()) { +- h.getValue(); +- } +- } +- return h.getValue(); +- } +- +- @Override +- public long hash(ByteBuffer buf, int off, int len, long seed) { +- byte[] bytes = new byte[len]; +- int originalPosition = buf.position(); +- try { +- buf.position(off); +- buf.get(bytes, 0, len); +- return hash(bytes, 0, len, seed); +- } finally { +- buf.position(originalPosition); +- } +- } +- +- public String toString() { +- return streamingHash(0).toString(); +- } +- +- } +- +- private static XXHash64[] INSTANCES = new XXHash64[] { +- XXHashFactory.nativeInstance().hash64(), +- XXHashFactory.unsafeInstance().hash64(), +- XXHashFactory.safeInstance().hash64(), +- new StreamingXXHash64Adapter() { +- protected StreamingXXHash64 streamingHash(long seed) { +- return XXHashFactory.nativeInstance().newStreamingHash64(seed); +- } +- }, +- new StreamingXXHash64Adapter() { +- protected StreamingXXHash64 streamingHash(long seed) { +- return XXHashFactory.unsafeInstance().newStreamingHash64(seed); +- } +- }, +- new StreamingXXHash64Adapter() { +- protected StreamingXXHash64 streamingHash(long seed) { +- return XXHashFactory.safeInstance().newStreamingHash64(seed); +- } +- } +- }; +- +- @Test +- public void testEmpty() { +- final long seed = randomLong(); +- for (XXHash64 xxHash : INSTANCES) { +- xxHash.hash(new byte[0], 0, 0, seed); +- xxHash.hash(copyOf(new byte[0], 0, 0), 0, 0, seed); +- } +- } +- +- @Test +- @Repeat(iterations = 20) +- public void testAIOOBE() { +- final long seed = randomLong(); +- final int max = randomBoolean() ? 64 : 1000; +- final int bufLen = randomIntBetween(1, max); +- final byte[] buf = new byte[bufLen]; +- for (int i = 0; i < buf.length; ++i) { +- buf[i] = randomByte(); +- } +- final int off = randomInt(buf.length - 1); +- final int len = randomInt(buf.length - off); +- for (XXHash64 xxHash : INSTANCES) { +- xxHash.hash(buf, off, len, seed); +- } +- } +- +- @Test +- @Repeat(iterations=40) +- public void testInstances() { +- final int maxLenLog = randomInt(20); +- final int bufLen = randomInt(1 << maxLenLog); +- byte[] buf = new byte[bufLen]; +- for (int i = 0; i < bufLen; ++i) { +- buf[i] = randomByte(); +- } +- final long seed = randomLong(); +- final int off = randomIntBetween(0, Math.max(0, bufLen - 1)); +- final int len = randomIntBetween(0, bufLen - off); +- +- final long ref = XXHashFactory.nativeInstance().hash64().hash(buf, off, len, seed); +- for (XXHash64 hash : INSTANCES) { +- final long h = hash.hash(buf, off, len, seed); +- assertEquals(hash.toString(), ref, h); +- final ByteBuffer copy = copyOf(buf, off, len); +- final long h2 = hash.hash(copy, off, len, seed); +- assertEquals(off, copy.position()); +- assertEquals(len, copy.remaining()); +- assertEquals(hash.toString(), ref, h2); +- } +- } +- +- @Test +- public void test4GB() { +- byte[] bytes = new byte[randomIntBetween(1 << 22, 1 << 26)]; +- for (int i = 0; i < bytes.length; ++i) { +- bytes[i] = randomByte(); +- } +- final int off = randomInt(5); +- final int len = randomIntBetween(bytes.length - off - 1024, bytes.length - off); +- long totalLen = 0; +- final long seed = randomLong(); +- StreamingXXHash64 hash1 = XXHashFactory.nativeInstance().newStreamingHash64(seed); +- StreamingXXHash64 hash2 = XXHashFactory.unsafeInstance().newStreamingHash64(seed); +- StreamingXXHash64 hash3 = XXHashFactory.safeInstance().newStreamingHash64(seed); +- while (totalLen < (1L << 33)) { +- hash1.update(bytes, off, len); +- hash2.update(bytes, off, len); +- hash3.update(bytes, off, len); +- assertEquals(hash2.toString() + " " + totalLen, hash1.getValue(), hash2.getValue()); +- assertEquals(hash3.toString() + " " + totalLen, hash1.getValue(), hash3.getValue()); +- totalLen += len; +- } +- } +- +- @Test +- public void testClose() { +- StreamingXXHash64 hash = XXHashFactory.nativeInstance().newStreamingHash64(randomInt()); +- hash.close(); +- hash.close(); +- try { +- hash.getValue(); +- assertTrue(hash.toString(), false); +- } catch (AssertionError e) { +- // OK +- } +- try { +- hash.update(null, 0, 0); +- assertTrue(hash.toString(), false); +- } catch (AssertionError e) { +- // OK +- } +- try { +- hash.reset(); +- assertTrue(hash.toString(), false); +- } catch (AssertionError e) { +- // OK +- } +- } +-} diff --git a/SOURCES/4-remove-javaversion.patch b/SOURCES/4-remove-javaversion.patch new file mode 100644 index 0000000..5b10a42 --- /dev/null +++ b/SOURCES/4-remove-javaversion.patch @@ -0,0 +1,15 @@ +diff --git a/build.xml b/build.xml +index 8c08fd3..b46990d 100644 +--- a/build.xml ++++ b/build.xml +@@ -54,10 +54,6 @@ + + + +- +- +- +- + + + diff --git a/SOURCES/5-build-libs.patch b/SOURCES/5-build-libs.patch new file mode 100644 index 0000000..f7e249f --- /dev/null +++ b/SOURCES/5-build-libs.patch @@ -0,0 +1,44 @@ +diff --git a/Makefile b/Makefile +index 3495c8f..7b20f5c 100644 +--- a/Makefile ++++ b/Makefile +@@ -4,22 +4,24 @@ BUILD_DIR = build + OBJECTS_DIR = $(BUILD_DIR)/objects + JNI_HEADERS_DIR = $(BUILD_DIR)/jni-headers + JNI_SOURCES_DIR = src/jni +-INCLUDE = -I $(JAVA_HOME)/include -I $(JAVA_HOME)/include/linux ++LZ4_LIB_DIR = src/lz4/lib ++INCLUDE = -I $(JAVA_HOME)/include -I $(JAVA_HOME)/include/linux -I $(LZ4_LIB_DIR) + +-LIBS = -llz4 -lxxhash + JNI_PREFIX = net_jpountz_ + + default: all move_objects generate_so + + all: ++ $(CC) -shared -o $(BUILD_DIR)/liblz4.so -fPIC $(LZ4_LIB_DIR)/lz4.c ++ $(CC) -shared -o $(BUILD_DIR)/liblz4hc.so -fPIC $(LZ4_LIB_DIR)/lz4hc.c ++ $(CC) -shared -o $(BUILD_DIR)/liblz4frame.so -fPIC $(LZ4_LIB_DIR)/lz4frame.c ++ $(CC) -shared -o $(BUILD_DIR)/libxxhash.so -fPIC $(LZ4_LIB_DIR)/xxhash.c + $(CC) -fPIC -I $(JNI_HEADERS_DIR) \ + $(INCLUDE) \ +- $(LIBS) \ + -c $(JNI_SOURCES_DIR)/$(JNI_PREFIX)lz4_LZ4JNI.c + + $(CC) -fPIC -I $(JNI_HEADERS_DIR) \ + $(INCLUDE) \ +- $(LIBS) \ + -c $(JNI_SOURCES_DIR)/$(JNI_PREFIX)xxhash_XXHashJNI.c + + move_objects: +@@ -28,6 +30,8 @@ move_objects: + generate_so: + gcc -fPIC -shared \ + $(OBJECTS_DIR)/*.o \ +- $(LIB_DIR)/liblz4.so \ +- $(LIB_DIR)/libxxhash.so \ ++ $(BUILD_DIR)/liblz4.so \ ++ $(BUILD_DIR)/liblz4hc.so \ ++ $(BUILD_DIR)/liblz4frame.so \ ++ $(BUILD_DIR)/libxxhash.so \ + -o $(BUILD_DIR)/jni/net/jpountz/util/$(PLATFORM)/$(ARCH)/liblz4-java.so diff --git a/SPECS/lz4-java.spec b/SPECS/lz4-java.spec new file mode 100644 index 0000000..e83b152 --- /dev/null +++ b/SPECS/lz4-java.spec @@ -0,0 +1,206 @@ +# empty debuginfo +%global debug_package %nil +%global lz4_version 1.9.2 + +Name: lz4-java +Version: 1.7.1 +Release: 14%{?dist} +Summary: LZ4 compression for Java +# GPL: +# src/lz4/ +# BSD: +# src/lz4/libs +License: ASL 2.0 and (BSD and GPLv2+) +# GPLv2+ and BSD for lz4 and xxhash libs that are shared in liblz4-java.so +URL: https://github.com/lz4/lz4-java +Source0: https://github.com/lz4/lz4-java/archive/%{version}.tar.gz +Source1: https://github.com/lz4/lz4/archive/v%{lz4_version}.tar.gz + +# lz4-java v1.3.0 introduced usage of sun.misc.Unsafe, which would later become +# depricated in jdk 9 and kept as an unexposed API in later jdk releases. +# lz4-java optionally uses Unsafe to achieve faster compression and decompression, +# however it's implementation is not critical to functionality, and can be removed. +Patch0: 0-remove-unsafe.patch +# After updating mvel to version 2.4.10, MVEL generated classes have formatting issues where +# code after comments are not being formatted with new lines. As a result, including comments +# in the templates results in classes with invalid code following the first comment. +# This patch simply removes comments from the templates so the classes can be generated as expected. +# Related bug: https://github.com/mvel/mvel/issues/152 +Patch1: 1-remove-comments-from-templates.patch +# Adds a simple makefile to be run in-place of the cpptasks in the build.xml +Patch2: 2-remove-cpptasks.patch +# some lz4-java tests require randomizedtesting, which is not currently +# shipped or maintained in Fedora; remove those and use system ant-junit to run applicable tests +Patch3: 3-remove-randomizedtesting-tests.patch +# RHSCL: condition doesn't support the nested "javaversion" element +Patch4: 4-remove-javaversion.patch +# RHSCL: build missing lz4 and xxhash libs required for liblz4-java.so +Patch5: 5-build-libs.patch + +ExclusiveArch: x86_64 + +# Build tools +BuildRequires: apache-parent +BuildRequires: ant +BuildRequires: ant-junit +BuildRequires: aqute-bnd +BuildRequires: gcc +BuildRequires: ivy-local +BuildRequires: java-devel +BuildRequires: javapackages-local +BuildRequires: lz4 +BuildRequires: mvel +BuildRequires: objectweb-asm +BuildRequires: xerces-j2 + +Provides: bundled(xxhash) = r37 +Provides: bundled(lz4) = 1.9.2 + +%description +LZ4 compression for Java, based on Yann Collet's work. +This library provides access to two compression methods +that both generate a valid LZ4 stream: + +* fast scan (LZ4): + ° low memory footprint (~ 16 KB), + ° very fast (fast scan with skipping heuristics in case the + input looks incompressible), + ° reasonable compression ratio (depending on the + redundancy of the input). +* high compression (LZ4 HC): + ° medium memory footprint (~ 256 KB), + ° rather slow (~ 10 times slower than LZ4), + ° good compression ratio (depending on the size and + the redundancy of the input). + +The streams produced by those 2 compression algorithms use the +same compression format, are very fast to decompress and can be +decompressed by the same decompressor instance. + +%package javadoc +Summary: Javadoc for %{name} +BuildArch: noarch + +%description javadoc +This package contains javadoc for %{name}. + +%prep +%setup -q -n %{name}-%{version} +%setup -q -T -D -a 1 -n %{name}-%{version} + +mv lz4-1.9.2/* src/lz4/ + +%patch0 -p1 +%patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 +%patch5 -p1 + +# Cleanup +find -name '*.dylib' -print -delete +find -name '*.so' -print -delete + +%build + export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk + +ant -Divy.mode=local -Divy.revision=1.7.1 -Divy.pom.version=1.7.1 jar test docs makepom +bnd wrap -p lz4-java.bnd -o dist/lz4-java-%{version}.jar --version %{version} dist/lz4-java.jar + +%install +%mvn_artifact dist/lz4-java-%{version}.pom dist/lz4-java-%{version}.jar +%mvn_install -J build/docs + +%files -f .mfiles +%doc CHANGES.md README.md + +%files javadoc -f .mfiles-javadoc +%license LICENSE.txt + +%changelog +* Fri Feb 19 2021 Alex Macdonald 1.7.1-14 +- Add ExclusiveArch: x86_64 + +* Wed Feb 17 2021 Alex Macdonald 1.7.1-13 +- Bundle missing xxhash and lz4 components & adjust local Makefile + +* Wed Jan 13 2021 Alex Macdonald 1.7.1-12 +- remove hardcoded lib directory in the Makefile + +* Fri Jan 08 2021 Alex Macdonald 1.7.1-11 +- remove hardcoded "amd64" directory path in the Makefile + +* Wed Dec 09 2020 Alex Macdonald 1.7.1-10 +- remove BuildArch: noarch + +* Tue Dec 01 2020 Alex Macdonald 1.7.1-9 +- run unit tests on classes that do not require randomizedtesting +- add liblz4-java.so generation step to Makefile +- remove mvn_file macro for lz4 + +* Thu Nov 19 2020 Alex Macdonald 1.7.1-8 +- remove dependency on cpptasks + +* Mon Nov 16 2020 Alex Macdonald 1.7.1-7 +- cleanup whitespace in the local patch to remove comments from templates +- use system lz4 and xxhash instead of bundling the dependencies + +* Tue Oct 06 2020 Alex Macdonald 1.7.1-6 +- include patch to strip comments from mvel templates + +* Tue Sep 15 2020 Alex Macdonald 1.7.1-5 +- add "BuildArch: noarch" to fix rpmlint error: no-binary + +* Wed Sep 09 2020 Alex Macdonald 1.7.1-4 +- fixed sources to have both lz4-java and lz4 + +* Wed Aug 05 2020 Alex Macdonald 1.7.1-3 +- used commit from Jie Kang's fork of lz4-java to update to upstream 1.7.1 +- this prevents tests from running; eliminates the need for randomizedtesting for f33 onward +- remove dependency on bea-stax +- remove all usage of sun.misc.Unsafe + +* Tue Aug 04 2020 Alex Macdonald 1.7.1-2 +- Included the lz4 submodule inside the lz4-java source tarball + +* Thu Jul 30 2020 Alex Macdonald 1.7.1-1 +- Update to version 1.7.1 + +* Wed Jan 29 2020 Fedora Release Engineering - 1.3.0-13 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild + +* Wed Jul 24 2019 Fabio Valentini - 1.3.0-12 +- Add BuildRequires: gcc to fix FTBFS issue. + +* Fri Feb 01 2019 Fedora Release Engineering - 1.3.0-11 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild + +* Fri Jul 13 2018 Fedora Release Engineering - 1.3.0-10 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild + +* Thu Feb 08 2018 Fedora Release Engineering - 1.3.0-9 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild + +* Thu Aug 03 2017 Fedora Release Engineering - 1.3.0-8 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild + +* Wed Jul 26 2017 Fedora Release Engineering - 1.3.0-7 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + +* Sun Feb 19 2017 gil cattaneo 1.3.0-6 +- disable test suite on ppc64 + +* Fri Feb 10 2017 Fedora Release Engineering - 1.3.0-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild + +* Mon Sep 12 2016 gil cattaneo 1.3.0-4 +- exclude aarch64 + +* Tue May 03 2016 gil cattaneo 1.3.0-3 +- fix test suite + +* Tue May 03 2016 gil cattaneo 1.3.0-2 +- unbundle lz4 code (lz4-java issues#74) + +* Mon Jul 20 2015 gil cattaneo 1.3.0-1 +- initial rpm