Browse Source

Lz4

final/10.0.3
Yee 6 years ago
parent
commit
64abd43f46
  1. 5
      build.third_step6.gradle
  2. BIN
      fine-lz4/resources/com/fr/third/net/jpountz/util/darwin/x86_64/liblz4-java.dylib
  3. BIN
      fine-lz4/resources/com/fr/third/net/jpountz/util/linux/aarch64/liblz4-java.so
  4. BIN
      fine-lz4/resources/com/fr/third/net/jpountz/util/linux/amd64/liblz4-java.so
  5. BIN
      fine-lz4/resources/com/fr/third/net/jpountz/util/linux/i386/liblz4-java.so
  6. BIN
      fine-lz4/resources/com/fr/third/net/jpountz/util/linux/ppc64le/liblz4-java.so
  7. BIN
      fine-lz4/resources/com/fr/third/net/jpountz/util/linux/s390x/liblz4-java.so
  8. BIN
      fine-lz4/resources/com/fr/third/net/jpountz/util/win32/amd64/liblz4-java.so
  9. 301
      fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4BlockInputStream.java
  10. 279
      fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4BlockOutputStream.java
  11. 237
      fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4ByteBufferUtils.java
  12. 168
      fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4Compressor.java
  13. 53
      fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4Constants.java
  14. 25
      fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4Decompressor.java
  15. 36
      fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4Exception.java
  16. 309
      fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4Factory.java
  17. 135
      fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4FastDecompressor.java
  18. 351
      fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4FrameInputStream.java
  19. 434
      fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4FrameOutputStream.java
  20. 86
      fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4HCJNICompressor.java
  21. 550
      fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4HCJavaSafeCompressor.java
  22. 550
      fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4HCJavaUnsafeCompressor.java
  23. 41
      fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4JNI.java
  24. 80
      fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4JNICompressor.java
  25. 82
      fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4JNIFastDecompressor.java
  26. 81
      fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4JNISafeDecompressor.java
  27. 511
      fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4JavaSafeCompressor.java
  28. 205
      fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4JavaSafeFastDecompressor.java
  29. 213
      fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4JavaSafeSafeDecompressor.java
  30. 511
      fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4JavaUnsafeCompressor.java
  31. 205
      fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4JavaUnsafeFastDecompressor.java
  32. 213
      fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4JavaUnsafeSafeDecompressor.java
  33. 155
      fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4SafeDecompressor.java
  34. 179
      fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4SafeUtils.java
  35. 27
      fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4UnknownSizeDecompressor.java
  36. 200
      fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4UnsafeUtils.java
  37. 68
      fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4Utils.java
  38. 55
      fine-lz4/src/com/fr/third/net/jpountz/lz4/package.html
  39. 92
      fine-lz4/src/com/fr/third/net/jpountz/util/ByteBufferUtils.java
  40. 133
      fine-lz4/src/com/fr/third/net/jpountz/util/Native.java
  41. 95
      fine-lz4/src/com/fr/third/net/jpountz/util/SafeUtils.java
  42. 147
      fine-lz4/src/com/fr/third/net/jpountz/util/UnsafeUtils.java
  43. 36
      fine-lz4/src/com/fr/third/net/jpountz/util/Utils.java
  44. 22
      fine-lz4/src/com/fr/third/net/jpountz/util/package.html
  45. 39
      fine-lz4/src/com/fr/third/net/jpountz/xxhash/AbstractStreamingXXHash32Java.java
  46. 40
      fine-lz4/src/com/fr/third/net/jpountz/xxhash/AbstractStreamingXXHash64Java.java
  47. 119
      fine-lz4/src/com/fr/third/net/jpountz/xxhash/StreamingXXHash32.java
  48. 71
      fine-lz4/src/com/fr/third/net/jpountz/xxhash/StreamingXXHash32JNI.java
  49. 142
      fine-lz4/src/com/fr/third/net/jpountz/xxhash/StreamingXXHash32JavaSafe.java
  50. 142
      fine-lz4/src/com/fr/third/net/jpountz/xxhash/StreamingXXHash32JavaUnsafe.java
  51. 119
      fine-lz4/src/com/fr/third/net/jpountz/xxhash/StreamingXXHash64.java
  52. 71
      fine-lz4/src/com/fr/third/net/jpountz/xxhash/StreamingXXHash64JNI.java
  53. 166
      fine-lz4/src/com/fr/third/net/jpountz/xxhash/StreamingXXHash64JavaSafe.java
  54. 166
      fine-lz4/src/com/fr/third/net/jpountz/xxhash/StreamingXXHash64JavaUnsafe.java
  55. 71
      fine-lz4/src/com/fr/third/net/jpountz/xxhash/XXHash32.java
  56. 52
      fine-lz4/src/com/fr/third/net/jpountz/xxhash/XXHash32JNI.java
  57. 154
      fine-lz4/src/com/fr/third/net/jpountz/xxhash/XXHash32JavaSafe.java
  58. 154
      fine-lz4/src/com/fr/third/net/jpountz/xxhash/XXHash32JavaUnsafe.java
  59. 71
      fine-lz4/src/com/fr/third/net/jpountz/xxhash/XXHash64.java
  60. 52
      fine-lz4/src/com/fr/third/net/jpountz/xxhash/XXHash64JNI.java
  61. 192
      fine-lz4/src/com/fr/third/net/jpountz/xxhash/XXHash64JavaSafe.java
  62. 192
      fine-lz4/src/com/fr/third/net/jpountz/xxhash/XXHash64JavaUnsafe.java
  63. 31
      fine-lz4/src/com/fr/third/net/jpountz/xxhash/XXHashConstants.java
  64. 257
      fine-lz4/src/com/fr/third/net/jpountz/xxhash/XXHashFactory.java
  65. 43
      fine-lz4/src/com/fr/third/net/jpountz/xxhash/XXHashJNI.java
  66. 65
      fine-lz4/src/com/fr/third/net/jpountz/xxhash/package.html

5
build.third_step6.gradle

@ -39,7 +39,8 @@ sourceSets{
"${srcDir}/fine-redisson/src",
"${srcDir}/fine-socketio/src",
"${srcDir}/fine-itext/src",
"${srcDir}/fine-kryo/src"
"${srcDir}/fine-kryo/src",
"${srcDir}/fine-lz4/src"
]
}
}
@ -99,6 +100,8 @@ task copyFiles(type:Copy,dependsOn:'compileJava'){
with dataContent.call("${srcDir}/fine-jedis/resources")
with dataContent.call("${srcDir}/fine-cssparser/src")
with dataContent.call("${srcDir}/fine-kryo/src")
with dataContent.call("${srcDir}/fine-lz4/src")
with dataContent.call("${srcDir}/fine-lz4/resources")
into "${classesDir}"
}
}

BIN
fine-lz4/resources/com/fr/third/net/jpountz/util/darwin/x86_64/liblz4-java.dylib

Binary file not shown.

BIN
fine-lz4/resources/com/fr/third/net/jpountz/util/linux/aarch64/liblz4-java.so

Binary file not shown.

BIN
fine-lz4/resources/com/fr/third/net/jpountz/util/linux/amd64/liblz4-java.so

Binary file not shown.

BIN
fine-lz4/resources/com/fr/third/net/jpountz/util/linux/i386/liblz4-java.so

Binary file not shown.

BIN
fine-lz4/resources/com/fr/third/net/jpountz/util/linux/ppc64le/liblz4-java.so

Binary file not shown.

BIN
fine-lz4/resources/com/fr/third/net/jpountz/util/linux/s390x/liblz4-java.so

Binary file not shown.

BIN
fine-lz4/resources/com/fr/third/net/jpountz/util/win32/amd64/liblz4-java.so

Binary file not shown.

301
fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4BlockInputStream.java

@ -0,0 +1,301 @@
package com.fr.third.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 com.fr.third.net.jpountz.lz4.LZ4BlockOutputStream.COMPRESSION_LEVEL_BASE;
import static com.fr.third.net.jpountz.lz4.LZ4BlockOutputStream.COMPRESSION_METHOD_LZ4;
import static com.fr.third.net.jpountz.lz4.LZ4BlockOutputStream.COMPRESSION_METHOD_RAW;
import static com.fr.third.net.jpountz.lz4.LZ4BlockOutputStream.DEFAULT_SEED;
import static com.fr.third.net.jpountz.lz4.LZ4BlockOutputStream.HEADER_LENGTH;
import static com.fr.third.net.jpountz.lz4.LZ4BlockOutputStream.MAGIC;
import static com.fr.third.net.jpountz.lz4.LZ4BlockOutputStream.MAGIC_LENGTH;
import java.io.EOFException;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.Checksum;
import com.fr.third.net.jpountz.util.SafeUtils;
import com.fr.third.net.jpountz.xxhash.StreamingXXHash32;
import com.fr.third.net.jpountz.xxhash.XXHash32;
import com.fr.third.net.jpountz.xxhash.XXHashFactory;
/**
* {@link InputStream} implementation to decode data written with
* {@link LZ4BlockOutputStream}. This class is not thread-safe and does not
* support {@link #mark(int)}/{@link #reset()}.
* @see LZ4BlockOutputStream
*/
public final class LZ4BlockInputStream extends FilterInputStream {
private final LZ4FastDecompressor decompressor;
private final Checksum checksum;
private final boolean stopOnEmptyBlock;
private byte[] buffer;
private byte[] compressedBuffer;
private int originalLen;
private int o;
private boolean finished;
/**
* Creates a new LZ4 input stream to read from the specified underlying InputStream.
*
* @param in the {@link InputStream} to poll
* @param decompressor the {@link LZ4FastDecompressor decompressor} instance to
* use
* @param checksum the {@link Checksum} instance to use, must be
* equivalent to the instance which has been used to
* write the stream
* @param stopOnEmptyBlock whether read is stopped on an empty block
*/
public LZ4BlockInputStream(InputStream in, LZ4FastDecompressor decompressor, Checksum checksum, boolean stopOnEmptyBlock) {
super(in);
this.decompressor = decompressor;
this.checksum = checksum;
this.stopOnEmptyBlock = stopOnEmptyBlock;
this.buffer = new byte[0];
this.compressedBuffer = new byte[HEADER_LENGTH];
o = originalLen = 0;
finished = false;
}
/**
* Creates a new LZ4 input stream to read from the specified underlying InputStream.
*
* @param in the {@link InputStream} to poll
* @param decompressor the {@link LZ4FastDecompressor decompressor} instance to
* use
* @param checksum the {@link Checksum} instance to use, must be
* equivalent to the instance which has been used to
* write the stream
*
* @see #LZ4BlockInputStream(InputStream, LZ4FastDecompressor, Checksum, boolean)
*/
public LZ4BlockInputStream(InputStream in, LZ4FastDecompressor decompressor, Checksum checksum) {
this(in, decompressor, checksum, true);
}
/**
* Creates a new LZ4 input stream to read from the specified underlying InputStream, using {@link XXHash32} for checksuming.
*
* @param in the {@link InputStream} to poll
* @param decompressor the {@link LZ4FastDecompressor decompressor} instance to
* use
*
* @see #LZ4BlockInputStream(InputStream, LZ4FastDecompressor, Checksum, boolean)
* @see StreamingXXHash32#asChecksum()
*/
public LZ4BlockInputStream(InputStream in, LZ4FastDecompressor decompressor) {
this(in, decompressor, XXHashFactory.fastestInstance().newStreamingHash32(DEFAULT_SEED).asChecksum(), true);
}
/**
* Creates a new LZ4 input stream to read from the specified underlying InputStream, using {@link XXHash32} for checksuming.
*
* @param in the {@link InputStream} to poll
* @param stopOnEmptyBlock whether read is stopped on an empty block
*
* @see #LZ4BlockInputStream(InputStream, LZ4FastDecompressor, Checksum, boolean)
* @see LZ4Factory#fastestInstance()
* @see StreamingXXHash32#asChecksum()
*/
public LZ4BlockInputStream(InputStream in, boolean stopOnEmptyBlock) {
this(in, LZ4Factory.fastestInstance().fastDecompressor(), XXHashFactory.fastestInstance().newStreamingHash32(DEFAULT_SEED).asChecksum(), stopOnEmptyBlock);
}
/**
* Creates a new LZ4 input stream to read from the specified underlying InputStream, using {@link XXHash32} for checksuming.
*
* @param in the {@link InputStream} to poll
*
* @see #LZ4BlockInputStream(InputStream, LZ4FastDecompressor)
* @see LZ4Factory#fastestInstance()
*/
public LZ4BlockInputStream(InputStream in) {
this(in, LZ4Factory.fastestInstance().fastDecompressor());
}
@Override
public int available() throws IOException {
return originalLen - o;
}
@Override
public int read() throws IOException {
if (finished) {
return -1;
}
if (o == originalLen) {
refill();
}
if (finished) {
return -1;
}
return buffer[o++] & 0xFF;
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
SafeUtils.checkRange(b, off, len);
if (finished) {
return -1;
}
if (o == originalLen) {
refill();
}
if (finished) {
return -1;
}
len = Math.min(len, originalLen - o);
System.arraycopy(buffer, o, b, off, len);
o += len;
return len;
}
@Override
public int read(byte[] b) throws IOException {
return read(b, 0, b.length);
}
@Override
public long skip(long n) throws IOException {
if (n <= 0 || finished) {
return 0;
}
if (o == originalLen) {
refill();
}
if (finished) {
return 0;
}
final int skipped = (int) Math.min(n, originalLen - o);
o += skipped;
return skipped;
}
private void refill() throws IOException {
try {
readFully(compressedBuffer, HEADER_LENGTH);
} catch (EOFException e) {
if (!stopOnEmptyBlock) {
finished = true;
} else {
throw e;
}
return;
}
for (int i = 0; i < MAGIC_LENGTH; ++i) {
if (compressedBuffer[i] != MAGIC[i]) {
throw new IOException("Stream is corrupted");
}
}
final int token = compressedBuffer[MAGIC_LENGTH] & 0xFF;
final int compressionMethod = token & 0xF0;
final int compressionLevel = COMPRESSION_LEVEL_BASE + (token & 0x0F);
if (compressionMethod != COMPRESSION_METHOD_RAW && compressionMethod != COMPRESSION_METHOD_LZ4) {
throw new IOException("Stream is corrupted");
}
final int compressedLen = SafeUtils.readIntLE(compressedBuffer, MAGIC_LENGTH + 1);
originalLen = SafeUtils.readIntLE(compressedBuffer, MAGIC_LENGTH + 5);
final int check = SafeUtils.readIntLE(compressedBuffer, MAGIC_LENGTH + 9);
assert HEADER_LENGTH == MAGIC_LENGTH + 13;
if (originalLen > 1 << compressionLevel
|| originalLen < 0
|| compressedLen < 0
|| (originalLen == 0 && compressedLen != 0)
|| (originalLen != 0 && compressedLen == 0)
|| (compressionMethod == COMPRESSION_METHOD_RAW && originalLen != compressedLen)) {
throw new IOException("Stream is corrupted");
}
if (originalLen == 0 && compressedLen == 0) {
if (check != 0) {
throw new IOException("Stream is corrupted");
}
if (!stopOnEmptyBlock) {
refill();
} else {
finished = true;
}
return;
}
if (buffer.length < originalLen) {
buffer = new byte[Math.max(originalLen, buffer.length * 3 / 2)];
}
switch (compressionMethod) {
case COMPRESSION_METHOD_RAW:
readFully(buffer, originalLen);
break;
case COMPRESSION_METHOD_LZ4:
if (compressedBuffer.length < compressedLen) {
compressedBuffer = new byte[Math.max(compressedLen, compressedBuffer.length * 3 / 2)];
}
readFully(compressedBuffer, compressedLen);
try {
final int compressedLen2 = decompressor.decompress(compressedBuffer, 0, buffer, 0, originalLen);
if (compressedLen != compressedLen2) {
throw new IOException("Stream is corrupted");
}
} catch (LZ4Exception e) {
throw new IOException("Stream is corrupted", e);
}
break;
default:
throw new AssertionError();
}
checksum.reset();
checksum.update(buffer, 0, originalLen);
if ((int) checksum.getValue() != check) {
throw new IOException("Stream is corrupted");
}
o = 0;
}
private void readFully(byte[] b, int len) throws IOException {
int read = 0;
while (read < len) {
final int r = in.read(b, read, len - read);
if (r < 0) {
throw new EOFException("Stream ended prematurely");
}
read += r;
}
assert len == read;
}
@Override
public boolean markSupported() {
return false;
}
@SuppressWarnings("sync-override")
@Override
public void mark(int readlimit) {
// unsupported
}
@SuppressWarnings("sync-override")
@Override
public void reset() throws IOException {
throw new IOException("mark/reset not supported");
}
@Override
public String toString() {
return getClass().getSimpleName() + "(in=" + in
+ ", decompressor=" + decompressor + ", checksum=" + checksum + ")";
}
}

279
fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4BlockOutputStream.java

@ -0,0 +1,279 @@
package com.fr.third.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.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.zip.Checksum;
import com.fr.third.net.jpountz.util.SafeUtils;
import com.fr.third.net.jpountz.xxhash.StreamingXXHash32;
import com.fr.third.net.jpountz.xxhash.XXHashFactory;
/**
* Streaming LZ4 (not compatible with the LZ4 Frame format).
* This class compresses data into fixed-size blocks of compressed data.
* This class uses its own format and is not compatible with the LZ4 Frame format.
* For interoperability with other LZ4 tools, use {@link LZ4FrameOutputStream},
* which is compatible with the LZ4 Frame format. This class remains for backward compatibility.
* @see LZ4BlockInputStream
* @see LZ4FrameOutputStream
*/
public final class LZ4BlockOutputStream extends FilterOutputStream {
static final byte[] MAGIC = new byte[] { 'L', 'Z', '4', 'B', 'l', 'o', 'c', 'k' };
static final int MAGIC_LENGTH = MAGIC.length;
static final int HEADER_LENGTH =
MAGIC_LENGTH // magic bytes
+ 1 // token
+ 4 // compressed length
+ 4 // decompressed length
+ 4; // checksum
static final int COMPRESSION_LEVEL_BASE = 10;
static final int MIN_BLOCK_SIZE = 64;
static final int MAX_BLOCK_SIZE = 1 << (COMPRESSION_LEVEL_BASE + 0x0F);
static final int COMPRESSION_METHOD_RAW = 0x10;
static final int COMPRESSION_METHOD_LZ4 = 0x20;
static final int DEFAULT_SEED = 0x9747b28c;
private static int compressionLevel(int blockSize) {
if (blockSize < MIN_BLOCK_SIZE) {
throw new IllegalArgumentException("blockSize must be >= " + MIN_BLOCK_SIZE + ", got " + blockSize);
} else if (blockSize > MAX_BLOCK_SIZE) {
throw new IllegalArgumentException("blockSize must be <= " + MAX_BLOCK_SIZE + ", got " + blockSize);
}
int compressionLevel = 32 - Integer.numberOfLeadingZeros(blockSize - 1); // ceil of log2
assert (1 << compressionLevel) >= blockSize;
assert blockSize * 2 > (1 << compressionLevel);
compressionLevel = Math.max(0, compressionLevel - COMPRESSION_LEVEL_BASE);
assert compressionLevel >= 0 && compressionLevel <= 0x0F;
return compressionLevel;
}
private final int blockSize;
private final int compressionLevel;
private final LZ4Compressor compressor;
private final Checksum checksum;
private final byte[] buffer;
private final byte[] compressedBuffer;
private final boolean syncFlush;
private boolean finished;
private int o;
/**
* Creates a new {@link OutputStream} with configurable block size. Large
* blocks require more memory at compression and decompression time but
* should improve the compression ratio.
*
* @param out the {@link OutputStream} to feed
* @param blockSize the maximum number of bytes to try to compress at once,
* must be &gt;= 64 and &lt;= 32 M
* @param compressor the {@link LZ4Compressor} instance to use to compress
* data
* @param checksum the {@link Checksum} instance to use to check data for
* integrity.
* @param syncFlush true if pending data should also be flushed on {@link #flush()}
*/
public LZ4BlockOutputStream(OutputStream out, int blockSize, LZ4Compressor compressor, Checksum checksum, boolean syncFlush) {
super(out);
this.blockSize = blockSize;
this.compressor = compressor;
this.checksum = checksum;
this.compressionLevel = compressionLevel(blockSize);
this.buffer = new byte[blockSize];
final int compressedBlockSize = HEADER_LENGTH + compressor.maxCompressedLength(blockSize);
this.compressedBuffer = new byte[compressedBlockSize];
this.syncFlush = syncFlush;
o = 0;
finished = false;
System.arraycopy(MAGIC, 0, compressedBuffer, 0, MAGIC_LENGTH);
}
/**
* Creates a new instance which checks stream integrity using
* {@link StreamingXXHash32} and doesn't sync flush.
*
* @param out the {@link OutputStream} to feed
* @param blockSize the maximum number of bytes to try to compress at once,
* must be &gt;= 64 and &lt;= 32 M
* @param compressor the {@link LZ4Compressor} instance to use to compress
* data
*
* @see #LZ4BlockOutputStream(OutputStream, int, LZ4Compressor, Checksum, boolean)
* @see StreamingXXHash32#asChecksum()
*/
public LZ4BlockOutputStream(OutputStream out, int blockSize, LZ4Compressor compressor) {
this(out, blockSize, compressor, XXHashFactory.fastestInstance().newStreamingHash32(DEFAULT_SEED).asChecksum(), false);
}
/**
* Creates a new instance which compresses with the standard LZ4 compression
* algorithm.
*
* @param out the {@link OutputStream} to feed
* @param blockSize the maximum number of bytes to try to compress at once,
* must be &gt;= 64 and &lt;= 32 M
*
* @see #LZ4BlockOutputStream(OutputStream, int, LZ4Compressor)
* @see LZ4Factory#fastCompressor()
*/
public LZ4BlockOutputStream(OutputStream out, int blockSize) {
this(out, blockSize, LZ4Factory.fastestInstance().fastCompressor());
}
/**
* Creates a new instance which compresses into blocks of 64 KB.
*
* @param out the {@link OutputStream} to feed
*
* @see #LZ4BlockOutputStream(OutputStream, int)
*/
public LZ4BlockOutputStream(OutputStream out) {
this(out, 1 << 16);
}
private void ensureNotFinished() {
if (finished) {
throw new IllegalStateException("This stream is already closed");
}
}
@Override
public void write(int b) throws IOException {
ensureNotFinished();
if (o == blockSize) {
flushBufferedData();
}
buffer[o++] = (byte) b;
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
SafeUtils.checkRange(b, off, len);
ensureNotFinished();
while (o + len > blockSize) {
final int l = blockSize - o;
System.arraycopy(b, off, buffer, o, blockSize - o);
o = blockSize;
flushBufferedData();
off += l;
len -= l;
}
System.arraycopy(b, off, buffer, o, len);
o += len;
}
@Override
public void write(byte[] b) throws IOException {
ensureNotFinished();
write(b, 0, b.length);
}
@Override
public void close() throws IOException {
if (!finished) {
finish();
}
if (out != null) {
out.close();
out = null;
}
}
private void flushBufferedData() throws IOException {
if (o == 0) {
return;
}
checksum.reset();
checksum.update(buffer, 0, o);
final int check = (int) checksum.getValue();
int compressedLength = compressor.compress(buffer, 0, o, compressedBuffer, HEADER_LENGTH);
final int compressMethod;
if (compressedLength >= o) {
compressMethod = COMPRESSION_METHOD_RAW;
compressedLength = o;
System.arraycopy(buffer, 0, compressedBuffer, HEADER_LENGTH, o);
} else {
compressMethod = COMPRESSION_METHOD_LZ4;
}
compressedBuffer[MAGIC_LENGTH] = (byte) (compressMethod | compressionLevel);
writeIntLE(compressedLength, compressedBuffer, MAGIC_LENGTH + 1);
writeIntLE(o, compressedBuffer, MAGIC_LENGTH + 5);
writeIntLE(check, compressedBuffer, MAGIC_LENGTH + 9);
assert MAGIC_LENGTH + 13 == HEADER_LENGTH;
out.write(compressedBuffer, 0, HEADER_LENGTH + compressedLength);
o = 0;
}
/**
* Flushes this compressed {@link OutputStream}.
*
* If the stream has been created with <code>syncFlush=true</code>, pending
* data will be compressed and appended to the underlying {@link OutputStream}
* before calling {@link OutputStream#flush()} on the underlying stream.
* Otherwise, this method just flushes the underlying stream, so pending
* data might not be available for reading until {@link #finish()} or
* {@link #close()} is called.
*/
@Override
public void flush() throws IOException {
if (out != null) {
if (syncFlush) {
flushBufferedData();
}
out.flush();
}
}
/**
* Same as {@link #close()} except that it doesn't close the underlying stream.
* This can be useful if you want to keep on using the underlying stream.
*
* @throws IOException if an I/O error occurs.
*/
public void finish() throws IOException {
ensureNotFinished();
flushBufferedData();
compressedBuffer[MAGIC_LENGTH] = (byte) (COMPRESSION_METHOD_RAW | compressionLevel);
writeIntLE(0, compressedBuffer, MAGIC_LENGTH + 1);
writeIntLE(0, compressedBuffer, MAGIC_LENGTH + 5);
writeIntLE(0, compressedBuffer, MAGIC_LENGTH + 9);
assert MAGIC_LENGTH + 13 == HEADER_LENGTH;
out.write(compressedBuffer, 0, HEADER_LENGTH);
finished = true;
out.flush();
}
private static void writeIntLE(int i, byte[] buf, int off) {
buf[off++] = (byte) i;
buf[off++] = (byte) (i >>> 8);
buf[off++] = (byte) (i >>> 16);
buf[off++] = (byte) (i >>> 24);
}
@Override
public String toString() {
return getClass().getSimpleName() + "(out=" + out + ", blockSize=" + blockSize
+ ", compressor=" + compressor + ", checksum=" + checksum + ")";
}
}

237
fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4ByteBufferUtils.java

