From ca10d0902040d5b3a93591db15aeff723045d878 Mon Sep 17 00:00:00 2001 From: "Yuan.Wang" Date: Fri, 9 Sep 2022 11:17:47 +0800 Subject: [PATCH] =?UTF-8?q?REPORT-78067=20=E4=B8=89=E6=96=B9=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E6=89=B9=E9=87=8F=E5=8D=87=E7=BA=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fine-lz4/README.md | 2 + .../net/jpountz/lz4/LZ4BlockInputStream.java | 25 +- .../net/jpountz/lz4/LZ4BlockOutputStream.java | 6 +- .../net/jpountz/lz4/LZ4ByteBufferUtils.java | 37 ++- .../third/net/jpountz/lz4/LZ4Compressor.java | 2 + .../jpountz/lz4/LZ4CompressorWithLength.java | 201 +++++++++++++ .../third/net/jpountz/lz4/LZ4Constants.java | 2 + .../net/jpountz/lz4/LZ4Decompressor.java | 4 +- .../lz4/LZ4DecompressorWithLength.java | 277 ++++++++++++++++++ .../third/net/jpountz/lz4/LZ4Exception.java | 2 + .../fr/third/net/jpountz/lz4/LZ4Factory.java | 43 ++- .../net/jpountz/lz4/LZ4FastDecompressor.java | 9 + .../net/jpountz/lz4/LZ4FrameInputStream.java | 112 ++++++- .../net/jpountz/lz4/LZ4FrameOutputStream.java | 40 ++- .../net/jpountz/lz4/LZ4HCJNICompressor.java | 6 +- .../com/fr/third/net/jpountz/lz4/LZ4JNI.java | 2 + .../net/jpountz/lz4/LZ4JNICompressor.java | 2 + .../jpountz/lz4/LZ4JNIFastDecompressor.java | 2 + .../jpountz/lz4/LZ4JNISafeDecompressor.java | 2 + .../net/jpountz/lz4/LZ4SafeDecompressor.java | 3 + .../third/net/jpountz/lz4/LZ4SafeUtils.java | 2 + .../lz4/LZ4UnknownSizeDecompressor.java | 4 +- .../third/net/jpountz/lz4/LZ4UnsafeUtils.java | 72 +++-- .../fr/third/net/jpountz/lz4/LZ4Utils.java | 2 + .../com/fr/third/net/jpountz/lz4/package.html | 8 +- .../net/jpountz/util/ByteBufferUtils.java | 16 + .../com/fr/third/net/jpountz/util/Native.java | 106 ++++--- .../fr/third/net/jpountz/util/SafeUtils.java | 2 + .../third/net/jpountz/util/UnsafeUtils.java | 4 +- .../com/fr/third/net/jpountz/util/Utils.java | 2 + .../fr/third/net/jpountz/util/package.html | 4 +- .../xxhash/AbstractStreamingXXHash32Java.java | 11 +- .../xxhash/AbstractStreamingXXHash64Java.java | 11 +- .../net/jpountz/xxhash/StreamingXXHash32.java | 15 +- .../jpountz/xxhash/StreamingXXHash32JNI.java | 36 ++- .../net/jpountz/xxhash/StreamingXXHash64.java | 15 +- .../jpountz/xxhash/StreamingXXHash64JNI.java | 36 ++- .../fr/third/net/jpountz/xxhash/XXHash32.java | 2 + .../third/net/jpountz/xxhash/XXHash32JNI.java | 9 +- .../fr/third/net/jpountz/xxhash/XXHash64.java | 2 + .../third/net/jpountz/xxhash/XXHash64JNI.java | 9 +- .../net/jpountz/xxhash/XXHashConstants.java | 2 + .../net/jpountz/xxhash/XXHashFactory.java | 10 +- .../third/net/jpountz/xxhash/XXHashJNI.java | 2 + .../fr/third/net/jpountz/xxhash/package.html | 8 +- .../util/darwin/aarch64/liblz4-java.dylib | Bin 0 -> 173774 bytes .../util/darwin/x86_64/liblz4-java.dylib | Bin 71996 -> 205000 bytes .../jpountz/util/linux/aarch64/liblz4-java.so | Bin 79568 -> 86081 bytes .../jpountz/util/linux/amd64/liblz4-java.so | Bin 56964 -> 154886 bytes .../jpountz/util/linux/i386/liblz4-java.so | Bin 68748 -> 68840 bytes .../jpountz/util/linux/ppc64le/liblz4-java.so | Bin 104776 -> 208664 bytes .../jpountz/util/linux/s390x/liblz4-java.so | Bin 74491 -> 97208 bytes .../jpountz/util/win32/amd64/liblz4-java.so | Bin 96608 -> 520219 bytes 53 files changed, 987 insertions(+), 182 deletions(-) create mode 100644 fine-lz4/README.md create mode 100644 fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4CompressorWithLength.java create mode 100644 fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4DecompressorWithLength.java create mode 100644 fine-lz4/src/main/resources/com/fr/third/net/jpountz/util/darwin/aarch64/liblz4-java.dylib diff --git a/fine-lz4/README.md b/fine-lz4/README.md new file mode 100644 index 000000000..3c540b405 --- /dev/null +++ b/fine-lz4/README.md @@ -0,0 +1,2 @@ +lz4的源码地址:https://github.com/lz4/lz4
+版本:1.8.0
\ No newline at end of file diff --git a/fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4BlockInputStream.java b/fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4BlockInputStream.java index c554ce5bd..f76753c8b 100644 --- a/fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4BlockInputStream.java +++ b/fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4BlockInputStream.java @@ -1,6 +1,8 @@ package com.fr.third.net.jpountz.lz4; /* + * Copyright 2020 Adrien Grand and the lz4-java contributors. + * * 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 @@ -28,8 +30,8 @@ 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.util.SafeUtils; import com.fr.third.net.jpountz.xxhash.XXHash32; import com.fr.third.net.jpountz.xxhash.XXHashFactory; @@ -39,7 +41,7 @@ import com.fr.third.net.jpountz.xxhash.XXHashFactory; * support {@link #mark(int)}/{@link #reset()}. * @see LZ4BlockOutputStream */ -public final class LZ4BlockInputStream extends FilterInputStream { +public class LZ4BlockInputStream extends FilterInputStream { private final LZ4FastDecompressor decompressor; private final Checksum checksum; @@ -187,13 +189,11 @@ public final class LZ4BlockInputStream extends FilterInputStream { } private void refill() throws IOException { - try { - readFully(compressedBuffer, HEADER_LENGTH); - } catch (EOFException e) { + if (!tryReadFully(compressedBuffer, HEADER_LENGTH)) { if (!stopOnEmptyBlock) { finished = true; } else { - throw e; + throw new EOFException("Stream ended prematurely"); } return; } @@ -263,16 +263,25 @@ public final class LZ4BlockInputStream extends FilterInputStream { o = 0; } - private void readFully(byte[] b, int len) throws IOException { + // Like readFully(), except it signals incomplete reads by returning + // false instead of throwing EOFException. + private boolean tryReadFully(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"); + return false; } read += r; } assert len == read; + return true; + } + + private void readFully(byte[] b, int len) throws IOException { + if (!tryReadFully(b, len)) { + throw new EOFException("Stream ended prematurely"); + } } @Override diff --git a/fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4BlockOutputStream.java b/fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4BlockOutputStream.java index 8ab77beeb..c71da2ca7 100644 --- a/fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4BlockOutputStream.java +++ b/fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4BlockOutputStream.java @@ -1,6 +1,8 @@ package com.fr.third.net.jpountz.lz4; /* + * Copyright 2020 Adrien Grand and the lz4-java contributors. + * * 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 @@ -19,9 +21,9 @@ 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; +import com.fr.third.net.jpountz.util.SafeUtils; /** * Streaming LZ4 (not compatible with the LZ4 Frame format). @@ -32,7 +34,7 @@ import com.fr.third.net.jpountz.xxhash.XXHashFactory; * @see LZ4BlockInputStream * @see LZ4FrameOutputStream */ -public final class LZ4BlockOutputStream extends FilterOutputStream { +public 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; diff --git a/fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4ByteBufferUtils.java b/fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4ByteBufferUtils.java index 29769aa7e..18bd6da98 100644 --- a/fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4ByteBufferUtils.java +++ b/fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4ByteBufferUtils.java @@ -1,6 +1,8 @@ package com.fr.third.net.jpountz.lz4; /* + * Copyright 2020 Adrien Grand and the lz4-java contributors. + * * 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 @@ -14,11 +16,6 @@ package com.fr.third.net.jpountz.lz4; * 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; @@ -84,7 +81,7 @@ enum LZ4ByteBufferUtils { writeInt(dest, dOff, readInt(dest, matchOff)); dOff += 4; matchOff -= dec; - } else if (dOff - matchOff < COPY_LENGTH) { + } else if (dOff - matchOff < LZ4Constants.COPY_LENGTH) { writeLong(dest, dOff, readLong(dest, matchOff)); dOff += dOff - matchOff; } @@ -147,16 +144,16 @@ enum LZ4ByteBufferUtils { final int runLen = matchOff - anchor; final int tokenOff = dOff++; - if (dOff + runLen + (2 + 1 + LAST_LITERALS) + (runLen >>> 8) > destEnd) { + if (dOff + runLen + (2 + 1 + LZ4Constants.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); + if (runLen >= LZ4Constants.RUN_MASK) { + token = (byte) (LZ4Constants.RUN_MASK << LZ4Constants.ML_BITS); + dOff = writeLen(runLen - LZ4Constants.RUN_MASK, dest, dOff); } else { - token = runLen << ML_BITS; + token = runLen << LZ4Constants.ML_BITS; } // copy literals @@ -170,12 +167,12 @@ enum LZ4ByteBufferUtils { // encode match len matchLen -= 4; - if (dOff + (1 + LAST_LITERALS) + (matchLen >>> 8) > destEnd) { + if (dOff + (1 + LZ4Constants.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); + if (matchLen >= LZ4Constants.ML_MASK) { + token |= LZ4Constants.ML_MASK; + dOff = writeLen(matchLen - LZ4Constants.RUN_MASK, dest, dOff); } else { token |= matchLen; } @@ -188,15 +185,15 @@ enum LZ4ByteBufferUtils { 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) { + if (dOff + runLen + 1 + (runLen + 255 - LZ4Constants.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); + if (runLen >= LZ4Constants.RUN_MASK) { + dest.put(dOff++, (byte) (LZ4Constants.RUN_MASK << LZ4Constants.ML_BITS)); + dOff = writeLen(runLen - LZ4Constants.RUN_MASK, dest, dOff); } else { - dest.put(dOff++, (byte) (runLen << ML_BITS)); + dest.put(dOff++, (byte) (runLen << LZ4Constants.ML_BITS)); } // copy literals safeArraycopy(src, sOff, dest, dOff, runLen); diff --git a/fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4Compressor.java b/fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4Compressor.java index 2ad6724db..2674c004a 100644 --- a/fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4Compressor.java +++ b/fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4Compressor.java @@ -1,6 +1,8 @@ package com.fr.third.net.jpountz.lz4; /* + * Copyright 2020 Adrien Grand and the lz4-java contributors. + * * 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 diff --git a/fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4CompressorWithLength.java b/fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4CompressorWithLength.java new file mode 100644 index 000000000..85b1e0c4d --- /dev/null +++ b/fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4CompressorWithLength.java @@ -0,0 +1,201 @@ +package com.fr.third.net.jpountz.lz4; + +/* + * Copyright 2020 Rei Odaira and the lz4-java contributors. + * + * 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; + +/** + * Covenience class to include the length of the original decompressed data + * in the output compressed data, so that the user does not need to save + * the length at anywhere else. The compressed data must be decompressed by + * {@link LZ4DecompressorWithLength} and is NOT compatible with any other + * decompressors in lz4-java or any other lz4 tools. This class deliberately + * does not extend {@link LZ4Compressor} because they are not interchangable. + */ + +public class LZ4CompressorWithLength { + + private final LZ4Compressor compressor; + + /** + * Creates a new compressor that includes the length of the original + * decompressed data in the output compressed data. + * + * @param compressor compressor to use + */ + public LZ4CompressorWithLength(LZ4Compressor compressor) { + this.compressor = compressor; + } + + private void putOriginalLength(byte[] dest, int destOff, int originalLength) { + dest[destOff] = (byte)originalLength; + dest[destOff + 1] = (byte)(originalLength >> 8); + dest[destOff + 2] = (byte)(originalLength >> 16); + dest[destOff + 3] = (byte)(originalLength >> 24); + } + + private void putOriginalLength(ByteBuffer dest, int destOff, int originalLength) { + dest.put(destOff, (byte)originalLength); + dest.put(destOff + 1, (byte)(originalLength >> 8)); + dest.put(destOff + 2, (byte)(originalLength >> 16)); + dest.put(destOff + 3, (byte)(originalLength >> 24)); + } + + /** + * Returns the maximum compressed length for an input of size length. + * + * @param length the input size in bytes + * @return the maximum compressed length in bytes + */ + public int maxCompressedLength(int length) { + return compressor.maxCompressedLength(length) + 4; + } + + /** + * 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 byte[] compress(byte[] src) { + return compress(src, 0, src.length); + } + + /** + * Convenience method which returns src[srcOff:srcOff+srcLen] + * compressed. + *

Warning: 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.

+ *

Here is how this method is implemented:

+ *
+   * 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);
+   * 
+ * + * @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 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, 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 int compress(byte[] src, byte[] dest) { + return compress(src, 0, src.length, dest, 0); + } + + /** + * 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 int compress(byte[] src, int srcOff, int srcLen, byte[] dest, int destOff) { + return compress(src, srcOff, srcLen, dest, destOff, dest.length - destOff); + } + + /** + * Compresses src[srcOff:srcOff+srcLen] into + * dest[destOff:destOff+maxDestLen] and returns the compressed + * length. + * + * This method will throw a {@link LZ4Exception} if this compressor is unable + * to compress the input into less than maxDestLen bytes. To + * prevent this exception to be thrown, you should make sure that + * maxDestLen >= maxCompressedLength(srcLen). + * + * @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 int compress(byte[] src, int srcOff, int srcLen, byte[] dest, int destOff, int maxDestLen) { + final int compressedLength = compressor.compress(src, srcOff, srcLen, dest, destOff + 4, maxDestLen - 4); + putOriginalLength(dest, destOff, srcLen); + return compressedLength + 4; + } + + /** + * Compresses src into dest. 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 void compress(ByteBuffer src, ByteBuffer dest) { + final int compressedLength = compress(src, src.position(), src.remaining(), dest, dest.position(), dest.remaining()); + src.position(src.limit()); + dest.position(dest.position() + compressedLength); + } + + /** + * Compresses src[srcOff:srcOff+srcLen] into + * dest[destOff:destOff+maxDestLen] and returns the compressed + * length. + * + * This method will throw a {@link LZ4Exception} if this compressor is unable + * to compress the input into less than maxDestLen bytes. To + * prevent this exception to be thrown, you should make sure that + * maxDestLen >= maxCompressedLength(srcLen). + * + * {@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 int compress(ByteBuffer src, int srcOff, int srcLen, ByteBuffer dest, int destOff, int maxDestLen) { + final int compressedLength = compressor.compress(src, srcOff, srcLen, dest, destOff + 4, maxDestLen - 4); + putOriginalLength(dest, destOff, srcLen); + return compressedLength + 4; + } +} diff --git a/fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4Constants.java b/fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4Constants.java index 7295dbf80..6831466c2 100644 --- a/fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4Constants.java +++ b/fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4Constants.java @@ -1,6 +1,8 @@ package com.fr.third.net.jpountz.lz4; /* + * Copyright 2020 Adrien Grand and the lz4-java contributors. + * * 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 diff --git a/fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4Decompressor.java b/fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4Decompressor.java index 05e98c10f..5fa049be0 100644 --- a/fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4Decompressor.java +++ b/fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4Decompressor.java @@ -1,6 +1,8 @@ package com.fr.third.net.jpountz.lz4; /* + * Copyright 2020 Adrien Grand and the lz4-java contributors. + * * 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 @@ -22,4 +24,4 @@ public interface LZ4Decompressor { int decompress(byte[] src, int srcOff, byte[] dest, int destOff, int destLen); -} \ No newline at end of file +} diff --git a/fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4DecompressorWithLength.java b/fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4DecompressorWithLength.java new file mode 100644 index 000000000..ce4570204 --- /dev/null +++ b/fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4DecompressorWithLength.java @@ -0,0 +1,277 @@ +package com.fr.third.net.jpountz.lz4; + +/* + * Copyright 2020 Rei Odaira and the lz4-java contributors. + * + * 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; + +/** + * Convenience class to decompress data compressed by {@link LZ4CompressorWithLength}. + * This decompressor is NOT compatible with any other compressors in lz4-java + * or any other lz4 tools. + * The user does not need to specify the length of the compressed data or + * original data because the length of the original decompressed data is + * included in the compressed data. + */ + +public class LZ4DecompressorWithLength { + + private final LZ4FastDecompressor fastDecompressor; + private final LZ4SafeDecompressor safeDecompressor; + + /** + * Returns the decompressed length of compressed data in src. + * + * @param src the compressed data + * @return the decompressed length + */ + public static int getDecompressedLength(byte[] src) { + return getDecompressedLength(src, 0); + } + + /** + * Returns the decompressed length of compressed data in src[srcOff:]. + * + * @param src the compressed data + * @param srcOff the start offset in src + * @return the decompressed length + */ + public static int getDecompressedLength(byte[] src, int srcOff) { + return (src[srcOff] & 0xFF) | (src[srcOff + 1] & 0xFF) << 8 | (src[srcOff + 2] & 0xFF) << 16 | src[srcOff + 3] << 24; + } + + /** + * Returns the decompressed length of compressed data in src. + * + * @param src the compressed data + * @return the decompressed length + */ + public static int getDecompressedLength(ByteBuffer src) { + return getDecompressedLength(src, src.position()); + } + + /** + * Returns the decompressed length of compressed data in src[srcOff:]. + * + * @param src the compressed data + * @param srcOff the start offset in src + * @return the decompressed length + */ + public static int getDecompressedLength(ByteBuffer src, int srcOff) { + return (src.get(srcOff) & 0xFF) | (src.get(srcOff + 1) & 0xFF) << 8 | (src.get(srcOff + 2) & 0xFF) << 16 | src.get(srcOff + 3) << 24; + } + + /** + * Creates a new decompressor to decompress data compressed by {@link LZ4CompressorWithLength}. + * Note that it is deprecated to use a JNI-binding instance of {@link LZ4FastDecompressor}. + * Please see {@link LZ4Factory#nativeInstance()} for details. + * + * @param fastDecompressor fast decompressor to use + */ + public LZ4DecompressorWithLength(LZ4FastDecompressor fastDecompressor) { + this.fastDecompressor = fastDecompressor; + this.safeDecompressor = null; + } + + /** + * Creates a new decompressor to decompress data compressed by {@link LZ4CompressorWithLength}. + * + * @param safeDecompressor safe decompressor to use + */ + public LZ4DecompressorWithLength(LZ4SafeDecompressor safeDecompressor) { + this.fastDecompressor = null; + this.safeDecompressor = safeDecompressor; + } + + /** + * Convenience method, equivalent to calling + * {@link #decompress(byte[], int, byte[], int) decompress(src, 0, dest, 0)}. + * + * @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 int decompress(byte[] src, byte[] dest) { + return decompress(src, 0, dest, 0); + } + + /** + * When {@link LZ4FastDecompressor} was specified to the constructor, + * decompresses src[srcOff:] into dest[destOff:] + * and returns the number of bytes read from src, and + * when {@link LZ4SafeDecompressor} was specified to the constructor, + * decompresses src[srcOff:src.length] into dest[destOff:] + * and returns the number of decompressed bytes written into dest. + * + * @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 + * @return the number of bytes read to restore the original input (when {@link LZ4FastDecompressor} is used), or the number of decompressed bytes (when {@link LZ4SafeDecompressor} is used) + */ + public int decompress(byte[] src, int srcOff, byte[] dest, int destOff) { + if (safeDecompressor != null) { + return decompress(src, srcOff, src.length - srcOff, dest, destOff); + } + final int destLen = getDecompressedLength(src, srcOff); + return fastDecompressor.decompress(src, srcOff + 4, dest, destOff, destLen) + 4; + } + + /** + * When {@link LZ4FastDecompressor} was specified to the constructor, + * decompresses src[srcOff:] into dest[destOff:] + * and returns the number of bytes read from src, and + * when {@link LZ4SafeDecompressor} was specified to the constructor, + * decompresses src[srcOff:srcOff+srcLen] into dest[destOff:] + * and returns the number of decompressed bytes written into dest. + * + * @param src the compressed data + * @param srcOff the start offset in src + * @param srcLen the exact size of the compressed data (ignored when {@link LZ4FastDecompressor} is used) + * @param dest the destination buffer to store the decompressed data + * @param destOff the start offset in dest + * @return the number of bytes read to restore the original input (when {@link LZ4FastDecompressor} is used), or the number of decompressed bytes (when {@link LZ4SafeDecompressor} is used) + */ + public int decompress(byte[] src, int srcOff, int srcLen, byte[] dest, int destOff) { + if (safeDecompressor == null) { + return decompress(src, srcOff, dest, destOff); + } + final int destLen = getDecompressedLength(src, srcOff); + return safeDecompressor.decompress(src, srcOff + 4, srcLen - 4, dest, destOff, destLen); + } + + /** + * Convenience method, equivalent to calling + * {@link #decompress(byte[], int) decompress(src, 0)}. + * + * @param src the compressed data + * @return the decompressed data + */ + public byte[] decompress(byte[] src) { + return decompress(src, 0); + } + + /** + * Convenience method which returns src[srcOff:] + * decompressed when {@link LZ4FastDecompressor} was specified to the constructor, + * or src[srcOff:src.length] decompressed when + * {@link LZ4SafeDecompressor} was specified to the constructor. + *

Warning: this method has an + * important overhead due to the fact that it needs to allocate a buffer to + * decompress into. + * + * @param src the compressed data + * @param srcOff the start offset in src + * @return the decompressed data + */ + public byte[] decompress(byte[] src, int srcOff) { + if (safeDecompressor != null) { + return decompress(src, srcOff, src.length - srcOff); + } + final int destLen = getDecompressedLength(src, srcOff); + return fastDecompressor.decompress(src, srcOff + 4, destLen); + } + + /** + * Convenience method which returns src[srcOff:] + * decompressed when {@link LZ4FastDecompressor} was specified to the constructor, + * or src[srcOff:srcOff+srcLen] decompressed when + * {@link LZ4SafeDecompressor} was specified to the constructor. + *

Warning: this method has an + * important overhead due to the fact that it needs to allocate a buffer to + * decompress into. + * + * @param src the compressed data + * @param srcOff the start offset in src + * @param srcLen the exact size of the compressed data (ignored when {@link LZ4FastDecompressor} is used) + * @return the decompressed data + */ + public byte[] decompress(byte[] src, int srcOff, int srcLen) { + if (safeDecompressor == null) { + return decompress(src, srcOff); + } + final int destLen = getDecompressedLength(src, srcOff); + return safeDecompressor.decompress(src, srcOff + 4, srcLen - 4, destLen); + } + + /** + * Decompresses src into dest. + * When {@link LZ4SafeDecompressor} was specified to the constructor, + * src'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 + */ + public void decompress(ByteBuffer src, ByteBuffer dest) { + final int destLen = getDecompressedLength(src, src.position()); + if (safeDecompressor == null) { + final int read = fastDecompressor.decompress(src, src.position() + 4, dest, dest.position(), destLen); + src.position(src.position() + 4 + read); + dest.position(dest.position() + destLen); + } else { + final int written = safeDecompressor.decompress(src, src.position() + 4, src.remaining() - 4, dest, dest.position(), destLen); + src.position(src.limit()); + dest.position(dest.position() + written); + } + } + + /** When {@link LZ4FastDecompressor} was specified to the constructor, + * decompresses src[srcOff:] into dest[destOff:] + * and returns the number of bytes read from src, and + * when {@link LZ4SafeDecompressor} was specified to the constructor, + * decompresses src[srcOff:src.remaining()] into dest[destOff:] + * and returns the number of decompressed bytes written into dest. + * 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 + * @return the number of bytes read to restore the original input (when {@link LZ4FastDecompressor} is used), or the number of decompressed bytes (when {@link LZ4SafeDecompressor} is used) + */ + public int decompress(ByteBuffer src, int srcOff, ByteBuffer dest, int destOff) { + if (safeDecompressor != null) { + return decompress(src, srcOff, src.remaining() - srcOff, dest, destOff); + } + final int destLen = getDecompressedLength(src, srcOff); + return fastDecompressor.decompress(src, srcOff + 4, dest, destOff, destLen) + 4; + } + + /** + * When {@link LZ4FastDecompressor} was specified to the constructor, + * decompresses src[srcOff:] into dest[destOff:] + * and returns the number of bytes read from src, and + * when {@link LZ4SafeDecompressor} was specified to the constructor, + * decompresses src[srcOff:srcOff+srcLen] into dest[destOff:] + * and returns the number of decompressed bytes written into dest. + * The positions and limits of the {@link ByteBuffer}s remain unchanged. + * + * @param src the compressed data + * @param srcOff the start offset in src + * @param srcLen the exact size of the compressed data (ignored when {@link LZ4FastDecompressor} is used) + * @param dest the destination buffer to store the decompressed data + * @param destOff the start offset in dest + * @return the number of bytes read to restore the original input (when {@link LZ4FastDecompressor} is used), or the number of decompressed bytes (when {@link LZ4SafeDecompressor} is used) + */ + public int decompress(ByteBuffer src, int srcOff, int srcLen, ByteBuffer dest, int destOff) { + if (safeDecompressor == null) { + return decompress(src, srcOff, dest, destOff); + } + final int destLen = getDecompressedLength(src, srcOff); + return safeDecompressor.decompress(src, srcOff + 4, srcLen - 4, dest, destOff, destLen); + } +} diff --git a/fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4Exception.java b/fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4Exception.java index 78355d46f..e9250de07 100644 --- a/fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4Exception.java +++ b/fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4Exception.java @@ -1,6 +1,8 @@ package com.fr.third.net.jpountz.lz4; /* + * Copyright 2020 Adrien Grand and the lz4-java contributors. + * * 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 diff --git a/fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4Factory.java b/fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4Factory.java index c0e6df16a..ba471e042 100644 --- a/fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4Factory.java +++ b/fine-lz4/src/main/java/com/fr/third/net/jpountz/lz4/LZ4Factory.java @@ -1,6 +1,8 @@ package com.fr.third.net.jpountz.lz4; /* + * Copyright 2020 Adrien Grand and the lz4-java contributors. + * * 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 @@ -21,13 +23,15 @@ import java.util.Arrays; import com.fr.third.net.jpountz.util.Native; import com.fr.third.net.jpountz.util.Utils; +import static com.fr.third.net.jpountz.lz4.LZ4Constants.DEFAULT_COMPRESSION_LEVEL; +import static com.fr.third.net.jpountz.lz4.LZ4Constants.MAX_COMPRESSION_LEVEL; /** * Entry point for the LZ4 API. *

* This class has 3 instances