added input stream and basic unit test, removed kotlin code
This commit is contained in:
6
.gitattributes
vendored
Normal file
6
.gitattributes
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#
|
||||
# https://help.github.com/articles/dealing-with-line-endings/
|
||||
#
|
||||
# These are explicitly windows files and should use crlf
|
||||
*.bat text eol=crlf
|
||||
|
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
# Ignore Gradle project-specific cache directory
|
||||
.gradle
|
||||
|
||||
# Ignore Gradle build output directory
|
||||
build
|
||||
|
||||
.idea
|
@@ -1,11 +1,3 @@
|
||||
/*
|
||||
* This file was generated by the Gradle 'init' task.
|
||||
*
|
||||
* This generated file contains a sample Kotlin library project to get you started.
|
||||
*/
|
||||
|
||||
fun property(name : String) = project.property(name).toString()
|
||||
|
||||
plugins {
|
||||
// Apply the Kotlin JVM plugin to add support for Kotlin.
|
||||
id("org.jetbrains.kotlin.jvm") version "1.3.70"
|
||||
@@ -15,6 +7,9 @@ plugins {
|
||||
application
|
||||
}
|
||||
|
||||
group = "net.woggioni"
|
||||
version = "0.1"
|
||||
|
||||
repositories {
|
||||
// Use jcenter for resolving dependencies.
|
||||
// You can declare any Maven/Ivy/file repository here.
|
||||
@@ -23,6 +18,8 @@ repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
fun property(name : String) = project.property(name).toString()
|
||||
|
||||
dependencies {
|
||||
// Align versions of all Kotlin components
|
||||
compileOnly(platform("org.jetbrains.kotlin:kotlin-bom"))
|
||||
@@ -32,7 +29,7 @@ dependencies {
|
||||
compileOnly("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
|
||||
testImplementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
|
||||
|
||||
implementation("net.java.dev.jna", "jna", "5.5.0")
|
||||
implementation("net.java.dev.jna", "jna", property("jna.version"))
|
||||
|
||||
// https://mvnrepository.com/artifact/org.projectlombok/lombok
|
||||
compileOnly("org.projectlombok", "lombok", property("lombok.version"))
|
||||
@@ -42,6 +39,7 @@ dependencies {
|
||||
testAnnotationProcessor("org.projectlombok", "lombok", property("lombok.version"))
|
||||
testRuntimeOnly("org.junit.jupiter", "junit-jupiter-engine", property("junit.version"))
|
||||
testImplementation("org.junit.jupiter","junit-jupiter-api", property("junit.version"))
|
||||
testImplementation("org.junit.jupiter","junit-jupiter-params", property("junit.version"))
|
||||
testImplementation("net.woggioni", "jwo", "1.0")
|
||||
|
||||
}
|
||||
|
@@ -1,2 +1,4 @@
|
||||
junit.version=5.6.2
|
||||
lombok.version=1.18.12
|
||||
jna.version=5.5.0
|
||||
kotlin.version=1.3.70
|
@@ -1,10 +1 @@
|
||||
/*
|
||||
* This file was generated by the Gradle 'init' task.
|
||||
*
|
||||
* The settings file is used to specify which projects to include in your build.
|
||||
*
|
||||
* Detailed information about configuring a multi-project build in Gradle can be found
|
||||
* in the user manual at https://docs.gradle.org/6.3/userguide/multi_project_builds.html
|
||||
*/
|
||||
|
||||
rootProject.name = "kzstd"
|
||||
rootProject.name = "jzstd"
|
||||
|
5
src/main/java/net/woggioni/jzstd/ZSTD_DCtx.java
Normal file
5
src/main/java/net/woggioni/jzstd/ZSTD_DCtx.java
Normal file
@@ -0,0 +1,5 @@
|
||||
package net.woggioni.jzstd;
|
||||
|
||||
import com.sun.jna.PointerType;
|
||||
|
||||
public class ZSTD_DCtx extends PointerType { }
|
5
src/main/java/net/woggioni/jzstd/ZSTD_DDict.java
Normal file
5
src/main/java/net/woggioni/jzstd/ZSTD_DDict.java
Normal file
@@ -0,0 +1,5 @@
|
||||
package net.woggioni.jzstd;
|
||||
|
||||
import com.sun.jna.PointerType;
|
||||
|
||||
public class ZSTD_DDict extends PointerType { }
|
110
src/main/java/net/woggioni/jzstd/ZstdInputStream.java
Normal file
110
src/main/java/net/woggioni/jzstd/ZstdInputStream.java
Normal file
@@ -0,0 +1,110 @@
|
||||
package net.woggioni.jzstd;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import net.woggioni.jzstd.internal.ZSTD_inBuffer;
|
||||
import net.woggioni.jzstd.internal.ZSTD_outBuffer;
|
||||
import net.woggioni.jzstd.internal.ZstdLibrary;
|
||||
import net.woggioni.jzstd.internal.size_t;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
public class ZstdInputStream extends InputStream {
|
||||
private final InputStream source;
|
||||
private final ZSTD_DCtx ctx;
|
||||
private final boolean ctx_owner;
|
||||
|
||||
private final ZSTD_inBuffer input;
|
||||
private final ZSTD_outBuffer output;
|
||||
|
||||
private enum State {
|
||||
AVAILABLE_INPUT, SOURCE_DEPLETED, CTX_FLUSHED
|
||||
}
|
||||
|
||||
private State state = State.AVAILABLE_INPUT;
|
||||
|
||||
private static final int inputBufferSize = ZstdLibrary.DStreamInSize();
|
||||
private static final int outputBufferSize = ZstdLibrary.DStreamOutSize();
|
||||
|
||||
private ZstdInputStream(InputStream source,
|
||||
ZSTD_DCtx ctx,
|
||||
boolean ctx_owner) {
|
||||
this.source = source;
|
||||
this.ctx = ctx;
|
||||
this.ctx_owner = ctx_owner;
|
||||
this.input = new ZSTD_inBuffer(inputBufferSize);
|
||||
this.output = new ZSTD_outBuffer(outputBufferSize);
|
||||
}
|
||||
|
||||
public static ZstdInputStream from(InputStream source) {
|
||||
ZSTD_DCtx ctx = ZstdLibrary.ZSTD_createDStream();
|
||||
return new ZstdInputStream(source, ctx, true);
|
||||
}
|
||||
|
||||
public static ZstdInputStream from(InputStream source, ZSTD_DCtx ctx) {
|
||||
return new ZstdInputStream(source, ctx, false);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
void fill() {
|
||||
size_t zero = new size_t(0);
|
||||
output.pos = zero;
|
||||
do {
|
||||
if (input.pos.intValue() == input.size.intValue()) {
|
||||
if (state == State.SOURCE_DEPLETED) {
|
||||
return;
|
||||
} else if(input.src.position() == input.src.capacity()) {
|
||||
input.src.position(0);
|
||||
}
|
||||
while (input.src.position() < input.src.capacity()) {
|
||||
int b = source.read();
|
||||
if (b < 0) {
|
||||
state = State.SOURCE_DEPLETED;
|
||||
break;
|
||||
}
|
||||
input.src.put((byte) b);
|
||||
}
|
||||
input.pos = zero;
|
||||
input.size = new size_t(input.src.position());
|
||||
output.pos = zero;
|
||||
}
|
||||
int rc = ZstdLibrary.decompressStream(ctx, output, input);
|
||||
if(rc == 0) {
|
||||
state = State.CTX_FLUSHED;
|
||||
break;
|
||||
}
|
||||
} while (output.pos.intValue() < output.size.intValue());
|
||||
output.dst.position(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() {
|
||||
if (output.dst.position() == output.pos.intValue()) {
|
||||
if (state == State.CTX_FLUSHED) return -1;
|
||||
else fill();
|
||||
}
|
||||
return output.dst.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] arr, int off, int len) {
|
||||
int totalRead = 0;
|
||||
while (totalRead < len) {
|
||||
if(output.pos.intValue() == output.dst.position()) {
|
||||
if(state == State.CTX_FLUSHED) {
|
||||
if(totalRead == 0) --totalRead;
|
||||
break;
|
||||
}
|
||||
else fill();
|
||||
}
|
||||
int toBeRead = Math.min(len, output.pos.intValue() - output.dst.position());
|
||||
output.dst.get(arr, off, toBeRead);
|
||||
totalRead += toBeRead;
|
||||
}
|
||||
return totalRead;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (ctx_owner) ZstdLibrary.freeDStream(ctx);
|
||||
}
|
||||
}
|
@@ -61,7 +61,7 @@ public class ZstdLibrary {
|
||||
public static native size_t ZSTD_initCStream(ZSTD_CCtx ctx, int compressionLevel);
|
||||
|
||||
public static native ZSTD_CCtx ZSTD_createCStream();
|
||||
public static native void ZSTD_freeCStream(ZSTD_CCtx ctx);
|
||||
public static native size_t ZSTD_freeCStream(ZSTD_CCtx ctx);
|
||||
public static native size_t ZSTD_compressStream2(
|
||||
ZSTD_CCtx cctx,
|
||||
ZSTD_outBuffer output,
|
||||
@@ -76,6 +76,44 @@ public class ZstdLibrary {
|
||||
public static native size_t ZSTD_CCtx_reset(ZSTD_CCtx ctx, int reset_directive);
|
||||
public static native size_t ZSTD_CCtx_refCDict(ZSTD_CCtx ctx, ZSTD_CDict cdict);
|
||||
|
||||
public static native ZSTD_DCtx ZSTD_createDStream();
|
||||
public static native size_t ZSTD_freeDStream(ZSTD_DCtx ctx);
|
||||
|
||||
public static native size_t ZSTD_initDStream(ZSTD_DCtx ctx);
|
||||
public static native size_t ZSTD_DCtx_reset(ZSTD_DCtx ctx, int reset_directive);
|
||||
public static native size_t ZSTD_DCtx_refDDict(ZSTD_CCtx ctx, ZSTD_DDict ddict);
|
||||
public static native size_t ZSTD_decompressStream(ZSTD_DCtx ctx, ZSTD_outBuffer output, ZSTD_inBuffer input);
|
||||
|
||||
public static native size_t ZSTD_DStreamInSize();
|
||||
public static native size_t ZSTD_DStreamOutSize();
|
||||
|
||||
public static void freeDStream(ZSTD_DCtx ctx) {
|
||||
checkReturnCode(ZSTD_freeDStream(ctx));
|
||||
}
|
||||
|
||||
public static void ZSTD_DCtx_reset(ZSTD_DCtx ctx, ZSTD_ResetDirective reset_directive) {
|
||||
checkReturnCode(ZSTD_DCtx_reset(ctx, reset_directive.value));
|
||||
}
|
||||
|
||||
public static void refDDict(ZSTD_CCtx ctx, ZSTD_DDict ddict) {
|
||||
checkReturnCode(ZSTD_DCtx_refDDict(ctx, ddict));
|
||||
}
|
||||
|
||||
public static int decompressStream(ZSTD_DCtx ctx, ZSTD_outBuffer output, ZSTD_inBuffer input) {
|
||||
size_t rc = ZSTD_decompressStream(ctx, output, input);
|
||||
checkReturnCode(rc);
|
||||
return rc.intValue();
|
||||
}
|
||||
|
||||
public static int DStreamInSize() {
|
||||
return ZSTD_DStreamInSize().intValue();
|
||||
}
|
||||
|
||||
public static int DStreamOutSize() {
|
||||
return ZSTD_DStreamOutSize().intValue();
|
||||
}
|
||||
|
||||
|
||||
static {
|
||||
Native.register("zstd");
|
||||
}
|
||||
|
@@ -1,336 +0,0 @@
|
||||
/*
|
||||
* This Kotlin source file was generated by the Gradle 'init' task.
|
||||
*/
|
||||
package net.woggioni.kzstd
|
||||
|
||||
import com.sun.jna.*
|
||||
import java.io.BufferedInputStream
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
import java.lang.IllegalArgumentException
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Paths
|
||||
import kotlin.math.min
|
||||
|
||||
import net.woggioni.jzstd.internal.ZSTD_inBuffer as jZSTD_inBuffer
|
||||
import net.woggioni.jzstd.internal.ZSTD_outBuffer as jZSTD_outBuffer
|
||||
import net.woggioni.jzstd.ZSTD_CCtx as jZSTD_CCtx
|
||||
|
||||
class ZstdInputStream private constructor(
|
||||
private val source: InputStream,
|
||||
private val ctx: ZstdLibrary.ZSTD_CCtx,
|
||||
private val ctx_owner: Boolean,
|
||||
bufferSize: Int) : InputStream() {
|
||||
|
||||
override fun read(): Int {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun read(b: ByteArray, off: Int, len: Int): Int {
|
||||
return super.read(b, off, len)
|
||||
}
|
||||
}
|
||||
|
||||
class ZstdOutputStream private constructor(
|
||||
private val sink: OutputStream,
|
||||
private val ctx: ZstdLibrary.ZSTD_CCtx,
|
||||
private val ctx_owner: Boolean,
|
||||
bufferSize: Int) : OutputStream() {
|
||||
|
||||
companion object {
|
||||
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun from(sink: OutputStream,
|
||||
ctx: ZstdLibrary.ZSTD_CCtx,
|
||||
bufferSize: Int = 0x10000) = let {
|
||||
ZstdLibrary.CCtx_reset(ctx, ZstdLibrary.ZSTD_ResetDirective.ZSTD_reset_session_only)
|
||||
ZstdLibrary.CCtx_refCDict(ctx, null)
|
||||
ZstdOutputStream(sink, ctx, false, bufferSize)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun from(sink: OutputStream,
|
||||
compressionLevel: Int = 3,
|
||||
bufferSize: Int = 0x10000) = let {
|
||||
val range = ZstdLibrary.ZSTD_cParam_getBounds(
|
||||
ZstdLibrary.ZSTD_cParameter.compressionLevel.value)
|
||||
if (compressionLevel < range.lowerBound || compressionLevel > range.upperBound) {
|
||||
throw IllegalArgumentException("Compression level must be between " +
|
||||
"${range.lowerBound} and ${range.upperBound}")
|
||||
}
|
||||
val ctx = ZstdLibrary.ZSTD_createCCtx()
|
||||
ZstdLibrary.CCtx_setParameter(ctx,
|
||||
ZstdLibrary.ZSTD_cParameter.compressionLevel, compressionLevel)
|
||||
ZstdOutputStream(sink, ctx, true, bufferSize)
|
||||
}
|
||||
}
|
||||
|
||||
private val buffer = ByteArray(bufferSize)
|
||||
private val input = ZstdLibrary.ZSTD_inBuffer(bufferSize)
|
||||
private val output = ZstdLibrary.ZSTD_outBuffer(bufferSize)
|
||||
private var pos = 0
|
||||
private var flag = ZstdLibrary.ZSTD_EndDirective.ZSTD_e_continue
|
||||
|
||||
|
||||
override fun flush() {
|
||||
input.src.put(buffer, 0, pos)
|
||||
input.src.position(0)
|
||||
input.pos = 0
|
||||
input.size = pos.toLong()
|
||||
pos = 0
|
||||
while (true) {
|
||||
val rc = ZstdLibrary.compressStream2(ctx, output, input, flag)
|
||||
if (output.pos > 0) {
|
||||
output.dst.get(buffer)
|
||||
output.dst.position(0)
|
||||
sink.write(buffer, 0, output.pos.toInt())
|
||||
output.pos = 0
|
||||
}
|
||||
if (input.pos == input.size && flag == ZstdLibrary.ZSTD_EndDirective.ZSTD_e_continue) {
|
||||
break
|
||||
} else if (flag == ZstdLibrary.ZSTD_EndDirective.ZSTD_e_end && rc == 0L) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun write(b: Int) {
|
||||
if (pos == buffer.size) flush()
|
||||
buffer[pos++] = b.toByte()
|
||||
}
|
||||
|
||||
override fun write(b: ByteArray, off: Int, len: Int) {
|
||||
var written = 0
|
||||
while (written < len - off) {
|
||||
val writeSize = min(len, buffer.size - pos)
|
||||
System.arraycopy(b, off, buffer, pos, writeSize)
|
||||
pos += writeSize
|
||||
if (pos == buffer.size) flush()
|
||||
written += writeSize
|
||||
}
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
flag = ZstdLibrary.ZSTD_EndDirective.ZSTD_e_end
|
||||
flush()
|
||||
sink.close()
|
||||
if (ctx_owner) ZstdLibrary.ZSTD_freeCCtx(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
class HelloWorld {
|
||||
|
||||
inline fun <reified T : AutoCloseable, R> withResource(closeable: T, body: (resource: T) -> R): R {
|
||||
return closeable.use {
|
||||
body(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkReturnCode(rc: Long) {
|
||||
if (ZstdLibrary.ZSTD_isError(rc)) {
|
||||
val error = ZstdLibrary.getErrorString(rc)
|
||||
throw RuntimeException(error)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun main(args: Array<String>) {
|
||||
|
||||
BufferedInputStream(HelloWorld::class.java.getResourceAsStream("/Richard_Dawkins_The_Selfish_Gene.pdf")).use { inputStream ->
|
||||
Paths.get("/tmp/Richard_Dawkins_The_Selfish_Gene.pdf.zst").let {
|
||||
ZstdOutputStream.from(Files.newOutputStream(it))
|
||||
}.use { outputStream ->
|
||||
val buffer = ByteArray(0x1000)
|
||||
while (true) {
|
||||
val read = inputStream.read(buffer)
|
||||
if (read < 0) break
|
||||
outputStream.write(buffer, 0, read)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object ZstdLibrary {
|
||||
|
||||
fun checkReturnCode(rc: Long) {
|
||||
if (ZSTD_isError(rc)) {
|
||||
val error = getErrorString(rc)
|
||||
throw RuntimeException(error)
|
||||
}
|
||||
}
|
||||
|
||||
class ZSTD_CCtx : PointerType()
|
||||
|
||||
class ZSTD_CDict : PointerType()
|
||||
|
||||
|
||||
@Structure.FieldOrder(value = ["src", "size", "pos"])
|
||||
class ZSTD_inBuffer(size: Int = 0) : Structure() {
|
||||
@JvmField
|
||||
var src = ByteBuffer.allocateDirect(size)
|
||||
|
||||
@JvmField
|
||||
var size: Long = src.capacity().toLong()
|
||||
|
||||
@JvmField
|
||||
var pos: Long = src.capacity().toLong()
|
||||
}
|
||||
|
||||
@Structure.FieldOrder(value = ["dst", "size", "pos"])
|
||||
class ZSTD_outBuffer(size: Int = 0) : Structure() {
|
||||
@JvmField
|
||||
var dst = ByteBuffer.allocateDirect(size)
|
||||
|
||||
@JvmField
|
||||
var size: Long = dst.capacity().toLong()
|
||||
|
||||
@JvmField
|
||||
var pos: Long = 0
|
||||
}
|
||||
|
||||
@Structure.FieldOrder(value = ["error", "lowerBound", "upperBound"])
|
||||
open class ZSTD_bounds(
|
||||
@JvmField
|
||||
var error: Long = 0,
|
||||
@JvmField
|
||||
var lowerBound: Int = 0,
|
||||
@JvmField
|
||||
var upperBound: Int = 0
|
||||
) : Structure() {
|
||||
class ByValue : ZSTD_bounds(), Structure.ByValue
|
||||
}
|
||||
|
||||
enum class ZSTD_ResetDirective(@JvmField val value: Int) {
|
||||
ZSTD_reset_session_only(1),
|
||||
ZSTD_reset_parameters(2),
|
||||
ZSTD_reset_session_and_parameters(3)
|
||||
}
|
||||
|
||||
enum class ZSTD_EndDirective(@JvmField val value: Int) {
|
||||
ZSTD_e_continue(0),
|
||||
ZSTD_e_flush(1),
|
||||
ZSTD_e_end(2)
|
||||
}
|
||||
|
||||
enum class ZSTD_cParameter(@JvmField val value: Int) {
|
||||
compressionLevel(100),
|
||||
windowLog(101),
|
||||
hashLog(102),
|
||||
chainLog(103),
|
||||
searchLog(104),
|
||||
minMatch(105),
|
||||
targetLength(106),
|
||||
strategy(107),
|
||||
enableLongDistanceMatching(160),
|
||||
ldmHashLog(161),
|
||||
ldmMinMatch(162),
|
||||
ldmBucketSizeLog(163),
|
||||
ldmHashRateLog(164),
|
||||
contentSizeFlag(200),
|
||||
checksumFlag(201),
|
||||
dictIDFlag(202),
|
||||
nbWorkers(400),
|
||||
jobSize(401),
|
||||
overlapLog(402)
|
||||
}
|
||||
|
||||
enum class ZSTD_ErrorCode(@JvmField val value: Int) {
|
||||
ZSTD_error_no_error(0),
|
||||
ZSTD_error_GENERIC(1),
|
||||
ZSTD_error_prefix_unknown(10),
|
||||
ZSTD_error_version_unsupported(12),
|
||||
ZSTD_error_frameParameter_unsupported(14),
|
||||
ZSTD_error_frameParameter_windowTooLarge(16),
|
||||
ZSTD_error_corruption_detected(20),
|
||||
ZSTD_error_checksum_wrong(22),
|
||||
ZSTD_error_dictionary_corrupted(30),
|
||||
ZSTD_error_dictionary_wrong(32),
|
||||
ZSTD_error_dictionaryCreation_failed(34),
|
||||
ZSTD_error_parameter_unsupported(40),
|
||||
ZSTD_error_parameter_outOfBound(42),
|
||||
ZSTD_error_tableLog_tooLarge(44),
|
||||
ZSTD_error_maxSymbolValue_tooLarge(46),
|
||||
ZSTD_error_maxSymbolValue_tooSmall(48),
|
||||
ZSTD_error_stage_wrong(60),
|
||||
ZSTD_error_init_missing(62),
|
||||
ZSTD_error_memory_allocation(64),
|
||||
ZSTD_error_workSpace_tooSmall(66),
|
||||
ZSTD_error_dstSize_tooSmall(70),
|
||||
ZSTD_error_srcSize_wrong(72),
|
||||
ZSTD_error_dstBuffer_null(74),
|
||||
}
|
||||
|
||||
fun compressStream2(
|
||||
cctx: ZSTD_CCtx,
|
||||
output: ZSTD_outBuffer,
|
||||
input: ZSTD_inBuffer,
|
||||
endOp: ZSTD_EndDirective): Long {
|
||||
val rc = ZSTD_compressStream2(cctx, output, input, endOp.value)
|
||||
checkReturnCode(rc)
|
||||
return rc
|
||||
}
|
||||
|
||||
fun cParam_getBounds(cParam: ZSTD_cParameter): ZSTD_bounds = let {
|
||||
val bounds = ZSTD_cParam_getBounds(cParam.value)
|
||||
if (ZSTD_isError(bounds.error)) throw RuntimeException()
|
||||
bounds
|
||||
}
|
||||
|
||||
fun CCtx_setParameter(cctx: ZSTD_CCtx, param: ZSTD_cParameter, value: Int) {
|
||||
val rc = ZSTD_CCtx_setParameter(cctx, param.value, value)
|
||||
if (ZSTD_isError(rc)) {
|
||||
throw RuntimeException(getErrorString(rc))
|
||||
}
|
||||
}
|
||||
|
||||
fun getErrorCode(functionResult: Long): ZSTD_ErrorCode {
|
||||
val code = ZSTD_getErrorCode(functionResult)
|
||||
for (result in ZSTD_ErrorCode.values()) {
|
||||
if (code == result.value) return result
|
||||
}
|
||||
throw IllegalArgumentException("Unknown error code $code")
|
||||
}
|
||||
|
||||
fun getErrorString(functionResult: Long): String {
|
||||
return ZSTD_getErrorString(getErrorCode(functionResult).value)
|
||||
}
|
||||
|
||||
fun CCtx_reset(ctx: ZSTD_CCtx, resetDirective: ZSTD_ResetDirective) {
|
||||
checkReturnCode(ZSTD_CCtx_reset(ctx, resetDirective.value))
|
||||
}
|
||||
|
||||
fun CCtx_refCDict(ctx: ZSTD_CCtx, cdict: ZSTD_CDict?) {
|
||||
checkReturnCode(ZSTD_CCtx_refCDict(ctx, cdict))
|
||||
}
|
||||
|
||||
external fun ZSTD_CCtx_setParameter(cctx: ZSTD_CCtx, param: Int, value: Int): Long
|
||||
external fun ZSTD_createCCtx(): ZSTD_CCtx
|
||||
external fun ZSTD_freeCCtx(cctx: ZSTD_CCtx): Long
|
||||
external fun ZSTD_initCStream(ctx: ZSTD_CCtx, compressionLevel: Int): Long
|
||||
|
||||
external fun ZSTD_createCStream(): ZSTD_CCtx
|
||||
external fun ZSTD_freeCStream(p: ZSTD_CCtx)
|
||||
external fun ZSTD_compressStream2(
|
||||
cctx: ZSTD_CCtx,
|
||||
output: ZSTD_outBuffer,
|
||||
input: ZSTD_inBuffer,
|
||||
endOp: Int): Long
|
||||
|
||||
external fun ZSTD_cParam_getBounds(cParam: Int): ZSTD_bounds.ByValue
|
||||
external fun ZSTD_isError(code: Long): Boolean
|
||||
external fun ZSTD_getErrorCode(functionResult: Long): Int
|
||||
external fun ZSTD_getErrorString(code: Int): String
|
||||
|
||||
external fun ZSTD_CCtx_reset(ctx: ZSTD_CCtx, reset_directive: Int): Long
|
||||
external fun ZSTD_CCtx_refCDict(ctx: ZSTD_CCtx, cdict: ZSTD_CDict?): Long
|
||||
|
||||
init {
|
||||
Native.register("zstd")
|
||||
}
|
||||
}
|
66
src/test/java/net/woggioni/jzstd/BasicTest.java
Normal file
66
src/test/java/net/woggioni/jzstd/BasicTest.java
Normal file
@@ -0,0 +1,66 @@
|
||||
package net.woggioni.jzstd;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.ArgumentsProvider;
|
||||
import org.junit.jupiter.params.provider.ArgumentsSource;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.DigestInputStream;
|
||||
import java.security.DigestOutputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
|
||||
class InputStreamProvider implements ArgumentsProvider {
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
|
||||
return Stream.of(
|
||||
Arguments.of(getClass().getResourceAsStream("/index.html")),
|
||||
Arguments.of(Files.newInputStream(Paths.get("/tmp/citylots.json")))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class BasicTest {
|
||||
|
||||
@SneakyThrows
|
||||
@ParameterizedTest
|
||||
@ArgumentsSource(InputStreamProvider.class)
|
||||
public void test(InputStream testStream) {
|
||||
MessageDigest md5 = MessageDigest.getInstance("MD5");
|
||||
|
||||
ByteArrayInputStream compressedStream;
|
||||
try (InputStream is = new BufferedInputStream(testStream)) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try (OutputStream os = new DigestOutputStream(ZstdOutputStream.from(baos), md5)) {
|
||||
byte[] buffer = new byte[0x1000];
|
||||
while (true) {
|
||||
int read = is.read(buffer);
|
||||
if (read < 0) break;
|
||||
os.write(buffer, 0, read);
|
||||
}
|
||||
}
|
||||
compressedStream = new ByteArrayInputStream(baos.toByteArray());
|
||||
}
|
||||
final byte[] originalDigest = md5.digest();
|
||||
md5.reset();
|
||||
try (InputStream is = new DigestInputStream(
|
||||
ZstdInputStream.from(compressedStream), md5)) {
|
||||
byte [] buffer = new byte[0x10000];
|
||||
while(true) {
|
||||
int read = is.read(buffer);
|
||||
if(read < 0) break;
|
||||
}
|
||||
}
|
||||
Assertions.assertArrayEquals(originalDigest, md5.digest());
|
||||
}
|
||||
}
|
@@ -1,61 +0,0 @@
|
||||
package net.woggioni.jzstd;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import net.woggioni.jwo.Chronometer;
|
||||
import net.woggioni.jzstd.internal.ZstdLibrary;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
|
||||
public class SillyTest {
|
||||
|
||||
@Test
|
||||
@SneakyThrows
|
||||
public void test() {
|
||||
var ctx = ZstdLibrary.ZSTD_createCCtx();
|
||||
ZstdLibrary.CCtx_setParameter(ctx, ZSTD_cParameter.compressionLevel, 3);
|
||||
try (InputStream is = new BufferedInputStream(
|
||||
getClass().getResourceAsStream("/Richard_Dawkins_The_Selfish_Gene.pdf"))) {
|
||||
try (OutputStream os =
|
||||
ZstdOutputStream.from(
|
||||
Files.newOutputStream(
|
||||
Paths.get("/tmp/Richard_Dawkins_The_Selfish_Gene.pdf.zst")))) {
|
||||
byte[] buffer = new byte[0x1000];
|
||||
while (true) {
|
||||
int read = is.read(buffer);
|
||||
if (read < 0) break;
|
||||
os.write(buffer, 0, read);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@SneakyThrows
|
||||
public void test4() {
|
||||
Chronometer chronometer = new Chronometer();
|
||||
Path file = Paths.get("/tmp/citylots.json");
|
||||
Path destination = file.getParent().resolve(file.getFileName().toString() + ".zst");
|
||||
try (InputStream is = new BufferedInputStream(Files.newInputStream(file))) {
|
||||
try (OutputStream os =
|
||||
ZstdOutputStream.from(
|
||||
Files.newOutputStream(destination), 11)) {
|
||||
chronometer.reset();
|
||||
byte[] buffer = new byte[0x1000];
|
||||
while (true) {
|
||||
int read = is.read(buffer);
|
||||
if (read < 0) break;
|
||||
os.write(buffer, 0, read);
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println(
|
||||
String.format("Elapsed time: %.3f s", chronometer.elapsed(Chronometer.UnitOfMeasure.SECONDS)));
|
||||
}
|
||||
}
|
@@ -1,58 +0,0 @@
|
||||
package net.woggioni.kstd
|
||||
|
||||
import lombok.SneakyThrows
|
||||
import net.woggioni.kzstd.ZstdLibrary
|
||||
import net.woggioni.kzstd.ZstdOutputStream
|
||||
import org.junit.jupiter.api.Test
|
||||
import java.io.BufferedInputStream
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Paths
|
||||
|
||||
import net.woggioni.jzstd.internal.ZstdLibrary as jZstdLibrary
|
||||
import net.woggioni.jzstd.ZSTD_CCtx
|
||||
import net.woggioni.jzstd.internal.size_t
|
||||
import net.woggioni.jzstd.internal.ZSTD_outBuffer as jZSTD_outBuffer
|
||||
import net.woggioni.jzstd.internal.ZSTD_inBuffer as jZSTD_inBuffer
|
||||
|
||||
class SillyTest {
|
||||
@Test
|
||||
@SneakyThrows
|
||||
fun test() {
|
||||
BufferedInputStream(
|
||||
javaClass.getResourceAsStream("/Richard_Dawkins_The_Selfish_Gene.pdf")).use { inputstream ->
|
||||
ZstdOutputStream.from(
|
||||
Files.newOutputStream(
|
||||
Paths.get("/tmp/Richard_Dawkins_The_Selfish_Gene.pdf.zst"))).use { outputStream ->
|
||||
val buffer = ByteArray(0x1000)
|
||||
while (true) {
|
||||
val read: Int = inputstream.read(buffer)
|
||||
if (read < 0) break
|
||||
outputStream.write(buffer, 0, read)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun test2() {
|
||||
val ctx = ZstdLibrary.ZSTD_createCCtx()
|
||||
ZstdLibrary.CCtx_setParameter(ctx, ZstdLibrary.ZSTD_cParameter.compressionLevel, 3)
|
||||
val input = ZstdLibrary.ZSTD_inBuffer(0x1000)
|
||||
input.pos = 0
|
||||
val output = ZstdLibrary.ZSTD_outBuffer(0x1000)
|
||||
ZstdLibrary.compressStream2(ctx, output, input, ZstdLibrary.ZSTD_EndDirective.ZSTD_e_continue)
|
||||
ZstdLibrary.ZSTD_freeCCtx(ctx)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test3() {
|
||||
val ctx = jZstdLibrary.ZSTD_createCCtx()
|
||||
// jZstdLibrary.CCtx_setParameter(ctx, ZstdLibrary.ZSTD_cParameter.compressionLevel, 3)
|
||||
val input = jZSTD_inBuffer(0x1000)
|
||||
input.pos = size_t(0)
|
||||
val output = jZSTD_outBuffer(0x1000)
|
||||
// ZstdLibrary.ZSTD_compressStream2(ctx, output, input, ZstdLibrary.ZSTD_EndDirective.ZSTD_e_continue.value)
|
||||
jZstdLibrary.ZSTD_freeCCtx(ctx)
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user