@ -0,0 +1,237 @@
package com.fr.third.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 com.fr.third.net.jpountz.lz4.LZ4Constants.COPY_LENGTH;
import static com.fr.third.net.jpountz.lz4.LZ4Constants.LAST_LITERALS;
import static com.fr.third.net.jpountz.lz4.LZ4Constants.ML_BITS;
import static com.fr.third.net.jpountz.lz4.LZ4Constants.ML_MASK;
import static com.fr.third.net.jpountz.lz4.LZ4Constants.RUN_MASK;
import static com.fr.third.net.jpountz.util.ByteBufferUtils.readByte;
import static com.fr.third.net.jpountz.util.ByteBufferUtils.readInt;
import static com.fr.third.net.jpountz.util.ByteBufferUtils.readLong;
import static com.fr.third.net.jpountz.util.ByteBufferUtils.writeByte;
import static com.fr.third.net.jpountz.util.ByteBufferUtils.writeInt;
import static com.fr.third.net.jpountz.util.ByteBufferUtils.writeLong;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
enum LZ4ByteBufferUtils {
;
static int hash(ByteBuffer buf, int i) {
return LZ4Utils.hash(readInt(buf, i));
}
static int hash64k(ByteBuffer buf, int i) {
return LZ4Utils.hash64k(readInt(buf, i));
}
static boolean readIntEquals(ByteBuffer buf, int i, int j) {
return buf.getInt(i) == buf.getInt(j);
}
static void safeIncrementalCopy(ByteBuffer dest, int matchOff, int dOff, int matchLen) {
for (int i = 0; i < matchLen; ++i) {
dest.put(dOff + i, dest.get(matchOff + i));
}
}
static void wildIncrementalCopy(ByteBuffer 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 int commonBytes(ByteBuffer 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 (src.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 commonBytesBackward(ByteBuffer b, int o1, int o2, int l1, int l2) {
int count = 0;
while (o1 > l1 && o2 > l2 && b.get(--o1) == b.get(--o2)) {
++count;
}
return count;
}
static void safeArraycopy(ByteBuffer src, int sOff, ByteBuffer dest, int dOff, int len) {
for (int i = 0; i < len; ++i) {
dest.put(dOff + i, src.get(sOff + i));
}
}
static void wildArraycopy(ByteBuffer src, int sOff, ByteBuffer dest, int dOff, int len) {
assert src.order().equals(dest.order());
try {
for (int i = 0; i < len; i += 8) {
dest.putLong(dOff + i, src.getLong(sOff + i));
}
} catch (IndexOutOfBoundsException e) {
throw new LZ4Exception("Malformed input at offset " + sOff);
}
}
static int encodeSequence(ByteBuffer src, int anchor, int matchOff, int matchRef, int matchLen, ByteBuffer dest, int dOff, int destEnd) {
final int runLen = matchOff - anchor;
final int tokenOff = dOff++;
if (dOff + runLen + (2 + 1 + LAST_LITERALS) + (runLen >>> 8) > destEnd) {
throw new LZ4Exception("maxDestLen is too small");
}
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.put(dOff++, (byte) matchDec);
dest.put(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.put(tokenOff, (byte) token);
return dOff;
}
static int lastLiterals(ByteBuffer src, int sOff, int srcLen, ByteBuffer dest, int dOff, int destEnd) {
final int runLen = srcLen;
if (dOff + runLen + 1 + (runLen + 255 - RUN_MASK) / 255 > destEnd) {
throw new LZ4Exception();
}
if (runLen >= RUN_MASK) {
dest.put(dOff++, (byte) (RUN_MASK << ML_BITS));
dOff = writeLen(runLen - RUN_MASK, dest, dOff);
} else {
dest.put(dOff++, (byte) (runLen << ML_BITS));
}
// copy literals
safeArraycopy(src, sOff, dest, dOff, runLen);
dOff += runLen;
return dOff;
}
static int writeLen(int len, ByteBuffer dest, int dOff) {
while (len >= 0xFF) {
dest.put(dOff++, (byte) 0xFF);
len -= 0xFF;
}
dest.put(dOff++, (byte) len);
return dOff;
}
static class Match {
int start, ref, len;
void fix(int correction) {
start += correction;
ref += correction;
len -= correction;
}
int end() {
return start + len;
}
}
static void copyTo(Match m1, Match m2) {
m2.len = m1.len;
m2.start = m1.start;
m2.ref = m1.ref;
}
}

168
fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4Compressor.java

@ -0,0 +1,168 @@
package com.fr.third.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.nio.ByteBuffer;
import java.util.Arrays;
/**
* LZ4 compressor.
* <p>
* Instances of this class are thread-safe.
*/
public abstract class LZ4Compressor {
/**
* Returns the maximum compressed length for an input of size <code>length</code>.
*
* @param length the input size in bytes
* @return the maximum compressed length in bytes
*/
@SuppressWarnings("static-method")
public final int maxCompressedLength(int length) {
return LZ4Utils.maxCompressedLength(length);
}
/**
* Compresses <code>src[srcOff:srcOff+srcLen]</code> into
* <code>dest[destOff:destOff+maxDestLen]</code> and returns the compressed
* length.
*
* This method will throw a {@link LZ4Exception} if this compressor is unable
* to compress the input into less than <code>maxDestLen</code> bytes. To
* prevent this exception to be thrown, you should make sure that
* <code>maxDestLen &gt;= maxCompressedLength(srcLen)</code>.
*
* @param src the source data
* @param srcOff the start offset in src
* @param srcLen the number of bytes to compress
* @param dest the destination buffer
* @param destOff the start offset in dest
* @param maxDestLen the maximum number of bytes to write in dest
* @throws LZ4Exception if maxDestLen is too small
* @return the compressed size
*/
public abstract int compress(byte[] src, int srcOff, int srcLen, byte[] dest, int destOff, int maxDestLen);
/**
* Compresses <code>src[srcOff:srcOff+srcLen]</code> into
* <code>dest[destOff:destOff+maxDestLen]</code> and returns the compressed
* length.
*
* This method will throw a {@link LZ4Exception} if this compressor is unable
* to compress the input into less than <code>maxDestLen</code> bytes. To
* prevent this exception to be thrown, you should make sure that
* <code>maxDestLen &gt;= maxCompressedLength(srcLen)</code>.
*
* {@link ByteBuffer} positions remain unchanged.
*
* @param src the source data
* @param srcOff the start offset in src
* @param srcLen the number of bytes to compress
* @param dest the destination buffer
* @param destOff the start offset in dest
* @param maxDestLen the maximum number of bytes to write in dest
* @throws LZ4Exception if maxDestLen is too small
* @return the compressed size
*/
public abstract int compress(ByteBuffer src, int srcOff, int srcLen, ByteBuffer dest, int destOff, int maxDestLen);
/**
* Convenience method, equivalent to calling
* {@link #compress(byte[], int, int, byte[], int, int) compress(src, srcOff, srcLen, dest, destOff, dest.length - destOff)}.
*
* @param src the source data
* @param srcOff the start offset in src
* @param srcLen the number of bytes to compress
* @param dest the destination buffer
* @param destOff the start offset in dest
* @throws LZ4Exception if dest is too small
* @return the compressed size
*/
public final int compress(byte[] src, int srcOff, int srcLen, byte[] dest, int destOff) {
return compress(src, srcOff, srcLen, dest, destOff, dest.length - destOff);
}
/**
* Convenience method, equivalent to calling
* {@link #compress(byte[], int, int, byte[], int) compress(src, 0, src.length, dest, 0)}.
*
* @param src the source data
* @param dest the destination buffer
* @throws LZ4Exception if dest is too small
* @return the compressed size
*/
public final int compress(byte[] src, byte[] dest) {
return compress(src, 0, src.length, dest, 0);
}
/**
* Convenience method which returns <code>src[srcOff:srcOff+srcLen]</code>
* compressed.
* <p><b><span style="color:red">Warning</span></b>: this method has an
* important overhead due to the fact that it needs to allocate a buffer to
* compress into, and then needs to resize this buffer to the actual
* compressed length.</p>
* <p>Here is how this method is implemented:</p>
* <pre>
* final int maxCompressedLength = maxCompressedLength(srcLen);
* final byte[] compressed = new byte[maxCompressedLength];
* final int compressedLength = compress(src, srcOff, srcLen, compressed, 0);
* return Arrays.copyOf(compressed, compressedLength);
* </pre>
*
* @param src the source data
* @param srcOff the start offset in src
* @param srcLen the number of bytes to compress
* @return the compressed data
*/
public final byte[] compress(byte[] src, int srcOff, int srcLen) {
final int maxCompressedLength = maxCompressedLength(srcLen);
final byte[] compressed = new byte[maxCompressedLength];
final int compressedLength = compress(src, srcOff, srcLen, compressed, 0);
return Arrays.copyOf(compressed, compressedLength);
}
/**
* Convenience method, equivalent to calling
* {@link #compress(byte[], int, int) compress(src, 0, src.length)}.
*
* @param src the source data
* @return the compressed data
*/
public final byte[] compress(byte[] src) {
return compress(src, 0, src.length);
}
/**
* Compresses <code>src</code> into <code>dest</code>. Calling this method
* will update the positions of both {@link ByteBuffer}s.
*
* @param src the source data
* @param dest the destination buffer
* @throws LZ4Exception if dest is too small
*/
public final void compress(ByteBuffer src, ByteBuffer dest) {
final int cpLen = compress(src, src.position(), src.remaining(), dest, dest.position(), dest.remaining());
src.position(src.limit());
dest.position(dest.position() + cpLen);
}
@Override
public String toString() {
return getClass().getSimpleName();
}
}

53
fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4Constants.java

@ -0,0 +1,53 @@
package com.fr.third.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.
*/
enum LZ4Constants {
;
static final int DEFAULT_COMPRESSION_LEVEL = 8+1;
static final int MAX_COMPRESSION_LEVEL = 16+1;
static final int MEMORY_USAGE = 14;
static final int NOT_COMPRESSIBLE_DETECTION_LEVEL = 6;
static final int MIN_MATCH = 4;
static final int HASH_LOG = MEMORY_USAGE - 2;
static final int HASH_TABLE_SIZE = 1 << HASH_LOG;
static final int SKIP_STRENGTH = Math.max(NOT_COMPRESSIBLE_DETECTION_LEVEL, 2);
static final int COPY_LENGTH = 8;
static final int LAST_LITERALS = 5;
static final int MF_LIMIT = COPY_LENGTH + MIN_MATCH;
static final int MIN_LENGTH = MF_LIMIT + 1;
static final int MAX_DISTANCE = 1 << 16;
static final int ML_BITS = 4;
static final int ML_MASK = (1 << ML_BITS) - 1;
static final int RUN_BITS = 8 - ML_BITS;
static final int RUN_MASK = (1 << RUN_BITS) - 1;
static final int LZ4_64K_LIMIT = (1 << 16) + (MF_LIMIT - 1);
static final int HASH_LOG_64K = HASH_LOG + 1;
static final int HASH_TABLE_SIZE_64K = 1 << HASH_LOG_64K;
static final int HASH_LOG_HC = 15;
static final int HASH_TABLE_SIZE_HC = 1 << HASH_LOG_HC;
static final int OPTIMAL_ML = ML_MASK - 1 + MIN_MATCH;
}

25
fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4Decompressor.java

@ -0,0 +1,25 @@
package com.fr.third.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.
*/
/**
* @deprecated Use {@link LZ4FastDecompressor} instead.
*/
@Deprecated
public interface LZ4Decompressor {
int decompress(byte[] src, int srcOff, byte[] dest, int destOff, int destLen);
}

36
fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4Exception.java

@ -0,0 +1,36 @@
package com.fr.third.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.
*/
/**
* LZ4 compression or decompression error.
*/
public class LZ4Exception extends RuntimeException {
private static final long serialVersionUID = 1L;
public LZ4Exception(String msg, Throwable t) {
super(msg, t);
}
public LZ4Exception(String msg) {
super(msg);
}
public LZ4Exception() {
super();
}
}

309
fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4Factory.java

@ -0,0 +1,309 @@
package com.fr.third.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.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import com.fr.third.net.jpountz.util.Native;
import com.fr.third.net.jpountz.util.Utils;
/**
* Entry point for the LZ4 API.
* <p>
* This class has 3 instances<ul>
* <li>a {@link #nativeInstance() native} instance which is a JNI binding to
* <a href="http://code.google.com/p/lz4/">the original LZ4 C implementation</a>.
* <li>a {@link #safeInstance() safe Java} instance which is a pure Java port
* of the original C library,</li>
* <li>an {@link #unsafeInstance() unsafe Java} instance which is a Java port
* using the unofficial {@link sun.misc.Unsafe} API.
* </ul>
* <p>
* Only the {@link #safeInstance() safe instance} is guaranteed to work on your
* JVM, as a consequence it is advised to use the {@link #fastestInstance()} or
* {@link #fastestJavaInstance()} to pull a {@link LZ4Factory} instance.
* <p>
* All methods from this class are very costly, so you should get an instance
* once, and then reuse it whenever possible. This is typically done by storing
* a {@link LZ4Factory} instance in a static field.
*/
public final class LZ4Factory {
private static LZ4Factory instance(String impl) {
try {
return new LZ4Factory(impl);
} catch (Exception e) {
throw new AssertionError(e);
}
}
private static LZ4Factory NATIVE_INSTANCE,
JAVA_UNSAFE_INSTANCE,
JAVA_SAFE_INSTANCE;
/**
* Returns a {@link LZ4Factory} instance that returns compressors and
* decompressors that are native bindings to the original C library.
* <p>
* Please note that this instance has some traps you should be aware of:<ol>
* <li>Upon loading this instance, files will be written to the temporary
* directory of the system. Although these files are supposed to be deleted
* when the JVM exits, they might remain on systems that don't support
* removal of files being used such as Windows.
* <li>The instance can only be loaded once per JVM. This can be a problem
* if your application uses multiple class loaders (such as most servlet
* containers): this instance will only be available to the children of the
* class loader which has loaded it. As a consequence, it is advised to
* either not use this instance in webapps or to put this library in the lib
* directory of your servlet container so that it is loaded by the system
* class loader.
* </ol>
*
* @return a {@link LZ4Factory} instance that returns compressors and
* decompressors that are native bindings to the original C library
*/
public static synchronized LZ4Factory nativeInstance() {
if (NATIVE_INSTANCE == null) {
NATIVE_INSTANCE = instance("JNI");
}
return NATIVE_INSTANCE;
}
/**
* Returns a {@link LZ4Factory} instance that returns compressors and
* decompressors that are written with Java's official API.
*
* @return a {@link LZ4Factory} instance that returns compressors and
* decompressors that are written with Java's official API.
*/
public static synchronized LZ4Factory safeInstance() {
if (JAVA_SAFE_INSTANCE == null) {
JAVA_SAFE_INSTANCE = instance("JavaSafe");
}
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}.
*
* @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();
}
}
/**
* Returns the fastest available {@link LZ4Factory} instance. If the class
* loader is the system class loader and if the
* {@link #nativeInstance() native instance} loads successfully, then the
* {@link #nativeInstance() native instance} is returned, otherwise the
* {@link #fastestJavaInstance() fastest Java instance} is returned.
* <p>
* Please read {@link #nativeInstance() javadocs of nativeInstance()} before
* using this method.
*
* @return the fastest available {@link LZ4Factory} instance
*/
public static LZ4Factory fastestInstance() {
if (Native.isLoaded()
|| Native.class.getClassLoader() == ClassLoader.getSystemClassLoader()) {
try {
return nativeInstance();
} catch (Throwable t) {
return fastestJavaInstance();
}
} else {
return fastestJavaInstance();
}
}
@SuppressWarnings("unchecked")
private static <T> T classInstance(String cls) throws NoSuchFieldException, SecurityException, ClassNotFoundException, IllegalArgumentException, IllegalAccessException {
ClassLoader loader = LZ4Factory.class.getClassLoader();
loader = loader == null ? ClassLoader.getSystemClassLoader() : loader;
final Class<?> c = loader.loadClass(cls);
Field f = c.getField("INSTANCE");
return (T) f.get(null);
}
private final String impl;
private final LZ4Compressor fastCompressor;
private final LZ4Compressor highCompressor;
private final LZ4FastDecompressor fastDecompressor;
private final LZ4SafeDecompressor safeDecompressor;
private final LZ4Compressor[] highCompressors = new LZ4Compressor[LZ4Constants.MAX_COMPRESSION_LEVEL+1];
private LZ4Factory(String impl) throws ClassNotFoundException, NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, NoSuchMethodException, InstantiationException, InvocationTargetException {
this.impl = impl;
fastCompressor = classInstance("com.fr.third.net.jpountz.lz4.LZ4" + impl + "Compressor");
highCompressor = classInstance("com.fr.third.net.jpountz.lz4.LZ4HC" + impl + "Compressor");
fastDecompressor = classInstance("com.fr.third.net.jpountz.lz4.LZ4" + impl + "FastDecompressor");
safeDecompressor = classInstance("com.fr.third.net.jpountz.lz4.LZ4" + impl + "SafeDecompressor");
Constructor<? extends LZ4Compressor> highConstructor = highCompressor.getClass().getDeclaredConstructor(int.class);
highCompressors[LZ4Constants.DEFAULT_COMPRESSION_LEVEL] = highCompressor;
for(int level = 1; level <= LZ4Constants.MAX_COMPRESSION_LEVEL; level++) {
if(level == LZ4Constants.DEFAULT_COMPRESSION_LEVEL) continue;
highCompressors[level] = highConstructor.newInstance(level);
}
// quickly test that everything works as expected
final byte[] original = new byte[] {'a','b','c','d',' ',' ',' ',' ',' ',' ','a','b','c','d','e','f','g','h','i','j'};
for (LZ4Compressor compressor : Arrays.asList(fastCompressor, highCompressor)) {
final int maxCompressedLength = compressor.maxCompressedLength(original.length);
final byte[] compressed = new byte[maxCompressedLength];
final int compressedLength = compressor.compress(original, 0, original.length, compressed, 0, maxCompressedLength);
final byte[] restored = new byte[original.length];
fastDecompressor.decompress(compressed, 0, restored, 0, original.length);
if (!Arrays.equals(original, restored)) {
throw new AssertionError();
}
Arrays.fill(restored, (byte) 0);
final int decompressedLength = safeDecompressor.decompress(compressed, 0, compressedLength, restored, 0);
if (decompressedLength != original.length || !Arrays.equals(original, restored)) {
throw new AssertionError();
}
}
}
/**
* Returns a blazing fast {@link LZ4Compressor}.
*
* @return a blazing fast {@link LZ4Compressor}
*/
public LZ4Compressor fastCompressor() {
return fastCompressor;
}
/**
* Returns a {@link LZ4Compressor} which requires more memory than
* {@link #fastCompressor()} and is slower but compresses more efficiently.
*
* @return a {@link LZ4Compressor} which requires more memory than
* {@link #fastCompressor()} and is slower but compresses more efficiently.
*/
public LZ4Compressor highCompressor() {
return highCompressor;
}
/**
* Returns a {@link LZ4Compressor} which requires more memory than
* {@link #fastCompressor()} and is slower but compresses more efficiently.
* The compression level can be customized.
* <p>For current implementations, the following is true about compression level:<ol>
* <li>It should be in range [1, 17]</li>
* <li>A compression level higher than 17 would be treated as 17.</li>
* <li>A compression level lower than 1 would be treated as 9.</li>
* </ol>
*
* @param compressionLevel the compression level between [1, 17]; the higher the level, the higher the compression ratio
* @return a {@link LZ4Compressor} which requires more memory than
* {@link #fastCompressor()} and is slower but compresses more efficiently.
*/
public LZ4Compressor highCompressor(int compressionLevel) {
if(compressionLevel > LZ4Constants.MAX_COMPRESSION_LEVEL) {
compressionLevel = LZ4Constants.MAX_COMPRESSION_LEVEL;
} else if (compressionLevel < 1) {
compressionLevel = LZ4Constants.DEFAULT_COMPRESSION_LEVEL;
}
return highCompressors[compressionLevel];
}
/**
* Returns a {@link LZ4FastDecompressor} instance.
*
* @return a {@link LZ4FastDecompressor} instance
*/
public LZ4FastDecompressor fastDecompressor() {
return fastDecompressor;
}
/**
* Returns a {@link LZ4SafeDecompressor} instance.
*
* @return a {@link LZ4SafeDecompressor} instance
*/
public LZ4SafeDecompressor safeDecompressor() {
return safeDecompressor;
}
/**
* Returns a {@link LZ4UnknownSizeDecompressor} instance.
* @deprecated use {@link #safeDecompressor()}
*
* @return a {@link LZ4UnknownSizeDecompressor} instance
*/
public LZ4UnknownSizeDecompressor unknownSizeDecompressor() {
return safeDecompressor();
}
/**
* Returns a {@link LZ4Decompressor} instance.
* @deprecated use {@link #fastDecompressor()}
*
* @return a {@link LZ4Decompressor} instance
*/
public LZ4Decompressor decompressor() {
return fastDecompressor();
}
/**
* Prints the fastest instance.
*
* @param args no argument required
*/
public static void main(String[] args) {
System.out.println("Fastest instance is " + fastestInstance());
System.out.println("Fastest Java instance is " + fastestJavaInstance());
}
@Override
public String toString() {
return getClass().getSimpleName() + ":" + impl;
}
}

135
fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4FastDecompressor.java

@ -0,0 +1,135 @@
package com.fr.third.net.jpountz.lz4;
import java.nio.ByteBuffer;
/*
* 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.
*/
/**
* LZ4 decompressor that requires the size of the original input to be known.
* Use {@link LZ4SafeDecompressor} if you only know the size of the
* compressed stream.
* <p>
* Instances of this class are thread-safe.
*/
public abstract class LZ4FastDecompressor implements LZ4Decompressor {
/** Decompresses <code>src[srcOff:]</code> into <code>dest[destOff:destOff+destLen]</code>
* and returns the number of bytes read from <code>src</code>.
* <code>destLen</code> must be exactly the size of the decompressed data.
*
* @param src the compressed data
* @param srcOff the start offset in src
* @param dest the destination buffer to store the decompressed data
* @param destOff the start offset in dest
* @param destLen the <b>exact</b> size of the original input
* @return the number of bytes read to restore the original input
*/
public abstract int decompress(byte[] src, int srcOff, byte[] dest, int destOff, int destLen);
/** Decompresses <code>src[srcOff:]</code> into <code>dest[destOff:destOff+destLen]</code>
* and returns the number of bytes read from <code>src</code>.
* <code>destLen</code> must be exactly the size of the decompressed data.
* The positions and limits of the {@link ByteBuffer}s remain unchanged.
*
* @param src the compressed data
* @param srcOff the start offset in src
* @param dest the destination buffer to store the decompressed data
* @param destOff the start offset in dest
* @param destLen the <b>exact</b> size of the original input
* @return the number of bytes read to restore the original input
*/
public abstract int decompress(ByteBuffer src, int srcOff, ByteBuffer dest, int destOff, int destLen);
/**
* Convenience method, equivalent to calling
* {@link #decompress(byte[], int, byte[], int, int) decompress(src, 0, dest, 0, destLen)}.
*
* @param src the compressed data
* @param dest the destination buffer to store the decompressed data
* @param destLen the <b>exact</b> size of the original input
* @return the number of bytes read to restore the original input
*/
public final int decompress(byte[] src, byte[] dest, int destLen) {
return decompress(src, 0, dest, 0, destLen);
}
/**
* Convenience method, equivalent to calling
* {@link #decompress(byte[], byte[], int) decompress(src, dest, dest.length)}.
*
* @param src the compressed data
* @param dest the destination buffer to store the decompressed data
* @return the number of bytes read to restore the original input
*/
public final int decompress(byte[] src, byte[] dest) {
return decompress(src, dest, dest.length);
}
/**
* Convenience method which returns <code>src[srcOff:?]</code>
* decompressed.
* <p><b><span style="color:red">Warning</span></b>: this method has an
* important overhead due to the fact that it needs to allocate a buffer to
* decompress into.</p>
* <p>Here is how this method is implemented:</p>
* <pre>
* final byte[] decompressed = new byte[destLen];
* decompress(src, srcOff, decompressed, 0, destLen);
* return decompressed;
* </pre>
*
* @param src the compressed data
* @param srcOff the start offset in src
* @param destLen the <b>exact</b> size of the original input
* @return the decompressed data
*/
public final byte[] decompress(byte[] src, int srcOff, int destLen) {
final byte[] decompressed = new byte[destLen];
decompress(src, srcOff, decompressed, 0, destLen);
return decompressed;
}
/**
* Convenience method, equivalent to calling
* {@link #decompress(byte[], int, int) decompress(src, 0, destLen)}.
*
* @param src the compressed data
* @param destLen the <b>exact</b> size of the original input
* @return the decompressed data
*/
public final byte[] decompress(byte[] src, int destLen) {
return decompress(src, 0, destLen);
}
/**
* Decompresses <code>src</code> into <code>dest</code>. <code>dest</code>'s
* {@link ByteBuffer#remaining()} must be exactly the size of the decompressed
* data. This method moves the positions of the buffers.
*
* @param src the compressed data
* @param dest the destination buffer to store the decompressed data
*/
public final void decompress(ByteBuffer src, ByteBuffer dest) {
final int read = decompress(src, src.position(), dest, dest.position(), dest.remaining());
dest.position(dest.limit());
src.position(src.position() + read);
}
@Override
public String toString() {
return getClass().getSimpleName();
}
}

351
fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4FrameInputStream.java

@ -0,0 +1,351 @@
package com.fr.third.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 com.fr.third.net.jpountz.xxhash.XXHash32;
import com.fr.third.net.jpountz.xxhash.XXHashFactory;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Locale;
/**
* Implementation of the v1.5.1 LZ4 Frame format. This class is NOT thread safe.
* <p>
* Not Supported:<ul>
* <li>Dependent blocks</li>
* <li>Legacy streams</li>
* </ul>
* <p>
* Originally based on kafka's KafkaLZ4BlockInputStream.
*
* @see <a href="https://github.com/lz4/lz4/blob/dev/doc/lz4_Frame_format.md">LZ4 Framing Format Spec 1.5.1</a>
*/
public class LZ4FrameInputStream extends FilterInputStream {
static final String PREMATURE_EOS = "Stream ended prematurely";
static final String NOT_SUPPORTED = "Stream unsupported";
static final String BLOCK_HASH_MISMATCH = "Block checksum mismatch";
static final String DESCRIPTOR_HASH_MISMATCH = "Stream frame descriptor corrupted";
static final int MAGIC_SKIPPABLE_BASE = 0x184D2A50;
private final LZ4SafeDecompressor decompressor;
private final XXHash32 checksum;
private final byte[] headerArray = new byte[LZ4FrameOutputStream.LZ4_MAX_HEADER_LENGTH];
private final ByteBuffer headerBuffer = ByteBuffer.wrap(headerArray).order(ByteOrder.LITTLE_ENDIAN);
private byte[] compressedBuffer;
private ByteBuffer buffer = null;
private byte[] rawBuffer = null;
private int maxBlockSize = -1;
private long expectedContentSize = -1L;
private long totalContentSize = 0L;
private LZ4FrameOutputStream.FrameInfo frameInfo = null;
/**
* Creates a new {@link InputStream} that will decompress data using fastest instances of {@link LZ4SafeDecompressor} and {@link XXHash32}.
*
* @param in the stream to decompress
* @throws IOException if an I/O error occurs
*
* @see #LZ4FrameInputStream(InputStream, LZ4SafeDecompressor, XXHash32)
* @see LZ4Factory#fastestInstance()
* @see XXHashFactory#fastestInstance()
*/
public LZ4FrameInputStream(InputStream in) throws IOException {
this(in, LZ4Factory.fastestInstance().safeDecompressor(), XXHashFactory.fastestInstance().hash32());
}
/**
* Creates a new {@link InputStream} that will decompress data using the LZ4 algorithm.
*
* @param in the stream to decompress
* @param decompressor the decompressor to use
* @param checksum the hash function to use
* @throws IOException if an I/O error occurs
*/
public LZ4FrameInputStream(InputStream in, LZ4SafeDecompressor decompressor, XXHash32 checksum) throws IOException {
super(in);
this.decompressor = decompressor;
this.checksum = checksum;
nextFrameInfo();
}
/**
* Try and load in the next valid frame info. This will skip over skippable frames.
* @return True if a frame was loaded. False if there are no more frames in the stream.
* @throws IOException On input stream read exception
*/
private boolean nextFrameInfo() throws IOException {
while (true) {
int size = 0;
do {
final int mySize = in.read(readNumberBuff.array(), size, LZ4FrameOutputStream.INTEGER_BYTES - size);
if (mySize < 0) {
return false;
}
size += mySize;
} while (size < LZ4FrameOutputStream.INTEGER_BYTES);
final int magic = readNumberBuff.getInt(0);
if (magic == LZ4FrameOutputStream.MAGIC) {
readHeader();
return true;
} else if ((magic >>> 4) == (MAGIC_SKIPPABLE_BASE >>> 4)) {
skippableFrame();
} else {
throw new IOException(NOT_SUPPORTED);
}
}
}
private void skippableFrame() throws IOException {
int skipSize = readInt(in);
final byte[] skipBuffer = new byte[1 << 10];
while (skipSize > 0) {
final int mySize = in.read(skipBuffer, 0, Math.min(skipSize, skipBuffer.length));
if (mySize < 0) {
throw new IOException(PREMATURE_EOS);
}
skipSize -= mySize;
}
}
/**
* Reads the frame descriptor from the underlying {@link InputStream}.
*
* @throws IOException
*/
private void readHeader() throws IOException {
headerBuffer.rewind();
final int flgRead = in.read();
if (flgRead < 0) {
throw new IOException(PREMATURE_EOS);
}
final int bdRead = in.read();
if (bdRead < 0) {
throw new IOException(PREMATURE_EOS);
}
final byte flgByte = (byte)(flgRead & 0xFF);
final LZ4FrameOutputStream.FLG flg = LZ4FrameOutputStream.FLG.fromByte(flgByte);
headerBuffer.put(flgByte);
final byte bdByte = (byte)(bdRead & 0xFF);
final LZ4FrameOutputStream.BD bd = LZ4FrameOutputStream.BD.fromByte(bdByte);
headerBuffer.put(bdByte);
this.frameInfo = new LZ4FrameOutputStream.FrameInfo(flg, bd);
if (flg.isEnabled(LZ4FrameOutputStream.FLG.Bits.CONTENT_SIZE)) {
expectedContentSize = readLong(in);
headerBuffer.putLong(expectedContentSize);
}
totalContentSize = 0L;
// check stream descriptor hash
final byte hash = (byte) ((checksum.hash(headerArray, 0, headerBuffer.position(), 0) >> 8) & 0xFF);
final int expectedHash = in.read();
if (expectedHash < 0) {
throw new IOException(PREMATURE_EOS);
}
if (hash != (byte)(expectedHash & 0xFF)) {
throw new IOException(DESCRIPTOR_HASH_MISMATCH);
}
maxBlockSize = frameInfo.getBD().getBlockMaximumSize();
compressedBuffer = new byte[maxBlockSize]; // Reused during different compressions
rawBuffer = new byte[maxBlockSize];
buffer = ByteBuffer.wrap(rawBuffer);
buffer.limit(0);
}
private final ByteBuffer readNumberBuff = ByteBuffer.allocate(LZ4FrameOutputStream.LONG_BYTES).order(ByteOrder.LITTLE_ENDIAN);
private long readLong(InputStream stream) throws IOException {
int offset = 0;
do {
final int mySize = stream.read(readNumberBuff.array(), offset, LZ4FrameOutputStream.LONG_BYTES - offset);
if (mySize < 0) {
throw new IOException(PREMATURE_EOS);
}
offset += mySize;
} while (offset < LZ4FrameOutputStream.LONG_BYTES);
return readNumberBuff.getLong(0);
}
private int readInt(InputStream stream) throws IOException {
int offset = 0;
do {
final int mySize = stream.read(readNumberBuff.array(), offset, LZ4FrameOutputStream.INTEGER_BYTES - offset);
if (mySize < 0) {
throw new IOException(PREMATURE_EOS);
}
offset += mySize;
} while (offset < LZ4FrameOutputStream.INTEGER_BYTES);
return readNumberBuff.getInt(0);
}
/**
* Decompress (if necessary) buffered data, optionally computes and validates a XXHash32 checksum, and writes the
* result to a buffer.
*
* @throws IOException
*/
private void readBlock() throws IOException {
int blockSize = readInt(in);
final boolean compressed = (blockSize & LZ4FrameOutputStream.LZ4_FRAME_INCOMPRESSIBLE_MASK) == 0;
blockSize &= ~LZ4FrameOutputStream.LZ4_FRAME_INCOMPRESSIBLE_MASK;
// Check for EndMark
if (blockSize == 0) {
if (frameInfo.isEnabled(LZ4FrameOutputStream.FLG.Bits.CONTENT_CHECKSUM)) {
final int contentChecksum = readInt(in);
if (contentChecksum != frameInfo.currentStreamHash()) {
throw new IOException("Content checksum mismatch");
}
}
if (frameInfo.isEnabled(LZ4FrameOutputStream.FLG.Bits.CONTENT_SIZE) && expectedContentSize != totalContentSize) {
throw new IOException("Size check mismatch");
}
frameInfo.finish();
return;
}
final byte[] tmpBuffer; // Use a temporary buffer, potentially one used for compression
if (compressed) {
tmpBuffer = compressedBuffer;
} else {
tmpBuffer = rawBuffer;
}
if (blockSize > maxBlockSize) {
throw new IOException(String.format(Locale.ROOT, "Block size %s exceeded max: %s", blockSize, maxBlockSize));
}
int offset = 0;
while (offset < blockSize) {
final int lastRead = in.read(tmpBuffer, offset, blockSize - offset);
if (lastRead < 0) {
throw new IOException(PREMATURE_EOS);
}
offset += lastRead;
}
// verify block checksum
if (frameInfo.isEnabled(LZ4FrameOutputStream.FLG.Bits.BLOCK_CHECKSUM)) {
final int hashCheck = readInt(in);
if (hashCheck != checksum.hash(tmpBuffer, 0, blockSize, 0)) {
throw new IOException(BLOCK_HASH_MISMATCH);
}
}
final int currentBufferSize;
if (compressed) {
try {
currentBufferSize = decompressor.decompress(tmpBuffer, 0, blockSize, rawBuffer, 0, rawBuffer.length);
} catch (LZ4Exception e) {
throw new IOException(e);
}
} else {
currentBufferSize = blockSize;
}
if (frameInfo.isEnabled(LZ4FrameOutputStream.FLG.Bits.CONTENT_CHECKSUM)) {
frameInfo.updateStreamHash(rawBuffer, 0, currentBufferSize);
}
totalContentSize += currentBufferSize;
buffer.limit(currentBufferSize);
buffer.rewind();
}
@Override
public int read() throws IOException {
while (buffer.remaining() == 0) {
if (frameInfo.isFinished()) {
if (!nextFrameInfo()) {
return -1;
}
}
readBlock();
}
return (int)buffer.get() & 0xFF;
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
if ((off < 0) || (len < 0) || (off + len > b.length)) {
throw new IndexOutOfBoundsException();
}
while (buffer.remaining() == 0) {
if (frameInfo.isFinished()) {
if (!nextFrameInfo()) {
return -1;
}
}
readBlock();
}
len = Math.min(len, buffer.remaining());
buffer.get(b, off, len);
return len;
}
@Override
public long skip(long n) throws IOException {
if (n <= 0) {
return 0;
}
while (buffer.remaining() == 0) {
if (frameInfo.isFinished()) {
if (!nextFrameInfo()) {
return 0;
}
}
readBlock();
}
n = Math.min(n, buffer.remaining());
buffer.position(buffer.position() + (int)n);
return n;
}
@Override
public int available() throws IOException {
return buffer.remaining();
}
@Override
public void close() throws IOException {
super.close();
}
@Override
public synchronized void mark(int readlimit) {
throw new UnsupportedOperationException("mark not supported");
}
@Override
public synchronized void reset() throws IOException {
throw new UnsupportedOperationException("reset not supported");
}
@Override
public boolean markSupported() {
return false;
}
}

434
fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4FrameOutputStream.java

@ -0,0 +1,434 @@
package com.fr.third.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 com.fr.third.net.jpountz.xxhash.StreamingXXHash32;
import com.fr.third.net.jpountz.xxhash.XXHash32;
import com.fr.third.net.jpountz.xxhash.XXHashFactory;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Locale;
/**
* Implementation of the v1.5.1 LZ4 Frame format. This class is NOT thread safe.
* <p>
* Not Supported:<ul>
* <li>Dependent blocks</li>
* <li>Legacy streams</li>
* <li>Multiple frames (one LZ4FrameOutputStream is one frame)</li>
* </ul>
* <p>
* Originally based on kafka's KafkaLZ4BlockOutputStream.
*
* @see <a href="https://github.com/lz4/lz4/blob/dev/doc/lz4_Frame_format.md">LZ4 Framing Format Spec 1.5.1</a>
*/
public class LZ4FrameOutputStream extends FilterOutputStream {
static final int INTEGER_BYTES = Integer.SIZE >>> 3; // or Integer.BYTES in Java 1.8
static final int LONG_BYTES = Long.SIZE >>> 3; // or Long.BYTES in Java 1.8
static final int MAGIC = 0x184D2204;
static final int LZ4_MAX_HEADER_LENGTH =
4 + // magic
1 + // FLG
1 + // BD
8 + // Content Size
1; // HC
static final int LZ4_FRAME_INCOMPRESSIBLE_MASK = 0x80000000;
static final FLG.Bits[] DEFAULT_FEATURES = new FLG.Bits[]{FLG.Bits.BLOCK_INDEPENDENCE};
static final String CLOSED_STREAM = "The stream is already closed";
public static enum BLOCKSIZE {
SIZE_64KB(4), SIZE_256KB(5), SIZE_1MB(6), SIZE_4MB(7);
private final int indicator;
BLOCKSIZE(int indicator) {
this.indicator = indicator;
}
public int getIndicator() {
return this.indicator;
}
public static BLOCKSIZE valueOf(int indicator) {
switch(indicator) {
case 7: return SIZE_4MB;
case 6: return SIZE_1MB;
case 5: return SIZE_256KB;
case 4: return SIZE_64KB;
default: throw new IllegalArgumentException(String.format(Locale.ROOT, "Block size must be 4-7. Cannot use value of [%d]", indicator));
}
}
}
private final LZ4Compressor compressor;
private final XXHash32 checksum;
private final ByteBuffer buffer; // Buffer for uncompressed input data
private final byte[] compressedBuffer; // Only allocated once so it can be reused
private final int maxBlockSize;
private final long knownSize;
private final ByteBuffer intLEBuffer = ByteBuffer.allocate(INTEGER_BYTES).order(ByteOrder.LITTLE_ENDIAN);
private FrameInfo frameInfo = null;
/**
* Creates a new {@link OutputStream} that will compress data of unknown size using the LZ4 algorithm.
*
* @param out the output stream to compress
* @param blockSize the BLOCKSIZE to use
* @param bits a set of features to use
* @throws IOException if an I/O error occurs
*
* @see #LZ4FrameOutputStream(OutputStream, BLOCKSIZE, long, FLG.Bits...)
*/
public LZ4FrameOutputStream(OutputStream out, BLOCKSIZE blockSize, FLG.Bits... bits) throws IOException {
this(out, blockSize, -1L, bits);
}
/**
* Creates a new {@link OutputStream} that will compress data using using fastest instances of {@link LZ4Compressor} and {@link XXHash32}.
*
* @param out the output stream to compress
* @param blockSize the BLOCKSIZE to use
* @param knownSize the size of the uncompressed data. A value less than zero means unknown.
* @param bits a set of features to use
* @throws IOException if an I/O error occurs
*/
public LZ4FrameOutputStream(OutputStream out, BLOCKSIZE blockSize, long knownSize, FLG.Bits... bits) throws IOException {
super(out);
compressor = LZ4Factory.fastestInstance().fastCompressor();
checksum = XXHashFactory.fastestInstance().hash32();
frameInfo = new FrameInfo(new FLG(FLG.DEFAULT_VERSION, bits), new BD(blockSize));
maxBlockSize = frameInfo.getBD().getBlockMaximumSize();
buffer = ByteBuffer.allocate(maxBlockSize).order(ByteOrder.LITTLE_ENDIAN);
compressedBuffer = new byte[compressor.maxCompressedLength(maxBlockSize)];
if (frameInfo.getFLG().isEnabled(FLG.Bits.CONTENT_SIZE) && knownSize < 0) {
throw new IllegalArgumentException("Known size must be greater than zero in order to use the known size feature");
}
this.knownSize = knownSize;
writeHeader();
}
/**
* Creates a new {@link OutputStream} that will compress data using the LZ4 algorithm. The block independence flag is set, and none of the other flags are set.
*
* @param out The stream to compress
* @param blockSize the BLOCKSIZE to use
* @throws IOException if an I/O error occurs
*
* @see #LZ4FrameOutputStream(OutputStream, BLOCKSIZE, FLG.Bits...)
*/
public LZ4FrameOutputStream(OutputStream out, BLOCKSIZE blockSize) throws IOException {
this(out, blockSize, DEFAULT_FEATURES);
}
/**
* Creates a new {@link OutputStream} that will compress data using the LZ4 algorithm with 4-MB blocks.
*
* @param out the output stream to compress
* @throws IOException if an I/O error occurs
*
* @see #LZ4FrameOutputStream(OutputStream, BLOCKSIZE)
*/
public LZ4FrameOutputStream(OutputStream out) throws IOException {
this(out, BLOCKSIZE.SIZE_4MB);
}
/**
* Writes the magic number and frame descriptor to the underlying {@link OutputStream}.
*
* @throws IOException
*/
private void writeHeader() throws IOException {
final ByteBuffer headerBuffer = ByteBuffer.allocate(LZ4_MAX_HEADER_LENGTH).order(ByteOrder.LITTLE_ENDIAN);
headerBuffer.putInt(MAGIC);
headerBuffer.put(frameInfo.getFLG().toByte());
headerBuffer.put(frameInfo.getBD().toByte());
if (frameInfo.isEnabled(FLG.Bits.CONTENT_SIZE)) {
headerBuffer.putLong(knownSize);
}
// compute checksum on all descriptor fields
final int hash = (checksum.hash(headerBuffer.array(), INTEGER_BYTES, headerBuffer.position() - INTEGER_BYTES, 0) >> 8) & 0xFF;
headerBuffer.put((byte) hash);
// write out frame descriptor
out.write(headerBuffer.array(), 0, headerBuffer.position());
}
/**
* Compresses buffered data, optionally computes an XXHash32 checksum, and writes the result to the underlying
* {@link OutputStream}.
*
* @throws IOException
*/
private void writeBlock() throws IOException {
if (buffer.position() == 0) {
return;
}
// Make sure there's no stale data
Arrays.fill(compressedBuffer, (byte) 0);
int compressedLength = compressor.compress(buffer.array(), 0, buffer.position(), compressedBuffer, 0);
final byte[] bufferToWrite;
final int compressMethod;
// Store block uncompressed if compressed length is greater (incompressible)
if (compressedLength >= buffer.position()) {
compressedLength = buffer.position();
bufferToWrite = Arrays.copyOf(buffer.array(), compressedLength);
compressMethod = LZ4_FRAME_INCOMPRESSIBLE_MASK;
} else {
bufferToWrite = compressedBuffer;
compressMethod = 0;
}
// Write content
intLEBuffer.putInt(0, compressedLength | compressMethod);
out.write(intLEBuffer.array());
out.write(bufferToWrite, 0, compressedLength);
// Calculate and write block checksum
if (frameInfo.isEnabled(FLG.Bits.BLOCK_CHECKSUM)) {
intLEBuffer.putInt(0, checksum.hash(bufferToWrite, 0, compressedLength, 0));
out.write(intLEBuffer.array());
}
buffer.rewind();
}
/**
* Similar to the {@link #writeBlock()} method. Writes a 0-length block (without block checksum) to signal the end
* of the block stream.
*
* @throws IOException
*/
private void writeEndMark() throws IOException {
intLEBuffer.putInt(0, 0);
out.write(intLEBuffer.array());
if (frameInfo.isEnabled(FLG.Bits.CONTENT_CHECKSUM)) {
intLEBuffer.putInt(0, frameInfo.currentStreamHash());
out.write(intLEBuffer.array());
}
frameInfo.finish();
}
@Override
public void write(int b) throws IOException {
ensureNotFinished();
if (buffer.position() == maxBlockSize) {
writeBlock();
}
buffer.put((byte) b);
if (frameInfo.isEnabled(FLG.Bits.CONTENT_CHECKSUM)) {
frameInfo.updateStreamHash(new byte[]{(byte) b}, 0, 1);
}
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
if ((off < 0) || (len < 0) || (off + len > b.length)) {
throw new IndexOutOfBoundsException();
}
ensureNotFinished();
// while b will fill the buffer
while (len > buffer.remaining()) {
int sizeWritten = buffer.remaining();
// fill remaining space in buffer
buffer.put(b, off, sizeWritten);
if (frameInfo.isEnabled(FLG.Bits.CONTENT_CHECKSUM)) {
frameInfo.updateStreamHash(b, off, sizeWritten);
}
writeBlock();
// compute new offset and length
off += sizeWritten;
len -= sizeWritten;
}
buffer.put(b, off, len);
if (frameInfo.isEnabled(FLG.Bits.CONTENT_CHECKSUM)) {
frameInfo.updateStreamHash(b, off, len);
}
}
@Override
public void flush() throws IOException {
if (!frameInfo.isFinished()) {
writeBlock();
}
super.flush();
}
/**
* A simple state check to ensure the stream is still open.
*/
private void ensureNotFinished() {
if (frameInfo.isFinished()) {
throw new IllegalStateException(CLOSED_STREAM);
}
}
@Override
public void close() throws IOException {
if (!frameInfo.isFinished()) {
flush();
writeEndMark();
}
super.close();
}
public static class FLG {
private static final int DEFAULT_VERSION = 1;
private final BitSet bitSet;
private final int version;
public enum Bits {
RESERVED_0(0),
RESERVED_1(1),
CONTENT_CHECKSUM(2),
CONTENT_SIZE(3),
BLOCK_CHECKSUM(4),
BLOCK_INDEPENDENCE(5);
private final int position;
Bits(int position) {
this.position = position;
}
}
public FLG(int version, Bits... bits) {
this.bitSet = new BitSet(8);
this.version = version;
if (bits != null) {
for (Bits bit : bits) {
bitSet.set(bit.position);
}
}
validate();
}
private FLG(int version, byte b) {
this.bitSet = BitSet.valueOf(new byte[]{b});
this.version = version;
validate();
}
public static FLG fromByte(byte flg) {
final byte versionMask = (byte)(flg & (3 << 6));
return new FLG(versionMask >>> 6, (byte) (flg ^ versionMask));
}
public byte toByte() {
return (byte)(bitSet.toByteArray()[0] | ((version & 3) << 6));
}
private void validate() {
if (bitSet.get(Bits.RESERVED_0.position)) {
throw new RuntimeException("Reserved0 field must be 0");
}
if (bitSet.get(Bits.RESERVED_1.position)) {
throw new RuntimeException("Reserved1 field must be 0");
}
if (!bitSet.get(Bits.BLOCK_INDEPENDENCE.position)) {
throw new RuntimeException("Dependent block stream is unsupported (BLOCK_INDEPENDENCE must be set)");
}
if (version != DEFAULT_VERSION) {
throw new RuntimeException(String.format(Locale.ROOT, "Version %d is unsupported", version));
}
}
public boolean isEnabled(Bits bit) {
return bitSet.get(bit.position);
}
public int getVersion() {
return version;
}
}
public static class BD {
private static final int RESERVED_MASK = 0x8F;
private final BLOCKSIZE blockSizeValue;
private BD(BLOCKSIZE blockSizeValue) {
this.blockSizeValue = blockSizeValue;
}
public static BD fromByte(byte bd) {
int blockMaximumSize = (bd >>> 4) & 7;
if ((bd & RESERVED_MASK) > 0) {
throw new RuntimeException("Reserved fields must be 0");
}
return new BD(BLOCKSIZE.valueOf(blockMaximumSize));
}
// 2^(2n+8)
public int getBlockMaximumSize() {
return 1 << ((2 * blockSizeValue.getIndicator()) + 8);
}
public byte toByte() {
return (byte) ((blockSizeValue.getIndicator() & 7) << 4);
}
}
static class FrameInfo {
private final FLG flg;
private final BD bd;
private final StreamingXXHash32 streamHash;
private boolean finished = false;
public FrameInfo(FLG flg, BD bd) {
this.flg = flg;
this.bd = bd;
this.streamHash = flg.isEnabled(FLG.Bits.CONTENT_CHECKSUM) ? XXHashFactory.fastestInstance().newStreamingHash32(0) : null;
}
public boolean isEnabled(FLG.Bits bit) {
return flg.isEnabled(bit);
}
public FLG getFLG() {
return this.flg;
}
public BD getBD() {
return this.bd;
}
public void updateStreamHash(byte[] buff, int off, int len) {
this.streamHash.update(buff, off, len);
}
public int currentStreamHash() {
return this.streamHash.getValue();
}
public void finish() {
this.finished = true;
}
public boolean isFinished() {
return this.finished;
}
}
}

86
fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4HCJNICompressor.java

@ -0,0 +1,86 @@
package com.fr.third.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.nio.ByteBuffer;
import com.fr.third.net.jpountz.util.ByteBufferUtils;
import com.fr.third.net.jpountz.util.SafeUtils;
/**
* High compression {@link LZ4Compressor}s implemented with JNI bindings to the
* original C implementation of LZ4.
*/
final class LZ4HCJNICompressor extends LZ4Compressor {
public static final LZ4HCJNICompressor INSTANCE = new LZ4HCJNICompressor();
private static LZ4Compressor SAFE_INSTANCE;
private final int compressionLevel;
LZ4HCJNICompressor() { this(LZ4Constants.DEFAULT_COMPRESSION_LEVEL); }
LZ4HCJNICompressor(int compressionLevel) {
this.compressionLevel = compressionLevel;
}
@Override
public int compress(byte[] src, int srcOff, int srcLen, byte[] dest, int destOff, int maxDestLen) {
SafeUtils.checkRange(src, srcOff, srcLen);
SafeUtils.checkRange(dest, destOff, maxDestLen);
final int result = LZ4JNI.LZ4_compressHC(src, null, srcOff, srcLen, dest, null, destOff, maxDestLen, compressionLevel);
if (result <= 0) {
throw new LZ4Exception();
}
return result;
}
@Override
public int compress(ByteBuffer src, int srcOff, int srcLen, ByteBuffer dest, int destOff, int maxDestLen) {
ByteBufferUtils.checkNotReadOnly(dest);
ByteBufferUtils.checkRange(src, srcOff, srcLen);
ByteBufferUtils.checkRange(dest, destOff, maxDestLen);
if ((src.hasArray() || src.isDirect()) && (dest.hasArray() || dest.isDirect())) {
byte[] srcArr = null, destArr = null;
ByteBuffer srcBuf = null, destBuf = null;
if (src.hasArray()) {
srcArr = src.array();
srcOff += src.arrayOffset();
} else {
assert src.isDirect();
srcBuf = src;
}
if (dest.hasArray()) {
destArr = dest.array();
destOff += dest.arrayOffset();
} else {
assert dest.isDirect();
destBuf = dest;
}
final int result = LZ4JNI.LZ4_compressHC(srcArr, srcBuf, srcOff, srcLen, destArr, destBuf, destOff, maxDestLen, compressionLevel);
if (result <= 0) {
throw new LZ4Exception();
}
return result;
} else {
LZ4Compressor safeInstance = SAFE_INSTANCE;
if (safeInstance == null) {
safeInstance = SAFE_INSTANCE = LZ4Factory.safeInstance().highCompressor(compressionLevel);
}
return safeInstance.compress(src, srcOff, srcLen, dest, destOff, maxDestLen);
}
}
}

550
fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4HCJavaSafeCompressor.java

@ -0,0 +1,550 @@
// Auto-generated: DO NOT EDIT
package com.fr.third.net.jpountz.lz4;
import static com.fr.third.net.jpountz.lz4.LZ4Constants.*;
import static com.fr.third.net.jpountz.lz4.LZ4Utils.*;
import java.nio.ByteBuffer;
import java.util.Arrays;
import com.fr.third.net.jpountz.lz4.LZ4Utils.Match;
import com.fr.third.net.jpountz.util.ByteBufferUtils;
import com.fr.third.net.jpountz.util.SafeUtils;
/**
* High compression compressor.
*/
final class LZ4HCJavaSafeCompressor extends LZ4Compressor {
public static final LZ4Compressor INSTANCE = new LZ4HCJavaSafeCompressor();
private final int maxAttempts;
final int compressionLevel;
LZ4HCJavaSafeCompressor() { this(DEFAULT_COMPRESSION_LEVEL); }
LZ4HCJavaSafeCompressor(int compressionLevel) {
this.maxAttempts = 1<<(compressionLevel-1);
this.compressionLevel = compressionLevel;
}
private class HashTable {
static final int MASK = MAX_DISTANCE - 1;
int nextToUpdate;
private final int base;
private final int[] hashTable;
private final short[] chainTable;
HashTable(int base) {
this.base = base;
nextToUpdate = base;
hashTable = new int[HASH_TABLE_SIZE_HC];
Arrays.fill(hashTable, -1);
chainTable = new short[MAX_DISTANCE];
}
private int hashPointer(byte[] bytes, int off) {
final int v = SafeUtils.readInt(bytes, off);
return hashPointer(v);
}
private int hashPointer(ByteBuffer bytes, int off) {
final int v = ByteBufferUtils.readInt(bytes, off);
return hashPointer(v);
}
private int hashPointer(int v) {
final int h = hashHC(v);
return hashTable[h];
}
private int next(int off) {
return off - (chainTable[off & MASK] & 0xFFFF);
}
private void addHash(byte[] bytes, int off) {
final int v = SafeUtils.readInt(bytes, off);
addHash(v, off);
}
private void addHash(ByteBuffer bytes, int off) {
final int v = ByteBufferUtils.readInt(bytes, off);
addHash(v, off);
}
private void addHash(int v, int off) {
final int h = hashHC(v);
int delta = off - hashTable[h];
assert delta > 0 : delta;
if (delta >= MAX_DISTANCE) {
delta = MAX_DISTANCE - 1;
}
chainTable[off & MASK] = (short) delta;
hashTable[h] = off;
}
void insert(int off, byte[] bytes) {
for (; nextToUpdate < off; ++nextToUpdate) {
addHash(bytes, nextToUpdate);
}
}
void insert(int off, ByteBuffer bytes) {
for (; nextToUpdate < off; ++nextToUpdate) {
addHash(bytes, nextToUpdate);
}
}
boolean insertAndFindBestMatch(byte[] buf, int off, int matchLimit, Match match) {
match.start = off;
match.len = 0;
int delta = 0;
int repl = 0;
insert(off, buf);
int ref = hashPointer(buf, off);
if (ref >= off - 4 && ref <= off && ref >= base) { // potential repetition
if (LZ4SafeUtils.readIntEquals(buf, ref, off)) { // confirmed
delta = off - ref;
repl = match.len = MIN_MATCH + LZ4SafeUtils.commonBytes(buf, ref + MIN_MATCH, off + MIN_MATCH, matchLimit);
match.ref = ref;
}
ref = next(ref);
}
for (int i = 0; i < maxAttempts; ++i) {
if (ref < Math.max(base, off - MAX_DISTANCE + 1) || ref > off) {
break;
}
if (LZ4SafeUtils.readIntEquals(buf, ref, off)) {
final int matchLen = MIN_MATCH + LZ4SafeUtils.commonBytes(buf, ref + MIN_MATCH, off + MIN_MATCH, matchLimit);
if (matchLen > match.len) {
match.ref = ref;
match.len = matchLen;
}
}
ref = next(ref);
}
if (repl != 0) {
int ptr = off;
final int end = off + repl - (MIN_MATCH - 1);
while (ptr < end - delta) {
chainTable[ptr & MASK] = (short) delta; // pre load
++ptr;
}
do {
chainTable[ptr & MASK] = (short) delta;
hashTable[hashHC(SafeUtils.readInt(buf, ptr))] = ptr;
++ptr;
} while (ptr < end);
nextToUpdate = end;
}
return match.len != 0;
}
boolean insertAndFindWiderMatch(byte[] buf, int off, int startLimit, int matchLimit, int minLen, Match match) {
match.len = minLen;
insert(off, buf);
final int delta = off - startLimit;
int ref = hashPointer(buf, off);
for (int i = 0; i < maxAttempts; ++i) {
if (ref < Math.max(base, off - MAX_DISTANCE + 1) || ref > off) {
break;
}
if (LZ4SafeUtils.readIntEquals(buf, ref, off)) {
final int matchLenForward = MIN_MATCH +LZ4SafeUtils.commonBytes(buf, ref + MIN_MATCH, off + MIN_MATCH, matchLimit);
final int matchLenBackward = LZ4SafeUtils.commonBytesBackward(buf, ref, off, base, startLimit);
final int matchLen = matchLenBackward + matchLenForward;
if (matchLen > match.len) {
match.len = matchLen;
match.ref = ref - matchLenBackward;
match.start = off - matchLenBackward;
}
}
ref = next(ref);
}
return match.len > minLen;
}
boolean insertAndFindBestMatch(ByteBuffer buf, int off, int matchLimit, Match match) {
match.start = off;
match.len = 0;
int delta = 0;
int repl = 0;
insert(off, buf);
int ref = hashPointer(buf, off);
if (ref >= off - 4 && ref <= off && ref >= base) { // potential repetition
if (LZ4ByteBufferUtils.readIntEquals(buf, ref, off)) { // confirmed
delta = off - ref;
repl = match.len = MIN_MATCH + LZ4ByteBufferUtils.commonBytes(buf, ref + MIN_MATCH, off + MIN_MATCH, matchLimit);
match.ref = ref;
}
ref = next(ref);
}
for (int i = 0; i < maxAttempts; ++i) {
if (ref < Math.max(base, off - MAX_DISTANCE + 1) || ref > off) {
break;
}
if (LZ4ByteBufferUtils.readIntEquals(buf, ref, off)) {
final int matchLen = MIN_MATCH + LZ4ByteBufferUtils.commonBytes(buf, ref + MIN_MATCH, off + MIN_MATCH, matchLimit);
if (matchLen > match.len) {
match.ref = ref;
match.len = matchLen;
}
}
ref = next(ref);
}
if (repl != 0) {
int ptr = off;
final int end = off + repl - (MIN_MATCH - 1);
while (ptr < end - delta) {
chainTable[ptr & MASK] = (short) delta; // pre load
++ptr;
}
do {
chainTable[ptr & MASK] = (short) delta;
hashTable[hashHC(ByteBufferUtils.readInt(buf, ptr))] = ptr;
++ptr;
} while (ptr < end);
nextToUpdate = end;
}
return match.len != 0;
}
boolean insertAndFindWiderMatch(ByteBuffer buf, int off, int startLimit, int matchLimit, int minLen, Match match) {
match.len = minLen;
insert(off, buf);
final int delta = off - startLimit;
int ref = hashPointer(buf, off);
for (int i = 0; i < maxAttempts; ++i) {
if (ref < Math.max(base, off - MAX_DISTANCE + 1) || ref > off) {
break;
}
if (LZ4ByteBufferUtils.readIntEquals(buf, ref, off)) {
final int matchLenForward = MIN_MATCH +LZ4ByteBufferUtils.commonBytes(buf, ref + MIN_MATCH, off + MIN_MATCH, matchLimit);
final int matchLenBackward = LZ4ByteBufferUtils.commonBytesBackward(buf, ref, off, base, startLimit);
final int matchLen = matchLenBackward + matchLenForward;
if (matchLen > match.len) {
match.len = matchLen;
match.ref = ref - matchLenBackward;
match.start = off - matchLenBackward;
}
}
ref = next(ref);
}
return match.len > minLen;
}
}
@Override
public int compress(byte[] src, int srcOff, int srcLen, byte[] dest, int destOff, int maxDestLen) {
SafeUtils.checkRange(src, srcOff, srcLen);
SafeUtils.checkRange(dest, destOff, maxDestLen);
final int srcEnd = srcOff + srcLen;
final int destEnd = destOff + maxDestLen;
final int mfLimit = srcEnd - MF_LIMIT;
final int matchLimit = srcEnd - LAST_LITERALS;
int sOff = srcOff;
int dOff = destOff;
int anchor = sOff++;
final HashTable ht = new HashTable(srcOff);
final Match match0 = new Match();
final Match match1 = new Match();
final Match match2 = new Match();
final Match match3 = new Match();
main:
while (sOff < mfLimit) {
if (!ht.insertAndFindBestMatch(src, sOff, matchLimit, match1)) {
++sOff;
continue;
}
// saved, in case we would skip too much
copyTo(match1, match0);
search2:
while (true) {
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 = LZ4SafeUtils.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
copyTo(match0, match1);
}
}
assert match2.start > match1.start;
if (match2.start - match1.start < 3) { // First Match too small : removed
copyTo(match2, match1);
continue search2;
}
search3:
while (true) {
if (match2.start - match1.start < OPTIMAL_ML) {
int newMatchLen = match1.len;
if (newMatchLen > OPTIMAL_ML) {
newMatchLen = OPTIMAL_ML;
}
if (match1.start + newMatchLen > match2.end() - MIN_MATCH) {
newMatchLen = match2.start - match1.start + match2.len - MIN_MATCH;
}
final int correction = newMatchLen - (match2.start - match1.start);
if (correction > 0) {
match2.fix(correction);
}
}
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 = LZ4SafeUtils.encodeSequence(src, anchor, match1.start, match1.ref, match1.len, dest, dOff, destEnd);
anchor = sOff = match1.end();
// encode seq 2
dOff = LZ4SafeUtils.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 (match2.start < match1.end()) {
final int correction = match1.end() - match2.start;
match2.fix(correction);
if (match2.len < MIN_MATCH) {
copyTo(match3, match2);
}
}
dOff = LZ4SafeUtils.encodeSequence(src, anchor, match1.start, match1.ref, match1.len, dest, dOff, destEnd);
anchor = sOff = match1.end();
copyTo(match3, match1);
copyTo(match2, match0);
continue search2;
}
copyTo(match3, match2);
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) {
match1.len = OPTIMAL_ML;
}
if (match1.end() > match2.end() - MIN_MATCH) {
match1.len = match2.end() - match1.start - MIN_MATCH;
}
final int correction = match1.end() - match2.start;
match2.fix(correction);
} else {
match1.len = match2.start - match1.start;
}
}
dOff = LZ4SafeUtils.encodeSequence(src, anchor, match1.start, match1.ref, match1.len, dest, dOff, destEnd);
anchor = sOff = match1.end();
copyTo(match2, match1);
copyTo(match3, match2);
continue search3;
}
}
}
dOff = LZ4SafeUtils.lastLiterals(src, anchor, srcEnd - anchor, dest, dOff, destEnd);
return dOff - destOff;
}
@Override
public int compress(ByteBuffer src, int srcOff, int srcLen, ByteBuffer dest, int destOff, int maxDestLen) {
if (src.hasArray() && dest.hasArray()) {
return compress(src.array(), srcOff + src.arrayOffset(), srcLen, dest.array(), destOff + dest.arrayOffset(), maxDestLen);
}
src = ByteBufferUtils.inNativeByteOrder(src);
dest = ByteBufferUtils.inNativeByteOrder(dest);
ByteBufferUtils.checkRange(src, srcOff, srcLen);
ByteBufferUtils.checkRange(dest, destOff, maxDestLen);
final int srcEnd = srcOff + srcLen;
final int destEnd = destOff + maxDestLen;
final int mfLimit = srcEnd - MF_LIMIT;
final int matchLimit = srcEnd - LAST_LITERALS;
int sOff = srcOff;
int dOff = destOff;
int anchor = sOff++;
final HashTable ht = new HashTable(srcOff);
final Match match0 = new Match();
final Match match1 = new Match();
final Match match2 = new Match();
final Match match3 = new Match();
main:
while (sOff < mfLimit) {
if (!ht.insertAndFindBestMatch(src, sOff, matchLimit, match1)) {
++sOff;
continue;
}
// saved, in case we would skip too much
copyTo(match1, match0);
search2:
while (true) {
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 = LZ4ByteBufferUtils.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
copyTo(match0, match1);
}
}
assert match2.start > match1.start;
if (match2.start - match1.start < 3) { // First Match too small : removed
copyTo(match2, match1);
continue search2;
}
search3:
while (true) {
if (match2.start - match1.start < OPTIMAL_ML) {
int newMatchLen = match1.len;
if (newMatchLen > OPTIMAL_ML) {
newMatchLen = OPTIMAL_ML;
}
if (match1.start + newMatchLen > match2.end() - MIN_MATCH) {
newMatchLen = match2.start - match1.start + match2.len - MIN_MATCH;
}
final int correction = newMatchLen - (match2.start - match1.start);
if (correction > 0) {
match2.fix(correction);
}
}
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 = LZ4ByteBufferUtils.encodeSequence(src, anchor, match1.start, match1.ref, match1.len, dest, dOff, destEnd);
anchor = sOff = match1.end();
// encode seq 2
dOff = LZ4ByteBufferUtils.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 (match2.start < match1.end()) {
final int correction = match1.end() - match2.start;
match2.fix(correction);
if (match2.len < MIN_MATCH) {
copyTo(match3, match2);
}
}
dOff = LZ4ByteBufferUtils.encodeSequence(src, anchor, match1.start, match1.ref, match1.len, dest, dOff, destEnd);
anchor = sOff = match1.end();
copyTo(match3, match1);
copyTo(match2, match0);
continue search2;
}
copyTo(match3, match2);
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) {
match1.len = OPTIMAL_ML;
}
if (match1.end() > match2.end() - MIN_MATCH) {
match1.len = match2.end() - match1.start - MIN_MATCH;
}
final int correction = match1.end() - match2.start;
match2.fix(correction);
} else {
match1.len = match2.start - match1.start;
}
}
dOff = LZ4ByteBufferUtils.encodeSequence(src, anchor, match1.start, match1.ref, match1.len, dest, dOff, destEnd);
anchor = sOff = match1.end();
copyTo(match2, match1);
copyTo(match3, match2);
continue search3;
}
}
}
dOff = LZ4ByteBufferUtils.lastLiterals(src, anchor, srcEnd - anchor, dest, dOff, destEnd);
return dOff - destOff;
}
}

550
fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4HCJavaUnsafeCompressor.java

@ -0,0 +1,550 @@
// Auto-generated: DO NOT EDIT
package com.fr.third.net.jpountz.lz4;
import static com.fr.third.net.jpountz.lz4.LZ4Constants.*;
import static com.fr.third.net.jpountz.lz4.LZ4Utils.*;
import java.nio.ByteBuffer;
import java.util.Arrays;
import com.fr.third.net.jpountz.lz4.LZ4Utils.Match;
import com.fr.third.net.jpountz.util.ByteBufferUtils;
import com.fr.third.net.jpountz.util.UnsafeUtils;
/**
* High compression compressor.
*/
final class LZ4HCJavaUnsafeCompressor extends LZ4Compressor {
public static final LZ4Compressor INSTANCE = new LZ4HCJavaUnsafeCompressor();
private final int maxAttempts;
final int compressionLevel;
LZ4HCJavaUnsafeCompressor() { this(DEFAULT_COMPRESSION_LEVEL); }
LZ4HCJavaUnsafeCompressor(int compressionLevel) {
this.maxAttempts = 1<<(compressionLevel-1);
this.compressionLevel = compressionLevel;
}
private class HashTable {
static final int MASK = MAX_DISTANCE - 1;
int nextToUpdate;
private final int base;
private final int[] hashTable;
private final short[] chainTable;
HashTable(int base) {
this.base = base;
nextToUpdate = base;
hashTable = new int[HASH_TABLE_SIZE_HC];
Arrays.fill(hashTable, -1);
chainTable = new short[MAX_DISTANCE];
}
private int hashPointer(byte[] bytes, int off) {
final int v = UnsafeUtils.readInt(bytes, off);
return hashPointer(v);
}
private int hashPointer(ByteBuffer bytes, int off) {
final int v = ByteBufferUtils.readInt(bytes, off);
return hashPointer(v);
}
private int hashPointer(int v) {
final int h = hashHC(v);
return hashTable[h];
}
private int next(int off) {
return off - (chainTable[off & MASK] & 0xFFFF);
}
private void addHash(byte[] bytes, int off) {
final int v = UnsafeUtils.readInt(bytes, off);
addHash(v, off);
}
private void addHash(ByteBuffer bytes, int off) {
final int v = ByteBufferUtils.readInt(bytes, off);
addHash(v, off);
}
private void addHash(int v, int off) {
final int h = hashHC(v);
int delta = off - hashTable[h];
assert delta > 0 : delta;
if (delta >= MAX_DISTANCE) {
delta = MAX_DISTANCE - 1;
}
chainTable[off & MASK] = (short) delta;
hashTable[h] = off;
}
void insert(int off, byte[] bytes) {
for (; nextToUpdate < off; ++nextToUpdate) {
addHash(bytes, nextToUpdate);
}
}
void insert(int off, ByteBuffer bytes) {
for (; nextToUpdate < off; ++nextToUpdate) {
addHash(bytes, nextToUpdate);
}
}
boolean insertAndFindBestMatch(byte[] buf, int off, int matchLimit, Match match) {
match.start = off;
match.len = 0;
int delta = 0;
int repl = 0;
insert(off, buf);
int ref = hashPointer(buf, off);
if (ref >= off - 4 && ref <= off && ref >= base) { // potential repetition
if (LZ4UnsafeUtils.readIntEquals(buf, ref, off)) { // confirmed
delta = off - ref;
repl = match.len = MIN_MATCH + LZ4UnsafeUtils.commonBytes(buf, ref + MIN_MATCH, off + MIN_MATCH, matchLimit);
match.ref = ref;
}
ref = next(ref);
}
for (int i = 0; i < maxAttempts; ++i) {
if (ref < Math.max(base, off - MAX_DISTANCE + 1) || ref > off) {
break;
}
if (LZ4UnsafeUtils.readIntEquals(buf, ref, off)) {
final int matchLen = MIN_MATCH + LZ4UnsafeUtils.commonBytes(buf, ref + MIN_MATCH, off + MIN_MATCH, matchLimit);
if (matchLen > match.len) {
match.ref = ref;
match.len = matchLen;
}
}
ref = next(ref);
}
if (repl != 0) {
int ptr = off;
final int end = off + repl - (MIN_MATCH - 1);
while (ptr < end - delta) {
chainTable[ptr & MASK] = (short) delta; // pre load
++ptr;
}
do {
chainTable[ptr & MASK] = (short) delta;
hashTable[hashHC(UnsafeUtils.readInt(buf, ptr))] = ptr;
++ptr;
} while (ptr < end);
nextToUpdate = end;
}
return match.len != 0;
}
boolean insertAndFindWiderMatch(byte[] buf, int off, int startLimit, int matchLimit, int minLen, Match match) {
match.len = minLen;
insert(off, buf);
final int delta = off - startLimit;
int ref = hashPointer(buf, off);
for (int i = 0; i < maxAttempts; ++i) {
if (ref < Math.max(base, off - MAX_DISTANCE + 1) || ref > off) {
break;
}
if (LZ4UnsafeUtils.readIntEquals(buf, ref, off)) {
final int matchLenForward = MIN_MATCH +LZ4UnsafeUtils.commonBytes(buf, ref + MIN_MATCH, off + MIN_MATCH, matchLimit);
final int matchLenBackward = LZ4UnsafeUtils.commonBytesBackward(buf, ref, off, base, startLimit);
final int matchLen = matchLenBackward + matchLenForward;
if (matchLen > match.len) {
match.len = matchLen;
match.ref = ref - matchLenBackward;
match.start = off - matchLenBackward;
}
}
ref = next(ref);
}
return match.len > minLen;
}
boolean insertAndFindBestMatch(ByteBuffer buf, int off, int matchLimit, Match match) {
match.start = off;
match.len = 0;
int delta = 0;
int repl = 0;
insert(off, buf);
int ref = hashPointer(buf, off);
if (ref >= off - 4 && ref <= off && ref >= base) { // potential repetition
if (LZ4ByteBufferUtils.readIntEquals(buf, ref, off)) { // confirmed
delta = off - ref;
repl = match.len = MIN_MATCH + LZ4ByteBufferUtils.commonBytes(buf, ref + MIN_MATCH, off + MIN_MATCH, matchLimit);
match.ref = ref;
}
ref = next(ref);
}
for (int i = 0; i < maxAttempts; ++i) {
if (ref < Math.max(base, off - MAX_DISTANCE + 1) || ref > off) {
break;
}
if (LZ4ByteBufferUtils.readIntEquals(buf, ref, off)) {
final int matchLen = MIN_MATCH + LZ4ByteBufferUtils.commonBytes(buf, ref + MIN_MATCH, off + MIN_MATCH, matchLimit);
if (matchLen > match.len) {
match.ref = ref;
match.len = matchLen;
}
}
ref = next(ref);
}
if (repl != 0) {
int ptr = off;
final int end = off + repl - (MIN_MATCH - 1);
while (ptr < end - delta) {
chainTable[ptr & MASK] = (short) delta; // pre load
++ptr;
}
do {
chainTable[ptr & MASK] = (short) delta;
hashTable[hashHC(ByteBufferUtils.readInt(buf, ptr))] = ptr;
++ptr;
} while (ptr < end);
nextToUpdate = end;
}
return match.len != 0;
}
boolean insertAndFindWiderMatch(ByteBuffer buf, int off, int startLimit, int matchLimit, int minLen, Match match) {
match.len = minLen;
insert(off, buf);
final int delta = off - startLimit;
int ref = hashPointer(buf, off);
for (int i = 0; i < maxAttempts; ++i) {
if (ref < Math.max(base, off - MAX_DISTANCE + 1) || ref > off) {
break;
}
if (LZ4ByteBufferUtils.readIntEquals(buf, ref, off)) {
final int matchLenForward = MIN_MATCH +LZ4ByteBufferUtils.commonBytes(buf, ref + MIN_MATCH, off + MIN_MATCH, matchLimit);
final int matchLenBackward = LZ4ByteBufferUtils.commonBytesBackward(buf, ref, off, base, startLimit);
final int matchLen = matchLenBackward + matchLenForward;
if (matchLen > match.len) {
match.len = matchLen;
match.ref = ref - matchLenBackward;
match.start = off - matchLenBackward;
}
}
ref = next(ref);
}
return match.len > minLen;
}
}
@Override
public int compress(byte[] src, int srcOff, int srcLen, byte[] dest, int destOff, int maxDestLen) {
UnsafeUtils.checkRange(src, srcOff, srcLen);
UnsafeUtils.checkRange(dest, destOff, maxDestLen);
final int srcEnd = srcOff + srcLen;
final int destEnd = destOff + maxDestLen;
final int mfLimit = srcEnd - MF_LIMIT;
final int matchLimit = srcEnd - LAST_LITERALS;
int sOff = srcOff;
int dOff = destOff;
int anchor = sOff++;
final HashTable ht = new HashTable(srcOff);
final Match match0 = new Match();
final Match match1 = new Match();
final Match match2 = new Match();
final Match match3 = new Match();
main:
while (sOff < mfLimit) {
if (!ht.insertAndFindBestMatch(src, sOff, matchLimit, match1)) {
++sOff;
continue;
}
// saved, in case we would skip too much
copyTo(match1, match0);
search2:
while (true) {
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 = LZ4UnsafeUtils.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
copyTo(match0, match1);
}
}
assert match2.start > match1.start;
if (match2.start - match1.start < 3) { // First Match too small : removed
copyTo(match2, match1);
continue search2;
}
search3:
while (true) {
if (match2.start - match1.start < OPTIMAL_ML) {
int newMatchLen = match1.len;
if (newMatchLen > OPTIMAL_ML) {
newMatchLen = OPTIMAL_ML;
}
if (match1.start + newMatchLen > match2.end() - MIN_MATCH) {
newMatchLen = match2.start - match1.start + match2.len - MIN_MATCH;
}
final int correction = newMatchLen - (match2.start - match1.start);
if (correction > 0) {
match2.fix(correction);
}
}
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 = LZ4UnsafeUtils.encodeSequence(src, anchor, match1.start, match1.ref, match1.len, dest, dOff, destEnd);
anchor = sOff = match1.end();
// encode seq 2
dOff = LZ4UnsafeUtils.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 (match2.start < match1.end()) {
final int correction = match1.end() - match2.start;
match2.fix(correction);
if (match2.len < MIN_MATCH) {
copyTo(match3, match2);
}
}
dOff = LZ4UnsafeUtils.encodeSequence(src, anchor, match1.start, match1.ref, match1.len, dest, dOff, destEnd);
anchor = sOff = match1.end();
copyTo(match3, match1);
copyTo(match2, match0);
continue search2;
}
copyTo(match3, match2);
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) {
match1.len = OPTIMAL_ML;
}
if (match1.end() > match2.end() - MIN_MATCH) {
match1.len = match2.end() - match1.start - MIN_MATCH;
}
final int correction = match1.end() - match2.start;
match2.fix(correction);
} else {
match1.len = match2.start - match1.start;
}
}
dOff = LZ4UnsafeUtils.encodeSequence(src, anchor, match1.start, match1.ref, match1.len, dest, dOff, destEnd);
anchor = sOff = match1.end();
copyTo(match2, match1);
copyTo(match3, match2);
continue search3;
}
}
}
dOff = LZ4UnsafeUtils.lastLiterals(src, anchor, srcEnd - anchor, dest, dOff, destEnd);
return dOff - destOff;
}
@Override
public int compress(ByteBuffer src, int srcOff, int srcLen, ByteBuffer dest, int destOff, int maxDestLen) {
if (src.hasArray() && dest.hasArray()) {
return compress(src.array(), srcOff + src.arrayOffset(), srcLen, dest.array(), destOff + dest.arrayOffset(), maxDestLen);
}
src = ByteBufferUtils.inNativeByteOrder(src);
dest = ByteBufferUtils.inNativeByteOrder(dest);
ByteBufferUtils.checkRange(src, srcOff, srcLen);
ByteBufferUtils.checkRange(dest, destOff, maxDestLen);
final int srcEnd = srcOff + srcLen;
final int destEnd = destOff + maxDestLen;
final int mfLimit = srcEnd - MF_LIMIT;
final int matchLimit = srcEnd - LAST_LITERALS;
int sOff = srcOff;
int dOff = destOff;
int anchor = sOff++;
final HashTable ht = new HashTable(srcOff);
final Match match0 = new Match();
final Match match1 = new Match();
final Match match2 = new Match();
final Match match3 = new Match();
main:
while (sOff < mfLimit) {
if (!ht.insertAndFindBestMatch(src, sOff, matchLimit, match1)) {
++sOff;
continue;
}
// saved, in case we would skip too much
copyTo(match1, match0);
search2:
while (true) {
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 = LZ4ByteBufferUtils.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
copyTo(match0, match1);
}
}
assert match2.start > match1.start;
if (match2.start - match1.start < 3) { // First Match too small : removed
copyTo(match2, match1);
continue search2;
}
search3:
while (true) {
if (match2.start - match1.start < OPTIMAL_ML) {
int newMatchLen = match1.len;
if (newMatchLen > OPTIMAL_ML) {
newMatchLen = OPTIMAL_ML;
}
if (match1.start + newMatchLen > match2.end() - MIN_MATCH) {
newMatchLen = match2.start - match1.start + match2.len - MIN_MATCH;
}
final int correction = newMatchLen - (match2.start - match1.start);
if (correction > 0) {
match2.fix(correction);
}
}
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 = LZ4ByteBufferUtils.encodeSequence(src, anchor, match1.start, match1.ref, match1.len, dest, dOff, destEnd);
anchor = sOff = match1.end();
// encode seq 2
dOff = LZ4ByteBufferUtils.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 (match2.start < match1.end()) {
final int correction = match1.end() - match2.start;
match2.fix(correction);
if (match2.len < MIN_MATCH) {
copyTo(match3, match2);
}
}
dOff = LZ4ByteBufferUtils.encodeSequence(src, anchor, match1.start, match1.ref, match1.len, dest, dOff, destEnd);
anchor = sOff = match1.end();
copyTo(match3, match1);
copyTo(match2, match0);
continue search2;
}
copyTo(match3, match2);
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) {
match1.len = OPTIMAL_ML;
}
if (match1.end() > match2.end() - MIN_MATCH) {
match1.len = match2.end() - match1.start - MIN_MATCH;
}
final int correction = match1.end() - match2.start;
match2.fix(correction);
} else {
match1.len = match2.start - match1.start;
}
}
dOff = LZ4ByteBufferUtils.encodeSequence(src, anchor, match1.start, match1.ref, match1.len, dest, dOff, destEnd);
anchor = sOff = match1.end();
copyTo(match2, match1);
copyTo(match3, match2);
continue search3;
}
}
}
dOff = LZ4ByteBufferUtils.lastLiterals(src, anchor, srcEnd - anchor, dest, dOff, destEnd);
return dOff - destOff;
}
}

41
fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4JNI.java

@ -0,0 +1,41 @@
package com.fr.third.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.nio.ByteBuffer;
import com.fr.third.net.jpountz.util.Native;
/**
* JNI bindings to the original C implementation of LZ4.
*/
enum LZ4JNI {
;
static {
Native.load();
init();
}
static native void init();
static native int LZ4_compress_limitedOutput(byte[] srcArray, ByteBuffer srcBuffer, int srcOff, int srcLen, byte[] destArray, ByteBuffer destBuffer, int destOff, int maxDestLen);
static native int LZ4_compressHC(byte[] srcArray, ByteBuffer srcBuffer, int srcOff, int srcLen, byte[] destArray, ByteBuffer destBuffer, int destOff, int maxDestLen, int compressionLevel);
static native int LZ4_decompress_fast(byte[] srcArray, ByteBuffer srcBuffer, int srcOff, byte[] destArray, ByteBuffer destBuffer, int destOff, int destLen);
static native int LZ4_decompress_safe(byte[] srcArray, ByteBuffer srcBuffer, int srcOff, int srcLen, byte[] destArray, ByteBuffer destBuffer, int destOff, int maxDestLen);
static native int LZ4_compressBound(int len);
}

80
fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4JNICompressor.java

@ -0,0 +1,80 @@
package com.fr.third.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 com.fr.third.net.jpountz.util.ByteBufferUtils.checkNotReadOnly;
import static com.fr.third.net.jpountz.util.ByteBufferUtils.checkRange;
import static com.fr.third.net.jpountz.util.SafeUtils.checkRange;
import java.nio.ByteBuffer;
/**
* Fast {@link LZ4FastCompressor}s implemented with JNI bindings to the original C
* implementation of LZ4.
*/
final class LZ4JNICompressor extends LZ4Compressor {
public static final LZ4Compressor INSTANCE = new LZ4JNICompressor();
private static LZ4Compressor SAFE_INSTANCE;
@Override
public int compress(byte[] src, int srcOff, int srcLen, byte[] dest, int destOff, int maxDestLen) {
checkRange(src, srcOff, srcLen);
checkRange(dest, destOff, maxDestLen);
final int result = LZ4JNI.LZ4_compress_limitedOutput(src, null, srcOff, srcLen, dest, null, destOff, maxDestLen);
if (result <= 0) {
throw new LZ4Exception("maxDestLen is too small");
}
return result;
}
@Override
public int compress(ByteBuffer src, int srcOff, int srcLen, ByteBuffer dest, int destOff, int maxDestLen) {
checkNotReadOnly(dest);
checkRange(src, srcOff, srcLen);
checkRange(dest, destOff, maxDestLen);
if ((src.hasArray() || src.isDirect()) && (dest.hasArray() || dest.isDirect())) {
byte[] srcArr = null, destArr = null;
ByteBuffer srcBuf = null, destBuf = null;
if (src.hasArray()) {
srcArr = src.array();
srcOff += src.arrayOffset();
} else {
assert src.isDirect();
srcBuf = src;
}
if (dest.hasArray()) {
destArr = dest.array();
destOff += dest.arrayOffset();
} else {
assert dest.isDirect();
destBuf = dest;
}
final int result = LZ4JNI.LZ4_compress_limitedOutput(srcArr, srcBuf, srcOff, srcLen, destArr, destBuf, destOff, maxDestLen);
if (result <= 0) {
throw new LZ4Exception("maxDestLen is too small");
}
return result;
} else {
LZ4Compressor safeInstance = SAFE_INSTANCE;
if (safeInstance == null) {
safeInstance = SAFE_INSTANCE = LZ4Factory.safeInstance().fastCompressor();
}
return safeInstance.compress(src, srcOff, srcLen, dest, destOff, maxDestLen);
}
}
}

82
fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4JNIFastDecompressor.java

@ -0,0 +1,82 @@
package com.fr.third.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.nio.ByteBuffer;
import com.fr.third.net.jpountz.util.ByteBufferUtils;
import com.fr.third.net.jpountz.util.SafeUtils;
/**
* {@link LZ4FastDecompressor} implemented with JNI bindings to the original C
* implementation of LZ4.
*/
final class LZ4JNIFastDecompressor extends LZ4FastDecompressor {
public static final LZ4JNIFastDecompressor INSTANCE = new LZ4JNIFastDecompressor();
private static LZ4FastDecompressor SAFE_INSTANCE;
@Override
public final int decompress(byte[] src, int srcOff, byte[] dest, int destOff, int destLen) {
SafeUtils.checkRange(src, srcOff);
SafeUtils.checkRange(dest, destOff, destLen);
final int result = LZ4JNI.LZ4_decompress_fast(src, null, srcOff, dest, null, destOff, destLen);
if (result < 0) {
throw new LZ4Exception("Error decoding offset " + (srcOff - result) + " of input buffer");
}
return result;
}
@Override
public int decompress(ByteBuffer src, int srcOff, ByteBuffer dest, int destOff, int destLen) {
ByteBufferUtils.checkNotReadOnly(dest);
ByteBufferUtils.checkRange(src, srcOff);
ByteBufferUtils.checkRange(dest, destOff, destLen);
if ((src.hasArray() || src.isDirect()) && (dest.hasArray() || dest.isDirect())) {
byte[] srcArr = null, destArr = null;
ByteBuffer srcBuf = null, destBuf = null;
if (src.hasArray()) {
srcArr = src.array();
srcOff += src.arrayOffset();
} else {
assert src.isDirect();
srcBuf = src;
}
if (dest.hasArray()) {
destArr = dest.array();
destOff += dest.arrayOffset();
} else {
assert dest.isDirect();
destBuf = dest;
}
final int result = LZ4JNI.LZ4_decompress_fast(srcArr, srcBuf, srcOff, destArr, destBuf, destOff, destLen);
if (result < 0) {
throw new LZ4Exception("Error decoding offset " + (srcOff - result) + " of input buffer");
}
return result;
} else {
LZ4FastDecompressor safeInstance = SAFE_INSTANCE;
if (safeInstance == null) {
safeInstance = SAFE_INSTANCE = LZ4Factory.safeInstance().fastDecompressor();
}
return safeInstance.decompress(src, srcOff, dest, destOff, destLen);
}
}
}

81
fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4JNISafeDecompressor.java

@ -0,0 +1,81 @@
package com.fr.third.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.nio.ByteBuffer;
import com.fr.third.net.jpountz.util.ByteBufferUtils;
import com.fr.third.net.jpountz.util.SafeUtils;
/**
* {@link LZ4SafeDecompressor} implemented with JNI bindings to the original C
* implementation of LZ4.
*/
final class LZ4JNISafeDecompressor extends LZ4SafeDecompressor {
public static final LZ4JNISafeDecompressor INSTANCE = new LZ4JNISafeDecompressor();
private static LZ4SafeDecompressor SAFE_INSTANCE;
@Override
public final int decompress(byte[] src, int srcOff, int srcLen, byte[] dest, int destOff, int maxDestLen) {
SafeUtils.checkRange(src, srcOff, srcLen);
SafeUtils.checkRange(dest, destOff, maxDestLen);
final int result = LZ4JNI.LZ4_decompress_safe(src, null, srcOff, srcLen, dest, null, destOff, maxDestLen);
if (result < 0) {
throw new LZ4Exception("Error decoding offset " + (srcOff - result) + " of input buffer");
}
return result;
}
@Override
public int decompress(ByteBuffer src, int srcOff, int srcLen, ByteBuffer dest, int destOff, int maxDestLen) {
ByteBufferUtils.checkNotReadOnly(dest);
ByteBufferUtils.checkRange(src, srcOff, srcLen);
ByteBufferUtils.checkRange(dest, destOff, maxDestLen);
if ((src.hasArray() || src.isDirect()) && (dest.hasArray() || dest.isDirect())) {
byte[] srcArr = null, destArr = null;
ByteBuffer srcBuf = null, destBuf = null;
if (src.hasArray()) {
srcArr = src.array();
srcOff += src.arrayOffset();
} else {
assert src.isDirect();
srcBuf = src;
}
if (dest.hasArray()) {
destArr = dest.array();
destOff += dest.arrayOffset();
} else {
assert dest.isDirect();
destBuf = dest;
}
final int result = LZ4JNI.LZ4_decompress_safe(srcArr, srcBuf, srcOff, srcLen, destArr, destBuf, destOff, maxDestLen);
if (result < 0) {
throw new LZ4Exception("Error decoding offset " + (srcOff - result) + " of input buffer");
}
return result;
} else {
LZ4SafeDecompressor safeInstance = SAFE_INSTANCE;
if (safeInstance == null) {
safeInstance = SAFE_INSTANCE = LZ4Factory.safeInstance().safeDecompressor();
}
return safeInstance.decompress(src, srcOff, srcLen, dest, destOff, maxDestLen);
}
}
}

511
fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4JavaSafeCompressor.java

@ -0,0 +1,511 @@
// Auto-generated: DO NOT EDIT
package com.fr.third.net.jpountz.lz4;
import static com.fr.third.net.jpountz.lz4.LZ4Constants.*;
import static com.fr.third.net.jpountz.lz4.LZ4Utils.*;
import java.nio.ByteBuffer;
import java.util.Arrays;
import com.fr.third.net.jpountz.util.ByteBufferUtils;
import com.fr.third.net.jpountz.util.SafeUtils;
/**
* Compressor.
*/
final class LZ4JavaSafeCompressor extends LZ4Compressor {
public static final LZ4Compressor INSTANCE = new LZ4JavaSafeCompressor();
static int compress64k(byte[] src, int srcOff, int srcLen, byte[] dest, int destOff, int destEnd) {
final int srcEnd = srcOff + srcLen;
final int srcLimit = srcEnd - LAST_LITERALS;
final int mflimit = srcEnd - MF_LIMIT;
int sOff = srcOff, dOff = destOff;
int anchor = sOff;
if (srcLen >= MIN_LENGTH) {
final short[] hashTable = new short[HASH_TABLE_SIZE_64K];
++sOff;
main:
while (true) {
// find a match
int forwardOff = sOff;
int ref;
int step = 1;
int searchMatchNb = 1 << SKIP_STRENGTH;
do {
sOff = forwardOff;
forwardOff += step;
step = searchMatchNb++ >>> SKIP_STRENGTH;
if (forwardOff > mflimit) {
break main;
}
final int h = hash64k(SafeUtils.readInt(src, sOff));
ref = srcOff + SafeUtils.readShort(hashTable, h);
SafeUtils.writeShort(hashTable, h, sOff - srcOff);
} while (!LZ4SafeUtils.readIntEquals(src, ref, sOff));
// catch up
final int excess = LZ4SafeUtils.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) {
throw new LZ4Exception("maxDestLen is too small");
}
if (runLen >= RUN_MASK) {
SafeUtils.writeByte(dest, tokenOff, RUN_MASK << ML_BITS);
dOff = LZ4SafeUtils.writeLen(runLen - RUN_MASK, dest, dOff);
} else {
SafeUtils.writeByte(dest, tokenOff, runLen << ML_BITS);
}
// copy literals
LZ4SafeUtils.wildArraycopy(src, anchor, dest, dOff, runLen);
dOff += runLen;
while (true) {
// encode offset
SafeUtils.writeShortLE(dest, dOff, (short) (sOff - ref));
dOff += 2;
// count nb matches
sOff += MIN_MATCH;
ref += MIN_MATCH;
final int matchLen = LZ4SafeUtils.commonBytes(src, ref, sOff, srcLimit);
if (dOff + (1 + LAST_LITERALS) + (matchLen >>> 8) > destEnd) {
throw new LZ4Exception("maxDestLen is too small");
}
sOff += matchLen;
// encode match len
if (matchLen >= ML_MASK) {
SafeUtils.writeByte(dest, tokenOff, SafeUtils.readByte(dest, tokenOff) | ML_MASK);
dOff = LZ4SafeUtils.writeLen(matchLen - ML_MASK, dest, dOff);
} else {
SafeUtils.writeByte(dest, tokenOff, SafeUtils.readByte(dest, tokenOff) | matchLen);
}
// test end of chunk
if (sOff > mflimit) {
anchor = sOff;
break main;
}
// fill table
SafeUtils.writeShort(hashTable, hash64k(SafeUtils.readInt(src, sOff - 2)), sOff - 2 - srcOff);
// test next position
final int h = hash64k(SafeUtils.readInt(src, sOff));
ref = srcOff + SafeUtils.readShort(hashTable, h);
SafeUtils.writeShort(hashTable, h, sOff - srcOff);
if (!LZ4SafeUtils.readIntEquals(src, sOff, ref)) {
break;
}
tokenOff = dOff++;
SafeUtils.writeByte(dest, tokenOff, 0);
}
// prepare next loop
anchor = sOff++;
}
}
dOff = LZ4SafeUtils.lastLiterals(src, anchor, srcEnd - anchor, dest, dOff, destEnd);
return dOff - destOff;
}
@Override
public int compress(byte[] src, final int srcOff, int srcLen, byte[] dest, final int destOff, int maxDestLen) {
SafeUtils.checkRange(src, srcOff, srcLen);
SafeUtils.checkRange(dest, destOff, maxDestLen);
final int destEnd = destOff + maxDestLen;
if (srcLen < LZ4_64K_LIMIT) {
return compress64k(src, srcOff, srcLen, dest, destOff, destEnd);
}
final int srcEnd = srcOff + srcLen;
final int srcLimit = srcEnd - LAST_LITERALS;
final int mflimit = srcEnd - MF_LIMIT;
int sOff = srcOff, dOff = destOff;
int anchor = sOff++;
final int[] hashTable = new int[HASH_TABLE_SIZE];
Arrays.fill(hashTable, anchor);
main:
while (true) {
// find a match
int forwardOff = sOff;
int ref;
int step = 1;
int searchMatchNb = 1 << SKIP_STRENGTH;
int back;
do {
sOff = forwardOff;
forwardOff += step;
step = searchMatchNb++ >>> SKIP_STRENGTH;
if (forwardOff > mflimit) {
break main;
}
final int h = hash(SafeUtils.readInt(src, sOff));
ref = SafeUtils.readInt(hashTable, h);
back = sOff - ref;
SafeUtils.writeInt(hashTable, h, sOff);
} while (back >= MAX_DISTANCE || !LZ4SafeUtils.readIntEquals(src, ref, sOff));
final int excess = LZ4SafeUtils.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) {
throw new LZ4Exception("maxDestLen is too small");
}
if (runLen >= RUN_MASK) {
SafeUtils.writeByte(dest, tokenOff, RUN_MASK << ML_BITS);
dOff = LZ4SafeUtils.writeLen(runLen - RUN_MASK, dest, dOff);
} else {
SafeUtils.writeByte(dest, tokenOff, runLen << ML_BITS);
}
// copy literals
LZ4SafeUtils.wildArraycopy(src, anchor, dest, dOff, runLen);
dOff += runLen;
while (true) {
// encode offset
SafeUtils.writeShortLE(dest, dOff, back);
dOff += 2;
// count nb matches
sOff += MIN_MATCH;
final int matchLen = LZ4SafeUtils.commonBytes(src, ref + MIN_MATCH, sOff, srcLimit);
if (dOff + (1 + LAST_LITERALS) + (matchLen >>> 8) > destEnd) {
throw new LZ4Exception("maxDestLen is too small");
}
sOff += matchLen;
// encode match len
if (matchLen >= ML_MASK) {
SafeUtils.writeByte(dest, tokenOff, SafeUtils.readByte(dest, tokenOff) | ML_MASK);
dOff = LZ4SafeUtils.writeLen(matchLen - ML_MASK, dest, dOff);
} else {
SafeUtils.writeByte(dest, tokenOff, SafeUtils.readByte(dest, tokenOff) | matchLen);
}
// test end of chunk
if (sOff > mflimit) {
anchor = sOff;
break main;
}
// fill table
SafeUtils.writeInt(hashTable, hash(SafeUtils.readInt(src, sOff - 2)), sOff - 2);
// test next position
final int h = hash(SafeUtils.readInt(src, sOff));
ref = SafeUtils.readInt(hashTable, h);
SafeUtils.writeInt(hashTable, h, sOff);
back = sOff - ref;
if (back >= MAX_DISTANCE || !LZ4SafeUtils.readIntEquals(src, ref, sOff)) {
break;
}
tokenOff = dOff++;
SafeUtils.writeByte(dest, tokenOff, 0);
}
// prepare next loop
anchor = sOff++;
}
dOff = LZ4SafeUtils.lastLiterals(src, anchor, srcEnd - anchor, dest, dOff, destEnd);
return dOff - destOff;
}
static int compress64k(ByteBuffer src, int srcOff, int srcLen, ByteBuffer dest, int destOff, int destEnd) {
final int srcEnd = srcOff + srcLen;
final int srcLimit = srcEnd - LAST_LITERALS;
final int mflimit = srcEnd - MF_LIMIT;
int sOff = srcOff, dOff = destOff;
int anchor = sOff;
if (srcLen >= MIN_LENGTH) {
final short[] hashTable = new short[HASH_TABLE_SIZE_64K];
++sOff;
main:
while (true) {
// find a match
int forwardOff = sOff;
int ref;
int step = 1;
int searchMatchNb = 1 << SKIP_STRENGTH;
do {
sOff = forwardOff;
forwardOff += step;
step = searchMatchNb++ >>> SKIP_STRENGTH;
if (forwardOff > mflimit) {
break main;
}
final int h = hash64k(ByteBufferUtils.readInt(src, sOff));
ref = srcOff + SafeUtils.readShort(hashTable, h);
SafeUtils.writeShort(hashTable, h, sOff - srcOff);
} while (!LZ4ByteBufferUtils.readIntEquals(src, ref, sOff));
// catch up
final int excess = LZ4ByteBufferUtils.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) {
throw new LZ4Exception("maxDestLen is too small");
}
if (runLen >= RUN_MASK) {
ByteBufferUtils.writeByte(dest, tokenOff, RUN_MASK << ML_BITS);
dOff = LZ4ByteBufferUtils.writeLen(runLen - RUN_MASK, dest, dOff);
} else {
ByteBufferUtils.writeByte(dest, tokenOff, runLen << ML_BITS);
}
// copy literals
LZ4ByteBufferUtils.wildArraycopy(src, anchor, dest, dOff, runLen);
dOff += runLen;
while (true) {
// encode offset
ByteBufferUtils.writeShortLE(dest, dOff, (short) (sOff - ref));
dOff += 2;
// count nb matches
sOff += MIN_MATCH;
ref += MIN_MATCH;
final int matchLen = LZ4ByteBufferUtils.commonBytes(src, ref, sOff, srcLimit);
if (dOff + (1 + LAST_LITERALS) + (matchLen >>> 8) > destEnd) {
throw new LZ4Exception("maxDestLen is too small");
}
sOff += matchLen;
// encode match len
if (matchLen >= ML_MASK) {
ByteBufferUtils.writeByte(dest, tokenOff, ByteBufferUtils.readByte(dest, tokenOff) | ML_MASK);
dOff = LZ4ByteBufferUtils.writeLen(matchLen - ML_MASK, dest, dOff);
} else {
ByteBufferUtils.writeByte(dest, tokenOff, ByteBufferUtils.readByte(dest, tokenOff) | matchLen);
}
// test end of chunk
if (sOff > mflimit) {
anchor = sOff;
break main;
}
// fill table
SafeUtils.writeShort(hashTable, hash64k(ByteBufferUtils.readInt(src, sOff - 2)), sOff - 2 - srcOff);
// test next position
final int h = hash64k(ByteBufferUtils.readInt(src, sOff));
ref = srcOff + SafeUtils.readShort(hashTable, h);
SafeUtils.writeShort(hashTable, h, sOff - srcOff);
if (!LZ4ByteBufferUtils.readIntEquals(src, sOff, ref)) {
break;
}
tokenOff = dOff++;
ByteBufferUtils.writeByte(dest, tokenOff, 0);
}
// prepare next loop
anchor = sOff++;
}
}
dOff = LZ4ByteBufferUtils.lastLiterals(src, anchor, srcEnd - anchor, dest, dOff, destEnd);
return dOff - destOff;
}
@Override
public int compress(ByteBuffer src, final int srcOff, int srcLen, ByteBuffer dest, final int destOff, int maxDestLen) {
if (src.hasArray() && dest.hasArray()) {
return compress(src.array(), srcOff + src.arrayOffset(), srcLen, dest.array(), destOff + dest.arrayOffset(), maxDestLen);
}
src = ByteBufferUtils.inNativeByteOrder(src);
dest = ByteBufferUtils.inNativeByteOrder(dest);
ByteBufferUtils.checkRange(src, srcOff, srcLen);
ByteBufferUtils.checkRange(dest, destOff, maxDestLen);
final int destEnd = destOff + maxDestLen;
if (srcLen < LZ4_64K_LIMIT) {
return compress64k(src, srcOff, srcLen, dest, destOff, destEnd);
}
final int srcEnd = srcOff + srcLen;
final int srcLimit = srcEnd - LAST_LITERALS;
final int mflimit = srcEnd - MF_LIMIT;
int sOff = srcOff, dOff = destOff;
int anchor = sOff++;
final int[] hashTable = new int[HASH_TABLE_SIZE];
Arrays.fill(hashTable, anchor);
main:
while (true) {
// find a match
int forwardOff = sOff;
int ref;
int step = 1;
int searchMatchNb = 1 << SKIP_STRENGTH;
int back;
do {
sOff = forwardOff;
forwardOff += step;
step = searchMatchNb++ >>> SKIP_STRENGTH;
if (forwardOff > mflimit) {
break main;
}
final int h = hash(ByteBufferUtils.readInt(src, sOff));
ref = SafeUtils.readInt(hashTable, h);
back = sOff - ref;
SafeUtils.writeInt(hashTable, h, sOff);
} while (back >= MAX_DISTANCE || !LZ4ByteBufferUtils.readIntEquals(src, ref, sOff));
final int excess = LZ4ByteBufferUtils.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) {
throw new LZ4Exception("maxDestLen is too small");
}
if (runLen >= RUN_MASK) {
ByteBufferUtils.writeByte(dest, tokenOff, RUN_MASK << ML_BITS);
dOff = LZ4ByteBufferUtils.writeLen(runLen - RUN_MASK, dest, dOff);
} else {
ByteBufferUtils.writeByte(dest, tokenOff, runLen << ML_BITS);
}
// copy literals
LZ4ByteBufferUtils.wildArraycopy(src, anchor, dest, dOff, runLen);
dOff += runLen;
while (true) {
// encode offset
ByteBufferUtils.writeShortLE(dest, dOff, back);
dOff += 2;
// count nb matches
sOff += MIN_MATCH;
final int matchLen = LZ4ByteBufferUtils.commonBytes(src, ref + MIN_MATCH, sOff, srcLimit);
if (dOff + (1 + LAST_LITERALS) + (matchLen >>> 8) > destEnd) {
throw new LZ4Exception("maxDestLen is too small");
}
sOff += matchLen;
// encode match len
if (matchLen >= ML_MASK) {
ByteBufferUtils.writeByte(dest, tokenOff, ByteBufferUtils.readByte(dest, tokenOff) | ML_MASK);
dOff = LZ4ByteBufferUtils.writeLen(matchLen - ML_MASK, dest, dOff);
} else {
ByteBufferUtils.writeByte(dest, tokenOff, ByteBufferUtils.readByte(dest, tokenOff) | matchLen);
}
// test end of chunk
if (sOff > mflimit) {
anchor = sOff;
break main;
}
// fill table
SafeUtils.writeInt(hashTable, hash(ByteBufferUtils.readInt(src, sOff - 2)), sOff - 2);
// test next position
final int h = hash(ByteBufferUtils.readInt(src, sOff));
ref = SafeUtils.readInt(hashTable, h);
SafeUtils.writeInt(hashTable, h, sOff);
back = sOff - ref;
if (back >= MAX_DISTANCE || !LZ4ByteBufferUtils.readIntEquals(src, ref, sOff)) {
break;
}
tokenOff = dOff++;
ByteBufferUtils.writeByte(dest, tokenOff, 0);
}
// prepare next loop
anchor = sOff++;
}
dOff = LZ4ByteBufferUtils.lastLiterals(src, anchor, srcEnd - anchor, dest, dOff, destEnd);
return dOff - destOff;
}
}

205
fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4JavaSafeFastDecompressor.java

@ -0,0 +1,205 @@
// Auto-generated: DO NOT EDIT
package com.fr.third.net.jpountz.lz4;
import static com.fr.third.net.jpountz.lz4.LZ4Constants.*;
import java.nio.ByteBuffer;
import com.fr.third.net.jpountz.util.ByteBufferUtils;
import com.fr.third.net.jpountz.util.SafeUtils;
/**
* Decompressor.
*/
final class LZ4JavaSafeFastDecompressor extends LZ4FastDecompressor {
public static final LZ4FastDecompressor INSTANCE = new LZ4JavaSafeFastDecompressor();
@Override
public int decompress(byte[] src, final int srcOff, byte[] dest, final int destOff, int destLen) {
SafeUtils.checkRange(src, srcOff);
SafeUtils.checkRange(dest, destOff, destLen);
if (destLen == 0) {
if (SafeUtils.readByte(src, srcOff) != 0) {
throw new LZ4Exception("Malformed input at " + srcOff);
}
return 1;
}
final int destEnd = destOff + destLen;
int sOff = srcOff;
int dOff = destOff;
while (true) {
final int token = SafeUtils.readByte(src, sOff) & 0xFF;
++sOff;
// literals
int literalLen = token >>> ML_BITS;
if (literalLen == RUN_MASK) {
byte len = (byte) 0xFF;
while ((len = SafeUtils.readByte(src, sOff++)) == (byte) 0xFF) {
literalLen += 0xFF;
}
literalLen += len & 0xFF;
}
final int literalCopyEnd = dOff + literalLen;
if (literalCopyEnd > destEnd - COPY_LENGTH) {
if (literalCopyEnd != destEnd) {
throw new LZ4Exception("Malformed input at " + sOff);
} else {
LZ4SafeUtils.safeArraycopy(src, sOff, dest, dOff, literalLen);
sOff += literalLen;
dOff = literalCopyEnd;
break; // EOF
}
}
LZ4SafeUtils.wildArraycopy(src, sOff, dest, dOff, literalLen);
sOff += literalLen;
dOff = literalCopyEnd;
// matchs
final int matchDec = SafeUtils.readShortLE(src, sOff);
sOff += 2;
int matchOff = dOff - matchDec;
if (matchOff < destOff) {
throw new LZ4Exception("Malformed input at " + sOff);
}
int matchLen = token & ML_MASK;
if (matchLen == ML_MASK) {
byte len = (byte) 0xFF;
while ((len = SafeUtils.readByte(src, sOff++)) == (byte) 0xFF) {
matchLen += 0xFF;
}
matchLen += len & 0xFF;
}
matchLen += MIN_MATCH;
final int matchCopyEnd = dOff + matchLen;
if (matchCopyEnd > destEnd - COPY_LENGTH) {
if (matchCopyEnd > destEnd) {
throw new LZ4Exception("Malformed input at " + sOff);
}
LZ4SafeUtils.safeIncrementalCopy(dest, matchOff, dOff, matchLen);
} else {
LZ4SafeUtils.wildIncrementalCopy(dest, matchOff, dOff, matchCopyEnd);
}
dOff = matchCopyEnd;
}
return sOff - srcOff;
}
@Override
public int decompress(ByteBuffer src, final int srcOff, ByteBuffer dest, final int destOff, int destLen) {
if (src.hasArray() && dest.hasArray()) {
return decompress(src.array(), srcOff + src.arrayOffset(), dest.array(), destOff + dest.arrayOffset(), destLen);
}
src = ByteBufferUtils.inNativeByteOrder(src);
dest = ByteBufferUtils.inNativeByteOrder(dest);
ByteBufferUtils.checkRange(src, srcOff);
ByteBufferUtils.checkRange(dest, destOff, destLen);
if (destLen == 0) {
if (ByteBufferUtils.readByte(src, srcOff) != 0) {
throw new LZ4Exception("Malformed input at " + srcOff);
}
return 1;
}
final int destEnd = destOff + destLen;
int sOff = srcOff;
int dOff = destOff;
while (true) {
final int token = ByteBufferUtils.readByte(src, sOff) & 0xFF;
++sOff;
// literals
int literalLen = token >>> ML_BITS;
if (literalLen == RUN_MASK) {
byte len = (byte) 0xFF;
while ((len = ByteBufferUtils.readByte(src, sOff++)) == (byte) 0xFF) {
literalLen += 0xFF;
}
literalLen += len & 0xFF;
}
final int literalCopyEnd = dOff + literalLen;
if (literalCopyEnd > destEnd - COPY_LENGTH) {
if (literalCopyEnd != destEnd) {
throw new LZ4Exception("Malformed input at " + sOff);
} else {
LZ4ByteBufferUtils.safeArraycopy(src, sOff, dest, dOff, literalLen);
sOff += literalLen;
dOff = literalCopyEnd;
break; // EOF
}
}
LZ4ByteBufferUtils.wildArraycopy(src, sOff, dest, dOff, literalLen);
sOff += literalLen;
dOff = literalCopyEnd;
// matchs
final int matchDec = ByteBufferUtils.readShortLE(src, sOff);
sOff += 2;
int matchOff = dOff - matchDec;
if (matchOff < destOff) {
throw new LZ4Exception("Malformed input at " + sOff);
}
int matchLen = token & ML_MASK;
if (matchLen == ML_MASK) {
byte len = (byte) 0xFF;
while ((len = ByteBufferUtils.readByte(src, sOff++)) == (byte) 0xFF) {
matchLen += 0xFF;
}
matchLen += len & 0xFF;
}
matchLen += MIN_MATCH;
final int matchCopyEnd = dOff + matchLen;
if (matchCopyEnd > destEnd - COPY_LENGTH) {
if (matchCopyEnd > destEnd) {
throw new LZ4Exception("Malformed input at " + sOff);
}
LZ4ByteBufferUtils.safeIncrementalCopy(dest, matchOff, dOff, matchLen);
} else {
LZ4ByteBufferUtils.wildIncrementalCopy(dest, matchOff, dOff, matchCopyEnd);
}
dOff = matchCopyEnd;
}
return sOff - srcOff;
}
}

213
fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4JavaSafeSafeDecompressor.java

@ -0,0 +1,213 @@
// Auto-generated: DO NOT EDIT
package com.fr.third.net.jpountz.lz4;
import static com.fr.third.net.jpountz.lz4.LZ4Constants.*;
import java.nio.ByteBuffer;
import com.fr.third.net.jpountz.util.ByteBufferUtils;
import com.fr.third.net.jpountz.util.SafeUtils;
/**
* Decompressor.
*/
final class LZ4JavaSafeSafeDecompressor extends LZ4SafeDecompressor {
public static final LZ4SafeDecompressor INSTANCE = new LZ4JavaSafeSafeDecompressor();
@Override
public int decompress(byte[] src, final int srcOff, final int srcLen , byte[] dest, final int destOff, int destLen) {
SafeUtils.checkRange(src, srcOff, srcLen);
SafeUtils.checkRange(dest, destOff, destLen);
if (destLen == 0) {
if (srcLen != 1 || SafeUtils.readByte(src, srcOff) != 0) {
throw new LZ4Exception("Output buffer too small");
}
return 0;
}
final int srcEnd = srcOff + srcLen;
final int destEnd = destOff + destLen;
int sOff = srcOff;
int dOff = destOff;
while (true) {
final int token = SafeUtils.readByte(src, sOff) & 0xFF;
++sOff;
// literals
int literalLen = token >>> ML_BITS;
if (literalLen == RUN_MASK) {
byte len = (byte) 0xFF;
while (sOff < srcEnd &&(len = SafeUtils.readByte(src, sOff++)) == (byte) 0xFF) {
literalLen += 0xFF;
}
literalLen += len & 0xFF;
}
final int literalCopyEnd = dOff + literalLen;
if (literalCopyEnd > destEnd - COPY_LENGTH || sOff + literalLen > srcEnd - COPY_LENGTH) {
if (literalCopyEnd > destEnd) {
throw new LZ4Exception();
} else if (sOff + literalLen != srcEnd) {
throw new LZ4Exception("Malformed input at " + sOff);
} else {
LZ4SafeUtils.safeArraycopy(src, sOff, dest, dOff, literalLen);
sOff += literalLen;
dOff = literalCopyEnd;
break; // EOF
}
}
LZ4SafeUtils.wildArraycopy(src, sOff, dest, dOff, literalLen);
sOff += literalLen;
dOff = literalCopyEnd;
// matchs
final int matchDec = SafeUtils.readShortLE(src, sOff);
sOff += 2;
int matchOff = dOff - matchDec;
if (matchOff < destOff) {
throw new LZ4Exception("Malformed input at " + sOff);
}
int matchLen = token & ML_MASK;
if (matchLen == ML_MASK) {
byte len = (byte) 0xFF;
while (sOff < srcEnd &&(len = SafeUtils.readByte(src, sOff++)) == (byte) 0xFF) {
matchLen += 0xFF;
}
matchLen += len & 0xFF;
}
matchLen += MIN_MATCH;
final int matchCopyEnd = dOff + matchLen;
if (matchCopyEnd > destEnd - COPY_LENGTH) {
if (matchCopyEnd > destEnd) {
throw new LZ4Exception("Malformed input at " + sOff);
}
LZ4SafeUtils.safeIncrementalCopy(dest, matchOff, dOff, matchLen);
} else {
LZ4SafeUtils.wildIncrementalCopy(dest, matchOff, dOff, matchCopyEnd);
}
dOff = matchCopyEnd;
}
return dOff - destOff;
}
@Override
public int decompress(ByteBuffer src, final int srcOff, final int srcLen , ByteBuffer dest, final int destOff, int destLen) {
if (src.hasArray() && dest.hasArray()) {
return decompress(src.array(), srcOff + src.arrayOffset(), srcLen, dest.array(), destOff + dest.arrayOffset(), destLen);
}
src = ByteBufferUtils.inNativeByteOrder(src);
dest = ByteBufferUtils.inNativeByteOrder(dest);
ByteBufferUtils.checkRange(src, srcOff, srcLen);
ByteBufferUtils.checkRange(dest, destOff, destLen);
if (destLen == 0) {
if (srcLen != 1 || ByteBufferUtils.readByte(src, srcOff) != 0) {
throw new LZ4Exception("Output buffer too small");
}
return 0;
}
final int srcEnd = srcOff + srcLen;
final int destEnd = destOff + destLen;
int sOff = srcOff;
int dOff = destOff;
while (true) {
final int token = ByteBufferUtils.readByte(src, sOff) & 0xFF;
++sOff;
// literals
int literalLen = token >>> ML_BITS;
if (literalLen == RUN_MASK) {
byte len = (byte) 0xFF;
while (sOff < srcEnd &&(len = ByteBufferUtils.readByte(src, sOff++)) == (byte) 0xFF) {
literalLen += 0xFF;
}
literalLen += len & 0xFF;
}
final int literalCopyEnd = dOff + literalLen;
if (literalCopyEnd > destEnd - COPY_LENGTH || sOff + literalLen > srcEnd - COPY_LENGTH) {
if (literalCopyEnd > destEnd) {
throw new LZ4Exception();
} else if (sOff + literalLen != srcEnd) {
throw new LZ4Exception("Malformed input at " + sOff);
} else {
LZ4ByteBufferUtils.safeArraycopy(src, sOff, dest, dOff, literalLen);
sOff += literalLen;
dOff = literalCopyEnd;
break; // EOF
}
}
LZ4ByteBufferUtils.wildArraycopy(src, sOff, dest, dOff, literalLen);
sOff += literalLen;
dOff = literalCopyEnd;
// matchs
final int matchDec = ByteBufferUtils.readShortLE(src, sOff);
sOff += 2;
int matchOff = dOff - matchDec;
if (matchOff < destOff) {
throw new LZ4Exception("Malformed input at " + sOff);
}
int matchLen = token & ML_MASK;
if (matchLen == ML_MASK) {
byte len = (byte) 0xFF;
while (sOff < srcEnd &&(len = ByteBufferUtils.readByte(src, sOff++)) == (byte) 0xFF) {
matchLen += 0xFF;
}
matchLen += len & 0xFF;
}
matchLen += MIN_MATCH;
final int matchCopyEnd = dOff + matchLen;
if (matchCopyEnd > destEnd - COPY_LENGTH) {
if (matchCopyEnd > destEnd) {
throw new LZ4Exception("Malformed input at " + sOff);
}
LZ4ByteBufferUtils.safeIncrementalCopy(dest, matchOff, dOff, matchLen);
} else {
LZ4ByteBufferUtils.wildIncrementalCopy(dest, matchOff, dOff, matchCopyEnd);
}
dOff = matchCopyEnd;
}
return dOff - destOff;
}
}

511
fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4JavaUnsafeCompressor.java

@ -0,0 +1,511 @@
// Auto-generated: DO NOT EDIT
package com.fr.third.net.jpountz.lz4;
import static com.fr.third.net.jpountz.lz4.LZ4Constants.*;
import static com.fr.third.net.jpountz.lz4.LZ4Utils.*;
import java.nio.ByteBuffer;
import java.util.Arrays;
import com.fr.third.net.jpountz.util.ByteBufferUtils;
import com.fr.third.net.jpountz.util.UnsafeUtils;
/**
* Compressor.
*/
final class LZ4JavaUnsafeCompressor extends LZ4Compressor {
public static final LZ4Compressor INSTANCE = new LZ4JavaUnsafeCompressor();
static int compress64k(byte[] src, int srcOff, int srcLen, byte[] dest, int destOff, int destEnd) {
final int srcEnd = srcOff + srcLen;
final int srcLimit = srcEnd - LAST_LITERALS;
final int mflimit = srcEnd - MF_LIMIT;
int sOff = srcOff, dOff = destOff;
int anchor = sOff;
if (srcLen >= MIN_LENGTH) {
final short[] hashTable = new short[HASH_TABLE_SIZE_64K];
++sOff;
main:
while (true) {
// find a match
int forwardOff = sOff;
int ref;
int step = 1;
int searchMatchNb = 1 << SKIP_STRENGTH;
do {
sOff = forwardOff;
forwardOff += step;
step = searchMatchNb++ >>> SKIP_STRENGTH;
if (forwardOff > mflimit) {
break main;
}
final int h = hash64k(UnsafeUtils.readInt(src, sOff));
ref = srcOff + UnsafeUtils.readShort(hashTable, h);
UnsafeUtils.writeShort(hashTable, h, sOff - srcOff);
} while (!LZ4UnsafeUtils.readIntEquals(src, ref, sOff));
// catch up
final int excess = LZ4UnsafeUtils.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) {
throw new LZ4Exception("maxDestLen is too small");
}
if (runLen >= RUN_MASK) {
UnsafeUtils.writeByte(dest, tokenOff, RUN_MASK << ML_BITS);
dOff = LZ4UnsafeUtils.writeLen(runLen - RUN_MASK, dest, dOff);
} else {
UnsafeUtils.writeByte(dest, tokenOff, runLen << ML_BITS);
}
// copy literals
LZ4UnsafeUtils.wildArraycopy(src, anchor, dest, dOff, runLen);
dOff += runLen;
while (true) {
// encode offset
UnsafeUtils.writeShortLE(dest, dOff, (short) (sOff - ref));
dOff += 2;
// count nb matches
sOff += MIN_MATCH;
ref += MIN_MATCH;
final int matchLen = LZ4UnsafeUtils.commonBytes(src, ref, sOff, srcLimit);
if (dOff + (1 + LAST_LITERALS) + (matchLen >>> 8) > destEnd) {
throw new LZ4Exception("maxDestLen is too small");
}
sOff += matchLen;
// encode match len
if (matchLen >= ML_MASK) {
UnsafeUtils.writeByte(dest, tokenOff, UnsafeUtils.readByte(dest, tokenOff) | ML_MASK);
dOff = LZ4UnsafeUtils.writeLen(matchLen - ML_MASK, dest, dOff);
} else {
UnsafeUtils.writeByte(dest, tokenOff, UnsafeUtils.readByte(dest, tokenOff) | matchLen);
}
// test end of chunk
if (sOff > mflimit) {
anchor = sOff;
break main;
}
// fill table
UnsafeUtils.writeShort(hashTable, hash64k(UnsafeUtils.readInt(src, sOff - 2)), sOff - 2 - srcOff);
// test next position
final int h = hash64k(UnsafeUtils.readInt(src, sOff));
ref = srcOff + UnsafeUtils.readShort(hashTable, h);
UnsafeUtils.writeShort(hashTable, h, sOff - srcOff);
if (!LZ4UnsafeUtils.readIntEquals(src, sOff, ref)) {
break;
}
tokenOff = dOff++;
UnsafeUtils.writeByte(dest, tokenOff, 0);
}
// prepare next loop
anchor = sOff++;
}
}
dOff = LZ4UnsafeUtils.lastLiterals(src, anchor, srcEnd - anchor, dest, dOff, destEnd);
return dOff - destOff;
}
@Override
public int compress(byte[] src, final int srcOff, int srcLen, byte[] dest, final int destOff, int maxDestLen) {
UnsafeUtils.checkRange(src, srcOff, srcLen);
UnsafeUtils.checkRange(dest, destOff, maxDestLen);
final int destEnd = destOff + maxDestLen;
if (srcLen < LZ4_64K_LIMIT) {
return compress64k(src, srcOff, srcLen, dest, destOff, destEnd);
}
final int srcEnd = srcOff + srcLen;
final int srcLimit = srcEnd - LAST_LITERALS;
final int mflimit = srcEnd - MF_LIMIT;
int sOff = srcOff, dOff = destOff;
int anchor = sOff++;
final int[] hashTable = new int[HASH_TABLE_SIZE];
Arrays.fill(hashTable, anchor);
main:
while (true) {
// find a match
int forwardOff = sOff;
int ref;
int step = 1;
int searchMatchNb = 1 << SKIP_STRENGTH;
int back;
do {
sOff = forwardOff;
forwardOff += step;
step = searchMatchNb++ >>> SKIP_STRENGTH;
if (forwardOff > mflimit) {
break main;
}
final int h = hash(UnsafeUtils.readInt(src, sOff));
ref = UnsafeUtils.readInt(hashTable, h);
back = sOff - ref;
UnsafeUtils.writeInt(hashTable, h, sOff);
} while (back >= MAX_DISTANCE || !LZ4UnsafeUtils.readIntEquals(src, ref, sOff));
final int excess = LZ4UnsafeUtils.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) {
throw new LZ4Exception("maxDestLen is too small");
}
if (runLen >= RUN_MASK) {
UnsafeUtils.writeByte(dest, tokenOff, RUN_MASK << ML_BITS);
dOff = LZ4UnsafeUtils.writeLen(runLen - RUN_MASK, dest, dOff);
} else {
UnsafeUtils.writeByte(dest, tokenOff, runLen << ML_BITS);
}
// copy literals
LZ4UnsafeUtils.wildArraycopy(src, anchor, dest, dOff, runLen);
dOff += runLen;
while (true) {
// encode offset
UnsafeUtils.writeShortLE(dest, dOff, back);
dOff += 2;
// count nb matches
sOff += MIN_MATCH;
final int matchLen = LZ4UnsafeUtils.commonBytes(src, ref + MIN_MATCH, sOff, srcLimit);
if (dOff + (1 + LAST_LITERALS) + (matchLen >>> 8) > destEnd) {
throw new LZ4Exception("maxDestLen is too small");
}
sOff += matchLen;
// encode match len
if (matchLen >= ML_MASK) {
UnsafeUtils.writeByte(dest, tokenOff, UnsafeUtils.readByte(dest, tokenOff) | ML_MASK);
dOff = LZ4UnsafeUtils.writeLen(matchLen - ML_MASK, dest, dOff);
} else {
UnsafeUtils.writeByte(dest, tokenOff, UnsafeUtils.readByte(dest, tokenOff) | matchLen);
}
// test end of chunk
if (sOff > mflimit) {
anchor = sOff;
break main;
}
// fill table
UnsafeUtils.writeInt(hashTable, hash(UnsafeUtils.readInt(src, sOff - 2)), sOff - 2);
// test next position
final int h = hash(UnsafeUtils.readInt(src, sOff));
ref = UnsafeUtils.readInt(hashTable, h);
UnsafeUtils.writeInt(hashTable, h, sOff);
back = sOff - ref;
if (back >= MAX_DISTANCE || !LZ4UnsafeUtils.readIntEquals(src, ref, sOff)) {
break;
}
tokenOff = dOff++;
UnsafeUtils.writeByte(dest, tokenOff, 0);
}
// prepare next loop
anchor = sOff++;
}
dOff = LZ4UnsafeUtils.lastLiterals(src, anchor, srcEnd - anchor, dest, dOff, destEnd);
return dOff - destOff;
}
static int compress64k(ByteBuffer src, int srcOff, int srcLen, ByteBuffer dest, int destOff, int destEnd) {
final int srcEnd = srcOff + srcLen;
final int srcLimit = srcEnd - LAST_LITERALS;
final int mflimit = srcEnd - MF_LIMIT;
int sOff = srcOff, dOff = destOff;
int anchor = sOff;
if (srcLen >= MIN_LENGTH) {
final short[] hashTable = new short[HASH_TABLE_SIZE_64K];
++sOff;
main:
while (true) {
// find a match
int forwardOff = sOff;
int ref;
int step = 1;
int searchMatchNb = 1 << SKIP_STRENGTH;
do {
sOff = forwardOff;
forwardOff += step;
step = searchMatchNb++ >>> SKIP_STRENGTH;
if (forwardOff > mflimit) {
break main;
}
final int h = hash64k(ByteBufferUtils.readInt(src, sOff));
ref = srcOff + UnsafeUtils.readShort(hashTable, h);
UnsafeUtils.writeShort(hashTable, h, sOff - srcOff);
} while (!LZ4ByteBufferUtils.readIntEquals(src, ref, sOff));
// catch up
final int excess = LZ4ByteBufferUtils.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) {
throw new LZ4Exception("maxDestLen is too small");
}
if (runLen >= RUN_MASK) {
ByteBufferUtils.writeByte(dest, tokenOff, RUN_MASK << ML_BITS);
dOff = LZ4ByteBufferUtils.writeLen(runLen - RUN_MASK, dest, dOff);
} else {
ByteBufferUtils.writeByte(dest, tokenOff, runLen << ML_BITS);
}
// copy literals
LZ4ByteBufferUtils.wildArraycopy(src, anchor, dest, dOff, runLen);
dOff += runLen;
while (true) {
// encode offset
ByteBufferUtils.writeShortLE(dest, dOff, (short) (sOff - ref));
dOff += 2;
// count nb matches
sOff += MIN_MATCH;
ref += MIN_MATCH;
final int matchLen = LZ4ByteBufferUtils.commonBytes(src, ref, sOff, srcLimit);
if (dOff + (1 + LAST_LITERALS) + (matchLen >>> 8) > destEnd) {
throw new LZ4Exception("maxDestLen is too small");
}
sOff += matchLen;
// encode match len
if (matchLen >= ML_MASK) {
ByteBufferUtils.writeByte(dest, tokenOff, ByteBufferUtils.readByte(dest, tokenOff) | ML_MASK);
dOff = LZ4ByteBufferUtils.writeLen(matchLen - ML_MASK, dest, dOff);
} else {
ByteBufferUtils.writeByte(dest, tokenOff, ByteBufferUtils.readByte(dest, tokenOff) | matchLen);
}
// test end of chunk
if (sOff > mflimit) {
anchor = sOff;
break main;
}
// fill table
UnsafeUtils.writeShort(hashTable, hash64k(ByteBufferUtils.readInt(src, sOff - 2)), sOff - 2 - srcOff);
// test next position
final int h = hash64k(ByteBufferUtils.readInt(src, sOff));
ref = srcOff + UnsafeUtils.readShort(hashTable, h);
UnsafeUtils.writeShort(hashTable, h, sOff - srcOff);
if (!LZ4ByteBufferUtils.readIntEquals(src, sOff, ref)) {
break;
}
tokenOff = dOff++;
ByteBufferUtils.writeByte(dest, tokenOff, 0);
}
// prepare next loop
anchor = sOff++;
}
}
dOff = LZ4ByteBufferUtils.lastLiterals(src, anchor, srcEnd - anchor, dest, dOff, destEnd);
return dOff - destOff;
}
@Override
public int compress(ByteBuffer src, final int srcOff, int srcLen, ByteBuffer dest, final int destOff, int maxDestLen) {
if (src.hasArray() && dest.hasArray()) {
return compress(src.array(), srcOff + src.arrayOffset(), srcLen, dest.array(), destOff + dest.arrayOffset(), maxDestLen);
}
src = ByteBufferUtils.inNativeByteOrder(src);
dest = ByteBufferUtils.inNativeByteOrder(dest);
ByteBufferUtils.checkRange(src, srcOff, srcLen);
ByteBufferUtils.checkRange(dest, destOff, maxDestLen);
final int destEnd = destOff + maxDestLen;
if (srcLen < LZ4_64K_LIMIT) {
return compress64k(src, srcOff, srcLen, dest, destOff, destEnd);
}
final int srcEnd = srcOff + srcLen;
final int srcLimit = srcEnd - LAST_LITERALS;
final int mflimit = srcEnd - MF_LIMIT;
int sOff = srcOff, dOff = destOff;
int anchor = sOff++;
final int[] hashTable = new int[HASH_TABLE_SIZE];
Arrays.fill(hashTable, anchor);
main:
while (true) {
// find a match
int forwardOff = sOff;
int ref;
int step = 1;
int searchMatchNb = 1 << SKIP_STRENGTH;
int back;
do {
sOff = forwardOff;
forwardOff += step;
step = searchMatchNb++ >>> SKIP_STRENGTH;
if (forwardOff > mflimit) {
break main;
}
final int h = hash(ByteBufferUtils.readInt(src, sOff));
ref = UnsafeUtils.readInt(hashTable, h);
back = sOff - ref;
UnsafeUtils.writeInt(hashTable, h, sOff);
} while (back >= MAX_DISTANCE || !LZ4ByteBufferUtils.readIntEquals(src, ref, sOff));
final int excess = LZ4ByteBufferUtils.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) {
throw new LZ4Exception("maxDestLen is too small");
}
if (runLen >= RUN_MASK) {
ByteBufferUtils.writeByte(dest, tokenOff, RUN_MASK << ML_BITS);
dOff = LZ4ByteBufferUtils.writeLen(runLen - RUN_MASK, dest, dOff);
} else {
ByteBufferUtils.writeByte(dest, tokenOff, runLen << ML_BITS);
}
// copy literals
LZ4ByteBufferUtils.wildArraycopy(src, anchor, dest, dOff, runLen);
dOff += runLen;
while (true) {
// encode offset
ByteBufferUtils.writeShortLE(dest, dOff, back);
dOff += 2;
// count nb matches
sOff += MIN_MATCH;
final int matchLen = LZ4ByteBufferUtils.commonBytes(src, ref + MIN_MATCH, sOff, srcLimit);
if (dOff + (1 + LAST_LITERALS) + (matchLen >>> 8) > destEnd) {
throw new LZ4Exception("maxDestLen is too small");
}
sOff += matchLen;
// encode match len
if (matchLen >= ML_MASK) {
ByteBufferUtils.writeByte(dest, tokenOff, ByteBufferUtils.readByte(dest, tokenOff) | ML_MASK);
dOff = LZ4ByteBufferUtils.writeLen(matchLen - ML_MASK, dest, dOff);
} else {
ByteBufferUtils.writeByte(dest, tokenOff, ByteBufferUtils.readByte(dest, tokenOff) | matchLen);
}
// test end of chunk
if (sOff > mflimit) {
anchor = sOff;
break main;
}
// fill table
UnsafeUtils.writeInt(hashTable, hash(ByteBufferUtils.readInt(src, sOff - 2)), sOff - 2);
// test next position
final int h = hash(ByteBufferUtils.readInt(src, sOff));
ref = UnsafeUtils.readInt(hashTable, h);
UnsafeUtils.writeInt(hashTable, h, sOff);
back = sOff - ref;
if (back >= MAX_DISTANCE || !LZ4ByteBufferUtils.readIntEquals(src, ref, sOff)) {
break;
}
tokenOff = dOff++;
ByteBufferUtils.writeByte(dest, tokenOff, 0);
}
// prepare next loop
anchor = sOff++;
}
dOff = LZ4ByteBufferUtils.lastLiterals(src, anchor, srcEnd - anchor, dest, dOff, destEnd);
return dOff - destOff;
}
}

205
fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4JavaUnsafeFastDecompressor.java

@ -0,0 +1,205 @@
// Auto-generated: DO NOT EDIT
package com.fr.third.net.jpountz.lz4;
import static com.fr.third.net.jpountz.lz4.LZ4Constants.*;
import java.nio.ByteBuffer;
import com.fr.third.net.jpountz.util.ByteBufferUtils;
import com.fr.third.net.jpountz.util.UnsafeUtils;
/**
* Decompressor.
*/
final class LZ4JavaUnsafeFastDecompressor extends LZ4FastDecompressor {
public static final LZ4FastDecompressor INSTANCE = new LZ4JavaUnsafeFastDecompressor();
@Override
public int decompress(byte[] src, final int srcOff, byte[] dest, final int destOff, int destLen) {
UnsafeUtils.checkRange(src, srcOff);
UnsafeUtils.checkRange(dest, destOff, destLen);
if (destLen == 0) {
if (UnsafeUtils.readByte(src, srcOff) != 0) {
throw new LZ4Exception("Malformed input at " + srcOff);
}
return 1;
}
final int destEnd = destOff + destLen;
int sOff = srcOff;
int dOff = destOff;
while (true) {
final int token = UnsafeUtils.readByte(src, sOff) & 0xFF;
++sOff;
// literals
int literalLen = token >>> ML_BITS;
if (literalLen == RUN_MASK) {
byte len = (byte) 0xFF;
while ((len = UnsafeUtils.readByte(src, sOff++)) == (byte) 0xFF) {
literalLen += 0xFF;
}
literalLen += len & 0xFF;
}
final int literalCopyEnd = dOff + literalLen;
if (literalCopyEnd > destEnd - COPY_LENGTH) {
if (literalCopyEnd != destEnd) {
throw new LZ4Exception("Malformed input at " + sOff);
} else {
LZ4UnsafeUtils.safeArraycopy(src, sOff, dest, dOff, literalLen);
sOff += literalLen;
dOff = literalCopyEnd;
break; // EOF
}
}
LZ4UnsafeUtils.wildArraycopy(src, sOff, dest, dOff, literalLen);
sOff += literalLen;
dOff = literalCopyEnd;
// matchs
final int matchDec = UnsafeUtils.readShortLE(src, sOff);
sOff += 2;
int matchOff = dOff - matchDec;
if (matchOff < destOff) {
throw new LZ4Exception("Malformed input at " + sOff);
}
int matchLen = token & ML_MASK;
if (matchLen == ML_MASK) {
byte len = (byte) 0xFF;
while ((len = UnsafeUtils.readByte(src, sOff++)) == (byte) 0xFF) {
matchLen += 0xFF;
}
matchLen += len & 0xFF;
}
matchLen += MIN_MATCH;
final int matchCopyEnd = dOff + matchLen;
if (matchCopyEnd > destEnd - COPY_LENGTH) {
if (matchCopyEnd > destEnd) {
throw new LZ4Exception("Malformed input at " + sOff);
}
LZ4UnsafeUtils.safeIncrementalCopy(dest, matchOff, dOff, matchLen);
} else {
LZ4UnsafeUtils.wildIncrementalCopy(dest, matchOff, dOff, matchCopyEnd);
}
dOff = matchCopyEnd;
}
return sOff - srcOff;
}
@Override
public int decompress(ByteBuffer src, final int srcOff, ByteBuffer dest, final int destOff, int destLen) {
if (src.hasArray() && dest.hasArray()) {
return decompress(src.array(), srcOff + src.arrayOffset(), dest.array(), destOff + dest.arrayOffset(), destLen);
}
src = ByteBufferUtils.inNativeByteOrder(src);
dest = ByteBufferUtils.inNativeByteOrder(dest);
ByteBufferUtils.checkRange(src, srcOff);
ByteBufferUtils.checkRange(dest, destOff, destLen);
if (destLen == 0) {
if (ByteBufferUtils.readByte(src, srcOff) != 0) {
throw new LZ4Exception("Malformed input at " + srcOff);
}
return 1;
}
final int destEnd = destOff + destLen;
int sOff = srcOff;
int dOff = destOff;
while (true) {
final int token = ByteBufferUtils.readByte(src, sOff) & 0xFF;
++sOff;
// literals
int literalLen = token >>> ML_BITS;
if (literalLen == RUN_MASK) {
byte len = (byte) 0xFF;
while ((len = ByteBufferUtils.readByte(src, sOff++)) == (byte) 0xFF) {
literalLen += 0xFF;
}
literalLen += len & 0xFF;
}
final int literalCopyEnd = dOff + literalLen;
if (literalCopyEnd > destEnd - COPY_LENGTH) {
if (literalCopyEnd != destEnd) {
throw new LZ4Exception("Malformed input at " + sOff);
} else {
LZ4ByteBufferUtils.safeArraycopy(src, sOff, dest, dOff, literalLen);
sOff += literalLen;
dOff = literalCopyEnd;
break; // EOF
}
}
LZ4ByteBufferUtils.wildArraycopy(src, sOff, dest, dOff, literalLen);
sOff += literalLen;
dOff = literalCopyEnd;
// matchs
final int matchDec = ByteBufferUtils.readShortLE(src, sOff);
sOff += 2;
int matchOff = dOff - matchDec;
if (matchOff < destOff) {
throw new LZ4Exception("Malformed input at " + sOff);
}
int matchLen = token & ML_MASK;
if (matchLen == ML_MASK) {
byte len = (byte) 0xFF;
while ((len = ByteBufferUtils.readByte(src, sOff++)) == (byte) 0xFF) {
matchLen += 0xFF;
}
matchLen += len & 0xFF;
}
matchLen += MIN_MATCH;
final int matchCopyEnd = dOff + matchLen;
if (matchCopyEnd > destEnd - COPY_LENGTH) {
if (matchCopyEnd > destEnd) {
throw new LZ4Exception("Malformed input at " + sOff);
}
LZ4ByteBufferUtils.safeIncrementalCopy(dest, matchOff, dOff, matchLen);
} else {
LZ4ByteBufferUtils.wildIncrementalCopy(dest, matchOff, dOff, matchCopyEnd);
}
dOff = matchCopyEnd;
}
return sOff - srcOff;
}
}

213
fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4JavaUnsafeSafeDecompressor.java

@ -0,0 +1,213 @@
// Auto-generated: DO NOT EDIT
package com.fr.third.net.jpountz.lz4;
import static com.fr.third.net.jpountz.lz4.LZ4Constants.*;
import java.nio.ByteBuffer;
import com.fr.third.net.jpountz.util.ByteBufferUtils;
import com.fr.third.net.jpountz.util.UnsafeUtils;
/**
* Decompressor.
*/
final class LZ4JavaUnsafeSafeDecompressor extends LZ4SafeDecompressor {
public static final LZ4SafeDecompressor INSTANCE = new LZ4JavaUnsafeSafeDecompressor();
@Override
public int decompress(byte[] src, final int srcOff, final int srcLen , byte[] dest, final int destOff, int destLen) {
UnsafeUtils.checkRange(src, srcOff, srcLen);
UnsafeUtils.checkRange(dest, destOff, destLen);
if (destLen == 0) {
if (srcLen != 1 || UnsafeUtils.readByte(src, srcOff) != 0) {
throw new LZ4Exception("Output buffer too small");
}
return 0;
}
final int srcEnd = srcOff + srcLen;
final int destEnd = destOff + destLen;
int sOff = srcOff;
int dOff = destOff;
while (true) {
final int token = UnsafeUtils.readByte(src, sOff) & 0xFF;
++sOff;
// literals
int literalLen = token >>> ML_BITS;
if (literalLen == RUN_MASK) {
byte len = (byte) 0xFF;
while (sOff < srcEnd &&(len = UnsafeUtils.readByte(src, sOff++)) == (byte) 0xFF) {
literalLen += 0xFF;
}
literalLen += len & 0xFF;
}
final int literalCopyEnd = dOff + literalLen;
if (literalCopyEnd > destEnd - COPY_LENGTH || sOff + literalLen > srcEnd - COPY_LENGTH) {
if (literalCopyEnd > destEnd) {
throw new LZ4Exception();
} else if (sOff + literalLen != srcEnd) {
throw new LZ4Exception("Malformed input at " + sOff);
} else {
LZ4UnsafeUtils.safeArraycopy(src, sOff, dest, dOff, literalLen);
sOff += literalLen;
dOff = literalCopyEnd;
break; // EOF
}
}
LZ4UnsafeUtils.wildArraycopy(src, sOff, dest, dOff, literalLen);
sOff += literalLen;
dOff = literalCopyEnd;
// matchs
final int matchDec = UnsafeUtils.readShortLE(src, sOff);
sOff += 2;
int matchOff = dOff - matchDec;
if (matchOff < destOff) {
throw new LZ4Exception("Malformed input at " + sOff);
}
int matchLen = token & ML_MASK;
if (matchLen == ML_MASK) {
byte len = (byte) 0xFF;
while (sOff < srcEnd &&(len = UnsafeUtils.readByte(src, sOff++)) == (byte) 0xFF) {
matchLen += 0xFF;
}
matchLen += len & 0xFF;
}
matchLen += MIN_MATCH;
final int matchCopyEnd = dOff + matchLen;
if (matchCopyEnd > destEnd - COPY_LENGTH) {
if (matchCopyEnd > destEnd) {
throw new LZ4Exception("Malformed input at " + sOff);
}
LZ4UnsafeUtils.safeIncrementalCopy(dest, matchOff, dOff, matchLen);
} else {
LZ4UnsafeUtils.wildIncrementalCopy(dest, matchOff, dOff, matchCopyEnd);
}
dOff = matchCopyEnd;
}
return dOff - destOff;
}
@Override
public int decompress(ByteBuffer src, final int srcOff, final int srcLen , ByteBuffer dest, final int destOff, int destLen) {
if (src.hasArray() && dest.hasArray()) {
return decompress(src.array(), srcOff + src.arrayOffset(), srcLen, dest.array(), destOff + dest.arrayOffset(), destLen);
}
src = ByteBufferUtils.inNativeByteOrder(src);
dest = ByteBufferUtils.inNativeByteOrder(dest);
ByteBufferUtils.checkRange(src, srcOff, srcLen);
ByteBufferUtils.checkRange(dest, destOff, destLen);
if (destLen == 0) {
if (srcLen != 1 || ByteBufferUtils.readByte(src, srcOff) != 0) {
throw new LZ4Exception("Output buffer too small");
}
return 0;
}
final int srcEnd = srcOff + srcLen;
final int destEnd = destOff + destLen;
int sOff = srcOff;
int dOff = destOff;
while (true) {
final int token = ByteBufferUtils.readByte(src, sOff) & 0xFF;
++sOff;
// literals
int literalLen = token >>> ML_BITS;
if (literalLen == RUN_MASK) {
byte len = (byte) 0xFF;
while (sOff < srcEnd &&(len = ByteBufferUtils.readByte(src, sOff++)) == (byte) 0xFF) {
literalLen += 0xFF;
}
literalLen += len & 0xFF;
}
final int literalCopyEnd = dOff + literalLen;
if (literalCopyEnd > destEnd - COPY_LENGTH || sOff + literalLen > srcEnd - COPY_LENGTH) {
if (literalCopyEnd > destEnd) {
throw new LZ4Exception();
} else if (sOff + literalLen != srcEnd) {
throw new LZ4Exception("Malformed input at " + sOff);
} else {
LZ4ByteBufferUtils.safeArraycopy(src, sOff, dest, dOff, literalLen);
sOff += literalLen;
dOff = literalCopyEnd;
break; // EOF
}
}
LZ4ByteBufferUtils.wildArraycopy(src, sOff, dest, dOff, literalLen);
sOff += literalLen;
dOff = literalCopyEnd;
// matchs
final int matchDec = ByteBufferUtils.readShortLE(src, sOff);
sOff += 2;
int matchOff = dOff - matchDec;
if (matchOff < destOff) {
throw new LZ4Exception("Malformed input at " + sOff);
}
int matchLen = token & ML_MASK;
if (matchLen == ML_MASK) {
byte len = (byte) 0xFF;
while (sOff < srcEnd &&(len = ByteBufferUtils.readByte(src, sOff++)) == (byte) 0xFF) {
matchLen += 0xFF;
}
matchLen += len & 0xFF;
}
matchLen += MIN_MATCH;
final int matchCopyEnd = dOff + matchLen;
if (matchCopyEnd > destEnd - COPY_LENGTH) {
if (matchCopyEnd > destEnd) {
throw new LZ4Exception("Malformed input at " + sOff);
}
LZ4ByteBufferUtils.safeIncrementalCopy(dest, matchOff, dOff, matchLen);
} else {
LZ4ByteBufferUtils.wildIncrementalCopy(dest, matchOff, dOff, matchCopyEnd);
}
dOff = matchCopyEnd;
}
return dOff - destOff;
}
}

155
fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4SafeDecompressor.java

@ -0,0 +1,155 @@
package com.fr.third.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.nio.ByteBuffer;
import java.util.Arrays;
/**
* LZ4 decompressor that requires the size of the compressed data to be known.
* <p>
* Implementations of this class are usually a little slower than those of
* {@link LZ4FastDecompressor} but do not require the size of the original data to
* be known.
*/
public abstract class LZ4SafeDecompressor implements LZ4UnknownSizeDecompressor {
/**
* Decompresses <code>src[srcOff:srcOff+srcLen]</code> into
* <code>dest[destOff:destOff+maxDestLen]</code> and returns the number of
* decompressed bytes written into <code>dest</code>.
*
* @param src the compressed data
* @param srcOff the start offset in src
* @param srcLen the exact size of the compressed data
* @param dest the destination buffer to store the decompressed data
* @param destOff the start offset in dest
* @param maxDestLen the maximum number of bytes to write in dest
* @return the original input size
* @throws LZ4Exception if maxDestLen is too small
*/
public abstract int decompress(byte[] src, int srcOff, int srcLen, byte[] dest, int destOff, int maxDestLen);
/**
* Decompresses <code>src[srcOff:srcOff+srcLen]</code> into
* <code>dest[destOff:destOff+maxDestLen]</code> and returns the number of
* decompressed bytes written into <code>dest</code>.
*
* @param src the compressed data
* @param srcOff the start offset in src
* @param srcLen the exact size of the compressed data
* @param dest the destination buffer to store the decompressed data
* @param destOff the start offset in dest
* @param maxDestLen the maximum number of bytes to write in dest
* @return the original input size
* @throws LZ4Exception if maxDestLen is too small
*/
public abstract int decompress(ByteBuffer src, int srcOff, int srcLen, ByteBuffer dest, int destOff, int maxDestLen);
/**
* Convenience method, equivalent to calling
* {@link #decompress(byte[], int, int, byte[], int, int) decompress(src, srcOff, srcLen, dest, destOff, dest.length - destOff)}.
*
* @param src the compressed data
* @param srcOff the start offset in src
* @param srcLen the exact size of the compressed data
* @param dest the destination buffer to store the decompressed data
* @param destOff the start offset in dest
* @return the original input size
* @throws LZ4Exception if dest is too small
*/
public final int decompress(byte[] src, int srcOff, int srcLen, byte[] dest, int destOff) {
return decompress(src, srcOff, srcLen, dest, destOff, dest.length - destOff);
}
/**
* Convenience method, equivalent to calling
* {@link #decompress(byte[], int, int, byte[], int) decompress(src, 0, src.length, dest, 0)}
*
* @param src the compressed data
* @param dest the destination buffer to store the decompressed data
* @return the original input size
* @throws LZ4Exception if dest is too small
*/
public final int decompress(byte[] src, byte[] dest) {
return decompress(src, 0, src.length, dest, 0);
}
/**
* Convenience method which returns <code>src[srcOff:srcOff+srcLen]</code>
* decompressed.
* <p><b><span style="color:red">Warning</span></b>: this method has an
* important overhead due to the fact that it needs to allocate a buffer to
* decompress into, and then needs to resize this buffer to the actual
* decompressed length.</p>
* <p>Here is how this method is implemented:</p>
* <pre>
* byte[] decompressed = new byte[maxDestLen];
* final int decompressedLength = decompress(src, srcOff, srcLen, decompressed, 0, maxDestLen);
* if (decompressedLength != decompressed.length) {
* decompressed = Arrays.copyOf(decompressed, decompressedLength);
* }
* return decompressed;
* </pre>
*
* @param src the compressed data
* @param srcOff the start offset in src
* @param srcLen the exact size of the compressed data
* @param maxDestLen the maximum number of bytes to write in dest
* @return the decompressed data
* @throws LZ4Exception if maxDestLen is too small
*/
public final byte[] decompress(byte[] src, int srcOff, int srcLen, int maxDestLen) {
byte[] decompressed = new byte[maxDestLen];
final int decompressedLength = decompress(src, srcOff, srcLen, decompressed, 0, maxDestLen);
if (decompressedLength != decompressed.length) {
decompressed = Arrays.copyOf(decompressed, decompressedLength);
}
return decompressed;
}
/**
* Convenience method, equivalent to calling
* {@link #decompress(byte[], int, int, int) decompress(src, 0, src.length, maxDestLen)}.
*
* @param src the compressed data
* @param maxDestLen the maximum number of bytes to write in dest
* @return the decompressed data
* @throws LZ4Exception if maxDestLen is too small
*/
public final byte[] decompress(byte[] src, int maxDestLen) {
return decompress(src, 0, src.length, maxDestLen);
}
/**
* Decompresses <code>src</code> into <code>dest</code>. <code>src</code>'s
* {@link ByteBuffer#remaining()} must be exactly the size of the compressed
* data. This method moves the positions of the buffers.
* @param src the compressed data
* @param dest the destination buffer to store the decompressed data
* @throws LZ4Exception if dest is too small
*/
public final void decompress(ByteBuffer src, ByteBuffer dest) {
final int decompressed = decompress(src, src.position(), src.remaining(), dest, dest.position(), dest.remaining());
src.position(src.limit());
dest.position(dest.position() + decompressed);
}
@Override
public String toString() {
return getClass().getSimpleName();
}
}

179
fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4SafeUtils.java

@ -0,0 +1,179 @@
package com.fr.third.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 com.fr.third.net.jpountz.lz4.LZ4Constants.LAST_LITERALS;
import static com.fr.third.net.jpountz.lz4.LZ4Constants.ML_BITS;
import static com.fr.third.net.jpountz.lz4.LZ4Constants.ML_MASK;
import static com.fr.third.net.jpountz.lz4.LZ4Constants.RUN_MASK;
import com.fr.third.net.jpountz.util.SafeUtils;
enum LZ4SafeUtils {
;
static int hash(byte[] buf, int i) {
return LZ4Utils.hash(SafeUtils.readInt(buf, i));
}
static int hash64k(byte[] buf, int i) {
return LZ4Utils.hash64k(SafeUtils.readInt(buf, i));
}
static boolean readIntEquals(byte[] buf, int i, int j) {
return buf[i] == buf[j] && buf[i+1] == buf[j+1] && buf[i+2] == buf[j+2] && buf[i+3] == buf[j+3];
}
static void safeIncrementalCopy(byte[] dest, int matchOff, int dOff, int matchLen) {
for (int i = 0; i < matchLen; ++i) {
dest[dOff + i] = dest[matchOff + i];
}
}
static void wildIncrementalCopy(byte[] dest, int matchOff, int dOff, int matchCopyEnd) {
do {
copy8Bytes(dest, matchOff, dest, dOff);
matchOff += 8;
dOff += 8;
} while (dOff < matchCopyEnd);
}
static void copy8Bytes(byte[] src, int sOff, byte[] dest, int dOff) {
for (int i = 0; i < 8; ++i) {
dest[dOff + i] = src[sOff + i];
}
}
static int commonBytes(byte[] b, int o1, int o2, int limit) {
int count = 0;
while (o2 < limit && b[o1++] == b[o2++]) {
++count;
}
return count;
}
static int commonBytesBackward(byte[] b, int o1, int o2, int l1, int l2) {
int count = 0;
while (o1 > l1 && o2 > l2 && b[--o1] == b[--o2]) {
++count;
}
return count;
}
static void safeArraycopy(byte[] src, int sOff, byte[] dest, int dOff, int len) {
System.arraycopy(src, sOff, dest, dOff, len);
}
static void wildArraycopy(byte[] src, int sOff, byte[] dest, int dOff, int len) {
try {
for (int i = 0; i < len; i += 8) {
copy8Bytes(src, sOff + i, dest, dOff + i);
}
} catch (ArrayIndexOutOfBoundsException e) {
throw new LZ4Exception("Malformed input at offset " + sOff);
}
}
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++;
if (dOff + runLen + (2 + 1 + LAST_LITERALS) + (runLen >>> 8) > destEnd) {
throw new LZ4Exception("maxDestLen is too small");
}
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 lastLiterals(byte[] src, int sOff, int srcLen, byte[] dest, int dOff, int destEnd) {
final int runLen = srcLen;
if (dOff + runLen + 1 + (runLen + 255 - RUN_MASK) / 255 > destEnd) {
throw new LZ4Exception();
}
if (runLen >= RUN_MASK) {
dest[dOff++] = (byte) (RUN_MASK << ML_BITS);
dOff = writeLen(runLen - RUN_MASK, dest, dOff);
} else {
dest[dOff++] = (byte) (runLen << ML_BITS);
}
// copy literals
System.arraycopy(src, sOff, dest, dOff, runLen);
dOff += runLen;
return dOff;
}
static int writeLen(int len, byte[] dest, int dOff) {
while (len >= 0xFF) {
dest[dOff++] = (byte) 0xFF;
len -= 0xFF;
}
dest[dOff++] = (byte) len;
return dOff;
}
static class Match {
int start, ref, len;
void fix(int correction) {
start += correction;
ref += correction;
len -= correction;
}
int end() {
return start + len;
}
}
static void copyTo(Match m1, Match m2) {
m2.len = m1.len;
m2.start = m1.start;
m2.ref = m1.ref;
}
}

27
fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4UnknownSizeDecompressor.java

@ -0,0 +1,27 @@
package com.fr.third.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.
*/
/**
* @deprecated Use {@link LZ4SafeDecompressor} instead.
*/
@Deprecated
public interface LZ4UnknownSizeDecompressor {
int decompress(byte[] src, int srcOff, int srcLen, byte[] dest, int destOff, int maxDestLen);
int decompress(byte[] src, int srcOff, int srcLen, byte[] dest, int destOff);
}

200
fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4UnsafeUtils.java

@ -0,0 +1,200 @@
package com.fr.third.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 com.fr.third.net.jpountz.util.UnsafeUtils;
import com.fr.third.net.jpountz.util.Utils;
import static com.fr.third.net.jpountz.util.UnsafeUtils.readInt;
import static com.fr.third.net.jpountz.util.UnsafeUtils.readShort;
import static com.fr.third.net.jpountz.util.UnsafeUtils.writeByte;
import static com.fr.third.net.jpountz.util.UnsafeUtils.writeInt;
import static com.fr.third.net.jpountz.util.UnsafeUtils.writeShort;
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) {
UnsafeUtils.writeByte(dest, destOff + fastLen + i, UnsafeUtils.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) {
UnsafeUtils.writeLong(dest, destOff + i, UnsafeUtils.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) {
UnsafeUtils.writeByte(dest, dOff+i, UnsafeUtils.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;
}
UnsafeUtils.writeInt(dest, dOff, UnsafeUtils.readInt(dest, matchOff));
dOff += 4;
matchOff -= dec;
} else if (dOff - matchOff < LZ4Constants.COPY_LENGTH) {
UnsafeUtils.writeLong(dest, dOff, UnsafeUtils.readLong(dest, matchOff));
dOff += dOff - matchOff;
}
while (dOff < matchCopyEnd) {
UnsafeUtils.writeLong(dest, dOff, UnsafeUtils.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];
UnsafeUtils.writeByte(dest, dOff + i, UnsafeUtils.readByte(dest, matchOff + i));
}
}
static int readShortLittleEndian(byte[] src, int srcOff) {
short s = UnsafeUtils.readShort(src, srcOff);
if (Utils.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 (Utils.NATIVE_BYTE_ORDER == ByteOrder.BIG_ENDIAN) {
s = Short.reverseBytes(s);
}
UnsafeUtils.writeShort(dest, destOff, s);
}
static boolean readIntEquals(byte[] src, int ref, int sOff) {
return UnsafeUtils.readInt(src, ref) == UnsafeUtils.readInt(src, sOff);
}
static int commonBytes(byte[] src, int ref, int sOff, int srcLimit) {
int matchLen = 0;
while (sOff <= srcLimit - 8) {
if (UnsafeUtils.readLong(src, sOff) == UnsafeUtils.readLong(src, ref)) {
matchLen += 8;
ref += 8;
sOff += 8;
} else {
final int zeroBits;
if (Utils.NATIVE_BYTE_ORDER == ByteOrder.BIG_ENDIAN) {
zeroBits = Long.numberOfLeadingZeros(UnsafeUtils.readLong(src, sOff) ^ UnsafeUtils.readLong(src, ref));
} else {
zeroBits = Long.numberOfTrailingZeros(UnsafeUtils.readLong(src, sOff) ^ UnsafeUtils.readLong(src, ref));
}
return matchLen + (zeroBits >>> 3);
}
}
while (sOff < srcLimit && UnsafeUtils.readByte(src, ref++) == UnsafeUtils.readByte(src, sOff++)) {
++matchLen;
}
return matchLen;
}
static int writeLen(int len, byte[] dest, int dOff) {
while (len >= 0xFF) {
UnsafeUtils.writeByte(dest, dOff++, 0xFF);
len -= 0xFF;
}
UnsafeUtils.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 >= LZ4Constants.RUN_MASK) {
token = (byte) (LZ4Constants.RUN_MASK << LZ4Constants.ML_BITS);
dOff = writeLen(runLen - LZ4Constants.RUN_MASK, dest, dOff);
} else {
token = runLen << LZ4Constants.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 + LZ4Constants.LAST_LITERALS) + (matchLen >>> 8) > destEnd) {
throw new LZ4Exception("maxDestLen is too small");
}
if (matchLen >= LZ4Constants.ML_MASK) {
token |= LZ4Constants.ML_MASK;
dOff = writeLen(matchLen - LZ4Constants.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 && UnsafeUtils.readByte(b, --o1) == UnsafeUtils.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);
}
}

68
fine-lz4/src/com/fr/third/net/jpountz/lz4/LZ4Utils.java

@ -0,0 +1,68 @@
package com.fr.third.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 com.fr.third.net.jpountz.lz4.LZ4Constants.HASH_LOG;
import static com.fr.third.net.jpountz.lz4.LZ4Constants.HASH_LOG_64K;
import static com.fr.third.net.jpountz.lz4.LZ4Constants.HASH_LOG_HC;
import static com.fr.third.net.jpountz.lz4.LZ4Constants.MIN_MATCH;
enum LZ4Utils {
;
private static final int MAX_INPUT_SIZE = 0x7E000000;
static int maxCompressedLength(int length) {
if (length < 0) {
throw new IllegalArgumentException("length must be >= 0, got " + length);
} else if (length >= MAX_INPUT_SIZE) {
throw new IllegalArgumentException("length must be < " + MAX_INPUT_SIZE);
}
return length + length / 255 + 16;
}
static int hash(int i) {
return (i * -1640531535) >>> ((MIN_MATCH * 8) - HASH_LOG);
}
static int hash64k(int i) {
return (i * -1640531535) >>> ((MIN_MATCH * 8) - HASH_LOG_64K);
}
static int hashHC(int i) {
return (i * -1640531535) >>> ((MIN_MATCH * 8) - HASH_LOG_HC);
}
static class Match {
int start, ref, len;
void fix(int correction) {
start += correction;
ref += correction;
len -= correction;
}
int end() {
return start + len;
}
}
static void copyTo(Match m1, Match m2) {
m2.len = m1.len;
m2.start = m1.start;
m2.ref = m1.ref;
}
}

55
fine-lz4/src/com/fr/third/net/jpountz/lz4/package.html

@ -0,0 +1,55 @@
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
<!--
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.
-->
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>
<body>
<p>LZ4 compression. The entry point of the API is the
{@link net.jpountz.lz4.LZ4Factory} class, which gives access to
{@link com.fr.third.net.jpountz.lz4.LZ4Compressor compressors} and
{@link com.fr.third.net.jpountz.lz4.LZ4SafeDecompressor decompressors}.</p>
<p>Sample usage:</p>
<pre class="prettyprint">
LZ4Factory factory = LZ4Factory.fastestInstance();
byte[] data = "12345345234572".getBytes("UTF-8");
final int decompressedLength = data.length;
// compress data
LZ4Compressor compressor = factory.fastCompressor();
int maxCompressedLength = compressor.maxCompressedLength(decompressedLength);
byte[] compressed = new byte[maxCompressedLength];
int compressedLength = compressor.compress(data, 0, decompressedLength, compressed, 0, maxCompressedLength);
// decompress data
// - method 1: when the decompressed length is known
LZ4FastDecompressor decompressor = factory.fastDecompressor();
byte[] restored = new byte[decompressedLength];
int compressedLength2 = decompressor.decompress(compressed, 0, restored, 0, decompressedLength);
// compressedLength == compressedLength2
// - method 2: when the compressed length is known (a little slower)
// the destination buffer needs to be over-sized
LZ4SafeDecompressor decompressor2 = factory.safeDecompressor();
int decompressedLength2 = decompressor2.decompress(compressed, 0, compressedLength, restored, 0);
// decompressedLength == decompressedLength2
</pre>
</body>
</html>

92
fine-lz4/src/com/fr/third/net/jpountz/util/ByteBufferUtils.java

@ -0,0 +1,92 @@
package com.fr.third.net.jpountz.util;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.ReadOnlyBufferException;
public enum ByteBufferUtils {
;
public static void checkRange(ByteBuffer buf, int off, int len) {
SafeUtils.checkLength(len);
if (len > 0) {
checkRange(buf, off);
checkRange(buf, off + len - 1);
}
}
public static void checkRange(ByteBuffer buf, int off) {
if (off < 0 || off >= buf.capacity()) {
throw new ArrayIndexOutOfBoundsException(off);
}
}
public static ByteBuffer inLittleEndianOrder(ByteBuffer buf) {
if (buf.order().equals(ByteOrder.LITTLE_ENDIAN)) {
return buf;
} else {
return buf.duplicate().order(ByteOrder.LITTLE_ENDIAN);
}
}
public static ByteBuffer inNativeByteOrder(ByteBuffer buf) {
if (buf.order().equals(Utils.NATIVE_BYTE_ORDER)) {
return buf;
} else {
return buf.duplicate().order(Utils.NATIVE_BYTE_ORDER);
}
}
public static byte readByte(ByteBuffer buf, int i) {
return buf.get(i);
}
public static void writeInt(ByteBuffer buf, int i, int v) {
assert buf.order() == Utils.NATIVE_BYTE_ORDER;
buf.putInt(i, v);
}
public static int readInt(ByteBuffer buf, int i) {
assert buf.order() == Utils.NATIVE_BYTE_ORDER;
return buf.getInt(i);
}
public static int readIntLE(ByteBuffer buf, int i) {
assert buf.order() == ByteOrder.LITTLE_ENDIAN;
return buf.getInt(i);
}
public static void writeLong(ByteBuffer buf, int i, long v) {
assert buf.order() == Utils.NATIVE_BYTE_ORDER;
buf.putLong(i, v);
}
public static long readLong(ByteBuffer buf, int i) {
assert buf.order() == Utils.NATIVE_BYTE_ORDER;
return buf.getLong(i);
}
public static long readLongLE(ByteBuffer buf, int i) {
assert buf.order() == ByteOrder.LITTLE_ENDIAN;
return buf.getLong(i);
}
public static void writeByte(ByteBuffer dest, int off, int i) {
dest.put(off, (byte) i);
}
public static void writeShortLE(ByteBuffer dest, int off, int i) {
dest.put(off, (byte) i);
dest.put(off + 1, (byte) (i >>> 8));
}
public static void checkNotReadOnly(ByteBuffer buffer) {
if (buffer.isReadOnly()) {
throw new ReadOnlyBufferException();
}
}
public static int readShortLE(ByteBuffer buf, int i) {
return (buf.get(i) & 0xFF) | ((buf.get(i+1) & 0xFF) << 8);
}
}

133
fine-lz4/src/com/fr/third/net/jpountz/util/Native.java

@ -0,0 +1,133 @@
package com.fr.third.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 java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
/** FOR INTERNAL USE ONLY */
public enum Native {
;
private enum OS {
// Even on Windows, the default compiler from cpptasks (gcc) uses .so as a shared lib extension
WINDOWS("win32", "so"), LINUX("linux", "so"), MAC("darwin", "dylib"), SOLARIS("solaris", "so");
public final String name, libExtension;
private OS(String name, String libExtension) {
this.name = name;
this.libExtension = libExtension;
}
}
private static String arch() {
return System.getProperty("os.arch");
}
private static OS os() {
String osName = System.getProperty("os.name");
if (osName.contains("Linux")) {
return OS.LINUX;
} else if (osName.contains("Mac")) {
return OS.MAC;
} else if (osName.contains("Windows")) {
return OS.WINDOWS;
} else if (osName.contains("Solaris") || osName.contains("SunOS")) {
return OS.SOLARIS;
} else {
throw new UnsupportedOperationException("Unsupported operating system: "
+ osName);
}
}
private static String resourceName() {
OS os = os();
String packagePrefix = Native.class.getPackage().getName().replace('.', '/');
return "/" + packagePrefix + "/" + os.name + "/" + arch() + "/liblz4-java." + os.libExtension;
}
private static boolean loaded = false;
public static synchronized boolean isLoaded() {
return loaded;
}
public static synchronized void load() {
if (loaded) {
return;
}
// Try to load lz4-java (liblz4-java.so on Linux) from the java.library.path.
try {
System.loadLibrary("lz4-java");
loaded = true;
return;
} catch (UnsatisfiedLinkError ex) {
// Doesn't exist, so proceed to loading bundled library.
}
String resourceName = resourceName();
InputStream is = Native.class.getResourceAsStream(resourceName);
if (is == null) {
throw new UnsupportedOperationException("Unsupported OS/arch, cannot find " + resourceName + ". Please try building from source.");
}
File tempLib;
try {
tempLib = File.createTempFile("liblz4-java", "." + os().libExtension);
// copy to tempLib
FileOutputStream out = new FileOutputStream(tempLib);
try {
byte[] buf = new byte[4096];
while (true) {
int read = is.read(buf);
if (read == -1) {
break;
}
out.write(buf, 0, read);
}
try {
out.close();
out = null;
} catch (IOException e) {
// ignore
}
System.load(tempLib.getAbsolutePath());
loaded = true;
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
// ignore
}
if (tempLib != null && tempLib.exists()) {
if (!loaded) {
tempLib.delete();
} else {
// try to delete on exit, does it work on Windows?
tempLib.deleteOnExit();
}
}
}
} catch (IOException e) {
throw new ExceptionInInitializerError("Cannot unpack liblz4-java");
}
}
}

95
fine-lz4/src/com/fr/third/net/jpountz/util/SafeUtils.java

@ -0,0 +1,95 @@
package com.fr.third.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 java.nio.ByteOrder;
public enum SafeUtils {
;
public static void checkRange(byte[] buf, int off) {
if (off < 0 || off >= buf.length) {
throw new ArrayIndexOutOfBoundsException(off);
}
}
public static void checkRange(byte[] buf, int off, int len) {
checkLength(len);
if (len > 0) {
checkRange(buf, off);
checkRange(buf, off + len - 1);
}
}
public static void checkLength(int len) {
if (len < 0) {
throw new IllegalArgumentException("lengths must be >= 0");
}
}
public static byte readByte(byte[] buf, int i) {
return buf[i];
}
public static int readIntBE(byte[] buf, int i) {
return ((buf[i] & 0xFF) << 24) | ((buf[i+1] & 0xFF) << 16) | ((buf[i+2] & 0xFF) << 8) | (buf[i+3] & 0xFF);
}
public static int readIntLE(byte[] buf, int i) {
return (buf[i] & 0xFF) | ((buf[i+1] & 0xFF) << 8) | ((buf[i+2] & 0xFF) << 16) | ((buf[i+3] & 0xFF) << 24);
}
public static int readInt(byte[] buf, int i) {
if (Utils.NATIVE_BYTE_ORDER == ByteOrder.BIG_ENDIAN) {
return readIntBE(buf, i);
} else {
return readIntLE(buf, i);
}
}
public static long readLongLE(byte[] buf, int i) {
return (buf[i] & 0xFFL) | ((buf[i+1] & 0xFFL) << 8) | ((buf[i+2] & 0xFFL) << 16) | ((buf[i+3] & 0xFFL) << 24)
| ((buf[i+4] & 0xFFL) << 32) | ((buf[i+5] & 0xFFL) << 40) | ((buf[i+6] & 0xFFL) << 48) | ((buf[i+7] & 0xFFL) << 56);
}
public static void writeShortLE(byte[] buf, int off, int v) {
buf[off++] = (byte) v;
buf[off++] = (byte) (v >>> 8);
}
public static void writeInt(int[] buf, int off, int v) {
buf[off] = v;
}
public static int readInt(int[] buf, int off) {
return buf[off];
}
public static void writeByte(byte[] dest, int off, int i) {
dest[off] = (byte) i;
}
public static void writeShort(short[] buf, int off, int v) {
buf[off] = (short) v;
}
public static int readShortLE(byte[] buf, int i) {
return (buf[i] & 0xFF) | ((buf[i+1] & 0xFF) << 8);
}
public static int readShort(short[] buf, int off) {
return buf[off] & 0xFFFF;
}
}

147
fine-lz4/src/com/fr/third/net/jpountz/util/UnsafeUtils.java

@ -0,0 +1,147 @@
package com.fr.third.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 com.fr.third.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);
}
}

36
fine-lz4/src/com/fr/third/net/jpountz/util/Utils.java

@ -0,0 +1,36 @@
package com.fr.third.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 java.nio.ByteOrder;
public enum Utils {
;
public static final ByteOrder NATIVE_BYTE_ORDER = ByteOrder.nativeOrder();
private static final boolean unalignedAccessAllowed;
static {
String arch = System.getProperty("os.arch");
unalignedAccessAllowed = arch.equals("i386") || arch.equals("x86")
|| arch.equals("amd64") || arch.equals("x86_64")
|| arch.equals("aarch64") || arch.equals("ppc64le");
}
public static boolean isUnalignedAccessAllowed() {
return unalignedAccessAllowed;
}
}

22
fine-lz4/src/com/fr/third/net/jpountz/util/package.html

@ -0,0 +1,22 @@
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
<!--
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.
-->
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>
<body>
<p>Utility classes.</p>
</body>
</html>

39
fine-lz4/src/com/fr/third/net/jpountz/xxhash/AbstractStreamingXXHash32Java.java

@ -0,0 +1,39 @@
package com.fr.third.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.
*/
abstract class AbstractStreamingXXHash32Java extends StreamingXXHash32 {
int v1, v2, v3, v4, memSize;
long totalLen;
final byte[] memory;
AbstractStreamingXXHash32Java(int seed) {
super(seed);
memory = new byte[16];
reset();
}
@Override
public void reset() {
v1 = seed + XXHashConstants.PRIME1 + XXHashConstants.PRIME2;
v2 = seed + XXHashConstants.PRIME2;
v3 = seed + 0;
v4 = seed - XXHashConstants.PRIME1;
totalLen = 0;
memSize = 0;
}
}

40
fine-lz4/src/com/fr/third/net/jpountz/xxhash/AbstractStreamingXXHash64Java.java

@ -0,0 +1,40 @@
package com.fr.third.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.
*/
abstract class AbstractStreamingXXHash64Java extends StreamingXXHash64 {
int memSize;
long v1, v2, v3, v4;
long totalLen;
final byte[] memory;
AbstractStreamingXXHash64Java(long seed) {
super(seed);
memory = new byte[32];
reset();
}
@Override
public void reset() {
v1 = seed + XXHashConstants.PRIME64_1 + XXHashConstants.PRIME64_2;
v2 = seed + XXHashConstants.PRIME64_2;
v3 = seed + 0;
v4 = seed - XXHashConstants.PRIME64_1;
totalLen = 0;
memSize = 0;
}
}

119
fine-lz4/src/com/fr/third/net/jpountz/xxhash/StreamingXXHash32.java

@ -0,0 +1,119 @@
package com.fr.third.net.jpountz.xxhash;
import java.util.zip.Checksum;
/*
* 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.
*/
/**
* Streaming interface for {@link XXHash32}.
* <p>
* This API is compatible with the {@link XXHash32 block API} and the following
* code samples are equivalent:
* <pre class="prettyprint">
* int hash(XXHashFactory xxhashFactory, byte[] buf, int off, int len, int seed) {
* return xxhashFactory.hash32().hash(buf, off, len, seed);
* }
* </pre>
* <pre class="prettyprint">
* int hash(XXHashFactory xxhashFactory, byte[] buf, int off, int len, int seed) {
* StreamingXXHash32 sh32 = xxhashFactory.newStreamingHash32(seed);
* sh32.update(buf, off, len);
* return sh32.getValue();
* }
* </pre>
* <p>
* Instances of this class are <b>not</b> thread-safe.
*/
public abstract class StreamingXXHash32 {
interface Factory {
StreamingXXHash32 newStreamingHash(int seed);
}
final int seed;
StreamingXXHash32(int seed) {
this.seed = seed;
}
/**
* Returns the value of the checksum.
*
* @return the checksum
*/
public abstract int getValue();
/**
* Updates the value of the hash with buf[off:off+len].
*
* @param buf the input data
* @param off the start offset in buf
* @param len the number of bytes to hash
*/
public abstract void update(byte[] buf, int off, int len);
/**
* Resets this instance to the state it had right after instantiation. The
* seed remains unchanged.
*/
public abstract void reset();
@Override
public String toString() {
return getClass().getSimpleName() + "(seed=" + seed + ")";
}
/**
* Returns a {@link Checksum} view of this instance. Modifications to the view
* will modify this instance too and vice-versa.
*
* @return the {@link Checksum} object representing this instance
*/
public final Checksum asChecksum() {
return new Checksum() {
@Override
public long getValue() {
return StreamingXXHash32.this.getValue() & 0xFFFFFFFL;
}
@Override
public void reset() {
StreamingXXHash32.this.reset();
}
@Override
public void update(int b) {
StreamingXXHash32.this.update(new byte[] {(byte) b}, 0, 1);
}
@Override
public void update(byte[] b, int off, int len) {
StreamingXXHash32.this.update(b, off, len);
}
@Override
public String toString() {
return StreamingXXHash32.this.toString();
}
};
}
}

71
fine-lz4/src/com/fr/third/net/jpountz/xxhash/StreamingXXHash32JNI.java

@ -0,0 +1,71 @@
package com.fr.third.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.
*/
final class StreamingXXHash32JNI extends StreamingXXHash32 {
static class Factory implements StreamingXXHash32.Factory {
public static final StreamingXXHash32.Factory INSTANCE = new Factory();
@Override
public StreamingXXHash32 newStreamingHash(int seed) {
return new StreamingXXHash32JNI(seed);
}
}
private long state;
StreamingXXHash32JNI(int seed) {
super(seed);
state = XXHashJNI.XXH32_init(seed);
}
private void checkState() {
if (state == 0) {
throw new AssertionError("Already finalized");
}
}
@Override
public void reset() {
checkState();
XXHashJNI.XXH32_free(state);
state = XXHashJNI.XXH32_init(seed);
}
@Override
public int getValue() {
checkState();
return XXHashJNI.XXH32_digest(state);
}
@Override
public void update(byte[] bytes, int off, int len) {
checkState();
XXHashJNI.XXH32_update(state, bytes, off, len);
}
@Override
protected void finalize() throws Throwable {
super.finalize();
// free memory
XXHashJNI.XXH32_free(state);
state = 0;
}
}

142
fine-lz4/src/com/fr/third/net/jpountz/xxhash/StreamingXXHash32JavaSafe.java

@ -0,0 +1,142 @@
// Auto-generated: DO NOT EDIT
package com.fr.third.net.jpountz.xxhash;
import static com.fr.third.net.jpountz.xxhash.XXHashConstants.*;
import static com.fr.third.net.jpountz.util.SafeUtils.*;
import static com.fr.third.net.jpountz.util.SafeUtils.checkRange;
import static java.lang.Integer.rotateLeft;
/**
* Streaming xxhash.
*/
final class StreamingXXHash32JavaSafe extends AbstractStreamingXXHash32Java {
static class Factory implements StreamingXXHash32.Factory {
public static final StreamingXXHash32.Factory INSTANCE = new Factory();
@Override
public StreamingXXHash32 newStreamingHash(int seed) {
return new StreamingXXHash32JavaSafe(seed);
}
}
StreamingXXHash32JavaSafe(int seed) {
super(seed);
}
@Override
public int getValue() {
int h32;
if (totalLen >= 16) {
h32 = rotateLeft(v1, 1) + rotateLeft(v2, 7) + rotateLeft(v3, 12) + rotateLeft(v4, 18);
} else {
h32 = seed + PRIME5;
}
h32 += totalLen;
int off = 0;
while (off <= memSize - 4) {
h32 += readIntLE(memory, off) * PRIME3;
h32 = rotateLeft(h32, 17) * PRIME4;
off += 4;
}
while (off < memSize) {
h32 += (readByte(memory, off) & 0xFF) * PRIME5;
h32 = rotateLeft(h32, 11) * PRIME1;
++off;
}
h32 ^= h32 >>> 15;
h32 *= PRIME2;
h32 ^= h32 >>> 13;
h32 *= PRIME3;
h32 ^= h32 >>> 16;
return h32;
}
@Override
public void update(byte[] buf, int off, int len) {
checkRange(buf, off, len);
totalLen += len;
if (memSize + len < 16) { // fill in tmp buffer
System.arraycopy(buf, off, memory, memSize, len);
memSize += len;
return;
}
final int end = off + len;
if (memSize > 0) { // data left from previous update
System.arraycopy(buf, off, memory, memSize, 16 - memSize);
v1 += readIntLE(memory, 0) * PRIME2;
v1 = rotateLeft(v1, 13);
v1 *= PRIME1;
v2 += readIntLE(memory, 4) * PRIME2;
v2 = rotateLeft(v2, 13);
v2 *= PRIME1;
v3 += readIntLE(memory, 8) * PRIME2;
v3 = rotateLeft(v3, 13);
v3 *= PRIME1;
v4 += readIntLE(memory, 12) * PRIME2;
v4 = rotateLeft(v4, 13);
v4 *= PRIME1;
off += 16 - memSize;
memSize = 0;
}
{
final int limit = end - 16;
int v1 = this.v1;
int v2 = this.v2;
int v3 = this.v3;
int v4 = this.v4;
while (off <= limit) {
v1 += readIntLE(buf, off) * PRIME2;
v1 = rotateLeft(v1, 13);
v1 *= PRIME1;
off += 4;
v2 += readIntLE(buf, off) * PRIME2;
v2 = rotateLeft(v2, 13);
v2 *= PRIME1;
off += 4;
v3 += readIntLE(buf, off) * PRIME2;
v3 = rotateLeft(v3, 13);
v3 *= PRIME1;
off += 4;
v4 += readIntLE(buf, off) * PRIME2;
v4 = rotateLeft(v4, 13);
v4 *= PRIME1;
off += 4;
}
this.v1 = v1;
this.v2 = v2;
this.v3 = v3;
this.v4 = v4;
}
if (off < end) {
System.arraycopy(buf, off, memory, 0, end - off);
memSize = end - off;
}
}
}

142
fine-lz4/src/com/fr/third/net/jpountz/xxhash/StreamingXXHash32JavaUnsafe.java

@ -0,0 +1,142 @@
// Auto-generated: DO NOT EDIT
package com.fr.third.net.jpountz.xxhash;
import static com.fr.third.net.jpountz.xxhash.XXHashConstants.*;
import static com.fr.third.net.jpountz.util.UnsafeUtils.*;
import static com.fr.third.net.jpountz.util.SafeUtils.checkRange;
import static java.lang.Integer.rotateLeft;
/**
* Streaming xxhash.
*/
final class StreamingXXHash32JavaUnsafe extends AbstractStreamingXXHash32Java {
static class Factory implements StreamingXXHash32.Factory {
public static final StreamingXXHash32.Factory INSTANCE = new Factory();
@Override
public StreamingXXHash32 newStreamingHash(int seed) {
return new StreamingXXHash32JavaUnsafe(seed);
}
}
StreamingXXHash32JavaUnsafe(int seed) {
super(seed);
}
@Override
public int getValue() {
int h32;
if (totalLen >= 16) {
h32 = rotateLeft(v1, 1) + rotateLeft(v2, 7) + rotateLeft(v3, 12) + rotateLeft(v4, 18);
} else {
h32 = seed + PRIME5;
}
h32 += totalLen;
int off = 0;
while (off <= memSize - 4) {
h32 += readIntLE(memory, off) * PRIME3;
h32 = rotateLeft(h32, 17) * PRIME4;
off += 4;
}
while (off < memSize) {
h32 += (readByte(memory, off) & 0xFF) * PRIME5;
h32 = rotateLeft(h32, 11) * PRIME1;
++off;
}
h32 ^= h32 >>> 15;
h32 *= PRIME2;
h32 ^= h32 >>> 13;
h32 *= PRIME3;
h32 ^= h32 >>> 16;
return h32;
}
@Override
public void update(byte[] buf, int off, int len) {
checkRange(buf, off, len);
totalLen += len;
if (memSize + len < 16) { // fill in tmp buffer
System.arraycopy(buf, off, memory, memSize, len);
memSize += len;
return;
}
final int end = off + len;
if (memSize > 0) { // data left from previous update
System.arraycopy(buf, off, memory, memSize, 16 - memSize);
v1 += readIntLE(memory, 0) * PRIME2;
v1 = rotateLeft(v1, 13);
v1 *= PRIME1;
v2 += readIntLE(memory, 4) * PRIME2;
v2 = rotateLeft(v2, 13);
v2 *= PRIME1;
v3 += readIntLE(memory, 8) * PRIME2;
v3 = rotateLeft(v3, 13);
v3 *= PRIME1;
v4 += readIntLE(memory, 12) * PRIME2;
v4 = rotateLeft(v4, 13);
v4 *= PRIME1;
off += 16 - memSize;
memSize = 0;
}
{
final int limit = end - 16;
int v1 = this.v1;
int v2 = this.v2;
int v3 = this.v3;
int v4 = this.v4;
while (off <= limit) {
v1 += readIntLE(buf, off) * PRIME2;
v1 = rotateLeft(v1, 13);
v1 *= PRIME1;
off += 4;
v2 += readIntLE(buf, off) * PRIME2;
v2 = rotateLeft(v2, 13);
v2 *= PRIME1;
off += 4;
v3 += readIntLE(buf, off) * PRIME2;
v3 = rotateLeft(v3, 13);
v3 *= PRIME1;
off += 4;
v4 += readIntLE(buf, off) * PRIME2;
v4 = rotateLeft(v4, 13);
v4 *= PRIME1;
off += 4;
}
this.v1 = v1;
this.v2 = v2;
this.v3 = v3;
this.v4 = v4;
}
if (off < end) {
System.arraycopy(buf, off, memory, 0, end - off);
memSize = end - off;
}
}
}

119
fine-lz4/src/com/fr/third/net/jpountz/xxhash/StreamingXXHash64.java

@ -0,0 +1,119 @@
package com.fr.third.net.jpountz.xxhash;
import java.util.zip.Checksum;
/*
* 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.
*/
/**
* Streaming interface for {@link XXHash64}.
* <p>
* This API is compatible with the {@link XXHash64 block API} and the following
* code samples are equivalent:
* <pre class="prettyprint">
* long hash(XXHashFactory xxhashFactory, byte[] buf, int off, int len, long seed) {
* return xxhashFactory.hash64().hash(buf, off, len, seed);
* }
* </pre>
* <pre class="prettyprint">
* long hash(XXHashFactory xxhashFactory, byte[] buf, int off, int len, long seed) {
* StreamingXXHash64 sh64 = xxhashFactory.newStreamingHash64(seed);
* sh64.update(buf, off, len);
* return sh64.getValue();
* }
* </pre>
* <p>
* Instances of this class are <b>not</b> thread-safe.
*/
public abstract class StreamingXXHash64 {
interface Factory {
StreamingXXHash64 newStreamingHash(long seed);
}
final long seed;
StreamingXXHash64(long seed) {
this.seed = seed;
}
/**
* Returns the value of the checksum.
*
* @return the checksum
*/
public abstract long getValue();
/**
* Updates the value of the hash with buf[off:off+len].
*
* @param buf the input data
* @param off the start offset in buf
* @param len the number of bytes to hash
*/
public abstract void update(byte[] buf, int off, int len);
/**
* Resets this instance to the state it had right after instantiation. The
* seed remains unchanged.
*/
public abstract void reset();
@Override
public String toString() {
return getClass().getSimpleName() + "(seed=" + seed + ")";
}
/**
* Returns a {@link Checksum} view of this instance. Modifications to the view
* will modify this instance too and vice-versa.
*
* @return the {@link Checksum} object representing this instance
*/
public final Checksum asChecksum() {
return new Checksum() {
@Override
public long getValue() {
return StreamingXXHash64.this.getValue();
}
@Override
public void reset() {
StreamingXXHash64.this.reset();
}
@Override
public void update(int b) {
StreamingXXHash64.this.update(new byte[] {(byte) b}, 0, 1);
}
@Override
public void update(byte[] b, int off, int len) {
StreamingXXHash64.this.update(b, off, len);
}
@Override
public String toString() {
return StreamingXXHash64.this.toString();
}
};
}
}

71
fine-lz4/src/com/fr/third/net/jpountz/xxhash/StreamingXXHash64JNI.java

@ -0,0 +1,71 @@
package com.fr.third.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.
*/
final class StreamingXXHash64JNI extends StreamingXXHash64 {
static class Factory implements StreamingXXHash64.Factory {
public static final StreamingXXHash64.Factory INSTANCE = new Factory();
@Override
public StreamingXXHash64 newStreamingHash(long seed) {
return new StreamingXXHash64JNI(seed);
}
}
private long state;
StreamingXXHash64JNI(long seed) {
super(seed);
state = XXHashJNI.XXH64_init(seed);
}
private void checkState() {
if (state == 0) {
throw new AssertionError("Already finalized");
}
}
@Override
public void reset() {
checkState();
XXHashJNI.XXH64_free(state);
state = XXHashJNI.XXH64_init(seed);
}
@Override
public long getValue() {
checkState();
return XXHashJNI.XXH64_digest(state);
}
@Override
public void update(byte[] bytes, int off, int len) {
checkState();
XXHashJNI.XXH64_update(state, bytes, off, len);
}
@Override
protected void finalize() throws Throwable {
super.finalize();
// free memory
XXHashJNI.XXH64_free(state);
state = 0;
}
}

166
fine-lz4/src/com/fr/third/net/jpountz/xxhash/StreamingXXHash64JavaSafe.java

@ -0,0 +1,166 @@
// Auto-generated: DO NOT EDIT
package com.fr.third.net.jpountz.xxhash;
import static com.fr.third.net.jpountz.xxhash.XXHashConstants.*;
import static com.fr.third.net.jpountz.util.SafeUtils.*;
import static com.fr.third.net.jpountz.util.SafeUtils.checkRange;
import static java.lang.Long.rotateLeft;
/**
* Streaming xxhash.
*/
final class StreamingXXHash64JavaSafe extends AbstractStreamingXXHash64Java {
static class Factory implements StreamingXXHash64.Factory {
public static final StreamingXXHash64.Factory INSTANCE = new Factory();
@Override
public StreamingXXHash64 newStreamingHash(long seed) {
return new StreamingXXHash64JavaSafe(seed);
}
}
StreamingXXHash64JavaSafe(long seed) {
super(seed);
}
@Override
public long getValue() {
long h64;
if (totalLen >= 32) {
long v1 = this.v1;
long v2 = this.v2;
long v3 = this.v3;
long v4 = this.v4;
h64 = rotateLeft(v1, 1) + rotateLeft(v2, 7) + rotateLeft(v3, 12) + rotateLeft(v4, 18);
v1 *= PRIME64_2; v1 = rotateLeft(v1, 31); v1 *= PRIME64_1; h64 ^= v1;
h64 = h64*PRIME64_1 + PRIME64_4;
v2 *= PRIME64_2; v2 = rotateLeft(v2, 31); v2 *= PRIME64_1; h64 ^= v2;
h64 = h64*PRIME64_1 + PRIME64_4;
v3 *= PRIME64_2; v3 = rotateLeft(v3, 31); v3 *= PRIME64_1; h64 ^= v3;
h64 = h64*PRIME64_1 + PRIME64_4;
v4 *= PRIME64_2; v4 = rotateLeft(v4, 31); v4 *= PRIME64_1; h64 ^= v4;
h64 = h64*PRIME64_1 + PRIME64_4;
} else {
h64 = seed + PRIME64_5;
}
h64 += totalLen;
int off = 0;
while (off <= memSize - 8) {
long k1 = readLongLE(memory, off);
k1 *= PRIME64_2; k1 = rotateLeft(k1, 31); k1 *= PRIME64_1; h64 ^= k1;
h64 = rotateLeft(h64, 27) * PRIME64_1 + PRIME64_4;
off += 8;
}
if (off <= memSize - 4) {
h64 ^= (readIntLE(memory, off) & 0xFFFFFFFFL) * PRIME64_1;
h64 = rotateLeft(h64, 23) * PRIME64_2 + PRIME64_3;
off += 4;
}
while (off < memSize) {
h64 ^= (memory[off] & 0xFF) * PRIME64_5;
h64 = rotateLeft(h64, 11) * PRIME64_1;
++off;
}
h64 ^= h64 >>> 33;
h64 *= PRIME64_2;
h64 ^= h64 >>> 29;
h64 *= PRIME64_3;
h64 ^= h64 >>> 32;
return h64;
}
@Override
public void update(byte[] buf, int off, int len) {
checkRange(buf, off, len);
totalLen += len;
if (memSize + len < 32) { // fill in tmp buffer
System.arraycopy(buf, off, memory, memSize, len);
memSize += len;
return;
}
final int end = off + len;
if (memSize > 0) { // data left from previous update
System.arraycopy(buf, off, memory, memSize, 32 - memSize);
v1 += readLongLE(memory, 0) * PRIME64_2;
v1 = rotateLeft(v1, 31);
v1 *= PRIME64_1;
v2 += readLongLE(memory, 8) * PRIME64_2;
v2 = rotateLeft(v2, 31);
v2 *= PRIME64_1;
v3 += readLongLE(memory, 16) * PRIME64_2;
v3 = rotateLeft(v3, 31);
v3 *= PRIME64_1;
v4 += readLongLE(memory, 24) * PRIME64_2;
v4 = rotateLeft(v4, 31);
v4 *= PRIME64_1;
off += 32 - memSize;
memSize = 0;
}
{
final int limit = end - 32;
long v1 = this.v1;
long v2 = this.v2;
long v3 = this.v3;
long v4 = this.v4;
while (off <= limit) {
v1 += readLongLE(buf, off) * PRIME64_2;
v1 = rotateLeft(v1, 31);
v1 *= PRIME64_1;
off += 8;
v2 += readLongLE(buf, off) * PRIME64_2;
v2 = rotateLeft(v2, 31);
v2 *= PRIME64_1;
off += 8;
v3 += readLongLE(buf, off) * PRIME64_2;
v3 = rotateLeft(v3, 31);
v3 *= PRIME64_1;
off += 8;
v4 += readLongLE(buf, off) * PRIME64_2;
v4 = rotateLeft(v4, 31);
v4 *= PRIME64_1;
off += 8;
}
this.v1 = v1;
this.v2 = v2;
this.v3 = v3;
this.v4 = v4;
}
if (off < end) {
System.arraycopy(buf, off, memory, 0, end - off);
memSize = end - off;
}
}
}

166
fine-lz4/src/com/fr/third/net/jpountz/xxhash/StreamingXXHash64JavaUnsafe.java

@ -0,0 +1,166 @@
// Auto-generated: DO NOT EDIT
package com.fr.third.net.jpountz.xxhash;
import static com.fr.third.net.jpountz.xxhash.XXHashConstants.*;
import static com.fr.third.net.jpountz.util.UnsafeUtils.*;
import static com.fr.third.net.jpountz.util.SafeUtils.checkRange;
import static java.lang.Long.rotateLeft;
/**
* Streaming xxhash.
*/
final class StreamingXXHash64JavaUnsafe extends AbstractStreamingXXHash64Java {
static class Factory implements StreamingXXHash64.Factory {
public static final StreamingXXHash64.Factory INSTANCE = new Factory();
@Override
public StreamingXXHash64 newStreamingHash(long seed) {
return new StreamingXXHash64JavaUnsafe(seed);
}
}
StreamingXXHash64JavaUnsafe(long seed) {
super(seed);
}
@Override
public long getValue() {
long h64;
if (totalLen >= 32) {
long v1 = this.v1;
long v2 = this.v2;
long v3 = this.v3;
long v4 = this.v4;
h64 = rotateLeft(v1, 1) + rotateLeft(v2, 7) + rotateLeft(v3, 12) + rotateLeft(v4, 18);
v1 *= PRIME64_2; v1 = rotateLeft(v1, 31); v1 *= PRIME64_1; h64 ^= v1;
h64 = h64*PRIME64_1 + PRIME64_4;
v2 *= PRIME64_2; v2 = rotateLeft(v2, 31); v2 *= PRIME64_1; h64 ^= v2;
h64 = h64*PRIME64_1 + PRIME64_4;
v3 *= PRIME64_2; v3 = rotateLeft(v3, 31); v3 *= PRIME64_1; h64 ^= v3;
h64 = h64*PRIME64_1 + PRIME64_4;
v4 *= PRIME64_2; v4 = rotateLeft(v4, 31); v4 *= PRIME64_1; h64 ^= v4;
h64 = h64*PRIME64_1 + PRIME64_4;
} else {
h64 = seed + PRIME64_5;
}
h64 += totalLen;
int off = 0;
while (off <= memSize - 8) {
long k1 = readLongLE(memory, off);
k1 *= PRIME64_2; k1 = rotateLeft(k1, 31); k1 *= PRIME64_1; h64 ^= k1;
h64 = rotateLeft(h64, 27) * PRIME64_1 + PRIME64_4;
off += 8;
}
if (off <= memSize - 4) {
h64 ^= (readIntLE(memory, off) & 0xFFFFFFFFL) * PRIME64_1;
h64 = rotateLeft(h64, 23) * PRIME64_2 + PRIME64_3;
off += 4;
}
while (off < memSize) {
h64 ^= (memory[off] & 0xFF) * PRIME64_5;
h64 = rotateLeft(h64, 11) * PRIME64_1;
++off;
}
h64 ^= h64 >>> 33;
h64 *= PRIME64_2;
h64 ^= h64 >>> 29;
h64 *= PRIME64_3;
h64 ^= h64 >>> 32;
return h64;
}
@Override
public void update(byte[] buf, int off, int len) {
checkRange(buf, off, len);
totalLen += len;
if (memSize + len < 32) { // fill in tmp buffer
System.arraycopy(buf, off, memory, memSize, len);
memSize += len;
return;
}
final int end = off + len;
if (memSize > 0) { // data left from previous update
System.arraycopy(buf, off, memory, memSize, 32 - memSize);
v1 += readLongLE(memory, 0) * PRIME64_2;
v1 = rotateLeft(v1, 31);
v1 *= PRIME64_1;
v2 += readLongLE(memory, 8) * PRIME64_2;
v2 = rotateLeft(v2, 31);
v2 *= PRIME64_1;
v3 += readLongLE(memory, 16) * PRIME64_2;
v3 = rotateLeft(v3, 31);
v3 *= PRIME64_1;
v4 += readLongLE(memory, 24) * PRIME64_2;
v4 = rotateLeft(v4, 31);
v4 *= PRIME64_1;
off += 32 - memSize;
memSize = 0;
}
{
final int limit = end - 32;
long v1 = this.v1;
long v2 = this.v2;
long v3 = this.v3;
long v4 = this.v4;
while (off <= limit) {
v1 += readLongLE(buf, off) * PRIME64_2;
v1 = rotateLeft(v1, 31);
v1 *= PRIME64_1;
off += 8;
v2 += readLongLE(buf, off) * PRIME64_2;
v2 = rotateLeft(v2, 31);
v2 *= PRIME64_1;
off += 8;
v3 += readLongLE(buf, off) * PRIME64_2;
v3 = rotateLeft(v3, 31);
v3 *= PRIME64_1;
off += 8;
v4 += readLongLE(buf, off) * PRIME64_2;
v4 = rotateLeft(v4, 31);
v4 *= PRIME64_1;
off += 8;
}
this.v1 = v1;
this.v2 = v2;
this.v3 = v3;
this.v4 = v4;
}
if (off < end) {
System.arraycopy(buf, off, memory, 0, end - off);
memSize = end - off;
}
}
}

71
fine-lz4/src/com/fr/third/net/jpountz/xxhash/XXHash32.java

@ -0,0 +1,71 @@
package com.fr.third.net.jpountz.xxhash;
import java.nio.ByteBuffer;
/*
* 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.
*/
/**
* A 32-bits hash.
* <p>
* Instances of this class are thread-safe.
*/
public abstract class XXHash32 {
/**
* Computes the 32-bits hash of <code>buf[off:off+len]</code> using seed
* <code>seed</code>.
*
* @param buf the input data
* @param off the start offset in buf
* @param len the number of bytes to hash
* @param seed the seed to use
* @return the hash value
*/
public abstract int hash(byte[] buf, int off, int len, int seed);
/**
* Computes the hash of the given slice of the {@link ByteBuffer}.
* {@link ByteBuffer#position() position} and {@link ByteBuffer#limit() limit}
* are not modified.
*
* @param buf the input data
* @param off the start offset in buf
* @param len the number of bytes to hash
* @param seed the seed to use
* @return the hash value
*/
public abstract int hash(ByteBuffer buf, int off, int len, int seed);
/**
* Computes the hash of the given {@link ByteBuffer}. The
* {@link ByteBuffer#position() position} is moved in order to reflect bytes
* which have been read.
*
* @param buf the input data
* @param seed the seed to use
* @return the hash value
*/
public final int hash(ByteBuffer buf, int seed) {
final int hash = hash(buf, buf.position(), buf.remaining(), seed);
buf.position(buf.limit());
return hash;
}
@Override
public String toString() {
return getClass().getSimpleName();
}
}

52
fine-lz4/src/com/fr/third/net/jpountz/xxhash/XXHash32JNI.java

@ -0,0 +1,52 @@
package com.fr.third.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 com.fr.third.net.jpountz.util.ByteBufferUtils;
import com.fr.third.net.jpountz.util.SafeUtils;
import static com.fr.third.net.jpountz.util.ByteBufferUtils.checkRange;
import static com.fr.third.net.jpountz.util.SafeUtils.checkRange;
import java.nio.ByteBuffer;
final class XXHash32JNI extends XXHash32 {
public static final XXHash32 INSTANCE = new XXHash32JNI();
private static XXHash32 SAFE_INSTANCE;
@Override
public int hash(byte[] buf, int off, int len, int seed) {
SafeUtils.checkRange(buf, off, len);
return XXHashJNI.XXH32(buf, off, len, seed);
}
@Override
public int hash(ByteBuffer buf, int off, int len, int seed) {
if (buf.isDirect()) {
ByteBufferUtils.checkRange(buf, off, len);
return XXHashJNI.XXH32BB(buf, off, len, seed);
} else if (buf.hasArray()) {
return hash(buf.array(), off + buf.arrayOffset(), len, seed);
} else {
XXHash32 safeInstance = SAFE_INSTANCE;
if (safeInstance == null) {
safeInstance = SAFE_INSTANCE = XXHashFactory.safeInstance().hash32();
}
return safeInstance.hash(buf, off, len, seed);
}
}
}

154
fine-lz4/src/com/fr/third/net/jpountz/xxhash/XXHash32JavaSafe.java

@ -0,0 +1,154 @@
// Auto-generated: DO NOT EDIT
package com.fr.third.net.jpountz.xxhash;
import static com.fr.third.net.jpountz.xxhash.XXHashConstants.*;
import static java.lang.Integer.rotateLeft;
import java.nio.ByteBuffer;
import com.fr.third.net.jpountz.util.SafeUtils;
import com.fr.third.net.jpountz.util.ByteBufferUtils;
/**
* {@link XXHash32} implementation.
*/
final class XXHash32JavaSafe extends XXHash32 {
public static final XXHash32 INSTANCE = new XXHash32JavaSafe();
@Override
public int hash(byte[] buf, int off, int len, int seed) {
SafeUtils.checkRange(buf, off, len);
final int end = off + len;
int h32;
if (len >= 16) {
final int limit = end - 16;
int v1 = seed + PRIME1 + PRIME2;
int v2 = seed + PRIME2;
int v3 = seed + 0;
int v4 = seed - PRIME1;
do {
v1 += SafeUtils.readIntLE(buf, off) * PRIME2;
v1 = rotateLeft(v1, 13);
v1 *= PRIME1;
off += 4;
v2 += SafeUtils.readIntLE(buf, off) * PRIME2;
v2 = rotateLeft(v2, 13);
v2 *= PRIME1;
off += 4;
v3 += SafeUtils.readIntLE(buf, off) * PRIME2;
v3 = rotateLeft(v3, 13);
v3 *= PRIME1;
off += 4;
v4 += SafeUtils.readIntLE(buf, off) * PRIME2;
v4 = rotateLeft(v4, 13);
v4 *= PRIME1;
off += 4;
} while (off <= limit);
h32 = rotateLeft(v1, 1) + rotateLeft(v2, 7) + rotateLeft(v3, 12) + rotateLeft(v4, 18);
} else {
h32 = seed + PRIME5;
}
h32 += len;
while (off <= end - 4) {
h32 += SafeUtils.readIntLE(buf, off) * PRIME3;
h32 = rotateLeft(h32, 17) * PRIME4;
off += 4;
}
while (off < end) {
h32 += (SafeUtils.readByte(buf, off) & 0xFF) * PRIME5;
h32 = rotateLeft(h32, 11) * PRIME1;
++off;
}
h32 ^= h32 >>> 15;
h32 *= PRIME2;
h32 ^= h32 >>> 13;
h32 *= PRIME3;
h32 ^= h32 >>> 16;
return h32;
}
@Override
public int hash(ByteBuffer buf, int off, int len, int seed) {
if (buf.hasArray()) {
return hash(buf.array(), off + buf.arrayOffset(), len, seed);
}
ByteBufferUtils.checkRange(buf, off, len);
buf = ByteBufferUtils.inLittleEndianOrder(buf);
final int end = off + len;
int h32;
if (len >= 16) {
final int limit = end - 16;
int v1 = seed + PRIME1 + PRIME2;
int v2 = seed + PRIME2;
int v3 = seed + 0;
int v4 = seed - PRIME1;
do {
v1 += ByteBufferUtils.readIntLE(buf, off) * PRIME2;
v1 = rotateLeft(v1, 13);
v1 *= PRIME1;
off += 4;
v2 += ByteBufferUtils.readIntLE(buf, off) * PRIME2;
v2 = rotateLeft(v2, 13);
v2 *= PRIME1;
off += 4;
v3 += ByteBufferUtils.readIntLE(buf, off) * PRIME2;
v3 = rotateLeft(v3, 13);
v3 *= PRIME1;
off += 4;
v4 += ByteBufferUtils.readIntLE(buf, off) * PRIME2;
v4 = rotateLeft(v4, 13);
v4 *= PRIME1;
off += 4;
} while (off <= limit);
h32 = rotateLeft(v1, 1) + rotateLeft(v2, 7) + rotateLeft(v3, 12) + rotateLeft(v4, 18);
} else {
h32 = seed + PRIME5;
}
h32 += len;
while (off <= end - 4) {
h32 += ByteBufferUtils.readIntLE(buf, off) * PRIME3;
h32 = rotateLeft(h32, 17) * PRIME4;
off += 4;
}
while (off < end) {
h32 += (ByteBufferUtils.readByte(buf, off) & 0xFF) * PRIME5;
h32 = rotateLeft(h32, 11) * PRIME1;
++off;
}
h32 ^= h32 >>> 15;
h32 *= PRIME2;
h32 ^= h32 >>> 13;
h32 *= PRIME3;
h32 ^= h32 >>> 16;
return h32;
}
}

154
fine-lz4/src/com/fr/third/net/jpountz/xxhash/XXHash32JavaUnsafe.java

@ -0,0 +1,154 @@
// Auto-generated: DO NOT EDIT
package com.fr.third.net.jpountz.xxhash;
import static com.fr.third.net.jpountz.xxhash.XXHashConstants.*;
import static java.lang.Integer.rotateLeft;
import java.nio.ByteBuffer;
import com.fr.third.net.jpountz.util.UnsafeUtils;
import com.fr.third.net.jpountz.util.ByteBufferUtils;
/**
* {@link XXHash32} implementation.
*/
final class XXHash32JavaUnsafe extends XXHash32 {
public static final XXHash32 INSTANCE = new XXHash32JavaUnsafe();
@Override
public int hash(byte[] buf, int off, int len, int seed) {
UnsafeUtils.checkRange(buf, off, len);
final int end = off + len;
int h32;
if (len >= 16) {
final int limit = end - 16;
int v1 = seed + PRIME1 + PRIME2;
int v2 = seed + PRIME2;
int v3 = seed + 0;
int v4 = seed - PRIME1;
do {
v1 += UnsafeUtils.readIntLE(buf, off) * PRIME2;
v1 = rotateLeft(v1, 13);
v1 *= PRIME1;
off += 4;
v2 += UnsafeUtils.readIntLE(buf, off) * PRIME2;
v2 = rotateLeft(v2, 13);
v2 *= PRIME1;
off += 4;
v3 += UnsafeUtils.readIntLE(buf, off) * PRIME2;
v3 = rotateLeft(v3, 13);
v3 *= PRIME1;
off += 4;
v4 += UnsafeUtils.readIntLE(buf, off) * PRIME2;
v4 = rotateLeft(v4, 13);
v4 *= PRIME1;
off += 4;
} while (off <= limit);
h32 = rotateLeft(v1, 1) + rotateLeft(v2, 7) + rotateLeft(v3, 12) + rotateLeft(v4, 18);
} else {
h32 = seed + PRIME5;
}
h32 += len;
while (off <= end - 4) {
h32 += UnsafeUtils.readIntLE(buf, off) * PRIME3;
h32 = rotateLeft(h32, 17) * PRIME4;
off += 4;
}
while (off < end) {
h32 += (UnsafeUtils.readByte(buf, off) & 0xFF) * PRIME5;
h32 = rotateLeft(h32, 11) * PRIME1;
++off;
}
h32 ^= h32 >>> 15;
h32 *= PRIME2;
h32 ^= h32 >>> 13;
h32 *= PRIME3;
h32 ^= h32 >>> 16;
return h32;
}
@Override
public int hash(ByteBuffer buf, int off, int len, int seed) {
if (buf.hasArray()) {
return hash(buf.array(), off + buf.arrayOffset(), len, seed);
}
ByteBufferUtils.checkRange(buf, off, len);
buf = ByteBufferUtils.inLittleEndianOrder(buf);
final int end = off + len;
int h32;
if (len >= 16) {
final int limit = end - 16;
int v1 = seed + PRIME1 + PRIME2;
int v2 = seed + PRIME2;
int v3 = seed + 0;
int v4 = seed - PRIME1;
do {
v1 += ByteBufferUtils.readIntLE(buf, off) * PRIME2;
v1 = rotateLeft(v1, 13);
v1 *= PRIME1;
off += 4;
v2 += ByteBufferUtils.readIntLE(buf, off) * PRIME2;
v2 = rotateLeft(v2, 13);
v2 *= PRIME1;
off += 4;
v3 += ByteBufferUtils.readIntLE(buf, off) * PRIME2;
v3 = rotateLeft(v3, 13);
v3 *= PRIME1;
off += 4;
v4 += ByteBufferUtils.readIntLE(buf, off) * PRIME2;
v4 = rotateLeft(v4, 13);
v4 *= PRIME1;
off += 4;
} while (off <= limit);
h32 = rotateLeft(v1, 1) + rotateLeft(v2, 7) + rotateLeft(v3, 12) + rotateLeft(v4, 18);
} else {
h32 = seed + PRIME5;
}
h32 += len;
while (off <= end - 4) {
h32 += ByteBufferUtils.readIntLE(buf, off) * PRIME3;
h32 = rotateLeft(h32, 17) * PRIME4;
off += 4;
}
while (off < end) {
h32 += (ByteBufferUtils.readByte(buf, off) & 0xFF) * PRIME5;
h32 = rotateLeft(h32, 11) * PRIME1;
++off;
}
h32 ^= h32 >>> 15;
h32 *= PRIME2;
h32 ^= h32 >>> 13;
h32 *= PRIME3;
h32 ^= h32 >>> 16;
return h32;
}
}

71
fine-lz4/src/com/fr/third/net/jpountz/xxhash/XXHash64.java

@ -0,0 +1,71 @@
package com.fr.third.net.jpountz.xxhash;
import java.nio.ByteBuffer;
/*
* 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.
*/
/**
* A 64-bits hash.
* <p>
* Instances of this class are thread-safe.
*/
public abstract class XXHash64 {
/**
* Computes the 64-bits hash of <code>buf[off:off+len]</code> using seed
* <code>seed</code>.
*
* @param buf the input data
* @param off the start offset in buf
* @param len the number of bytes to hash
* @param seed the seed to use
* @return the hash value
*/
public abstract long hash(byte[] buf, int off, int len, long seed);
/**
* Computes the hash of the given slice of the {@link ByteBuffer}.
* {@link ByteBuffer#position() position} and {@link ByteBuffer#limit() limit}
* are not modified.
*
* @param buf the input data
* @param off the start offset in buf
* @param len the number of bytes to hash
* @param seed the seed to use
* @return the hash value
*/
public abstract long hash(ByteBuffer buf, int off, int len, long seed);
/**
* Computes the hash of the given {@link ByteBuffer}. The
* {@link ByteBuffer#position() position} is moved in order to reflect bytes
* which have been read.
*
* @param buf the input data
* @param seed the seed to use
* @return the hash value
*/
public final long hash(ByteBuffer buf, long seed) {
final long hash = hash(buf, buf.position(), buf.remaining(), seed);
buf.position(buf.limit());
return hash;
}
@Override
public String toString() {
return getClass().getSimpleName();
}
}

52
fine-lz4/src/com/fr/third/net/jpountz/xxhash/XXHash64JNI.java

@ -0,0 +1,52 @@
package com.fr.third.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 com.fr.third.net.jpountz.util.ByteBufferUtils;
import com.fr.third.net.jpountz.util.SafeUtils;
import static com.fr.third.net.jpountz.util.ByteBufferUtils.checkRange;
import static com.fr.third.net.jpountz.util.SafeUtils.checkRange;
import java.nio.ByteBuffer;
final class XXHash64JNI extends XXHash64 {
public static final XXHash64 INSTANCE = new XXHash64JNI();
private static XXHash64 SAFE_INSTANCE;
@Override
public long hash(byte[] buf, int off, int len, long seed) {
SafeUtils.checkRange(buf, off, len);
return XXHashJNI.XXH64(buf, off, len, seed);
}
@Override
public long hash(ByteBuffer buf, int off, int len, long seed) {
if (buf.isDirect()) {
ByteBufferUtils.checkRange(buf, off, len);
return XXHashJNI.XXH64BB(buf, off, len, seed);
} else if (buf.hasArray()) {
return hash(buf.array(), off + buf.arrayOffset(), len, seed);
} else {
XXHash64 safeInstance = SAFE_INSTANCE;
if (safeInstance == null) {
safeInstance = SAFE_INSTANCE = XXHashFactory.safeInstance().hash64();
}
return safeInstance.hash(buf, off, len, seed);
}
}
}

192
fine-lz4/src/com/fr/third/net/jpountz/xxhash/XXHash64JavaSafe.java

@ -0,0 +1,192 @@
// Auto-generated: DO NOT EDIT
package com.fr.third.net.jpountz.xxhash;
import static com.fr.third.net.jpountz.xxhash.XXHashConstants.*;
import static java.lang.Long.rotateLeft;
import java.nio.ByteBuffer;
import com.fr.third.net.jpountz.util.SafeUtils;
import com.fr.third.net.jpountz.util.ByteBufferUtils;
/**
* {@link XXHash64} implementation.
*/
final class XXHash64JavaSafe extends XXHash64 {
public static final XXHash64 INSTANCE = new XXHash64JavaSafe();
@Override
public long hash(byte[] buf, int off, int len, long seed) {
SafeUtils.checkRange(buf, off, len);
final int end = off + len;
long h64;
if (len >= 32) {
final int limit = end - 32;
long v1 = seed + PRIME64_1 + PRIME64_2;
long v2 = seed + PRIME64_2;
long v3 = seed + 0;
long v4 = seed - PRIME64_1;
do {
v1 += SafeUtils.readLongLE(buf, off) * PRIME64_2;
v1 = rotateLeft(v1, 31);
v1 *= PRIME64_1;
off += 8;
v2 += SafeUtils.readLongLE(buf, off) * PRIME64_2;
v2 = rotateLeft(v2, 31);
v2 *= PRIME64_1;
off += 8;
v3 += SafeUtils.readLongLE(buf, off) * PRIME64_2;
v3 = rotateLeft(v3, 31);
v3 *= PRIME64_1;
off += 8;
v4 += SafeUtils.readLongLE(buf, off) * PRIME64_2;
v4 = rotateLeft(v4, 31);
v4 *= PRIME64_1;
off += 8;
} while (off <= limit);
h64 = rotateLeft(v1, 1) + rotateLeft(v2, 7) + rotateLeft(v3, 12) + rotateLeft(v4, 18);
v1 *= PRIME64_2; v1 = rotateLeft(v1, 31); v1 *= PRIME64_1; h64 ^= v1;
h64 = h64 * PRIME64_1 + PRIME64_4;
v2 *= PRIME64_2; v2 = rotateLeft(v2, 31); v2 *= PRIME64_1; h64 ^= v2;
h64 = h64 * PRIME64_1 + PRIME64_4;
v3 *= PRIME64_2; v3 = rotateLeft(v3, 31); v3 *= PRIME64_1; h64 ^= v3;
h64 = h64 * PRIME64_1 + PRIME64_4;
v4 *= PRIME64_2; v4 = rotateLeft(v4, 31); v4 *= PRIME64_1; h64 ^= v4;
h64 = h64 * PRIME64_1 + PRIME64_4;
} else {
h64 = seed + PRIME64_5;
}
h64 += len;
while (off <= end - 8) {
long k1 = SafeUtils.readLongLE(buf, off);
k1 *= PRIME64_2; k1 = rotateLeft(k1, 31); k1 *= PRIME64_1; h64 ^= k1;
h64 = rotateLeft(h64, 27) * PRIME64_1 + PRIME64_4;
off += 8;
}
if (off <= end - 4) {
h64 ^= (SafeUtils.readIntLE(buf, off) & 0xFFFFFFFFL) * PRIME64_1;
h64 = rotateLeft(h64, 23) * PRIME64_2 + PRIME64_3;
off += 4;
}
while (off < end) {
h64 ^= (SafeUtils.readByte(buf, off) & 0xFF) * PRIME64_5;
h64 = rotateLeft(h64, 11) * PRIME64_1;
++off;
}
h64 ^= h64 >>> 33;
h64 *= PRIME64_2;
h64 ^= h64 >>> 29;
h64 *= PRIME64_3;
h64 ^= h64 >>> 32;
return h64;
}
@Override
public long hash(ByteBuffer buf, int off, int len, long seed) {
if (buf.hasArray()) {
return hash(buf.array(), off + buf.arrayOffset(), len, seed);
}
ByteBufferUtils.checkRange(buf, off, len);
buf = ByteBufferUtils.inLittleEndianOrder(buf);
final int end = off + len;
long h64;
if (len >= 32) {
final int limit = end - 32;
long v1 = seed + PRIME64_1 + PRIME64_2;
long v2 = seed + PRIME64_2;
long v3 = seed + 0;
long v4 = seed - PRIME64_1;
do {
v1 += ByteBufferUtils.readLongLE(buf, off) * PRIME64_2;
v1 = rotateLeft(v1, 31);
v1 *= PRIME64_1;
off += 8;
v2 += ByteBufferUtils.readLongLE(buf, off) * PRIME64_2;
v2 = rotateLeft(v2, 31);
v2 *= PRIME64_1;
off += 8;
v3 += ByteBufferUtils.readLongLE(buf, off) * PRIME64_2;
v3 = rotateLeft(v3, 31);
v3 *= PRIME64_1;
off += 8;
v4 += ByteBufferUtils.readLongLE(buf, off) * PRIME64_2;
v4 = rotateLeft(v4, 31);
v4 *= PRIME64_1;
off += 8;
} while (off <= limit);
h64 = rotateLeft(v1, 1) + rotateLeft(v2, 7) + rotateLeft(v3, 12) + rotateLeft(v4, 18);
v1 *= PRIME64_2; v1 = rotateLeft(v1, 31); v1 *= PRIME64_1; h64 ^= v1;
h64 = h64 * PRIME64_1 + PRIME64_4;
v2 *= PRIME64_2; v2 = rotateLeft(v2, 31); v2 *= PRIME64_1; h64 ^= v2;
h64 = h64 * PRIME64_1 + PRIME64_4;
v3 *= PRIME64_2; v3 = rotateLeft(v3, 31); v3 *= PRIME64_1; h64 ^= v3;
h64 = h64 * PRIME64_1 + PRIME64_4;
v4 *= PRIME64_2; v4 = rotateLeft(v4, 31); v4 *= PRIME64_1; h64 ^= v4;
h64 = h64 * PRIME64_1 + PRIME64_4;
} else {
h64 = seed + PRIME64_5;
}
h64 += len;
while (off <= end - 8) {
long k1 = ByteBufferUtils.readLongLE(buf, off);
k1 *= PRIME64_2; k1 = rotateLeft(k1, 31); k1 *= PRIME64_1; h64 ^= k1;
h64 = rotateLeft(h64, 27) * PRIME64_1 + PRIME64_4;
off += 8;
}
if (off <= end - 4) {
h64 ^= (ByteBufferUtils.readIntLE(buf, off) & 0xFFFFFFFFL) * PRIME64_1;
h64 = rotateLeft(h64, 23) * PRIME64_2 + PRIME64_3;
off += 4;
}
while (off < end) {
h64 ^= (ByteBufferUtils.readByte(buf, off) & 0xFF) * PRIME64_5;
h64 = rotateLeft(h64, 11) * PRIME64_1;
++off;
}
h64 ^= h64 >>> 33;
h64 *= PRIME64_2;
h64 ^= h64 >>> 29;
h64 *= PRIME64_3;
h64 ^= h64 >>> 32;
return h64;
}
}

192
fine-lz4/src/com/fr/third/net/jpountz/xxhash/XXHash64JavaUnsafe.java

@ -0,0 +1,192 @@
// Auto-generated: DO NOT EDIT
package com.fr.third.net.jpountz.xxhash;
import static com.fr.third.net.jpountz.xxhash.XXHashConstants.*;
import static java.lang.Long.rotateLeft;
import java.nio.ByteBuffer;
import com.fr.third.net.jpountz.util.UnsafeUtils;
import com.fr.third.net.jpountz.util.ByteBufferUtils;
/**
* {@link XXHash64} implementation.
*/
final class XXHash64JavaUnsafe extends XXHash64 {
public static final XXHash64 INSTANCE = new XXHash64JavaUnsafe();
@Override
public long hash(byte[] buf, int off, int len, long seed) {
UnsafeUtils.checkRange(buf, off, len);
final int end = off + len;
long h64;
if (len >= 32) {
final int limit = end - 32;
long v1 = seed + PRIME64_1 + PRIME64_2;
long v2 = seed + PRIME64_2;
long v3 = seed + 0;
long v4 = seed - PRIME64_1;
do {
v1 += UnsafeUtils.readLongLE(buf, off) * PRIME64_2;
v1 = rotateLeft(v1, 31);
v1 *= PRIME64_1;
off += 8;
v2 += UnsafeUtils.readLongLE(buf, off) * PRIME64_2;
v2 = rotateLeft(v2, 31);
v2 *= PRIME64_1;
off += 8;
v3 += UnsafeUtils.readLongLE(buf, off) * PRIME64_2;
v3 = rotateLeft(v3, 31);
v3 *= PRIME64_1;
off += 8;
v4 += UnsafeUtils.readLongLE(buf, off) * PRIME64_2;
v4 = rotateLeft(v4, 31);
v4 *= PRIME64_1;
off += 8;
} while (off <= limit);
h64 = rotateLeft(v1, 1) + rotateLeft(v2, 7) + rotateLeft(v3, 12) + rotateLeft(v4, 18);
v1 *= PRIME64_2; v1 = rotateLeft(v1, 31); v1 *= PRIME64_1; h64 ^= v1;
h64 = h64 * PRIME64_1 + PRIME64_4;
v2 *= PRIME64_2; v2 = rotateLeft(v2, 31); v2 *= PRIME64_1; h64 ^= v2;
h64 = h64 * PRIME64_1 + PRIME64_4;
v3 *= PRIME64_2; v3 = rotateLeft(v3, 31); v3 *= PRIME64_1; h64 ^= v3;
h64 = h64 * PRIME64_1 + PRIME64_4;
v4 *= PRIME64_2; v4 = rotateLeft(v4, 31); v4 *= PRIME64_1; h64 ^= v4;
h64 = h64 * PRIME64_1 + PRIME64_4;
} else {
h64 = seed + PRIME64_5;
}
h64 += len;
while (off <= end - 8) {
long k1 = UnsafeUtils.readLongLE(buf, off);
k1 *= PRIME64_2; k1 = rotateLeft(k1, 31); k1 *= PRIME64_1; h64 ^= k1;
h64 = rotateLeft(h64, 27) * PRIME64_1 + PRIME64_4;
off += 8;
}
if (off <= end - 4) {
h64 ^= (UnsafeUtils.readIntLE(buf, off) & 0xFFFFFFFFL) * PRIME64_1;
h64 = rotateLeft(h64, 23) * PRIME64_2 + PRIME64_3;
off += 4;
}
while (off < end) {
h64 ^= (UnsafeUtils.readByte(buf, off) & 0xFF) * PRIME64_5;
h64 = rotateLeft(h64, 11) * PRIME64_1;
++off;
}
h64 ^= h64 >>> 33;
h64 *= PRIME64_2;
h64 ^= h64 >>> 29;
h64 *= PRIME64_3;
h64 ^= h64 >>> 32;
return h64;
}
@Override
public long hash(ByteBuffer buf, int off, int len, long seed) {
if (buf.hasArray()) {
return hash(buf.array(), off + buf.arrayOffset(), len, seed);
}
ByteBufferUtils.checkRange(buf, off, len);
buf = ByteBufferUtils.inLittleEndianOrder(buf);
final int end = off + len;
long h64;
if (len >= 32) {
final int limit = end - 32;
long v1 = seed + PRIME64_1 + PRIME64_2;
long v2 = seed + PRIME64_2;
long v3 = seed + 0;
long v4 = seed - PRIME64_1;
do {
v1 += ByteBufferUtils.readLongLE(buf, off) * PRIME64_2;
v1 = rotateLeft(v1, 31);
v1 *= PRIME64_1;
off += 8;
v2 += ByteBufferUtils.readLongLE(buf, off) * PRIME64_2;
v2 = rotateLeft(v2, 31);
v2 *= PRIME64_1;
off += 8;
v3 += ByteBufferUtils.readLongLE(buf, off) * PRIME64_2;
v3 = rotateLeft(v3, 31);
v3 *= PRIME64_1;
off += 8;
v4 += ByteBufferUtils.readLongLE(buf, off) * PRIME64_2;
v4 = rotateLeft(v4, 31);
v4 *= PRIME64_1;
off += 8;
} while (off <= limit);
h64 = rotateLeft(v1, 1) + rotateLeft(v2, 7) + rotateLeft(v3, 12) + rotateLeft(v4, 18);
v1 *= PRIME64_2; v1 = rotateLeft(v1, 31); v1 *= PRIME64_1; h64 ^= v1;
h64 = h64 * PRIME64_1 + PRIME64_4;
v2 *= PRIME64_2; v2 = rotateLeft(v2, 31); v2 *= PRIME64_1; h64 ^= v2;
h64 = h64 * PRIME64_1 + PRIME64_4;
v3 *= PRIME64_2; v3 = rotateLeft(v3, 31); v3 *= PRIME64_1; h64 ^= v3;
h64 = h64 * PRIME64_1 + PRIME64_4;
v4 *= PRIME64_2; v4 = rotateLeft(v4, 31); v4 *= PRIME64_1; h64 ^= v4;
h64 = h64 * PRIME64_1 + PRIME64_4;
} else {
h64 = seed + PRIME64_5;
}
h64 += len;
while (off <= end - 8) {
long k1 = ByteBufferUtils.readLongLE(buf, off);
k1 *= PRIME64_2; k1 = rotateLeft(k1, 31); k1 *= PRIME64_1; h64 ^= k1;
h64 = rotateLeft(h64, 27) * PRIME64_1 + PRIME64_4;
off += 8;
}
if (off <= end - 4) {
h64 ^= (ByteBufferUtils.readIntLE(buf, off) & 0xFFFFFFFFL) * PRIME64_1;
h64 = rotateLeft(h64, 23) * PRIME64_2 + PRIME64_3;
off += 4;
}
while (off < end) {
h64 ^= (ByteBufferUtils.readByte(buf, off) & 0xFF) * PRIME64_5;
h64 = rotateLeft(h64, 11) * PRIME64_1;
++off;
}
h64 ^= h64 >>> 33;
h64 *= PRIME64_2;
h64 ^= h64 >>> 29;
h64 *= PRIME64_3;
h64 ^= h64 >>> 32;
return h64;
}
}

31
fine-lz4/src/com/fr/third/net/jpountz/xxhash/XXHashConstants.java

@ -0,0 +1,31 @@
package com.fr.third.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.
*/
enum XXHashConstants {
;
static final int PRIME1 = -1640531535;
static final int PRIME2 = -2048144777;
static final int PRIME3 = -1028477379;
static final int PRIME4 = 668265263;
static final int PRIME5 = 374761393;
static final long PRIME64_1 = -7046029288634856825L; //11400714785074694791
static final long PRIME64_2 = -4417276706812531889L; //14029467366897019727
static final long PRIME64_3 = 1609587929392839161L;
static final long PRIME64_4 = -8796714831421723037L; //9650029242287828579
static final long PRIME64_5 = 2870177450012600261L;
}

257
fine-lz4/src/com/fr/third/net/jpountz/xxhash/XXHashFactory.java

@ -0,0 +1,257 @@
package com.fr.third.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.lang.reflect.Field;
import java.util.Random;
import com.fr.third.net.jpountz.util.Native;
import com.fr.third.net.jpountz.util.Utils;
/**
* Entry point to get {@link XXHash32} and {@link StreamingXXHash32} instances.
* <p>
* This class has 3 instances<ul>
* <li>a {@link #nativeInstance() native} instance which is a JNI binding to
* <a href="http://code.google.com/p/xxhash/">the original LZ4 C implementation</a>.
* <li>a {@link #safeInstance() safe Java} instance which is a pure Java port
* of the original C library,</li>
* <li>an {@link #unsafeInstance() unsafe Java} instance which is a Java port
* using the unofficial {@link sun.misc.Unsafe} API.
* </ul>
* <p>
* Only the {@link #safeInstance() safe instance} is guaranteed to work on your
* JVM, as a consequence it is advised to use the {@link #fastestInstance()} or
* {@link #fastestJavaInstance()} to pull a {@link XXHashFactory} instance.
* <p>
* All methods from this class are very costly, so you should get an instance
* once, and then reuse it whenever possible. This is typically done by storing
* a {@link XXHashFactory} instance in a static field.
*/
public final class XXHashFactory {
private static XXHashFactory instance(String impl) {
try {
return new XXHashFactory(impl);
} catch (Exception e) {
throw new AssertionError(e);
}
}
private static XXHashFactory NATIVE_INSTANCE,
JAVA_UNSAFE_INSTANCE,
JAVA_SAFE_INSTANCE;
/**
* Returns a {@link XXHashFactory} that returns {@link XXHash32} instances that
* are native bindings to the original C API.
* <p>
* Please note that this instance has some traps you should be aware of:<ol>
* <li>Upon loading this instance, files will be written to the temporary
* directory of the system. Although these files are supposed to be deleted
* when the JVM exits, they might remain on systems that don't support
* removal of files being used such as Windows.
* <li>The instance can only be loaded once per JVM. This can be a problem
* if your application uses multiple class loaders (such as most servlet
* containers): this instance will only be available to the children of the
* class loader which has loaded it. As a consequence, it is advised to
* either not use this instance in webapps or to put this library in the lib
* directory of your servlet container so that it is loaded by the system
* class loader.
* </ol>
*
* @return a {@link XXHashFactory} that returns {@link XXHash32} instances that
* are native bindings to the original C API.
*/
public static synchronized XXHashFactory nativeInstance() {
if (NATIVE_INSTANCE == null) {
NATIVE_INSTANCE = instance("JNI");
}
return NATIVE_INSTANCE;
}
/**
* Returns a {@link XXHashFactory} that returns {@link XXHash32} instances that
* are written with Java's official API.
*
* @return a {@link XXHashFactory} that returns {@link XXHash32} instances that
* are written with Java's official API.
*/
public static synchronized XXHashFactory safeInstance() {
if (JAVA_SAFE_INSTANCE == null) {
JAVA_SAFE_INSTANCE = instance("JavaSafe");
}
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}.
*
* @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();
}
}
/**
* Returns the fastest available {@link XXHashFactory} instance. If the class
* loader is the system class loader and if the
* {@link #nativeInstance() native instance} loads successfully, then the
* {@link #nativeInstance() native instance} is returned, otherwise the
* {@link #fastestJavaInstance() fastest Java instance} is returned.
* <p>
* Please read {@link #nativeInstance() javadocs of nativeInstance()} before
* using this method.
*
* @return the fastest available {@link XXHashFactory} instance.
*/
public static XXHashFactory fastestInstance() {
if (Native.isLoaded()
|| Native.class.getClassLoader() == ClassLoader.getSystemClassLoader()) {
try {
return nativeInstance();
} catch (Throwable t) {
return fastestJavaInstance();
}
} else {
return fastestJavaInstance();
}
}
@SuppressWarnings("unchecked")
private static <T> T classInstance(String cls) throws NoSuchFieldException, SecurityException, ClassNotFoundException, IllegalArgumentException, IllegalAccessException {
ClassLoader loader = XXHashFactory.class.getClassLoader();
loader = loader == null ? ClassLoader.getSystemClassLoader() : loader;
final Class<?> c = loader.loadClass(cls);
Field f = c.getField("INSTANCE");
return (T) f.get(null);
}
private final String impl;
private final XXHash32 hash32;
private final XXHash64 hash64;
private final StreamingXXHash32.Factory streamingHash32Factory;
private final StreamingXXHash64.Factory streamingHash64Factory;
private XXHashFactory(String impl) throws ClassNotFoundException, NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
this.impl = impl;
hash32 = classInstance("XXHash32" + impl);
streamingHash32Factory = classInstance("StreamingXXHash32" + impl + "$Factory");
hash64 = classInstance("XXHash64" + impl);
streamingHash64Factory = classInstance("StreamingXXHash64" + impl + "$Factory");
// make sure it can run
final byte[] bytes = new byte[100];
final Random random = new Random();
random.nextBytes(bytes);
final int seed = random.nextInt();
final int h1 = hash32.hash(bytes, 0, bytes.length, seed);
final StreamingXXHash32 streamingHash32 = newStreamingHash32(seed);
streamingHash32.update(bytes, 0, bytes.length);
final int h2 = streamingHash32.getValue();
final long h3 = hash64.hash(bytes, 0, bytes.length, seed);
final StreamingXXHash64 streamingHash64 = newStreamingHash64(seed);
streamingHash64.update(bytes, 0, bytes.length);
final long h4 = streamingHash64.getValue();
if (h1 != h2) {
throw new AssertionError();
}
if (h3 != h4) {
throw new AssertionError();
}
}
/**
* Returns a {@link XXHash32} instance.
*
* @return a {@link XXHash32} instance.
*/
public XXHash32 hash32() {
return hash32;
}
/**
* Returns a {@link XXHash64} instance.
*
* @return a {@link XXHash64} instance.
*/
public XXHash64 hash64() {
return hash64;
}
/**
* Return a new {@link StreamingXXHash32} instance.
*
* @param seed the seed to use
* @return a {@link StreamingXXHash32} instance
*/
public StreamingXXHash32 newStreamingHash32(int seed) {
return streamingHash32Factory.newStreamingHash(seed);
}
/**
* Return a new {@link StreamingXXHash64} instance.
*
* @param seed the seed to use
* @return a {@link StreamingXXHash64} instance
*/
public StreamingXXHash64 newStreamingHash64(long seed) {
return streamingHash64Factory.newStreamingHash(seed);
}
/**
* Prints the fastest instance.
*
* @param args no argument required
*/
public static void main(String[] args) {
System.out.println("Fastest instance is " + fastestInstance());
System.out.println("Fastest Java instance is " + fastestJavaInstance());
}
@Override
public String toString() {
return getClass().getSimpleName() + ":" + impl;
}
}

43
fine-lz4/src/com/fr/third/net/jpountz/xxhash/XXHashJNI.java

@ -0,0 +1,43 @@
package com.fr.third.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 com.fr.third.net.jpountz.util.Native;
enum XXHashJNI {
;
static {
Native.load();
init();
}
private static native void init();
static native int XXH32(byte[] input, int offset, int len, int seed);
static native int XXH32BB(ByteBuffer input, int offset, int len, int seed);
static native long XXH32_init(int seed);
static native void XXH32_update(long state, byte[] input, int offset, int len);
static native int XXH32_digest(long state);
static native void XXH32_free(long state);
static native long XXH64(byte[] input, int offset, int len, long seed);
static native long XXH64BB(ByteBuffer input, int offset, int len, long seed);
static native long XXH64_init(long seed);
static native void XXH64_update(long state, byte[] input, int offset, int len);
static native long XXH64_digest(long state);
static native void XXH64_free(long state);
}

65
fine-lz4/src/com/fr/third/net/jpountz/xxhash/package.html

@ -0,0 +1,65 @@
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
<!--
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.
-->
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>
<body>
<p>xxhash hashing. This package supports both block hashing via
{@link net.jpountz.xxhash.XXHash32} and streaming hashing via
{@link net.jpountz.xxhash.StreamingXXHash32}. Have a look at
{@link net.jpountz.xxhash.XXHashFactory} to know how to get instances of these
interfaces.</p>
<p>Streaming hashing is a little slower but doesn't require to load the whole
stream into memory.</p>
<p>Sample block usage:</p>
<pre class="prettyprint">
XXHashFactory factory = XXHashFactory.fastestInstance();
byte[] data = "12345345234572".getBytes("UTF-8");
XXHash32 hash32 = factory.hash32();
int seed = 0x9747b28c; // used to initialize the hash value, use whatever
// value you want, but always the same
int hash = hash32.hash(data, 0, data.length, seed);
</pre>
<p>Sample streaming usage:</p>
<pre class="prettyprint">
XXHashFactory factory = XXHashFactory.fastestInstance();
byte[] data = "12345345234572".getBytes("UTF-8");
ByteArrayInputStream in = new ByteArrayInputStream(data);
int seed = 0x9747b28c; // used to initialize the hash value, use whatever
// value you want, but always the same
StreamingXXHash32 hash32 = factory.newStreamingHash32(seed);
byte[] buf = new byte[8]; // for real-world usage, use a larger buffer, like 8192 bytes
for (;;) {
int read = in.read(buf);
if (read == -1) {
break;
}
hash32.update(buf, 0, read);
}
int hash = hash32.getValue();
</pre>
</body>
</html>
Loading…
Cancel
Save