mirror of
https://github.com/oven-sh/bun
synced 2026-02-02 15:08:46 +00:00
node:zlib: add zstd (#20313)
Co-authored-by: nektro <5464072+nektro@users.noreply.github.com>
This commit is contained in:
10
.github/workflows/update-zstd.yml
vendored
10
.github/workflows/update-zstd.yml
vendored
@@ -21,16 +21,16 @@ jobs:
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
# Extract the commit hash from the line after COMMIT
|
# Extract the commit hash from the line after COMMIT
|
||||||
CURRENT_VERSION=$(awk '/[[:space:]]*COMMIT[[:space:]]*$/{getline; gsub(/^[[:space:]]+|[[:space:]]+$/,"",$0); print}' cmake/targets/BuildZstd.cmake)
|
CURRENT_VERSION=$(awk '/[[:space:]]*COMMIT[[:space:]]*$/{getline; gsub(/^[[:space:]]+|[[:space:]]+$/,"",$0); print}' cmake/targets/CloneZstd.cmake)
|
||||||
|
|
||||||
if [ -z "$CURRENT_VERSION" ]; then
|
if [ -z "$CURRENT_VERSION" ]; then
|
||||||
echo "Error: Could not find COMMIT line in BuildZstd.cmake"
|
echo "Error: Could not find COMMIT line in CloneZstd.cmake"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Validate that it looks like a git hash
|
# Validate that it looks like a git hash
|
||||||
if ! [[ $CURRENT_VERSION =~ ^[0-9a-f]{40}$ ]]; then
|
if ! [[ $CURRENT_VERSION =~ ^[0-9a-f]{40}$ ]]; then
|
||||||
echo "Error: Invalid git hash format in BuildZstd.cmake"
|
echo "Error: Invalid git hash format in CloneZstd.cmake"
|
||||||
echo "Found: $CURRENT_VERSION"
|
echo "Found: $CURRENT_VERSION"
|
||||||
echo "Expected: 40 character hexadecimal string"
|
echo "Expected: 40 character hexadecimal string"
|
||||||
exit 1
|
exit 1
|
||||||
@@ -76,7 +76,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
# Handle multi-line format where COMMIT and its value are on separate lines
|
# Handle multi-line format where COMMIT and its value are on separate lines
|
||||||
sed -i -E '/[[:space:]]*COMMIT[[:space:]]*$/{n;s/[[:space:]]*([0-9a-f]+)[[:space:]]*$/ ${{ steps.check-version.outputs.latest }}/}' cmake/targets/BuildZstd.cmake
|
sed -i -E '/[[:space:]]*COMMIT[[:space:]]*$/{n;s/[[:space:]]*([0-9a-f]+)[[:space:]]*$/ ${{ steps.check-version.outputs.latest }}/}' cmake/targets/CloneZstd.cmake
|
||||||
|
|
||||||
- name: Create Pull Request
|
- name: Create Pull Request
|
||||||
if: success() && steps.check-version.outputs.current != steps.check-version.outputs.latest
|
if: success() && steps.check-version.outputs.current != steps.check-version.outputs.latest
|
||||||
@@ -84,7 +84,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
add-paths: |
|
add-paths: |
|
||||||
cmake/targets/BuildZstd.cmake
|
cmake/targets/CloneZstd.cmake
|
||||||
commit-message: "deps: update zstd to ${{ steps.check-version.outputs.tag }} (${{ steps.check-version.outputs.latest }})"
|
commit-message: "deps: update zstd to ${{ steps.check-version.outputs.tag }} (${{ steps.check-version.outputs.latest }})"
|
||||||
title: "deps: update zstd to ${{ steps.check-version.outputs.tag }}"
|
title: "deps: update zstd to ${{ steps.check-version.outputs.tag }}"
|
||||||
delete-branch: true
|
delete-branch: true
|
||||||
|
|||||||
@@ -513,6 +513,8 @@ fn getTranslateC(b: *Build, initial_target: std.Build.ResolvedTarget, optimize:
|
|||||||
translate_c.defineCMacroRaw(b.fmt("{s}={d}", .{ str, @intFromBool(value) }));
|
translate_c.defineCMacroRaw(b.fmt("{s}={d}", .{ str, @intFromBool(value) }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
translate_c.addIncludePath(b.path("vendor/zstd/lib"));
|
||||||
|
|
||||||
if (target.result.os.tag == .windows) {
|
if (target.result.os.tag == .windows) {
|
||||||
// translate-c is unable to translate the unsuffixed windows functions
|
// translate-c is unable to translate the unsuffixed windows functions
|
||||||
// like `SetCurrentDirectory` since they are defined with an odd macro
|
// like `SetCurrentDirectory` since they are defined with an odd macro
|
||||||
|
|||||||
@@ -199,6 +199,7 @@ src/bun.js/node/util/parse_args_utils.zig
|
|||||||
src/bun.js/node/util/parse_args.zig
|
src/bun.js/node/util/parse_args.zig
|
||||||
src/bun.js/node/util/validators.zig
|
src/bun.js/node/util/validators.zig
|
||||||
src/bun.js/node/win_watcher.zig
|
src/bun.js/node/win_watcher.zig
|
||||||
|
src/bun.js/node/zlib/NativeZstd.zig
|
||||||
src/bun.js/ProcessAutoKiller.zig
|
src/bun.js/ProcessAutoKiller.zig
|
||||||
src/bun.js/rare_data.zig
|
src/bun.js/rare_data.zig
|
||||||
src/bun.js/ResolveMessage.zig
|
src/bun.js/ResolveMessage.zig
|
||||||
|
|||||||
@@ -42,6 +42,29 @@ else()
|
|||||||
set(CONFIGURE_DEPENDS "")
|
set(CONFIGURE_DEPENDS "")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# --- Dependencies ---
|
||||||
|
|
||||||
|
set(BUN_DEPENDENCIES
|
||||||
|
BoringSSL
|
||||||
|
Brotli
|
||||||
|
Cares
|
||||||
|
Highway
|
||||||
|
LibDeflate
|
||||||
|
LolHtml
|
||||||
|
Lshpack
|
||||||
|
Mimalloc
|
||||||
|
TinyCC
|
||||||
|
Zlib
|
||||||
|
LibArchive # must be loaded after zlib
|
||||||
|
HdrHistogram # must be loaded after zlib
|
||||||
|
Zstd
|
||||||
|
)
|
||||||
|
|
||||||
|
include(CloneZstd)
|
||||||
|
# foreach(dependency ${BUN_DEPENDENCIES})
|
||||||
|
# include(Clone${dependency})
|
||||||
|
# endforeach()
|
||||||
|
|
||||||
# --- Codegen ---
|
# --- Codegen ---
|
||||||
|
|
||||||
set(BUN_ERROR_SOURCE ${CWD}/packages/bun-error)
|
set(BUN_ERROR_SOURCE ${CWD}/packages/bun-error)
|
||||||
@@ -582,6 +605,7 @@ register_command(
|
|||||||
${BUN_ZIG_OUTPUT}
|
${BUN_ZIG_OUTPUT}
|
||||||
TARGETS
|
TARGETS
|
||||||
clone-zig
|
clone-zig
|
||||||
|
clone-zstd
|
||||||
SOURCES
|
SOURCES
|
||||||
${BUN_ZIG_SOURCES}
|
${BUN_ZIG_SOURCES}
|
||||||
${BUN_ZIG_GENERATED_SOURCES}
|
${BUN_ZIG_GENERATED_SOURCES}
|
||||||
@@ -1054,22 +1078,6 @@ endif()
|
|||||||
|
|
||||||
# --- Dependencies ---
|
# --- Dependencies ---
|
||||||
|
|
||||||
set(BUN_DEPENDENCIES
|
|
||||||
BoringSSL
|
|
||||||
Brotli
|
|
||||||
Cares
|
|
||||||
Highway
|
|
||||||
LibDeflate
|
|
||||||
LolHtml
|
|
||||||
Lshpack
|
|
||||||
Mimalloc
|
|
||||||
TinyCC
|
|
||||||
Zlib
|
|
||||||
LibArchive # must be loaded after zlib
|
|
||||||
HdrHistogram # must be loaded after zlib
|
|
||||||
Zstd
|
|
||||||
)
|
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
list(APPEND BUN_DEPENDENCIES Libuv)
|
list(APPEND BUN_DEPENDENCIES Libuv)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -1,12 +1,3 @@
|
|||||||
register_repository(
|
|
||||||
NAME
|
|
||||||
zstd
|
|
||||||
REPOSITORY
|
|
||||||
facebook/zstd
|
|
||||||
COMMIT
|
|
||||||
f8745da6ff1ad1e7bab384bd1f9d742439278e99
|
|
||||||
)
|
|
||||||
|
|
||||||
register_cmake_command(
|
register_cmake_command(
|
||||||
TARGET
|
TARGET
|
||||||
zstd
|
zstd
|
||||||
@@ -23,4 +14,6 @@ register_cmake_command(
|
|||||||
LIBRARIES
|
LIBRARIES
|
||||||
zstd_static WIN32
|
zstd_static WIN32
|
||||||
zstd UNIX
|
zstd UNIX
|
||||||
|
INCLUDES
|
||||||
|
lib
|
||||||
)
|
)
|
||||||
|
|||||||
8
cmake/targets/CloneZstd.cmake
Normal file
8
cmake/targets/CloneZstd.cmake
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
register_repository(
|
||||||
|
NAME
|
||||||
|
zstd
|
||||||
|
REPOSITORY
|
||||||
|
facebook/zstd
|
||||||
|
COMMIT
|
||||||
|
f8745da6ff1ad1e7bab384bd1f9d742439278e99
|
||||||
|
)
|
||||||
@@ -44,6 +44,7 @@ pub const SocketHandlers = @import("api/bun/socket.zig").Handlers;
|
|||||||
pub const UDPSocket = @import("api/bun/udp_socket.zig").UDPSocket;
|
pub const UDPSocket = @import("api/bun/udp_socket.zig").UDPSocket;
|
||||||
pub const Valkey = @import("../valkey/js_valkey.zig").JSValkeyClient;
|
pub const Valkey = @import("../valkey/js_valkey.zig").JSValkeyClient;
|
||||||
pub const BlockList = @import("./node/net/BlockList.zig");
|
pub const BlockList = @import("./node/net/BlockList.zig");
|
||||||
|
pub const NativeZstd = @import("./node/zlib/NativeZstd.zig");
|
||||||
|
|
||||||
pub const napi = @import("../napi/napi.zig");
|
pub const napi = @import("../napi/napi.zig");
|
||||||
|
|
||||||
|
|||||||
@@ -24,4 +24,4 @@ function generate(name: string) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default [generate("NativeZlib"), generate("NativeBrotli")];
|
export default [generate("NativeZlib"), generate("NativeBrotli"), generate("NativeZstd")];
|
||||||
|
|||||||
@@ -2263,6 +2263,14 @@ JSC_DEFINE_HOST_FUNCTION(Bun::jsFunctionMakeErrorWithCode, (JSC::JSGlobalObject
|
|||||||
return JSC::JSValue::encode(error);
|
return JSC::JSValue::encode(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case Bun::ErrorCode::ERR_ZSTD_INVALID_PARAM: {
|
||||||
|
auto arg0 = callFrame->argument(1);
|
||||||
|
auto str0 = arg0.toWTFString(globalObject);
|
||||||
|
RETURN_IF_EXCEPTION(scope, {});
|
||||||
|
auto message = makeString(str0, " is not a valid zstd parameter"_s);
|
||||||
|
return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_ZSTD_INVALID_PARAM, message));
|
||||||
|
}
|
||||||
|
|
||||||
case ErrorCode::ERR_IPC_DISCONNECTED:
|
case ErrorCode::ERR_IPC_DISCONNECTED:
|
||||||
return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_IPC_DISCONNECTED, "IPC channel is already disconnected"_s));
|
return JSC::JSValue::encode(createError(globalObject, ErrorCode::ERR_IPC_DISCONNECTED, "IPC channel is already disconnected"_s));
|
||||||
case ErrorCode::ERR_SERVER_NOT_RUNNING:
|
case ErrorCode::ERR_SERVER_NOT_RUNNING:
|
||||||
|
|||||||
@@ -254,6 +254,7 @@ const errors: ErrorCodeMapping = [
|
|||||||
["ERR_UNKNOWN_CREDENTIAL", Error],
|
["ERR_UNKNOWN_CREDENTIAL", Error],
|
||||||
["ERR_UNKNOWN_ENCODING", TypeError],
|
["ERR_UNKNOWN_ENCODING", TypeError],
|
||||||
["ERR_UNKNOWN_SIGNAL", TypeError],
|
["ERR_UNKNOWN_SIGNAL", TypeError],
|
||||||
|
["ERR_ZSTD_INVALID_PARAM", RangeError],
|
||||||
["ERR_USE_AFTER_CLOSE", Error],
|
["ERR_USE_AFTER_CLOSE", Error],
|
||||||
["ERR_WASI_NOT_STARTED", Error],
|
["ERR_WASI_NOT_STARTED", Error],
|
||||||
["ERR_WORKER_INIT_FAILED", Error],
|
["ERR_WORKER_INIT_FAILED", Error],
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
#include <brotli/encode.h>
|
#include <brotli/encode.h>
|
||||||
#include <brotli/decode.h>
|
#include <brotli/decode.h>
|
||||||
|
#include <zstd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
@@ -1016,6 +1017,8 @@ static JSValue processBindingConstantsGetZlib(VM& vm, JSObject* bindingObject)
|
|||||||
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "UNZIP"_s)), jsNumber(7));
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "UNZIP"_s)), jsNumber(7));
|
||||||
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "BROTLI_DECODE"_s)), jsNumber(8));
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "BROTLI_DECODE"_s)), jsNumber(8));
|
||||||
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "BROTLI_ENCODE"_s)), jsNumber(9));
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "BROTLI_ENCODE"_s)), jsNumber(9));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_COMPRESS"_s)), jsNumber(10));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_DECOMPRESS"_s)), jsNumber(11));
|
||||||
|
|
||||||
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "Z_MIN_WINDOWBITS"_s)), jsNumber(8));
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "Z_MIN_WINDOWBITS"_s)), jsNumber(8));
|
||||||
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "Z_MAX_WINDOWBITS"_s)), jsNumber(15));
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "Z_MAX_WINDOWBITS"_s)), jsNumber(15));
|
||||||
@@ -1092,6 +1095,69 @@ static JSValue processBindingConstantsGetZlib(VM& vm, JSObject* bindingObject)
|
|||||||
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES"_s)), jsNumber(BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES));
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES"_s)), jsNumber(BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES));
|
||||||
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "BROTLI_DECODER_ERROR_UNREACHABLE"_s)), jsNumber(BROTLI_DECODER_ERROR_UNREACHABLE));
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "BROTLI_DECODER_ERROR_UNREACHABLE"_s)), jsNumber(BROTLI_DECODER_ERROR_UNREACHABLE));
|
||||||
|
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_e_continue"_s)), jsNumber(ZSTD_e_continue));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_e_flush"_s)), jsNumber(ZSTD_e_flush));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_e_end"_s)), jsNumber(ZSTD_e_end));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_fast"_s)), jsNumber(ZSTD_fast));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_dfast"_s)), jsNumber(ZSTD_dfast));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_greedy"_s)), jsNumber(ZSTD_greedy));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_lazy"_s)), jsNumber(ZSTD_lazy));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_lazy2"_s)), jsNumber(ZSTD_lazy2));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_btlazy2"_s)), jsNumber(ZSTD_btlazy2));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_btopt"_s)), jsNumber(ZSTD_btopt));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_btultra"_s)), jsNumber(ZSTD_btultra));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_btultra2"_s)), jsNumber(ZSTD_btultra2));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_c_compressionLevel"_s)), jsNumber(ZSTD_c_compressionLevel));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_c_windowLog"_s)), jsNumber(ZSTD_c_windowLog));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_c_hashLog"_s)), jsNumber(ZSTD_c_hashLog));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_c_chainLog"_s)), jsNumber(ZSTD_c_chainLog));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_c_searchLog"_s)), jsNumber(ZSTD_c_searchLog));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_c_minMatch"_s)), jsNumber(ZSTD_c_minMatch));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_c_targetLength"_s)), jsNumber(ZSTD_c_targetLength));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_c_strategy"_s)), jsNumber(ZSTD_c_strategy));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_c_enableLongDistanceMatching"_s)), jsNumber(ZSTD_c_enableLongDistanceMatching));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_c_ldmHashLog"_s)), jsNumber(ZSTD_c_ldmHashLog));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_c_ldmMinMatch"_s)), jsNumber(ZSTD_c_ldmMinMatch));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_c_ldmBucketSizeLog"_s)), jsNumber(ZSTD_c_ldmBucketSizeLog));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_c_ldmHashRateLog"_s)), jsNumber(ZSTD_c_ldmHashRateLog));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_c_contentSizeFlag"_s)), jsNumber(ZSTD_c_contentSizeFlag));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_c_checksumFlag"_s)), jsNumber(ZSTD_c_checksumFlag));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_c_dictIDFlag"_s)), jsNumber(ZSTD_c_dictIDFlag));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_c_nbWorkers"_s)), jsNumber(ZSTD_c_nbWorkers));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_c_jobSize"_s)), jsNumber(ZSTD_c_jobSize));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_c_overlapLog"_s)), jsNumber(ZSTD_c_overlapLog));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_d_windowLogMax"_s)), jsNumber(ZSTD_d_windowLogMax));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_CLEVEL_DEFAULT"_s)), jsNumber(ZSTD_CLEVEL_DEFAULT));
|
||||||
|
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_error_no_error"_s)), jsNumber(ZSTD_error_no_error));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_error_GENERIC"_s)), jsNumber(ZSTD_error_GENERIC));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_error_prefix_unknown"_s)), jsNumber(ZSTD_error_prefix_unknown));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_error_version_unsupported"_s)), jsNumber(ZSTD_error_version_unsupported));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_error_frameParameter_unsupported"_s)), jsNumber(ZSTD_error_frameParameter_unsupported));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_error_frameParameter_windowTooLarge"_s)), jsNumber(ZSTD_error_frameParameter_windowTooLarge));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_error_corruption_detected"_s)), jsNumber(ZSTD_error_corruption_detected));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_error_checksum_wrong"_s)), jsNumber(ZSTD_error_checksum_wrong));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_error_literals_headerWrong"_s)), jsNumber(ZSTD_error_literals_headerWrong));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_error_dictionary_corrupted"_s)), jsNumber(ZSTD_error_dictionary_corrupted));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_error_dictionary_wrong"_s)), jsNumber(ZSTD_error_dictionary_wrong));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_error_dictionaryCreation_failed"_s)), jsNumber(ZSTD_error_dictionaryCreation_failed));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_error_parameter_unsupported"_s)), jsNumber(ZSTD_error_parameter_unsupported));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_error_parameter_combination_unsupported"_s)), jsNumber(ZSTD_error_parameter_combination_unsupported));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_error_parameter_outOfBound"_s)), jsNumber(ZSTD_error_parameter_outOfBound));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_error_tableLog_tooLarge"_s)), jsNumber(ZSTD_error_tableLog_tooLarge));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_error_maxSymbolValue_tooLarge"_s)), jsNumber(ZSTD_error_maxSymbolValue_tooLarge));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_error_maxSymbolValue_tooSmall"_s)), jsNumber(ZSTD_error_maxSymbolValue_tooSmall));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_error_stabilityCondition_notRespected"_s)), jsNumber(ZSTD_error_stabilityCondition_notRespected));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_error_stage_wrong"_s)), jsNumber(ZSTD_error_stage_wrong));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_error_init_missing"_s)), jsNumber(ZSTD_error_init_missing));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_error_memory_allocation"_s)), jsNumber(ZSTD_error_memory_allocation));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_error_workSpace_tooSmall"_s)), jsNumber(ZSTD_error_workSpace_tooSmall));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_error_dstSize_tooSmall"_s)), jsNumber(ZSTD_error_dstSize_tooSmall));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_error_srcSize_wrong"_s)), jsNumber(ZSTD_error_srcSize_wrong));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_error_dstBuffer_null"_s)), jsNumber(ZSTD_error_dstBuffer_null));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_error_noForwardProgress_destFull"_s)), jsNumber(ZSTD_error_noForwardProgress_destFull));
|
||||||
|
object->putDirect(vm, PropertyName(Identifier::fromString(vm, "ZSTD_error_noForwardProgress_inputEmpty"_s)), jsNumber(ZSTD_error_noForwardProgress_inputEmpty));
|
||||||
|
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -86,4 +86,5 @@ pub const Classes = struct {
|
|||||||
pub const HTMLBundle = api.HTMLBundle;
|
pub const HTMLBundle = api.HTMLBundle;
|
||||||
pub const RedisClient = api.Valkey;
|
pub const RedisClient = api.Valkey;
|
||||||
pub const BlockList = api.BlockList;
|
pub const BlockList = api.BlockList;
|
||||||
|
pub const NativeZstd = api.NativeZstd;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ pub const Task = TaggedPointerUnion(.{
|
|||||||
NapiFinalizerTask,
|
NapiFinalizerTask,
|
||||||
NativeBrotli,
|
NativeBrotli,
|
||||||
NativeZlib,
|
NativeZlib,
|
||||||
|
NativeZstd,
|
||||||
Open,
|
Open,
|
||||||
PollPendingModulesTask,
|
PollPendingModulesTask,
|
||||||
PosixSignalTask,
|
PosixSignalTask,
|
||||||
@@ -448,6 +449,10 @@ pub fn tickQueueWithCount(this: *EventLoop, virtual_machine: *VirtualMachine) u3
|
|||||||
var any: *NativeBrotli = task.get(NativeBrotli).?;
|
var any: *NativeBrotli = task.get(NativeBrotli).?;
|
||||||
any.runFromJSThread();
|
any.runFromJSThread();
|
||||||
},
|
},
|
||||||
|
@field(Task.Tag, @typeName(NativeZstd)) => {
|
||||||
|
var any: *NativeZstd = task.get(NativeZstd).?;
|
||||||
|
any.runFromJSThread();
|
||||||
|
},
|
||||||
@field(Task.Tag, @typeName(ProcessWaiterThreadTask)) => {
|
@field(Task.Tag, @typeName(ProcessWaiterThreadTask)) => {
|
||||||
bun.markPosixOnly();
|
bun.markPosixOnly();
|
||||||
var any: *ProcessWaiterThreadTask = task.get(ProcessWaiterThreadTask).?;
|
var any: *ProcessWaiterThreadTask = task.get(ProcessWaiterThreadTask).?;
|
||||||
@@ -558,6 +563,7 @@ const StatFS = AsyncFS.statfs;
|
|||||||
const Unlink = AsyncFS.unlink;
|
const Unlink = AsyncFS.unlink;
|
||||||
const NativeZlib = JSC.API.NativeZlib;
|
const NativeZlib = JSC.API.NativeZlib;
|
||||||
const NativeBrotli = JSC.API.NativeBrotli;
|
const NativeBrotli = JSC.API.NativeBrotli;
|
||||||
|
const NativeZstd = JSC.API.NativeZstd;
|
||||||
|
|
||||||
const ShellGlobTask = shell.interpret.Interpreter.Expansion.ShellGlobTask;
|
const ShellGlobTask = shell.interpret.Interpreter.Expansion.ShellGlobTask;
|
||||||
const ShellRmTask = shell.Interpreter.Builtin.Rm.ShellRmTask;
|
const ShellRmTask = shell.Interpreter.Builtin.Rm.ShellRmTask;
|
||||||
|
|||||||
@@ -264,7 +264,7 @@ pub fn CompressionStream(comptime T: type) type {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emitError(this: *T, globalThis: *JSC.JSGlobalObject, this_value: JSC.JSValue, err_: Error) !void {
|
pub fn emitError(this: *T, globalThis: *JSC.JSGlobalObject, this_value: JSC.JSValue, err_: Error) !void {
|
||||||
var msg_str = bun.String.createFormat("{s}", .{std.mem.sliceTo(err_.msg, 0) orelse ""}) catch bun.outOfMemory();
|
var msg_str = bun.String.createFormat("{s}", .{std.mem.sliceTo(err_.msg, 0) orelse ""}) catch bun.outOfMemory();
|
||||||
const msg_value = msg_str.transferToJS(globalThis);
|
const msg_value = msg_str.transferToJS(globalThis);
|
||||||
const err_value = JSC.jsNumber(err_.err);
|
const err_value = JSC.jsNumber(err_.err);
|
||||||
@@ -287,7 +287,7 @@ pub fn CompressionStream(comptime T: type) type {
|
|||||||
|
|
||||||
pub const NativeZlib = JSC.Codegen.JSNativeZlib.getConstructor;
|
pub const NativeZlib = JSC.Codegen.JSNativeZlib.getConstructor;
|
||||||
|
|
||||||
const CountedKeepAlive = struct {
|
pub const CountedKeepAlive = struct {
|
||||||
keep_alive: bun.Async.KeepAlive = .{},
|
keep_alive: bun.Async.KeepAlive = .{},
|
||||||
ref_count: u32 = 0,
|
ref_count: u32 = 0,
|
||||||
|
|
||||||
@@ -428,7 +428,7 @@ pub const SNativeZlib = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const Error = struct {
|
pub const Error = struct {
|
||||||
msg: ?[*:0]const u8,
|
msg: ?[*:0]const u8,
|
||||||
err: c_int,
|
err: c_int,
|
||||||
code: ?[*:0]const u8,
|
code: ?[*:0]const u8,
|
||||||
@@ -471,6 +471,7 @@ const ZlibContext = struct {
|
|||||||
.UNZIP => windowBits + 32,
|
.UNZIP => windowBits + 32,
|
||||||
.DEFLATERAW, .INFLATERAW => windowBits * -1,
|
.DEFLATERAW, .INFLATERAW => windowBits * -1,
|
||||||
.BROTLI_DECODE, .BROTLI_ENCODE => unreachable,
|
.BROTLI_DECODE, .BROTLI_ENCODE => unreachable,
|
||||||
|
.ZSTD_COMPRESS, .ZSTD_DECOMPRESS => unreachable,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.dictionary = dictionary orelse "";
|
this.dictionary = dictionary orelse "";
|
||||||
@@ -479,8 +480,8 @@ const ZlibContext = struct {
|
|||||||
.NONE => unreachable,
|
.NONE => unreachable,
|
||||||
.DEFLATE, .GZIP, .DEFLATERAW => this.err = c.deflateInit2_(&this.state, level, 8, windowBitsActual, memLevel, strategy, c.zlibVersion(), @sizeOf(c.z_stream)),
|
.DEFLATE, .GZIP, .DEFLATERAW => this.err = c.deflateInit2_(&this.state, level, 8, windowBitsActual, memLevel, strategy, c.zlibVersion(), @sizeOf(c.z_stream)),
|
||||||
.INFLATE, .GUNZIP, .UNZIP, .INFLATERAW => this.err = c.inflateInit2_(&this.state, windowBitsActual, c.zlibVersion(), @sizeOf(c.z_stream)),
|
.INFLATE, .GUNZIP, .UNZIP, .INFLATERAW => this.err = c.inflateInit2_(&this.state, windowBitsActual, c.zlibVersion(), @sizeOf(c.z_stream)),
|
||||||
.BROTLI_DECODE => @panic("TODO"),
|
.BROTLI_DECODE, .BROTLI_ENCODE => unreachable,
|
||||||
.BROTLI_ENCODE => @panic("TODO"),
|
.ZSTD_COMPRESS, .ZSTD_DECOMPRESS => unreachable,
|
||||||
}
|
}
|
||||||
if (this.err != .Ok) {
|
if (this.err != .Ok) {
|
||||||
this.mode = .NONE;
|
this.mode = .NONE;
|
||||||
@@ -619,6 +620,7 @@ const ZlibContext = struct {
|
|||||||
},
|
},
|
||||||
.NONE => {},
|
.NONE => {},
|
||||||
.BROTLI_ENCODE, .BROTLI_DECODE => {},
|
.BROTLI_ENCODE, .BROTLI_DECODE => {},
|
||||||
|
.ZSTD_COMPRESS, .ZSTD_DECOMPRESS => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -684,6 +686,7 @@ const ZlibContext = struct {
|
|||||||
},
|
},
|
||||||
.NONE => {},
|
.NONE => {},
|
||||||
.BROTLI_ENCODE, .BROTLI_DECODE => {},
|
.BROTLI_ENCODE, .BROTLI_DECODE => {},
|
||||||
|
.ZSTD_COMPRESS, .ZSTD_DECOMPRESS => {},
|
||||||
}
|
}
|
||||||
bun.assert(status == .Ok or status == .DataError);
|
bun.assert(status == .Ok or status == .DataError);
|
||||||
this.mode = .NONE;
|
this.mode = .NONE;
|
||||||
@@ -722,9 +725,7 @@ pub const SNativeBrotli = struct {
|
|||||||
write_in_progress: bool = false,
|
write_in_progress: bool = false,
|
||||||
pending_close: bool = false,
|
pending_close: bool = false,
|
||||||
closed: bool = false,
|
closed: bool = false,
|
||||||
task: JSC.WorkPoolTask = .{
|
task: JSC.WorkPoolTask = .{ .callback = undefined },
|
||||||
.callback = undefined,
|
|
||||||
},
|
|
||||||
|
|
||||||
pub fn constructor(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!*@This() {
|
pub fn constructor(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!*@This() {
|
||||||
const arguments = callframe.argumentsUndef(1).ptr;
|
const arguments = callframe.argumentsUndef(1).ptr;
|
||||||
@@ -960,3 +961,5 @@ const BrotliContext = struct {
|
|||||||
unreachable;
|
unreachable;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const NativeZstd = JSC.Codegen.JSNativeZstd.getConstructor;
|
||||||
|
|||||||
266
src/bun.js/node/zlib/NativeZstd.zig
Normal file
266
src/bun.js/node/zlib/NativeZstd.zig
Normal file
@@ -0,0 +1,266 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const bun = @import("bun");
|
||||||
|
const JSC = bun.JSC;
|
||||||
|
const CompressionStream = @import("./../node_zlib_binding.zig").CompressionStream;
|
||||||
|
const CountedKeepAlive = @import("./../node_zlib_binding.zig").CountedKeepAlive;
|
||||||
|
const Error = @import("./../node_zlib_binding.zig").Error;
|
||||||
|
const validators = @import("./../util/validators.zig");
|
||||||
|
|
||||||
|
const RefCount = bun.ptr.RefCount(@This(), "ref_count", deinit, .{});
|
||||||
|
pub const ref = RefCount.ref;
|
||||||
|
pub const deref = RefCount.deref;
|
||||||
|
|
||||||
|
pub const js = JSC.Codegen.JSNativeZstd;
|
||||||
|
pub const toJS = js.toJS;
|
||||||
|
pub const fromJS = js.fromJS;
|
||||||
|
pub const fromJSDirect = js.fromJSDirect;
|
||||||
|
|
||||||
|
const impl = CompressionStream(@This());
|
||||||
|
pub const write = impl.write;
|
||||||
|
pub const runFromJSThread = impl.runFromJSThread;
|
||||||
|
pub const writeSync = impl.writeSync;
|
||||||
|
pub const reset = impl.reset;
|
||||||
|
pub const close = impl.close;
|
||||||
|
pub const setOnError = impl.setOnError;
|
||||||
|
pub const getOnError = impl.getOnError;
|
||||||
|
pub const finalize = impl.finalize;
|
||||||
|
|
||||||
|
ref_count: RefCount,
|
||||||
|
mode: bun.zlib.NodeMode,
|
||||||
|
globalThis: *JSC.JSGlobalObject,
|
||||||
|
stream: Context = .{},
|
||||||
|
write_result: ?[*]u32 = null,
|
||||||
|
poll_ref: CountedKeepAlive = .{},
|
||||||
|
this_value: JSC.Strong.Optional = .empty,
|
||||||
|
write_in_progress: bool = false,
|
||||||
|
pending_close: bool = false,
|
||||||
|
closed: bool = false,
|
||||||
|
task: JSC.WorkPoolTask = .{ .callback = undefined },
|
||||||
|
|
||||||
|
pub fn constructor(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!*@This() {
|
||||||
|
const arguments = callframe.argumentsAsArray(1);
|
||||||
|
|
||||||
|
var mode = arguments[0];
|
||||||
|
if (!mode.isNumber()) {
|
||||||
|
return globalThis.throwInvalidArgumentTypeValue("mode", "number", mode);
|
||||||
|
}
|
||||||
|
const mode_double = mode.asNumber();
|
||||||
|
if (@mod(mode_double, 1.0) != 0.0) {
|
||||||
|
return globalThis.throwInvalidArgumentTypeValue("mode", "integer", mode);
|
||||||
|
}
|
||||||
|
const mode_int: i64 = @intFromFloat(mode_double);
|
||||||
|
if (mode_int < 10 or mode_int > 11) {
|
||||||
|
return globalThis.throwRangeError(mode_int, .{ .field_name = "mode", .min = 10, .max = 11 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const ptr = bun.new(@This(), .{
|
||||||
|
.ref_count = .init(),
|
||||||
|
.mode = @enumFromInt(mode_int),
|
||||||
|
.globalThis = globalThis,
|
||||||
|
});
|
||||||
|
ptr.stream.mode = ptr.mode;
|
||||||
|
ptr.stream.mode_ = ptr.mode;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn estimatedSize(this: *const @This()) usize {
|
||||||
|
return @sizeOf(@This()) + switch (this.stream.mode_) {
|
||||||
|
.ZSTD_COMPRESS => bun.c.ZSTD_sizeof_CCtx(@ptrCast(this.stream.state)),
|
||||||
|
.ZSTD_DECOMPRESS => bun.c.ZSTD_sizeof_DCtx(@ptrCast(this.stream.state)),
|
||||||
|
else => 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init(this: *@This(), globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSC.JSValue {
|
||||||
|
const arguments = callframe.argumentsAsArray(4);
|
||||||
|
const this_value = callframe.this();
|
||||||
|
if (callframe.argumentsCount() != 4) return globalThis.ERR(.MISSING_ARGS, "init(initParamsArray, pledgedSrcSize, writeState, processCallback)", .{}).throw();
|
||||||
|
|
||||||
|
const initParamsArray_value = arguments[0];
|
||||||
|
const pledgedSrcSize_value = arguments[1];
|
||||||
|
const writeState_value = arguments[2];
|
||||||
|
const processCallback_value = arguments[3];
|
||||||
|
|
||||||
|
const writeState = writeState_value.asArrayBuffer(globalThis) orelse return globalThis.throwInvalidArgumentTypeValue("writeState", "Uint32Array", writeState_value);
|
||||||
|
if (writeState.typed_array_type != .Uint32Array) return globalThis.throwInvalidArgumentTypeValue("writeState", "Uint32Array", writeState_value);
|
||||||
|
this.write_result = writeState.asU32().ptr;
|
||||||
|
|
||||||
|
const write_js_callback = try validators.validateFunction(globalThis, "processCallback", processCallback_value);
|
||||||
|
js.writeCallbackSetCached(this_value, globalThis, write_js_callback);
|
||||||
|
|
||||||
|
var pledged_src_size: u64 = std.math.maxInt(u64);
|
||||||
|
if (pledgedSrcSize_value.isNumber()) {
|
||||||
|
pledged_src_size = try validators.validateUint32(globalThis, pledgedSrcSize_value, "pledgedSrcSize", .{}, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
var err = this.stream.init(pledged_src_size);
|
||||||
|
if (err.isError()) {
|
||||||
|
try impl.emitError(this, globalThis, this_value, err);
|
||||||
|
return .jsBoolean(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const params_ = initParamsArray_value.asArrayBuffer(globalThis) orelse return globalThis.throwInvalidArgumentTypeValue("initParamsArray", "Uint32Array", initParamsArray_value);
|
||||||
|
if (params_.typed_array_type != .Uint32Array) return globalThis.throwInvalidArgumentTypeValue("initParamsArray", "Uint32Array", initParamsArray_value);
|
||||||
|
for (params_.asU32(), 0..) |x, i| {
|
||||||
|
if (x == std.math.maxInt(u32)) continue;
|
||||||
|
const err_ = this.stream.setParams(@intCast(i), x);
|
||||||
|
if (err_.isError()) return globalThis.ERR(.ZLIB_INITIALIZATION_FAILED, "{s}", .{std.mem.sliceTo(err_.msg.?, 0)}).throw();
|
||||||
|
}
|
||||||
|
|
||||||
|
return .jsBoolean(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn params(this: *@This(), globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSC.JSValue {
|
||||||
|
_ = this;
|
||||||
|
_ = globalThis;
|
||||||
|
_ = callframe;
|
||||||
|
// intentionally left empty
|
||||||
|
return .undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deinit(this: *@This()) void {
|
||||||
|
this.poll_ref.deinit();
|
||||||
|
switch (this.stream.mode) {
|
||||||
|
.ZSTD_COMPRESS, .ZSTD_DECOMPRESS => this.stream.close(),
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
bun.destroy(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Context = struct {
|
||||||
|
const c = bun.c;
|
||||||
|
|
||||||
|
mode: bun.zlib.NodeMode = .NONE,
|
||||||
|
mode_: bun.zlib.NodeMode = .NONE,
|
||||||
|
state: ?*anyopaque = null,
|
||||||
|
flush: c_int = c.ZSTD_e_continue,
|
||||||
|
input: c.ZSTD_inBuffer = .{ .src = null, .size = 0, .pos = 0 },
|
||||||
|
output: c.ZSTD_outBuffer = .{ .dst = null, .size = 0, .pos = 0 },
|
||||||
|
pledged_src_size: u64 = std.math.maxInt(u64),
|
||||||
|
remaining: u64 = 0,
|
||||||
|
|
||||||
|
pub fn init(this: *Context, pledged_src_size: u64) Error {
|
||||||
|
switch (this.mode_) {
|
||||||
|
.ZSTD_COMPRESS => {
|
||||||
|
this.pledged_src_size = pledged_src_size;
|
||||||
|
const state = c.ZSTD_createCCtx();
|
||||||
|
if (state == null) return .init("Could not initialize zstd instance", -1, "ERR_ZLIB_INITIALIZATION_FAILED");
|
||||||
|
this.state = state.?;
|
||||||
|
const result = c.ZSTD_CCtx_setPledgedSrcSize(state, pledged_src_size);
|
||||||
|
if (c.ZSTD_isError(result) > 0) return .init("Could not set pledged src size", -1, "ERR_ZLIB_INITIALIZATION_FAILED");
|
||||||
|
return .ok;
|
||||||
|
},
|
||||||
|
.ZSTD_DECOMPRESS => {
|
||||||
|
const state = c.ZSTD_createDCtx();
|
||||||
|
if (state == null) return .init("Could not initialize zstd instance", -1, "ERR_ZLIB_INITIALIZATION_FAILED");
|
||||||
|
this.state = state.?;
|
||||||
|
return .ok;
|
||||||
|
},
|
||||||
|
else => @panic("unreachable"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setParams(this: *Context, key: c_uint, value: u32) Error {
|
||||||
|
switch (this.mode_) {
|
||||||
|
.ZSTD_COMPRESS => {
|
||||||
|
const result = c.ZSTD_CCtx_setParameter(@ptrCast(this.state), key, @bitCast(value));
|
||||||
|
if (c.ZSTD_isError(result) > 0) return .init("Setting parameter failed", -1, "ERR_ZSTD_PARAM_SET_FAILED");
|
||||||
|
return .ok;
|
||||||
|
},
|
||||||
|
.ZSTD_DECOMPRESS => {
|
||||||
|
const result = c.ZSTD_DCtx_setParameter(@ptrCast(this.state), key, @bitCast(value));
|
||||||
|
if (c.ZSTD_isError(result) > 0) return .init("Setting parameter failed", -1, "ERR_ZSTD_PARAM_SET_FAILED");
|
||||||
|
return .ok;
|
||||||
|
},
|
||||||
|
else => @panic("unreachable"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reset(this: *Context) Error {
|
||||||
|
return this.init(this.pledged_src_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setBuffers(this: *Context, in: ?[]const u8, out: ?[]u8) void {
|
||||||
|
this.input.src = if (in) |p| p.ptr else null;
|
||||||
|
this.input.size = if (in) |p| p.len else 0;
|
||||||
|
this.input.pos = 0;
|
||||||
|
this.output.dst = if (out) |p| p.ptr else null;
|
||||||
|
this.output.size = if (out) |p| p.len else 0;
|
||||||
|
this.output.pos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setFlush(this: *Context, flush: c_int) void {
|
||||||
|
this.flush = flush;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn doWork(this: *Context) void {
|
||||||
|
this.remaining = switch (this.mode_) {
|
||||||
|
.ZSTD_COMPRESS => c.ZSTD_compressStream2(@ptrCast(this.state), &this.output, &this.input, @intCast(this.flush)),
|
||||||
|
.ZSTD_DECOMPRESS => c.ZSTD_decompressStream(@ptrCast(this.state), &this.output, &this.input),
|
||||||
|
else => @panic("unreachable"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn updateWriteResult(this: *Context, avail_in: *u32, avail_out: *u32) void {
|
||||||
|
avail_in.* = @intCast(this.input.size - this.input.pos);
|
||||||
|
avail_out.* = @intCast(this.output.size - this.output.pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getErrorInfo(this: *Context) Error {
|
||||||
|
defer this.remaining = 0;
|
||||||
|
const err = c.ZSTD_getErrorCode(this.remaining);
|
||||||
|
if (err == 0) {
|
||||||
|
return .ok;
|
||||||
|
}
|
||||||
|
return Error{
|
||||||
|
.err = @intCast(err),
|
||||||
|
.msg = c.ZSTD_getErrorString(err),
|
||||||
|
.code = switch (err) {
|
||||||
|
c.ZSTD_error_no_error => "ZSTD_error_no_error",
|
||||||
|
c.ZSTD_error_GENERIC => "ZSTD_error_GENERIC",
|
||||||
|
c.ZSTD_error_prefix_unknown => "ZSTD_error_prefix_unknown",
|
||||||
|
c.ZSTD_error_version_unsupported => "ZSTD_error_version_unsupported",
|
||||||
|
c.ZSTD_error_frameParameter_unsupported => "ZSTD_error_frameParameter_unsupported",
|
||||||
|
c.ZSTD_error_frameParameter_windowTooLarge => "ZSTD_error_frameParameter_windowTooLarge",
|
||||||
|
c.ZSTD_error_corruption_detected => "ZSTD_error_corruption_detected",
|
||||||
|
c.ZSTD_error_checksum_wrong => "ZSTD_error_checksum_wrong",
|
||||||
|
c.ZSTD_error_literals_headerWrong => "ZSTD_error_literals_headerWrong",
|
||||||
|
c.ZSTD_error_dictionary_corrupted => "ZSTD_error_dictionary_corrupted",
|
||||||
|
c.ZSTD_error_dictionary_wrong => "ZSTD_error_dictionary_wrong",
|
||||||
|
c.ZSTD_error_dictionaryCreation_failed => "ZSTD_error_dictionaryCreation_failed",
|
||||||
|
c.ZSTD_error_parameter_unsupported => "ZSTD_error_parameter_unsupported",
|
||||||
|
c.ZSTD_error_parameter_combination_unsupported => "ZSTD_error_parameter_combination_unsupported",
|
||||||
|
c.ZSTD_error_parameter_outOfBound => "ZSTD_error_parameter_outOfBound",
|
||||||
|
c.ZSTD_error_tableLog_tooLarge => "ZSTD_error_tableLog_tooLarge",
|
||||||
|
c.ZSTD_error_maxSymbolValue_tooLarge => "ZSTD_error_maxSymbolValue_tooLarge",
|
||||||
|
c.ZSTD_error_maxSymbolValue_tooSmall => "ZSTD_error_maxSymbolValue_tooSmall",
|
||||||
|
c.ZSTD_error_stabilityCondition_notRespected => "ZSTD_error_stabilityCondition_notRespected",
|
||||||
|
c.ZSTD_error_stage_wrong => "ZSTD_error_stage_wrong",
|
||||||
|
c.ZSTD_error_init_missing => "ZSTD_error_init_missing",
|
||||||
|
c.ZSTD_error_memory_allocation => "ZSTD_error_memory_allocation",
|
||||||
|
c.ZSTD_error_workSpace_tooSmall => "ZSTD_error_workSpace_tooSmall",
|
||||||
|
c.ZSTD_error_dstSize_tooSmall => "ZSTD_error_dstSize_tooSmall",
|
||||||
|
c.ZSTD_error_srcSize_wrong => "ZSTD_error_srcSize_wrong",
|
||||||
|
c.ZSTD_error_dstBuffer_null => "ZSTD_error_dstBuffer_null",
|
||||||
|
c.ZSTD_error_noForwardProgress_destFull => "ZSTD_error_noForwardProgress_destFull",
|
||||||
|
c.ZSTD_error_noForwardProgress_inputEmpty => "ZSTD_error_noForwardProgress_inputEmpty",
|
||||||
|
else => "ZSTD_error_GENERIC",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn close(this: *Context) void {
|
||||||
|
_ = switch (this.mode_) {
|
||||||
|
.ZSTD_COMPRESS => c.ZSTD_CCtx_reset(@ptrCast(this.state), c.ZSTD_reset_session_and_parameters),
|
||||||
|
.ZSTD_DECOMPRESS => c.ZSTD_DCtx_reset(@ptrCast(this.state), c.ZSTD_reset_session_and_parameters),
|
||||||
|
else => unreachable,
|
||||||
|
};
|
||||||
|
_ = switch (this.mode_) {
|
||||||
|
.ZSTD_COMPRESS => c.ZSTD_freeCCtx(@ptrCast(this.state)),
|
||||||
|
.ZSTD_DECOMPRESS => c.ZSTD_freeDCtx(@ptrCast(this.state)),
|
||||||
|
else => unreachable,
|
||||||
|
};
|
||||||
|
this.mode = .NONE;
|
||||||
|
this.state = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -61,11 +61,9 @@
|
|||||||
#include <winternl.h>
|
#include <winternl.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if WINDOWS
|
|
||||||
#include <windows.h>
|
|
||||||
#include <winternl.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#undef lstat
|
#undef lstat
|
||||||
#undef fstat
|
#undef fstat
|
||||||
#undef stat
|
#undef stat
|
||||||
|
|
||||||
|
#include <zstd.h>
|
||||||
|
#include <zstd_errors.h>
|
||||||
|
|||||||
@@ -1,186 +1,6 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const bun = @import("bun");
|
const bun = @import("bun");
|
||||||
pub extern fn ZSTD_versionNumber() c_uint;
|
const c = bun.c;
|
||||||
pub extern fn ZSTD_versionString() [*c]const u8;
|
|
||||||
pub extern fn ZSTD_compress(dst: ?*anyopaque, dstCapacity: usize, src: ?*const anyopaque, srcSize: usize, compressionLevel: c_int) usize;
|
|
||||||
pub extern fn ZSTD_decompress(dst: ?*anyopaque, dstCapacity: usize, src: ?*const anyopaque, compressedSize: usize) usize;
|
|
||||||
pub extern fn ZSTD_getFrameContentSize(src: ?*const anyopaque, srcSize: usize) c_ulonglong;
|
|
||||||
pub extern fn ZSTD_getDecompressedSize(src: ?*const anyopaque, srcSize: usize) c_ulonglong;
|
|
||||||
pub extern fn ZSTD_findFrameCompressedSize(src: ?*const anyopaque, srcSize: usize) usize;
|
|
||||||
pub extern fn ZSTD_compressBound(srcSize: usize) usize;
|
|
||||||
pub extern fn ZSTD_isError(code: usize) c_uint;
|
|
||||||
pub extern fn ZSTD_getErrorName(code: usize) [*:0]const u8;
|
|
||||||
pub extern fn ZSTD_minCLevel() c_int;
|
|
||||||
pub extern fn ZSTD_maxCLevel() c_int;
|
|
||||||
pub extern fn ZSTD_defaultCLevel() c_int;
|
|
||||||
pub const struct_ZSTD_CCtx_s = opaque {};
|
|
||||||
pub const ZSTD_CCtx = struct_ZSTD_CCtx_s;
|
|
||||||
pub extern fn ZSTD_createCCtx() ?*ZSTD_CCtx;
|
|
||||||
pub extern fn ZSTD_freeCCtx(cctx: ?*ZSTD_CCtx) usize;
|
|
||||||
pub extern fn ZSTD_compressCCtx(cctx: ?*ZSTD_CCtx, dst: ?*anyopaque, dstCapacity: usize, src: ?*const anyopaque, srcSize: usize, compressionLevel: c_int) usize;
|
|
||||||
pub const struct_ZSTD_DCtx_s = opaque {};
|
|
||||||
pub const ZSTD_DCtx = struct_ZSTD_DCtx_s;
|
|
||||||
pub extern fn ZSTD_createDCtx() ?*ZSTD_DCtx;
|
|
||||||
pub extern fn ZSTD_freeDCtx(dctx: ?*ZSTD_DCtx) usize;
|
|
||||||
pub extern fn ZSTD_decompressDCtx(dctx: ?*ZSTD_DCtx, dst: ?*anyopaque, dstCapacity: usize, src: ?*const anyopaque, srcSize: usize) usize;
|
|
||||||
pub const ZSTD_fast: c_int = 1;
|
|
||||||
pub const ZSTD_dfast: c_int = 2;
|
|
||||||
pub const ZSTD_greedy: c_int = 3;
|
|
||||||
pub const ZSTD_lazy: c_int = 4;
|
|
||||||
pub const ZSTD_lazy2: c_int = 5;
|
|
||||||
pub const ZSTD_btlazy2: c_int = 6;
|
|
||||||
pub const ZSTD_btopt: c_int = 7;
|
|
||||||
pub const ZSTD_btultra: c_int = 8;
|
|
||||||
pub const ZSTD_btultra2: c_int = 9;
|
|
||||||
pub const ZSTD_strategy = c_uint;
|
|
||||||
pub const ZSTD_c_compressionLevel: c_int = 100;
|
|
||||||
pub const ZSTD_c_windowLog: c_int = 101;
|
|
||||||
pub const ZSTD_c_hashLog: c_int = 102;
|
|
||||||
pub const ZSTD_c_chainLog: c_int = 103;
|
|
||||||
pub const ZSTD_c_searchLog: c_int = 104;
|
|
||||||
pub const ZSTD_c_minMatch: c_int = 105;
|
|
||||||
pub const ZSTD_c_targetLength: c_int = 106;
|
|
||||||
pub const ZSTD_c_strategy: c_int = 107;
|
|
||||||
pub const ZSTD_c_enableLongDistanceMatching: c_int = 160;
|
|
||||||
pub const ZSTD_c_ldmHashLog: c_int = 161;
|
|
||||||
pub const ZSTD_c_ldmMinMatch: c_int = 162;
|
|
||||||
pub const ZSTD_c_ldmBucketSizeLog: c_int = 163;
|
|
||||||
pub const ZSTD_c_ldmHashRateLog: c_int = 164;
|
|
||||||
pub const ZSTD_c_contentSizeFlag: c_int = 200;
|
|
||||||
pub const ZSTD_c_checksumFlag: c_int = 201;
|
|
||||||
pub const ZSTD_c_dictIDFlag: c_int = 202;
|
|
||||||
pub const ZSTD_c_nbWorkers: c_int = 400;
|
|
||||||
pub const ZSTD_c_jobSize: c_int = 401;
|
|
||||||
pub const ZSTD_c_overlapLog: c_int = 402;
|
|
||||||
pub const ZSTD_c_experimentalParam1: c_int = 500;
|
|
||||||
pub const ZSTD_c_experimentalParam2: c_int = 10;
|
|
||||||
pub const ZSTD_c_experimentalParam3: c_int = 1000;
|
|
||||||
pub const ZSTD_c_experimentalParam4: c_int = 1001;
|
|
||||||
pub const ZSTD_c_experimentalParam5: c_int = 1002;
|
|
||||||
pub const ZSTD_c_experimentalParam6: c_int = 1003;
|
|
||||||
pub const ZSTD_c_experimentalParam7: c_int = 1004;
|
|
||||||
pub const ZSTD_c_experimentalParam8: c_int = 1005;
|
|
||||||
pub const ZSTD_c_experimentalParam9: c_int = 1006;
|
|
||||||
pub const ZSTD_c_experimentalParam10: c_int = 1007;
|
|
||||||
pub const ZSTD_c_experimentalParam11: c_int = 1008;
|
|
||||||
pub const ZSTD_c_experimentalParam12: c_int = 1009;
|
|
||||||
pub const ZSTD_c_experimentalParam13: c_int = 1010;
|
|
||||||
pub const ZSTD_c_experimentalParam14: c_int = 1011;
|
|
||||||
pub const ZSTD_c_experimentalParam15: c_int = 1012;
|
|
||||||
pub const ZSTD_c_experimentalParam16: c_int = 1013;
|
|
||||||
pub const ZSTD_c_experimentalParam17: c_int = 1014;
|
|
||||||
pub const ZSTD_c_experimentalParam18: c_int = 1015;
|
|
||||||
pub const ZSTD_c_experimentalParam19: c_int = 1016;
|
|
||||||
pub const ZSTD_cParameter = c_uint;
|
|
||||||
pub const ZSTD_bounds = extern struct {
|
|
||||||
@"error": usize,
|
|
||||||
lowerBound: c_int,
|
|
||||||
upperBound: c_int,
|
|
||||||
};
|
|
||||||
pub extern fn ZSTD_cParam_getBounds(cParam: ZSTD_cParameter) ZSTD_bounds;
|
|
||||||
pub extern fn ZSTD_CCtx_setParameter(cctx: ?*ZSTD_CCtx, param: ZSTD_cParameter, value: c_int) usize;
|
|
||||||
pub extern fn ZSTD_CCtx_setPledgedSrcSize(cctx: ?*ZSTD_CCtx, pledgedSrcSize: c_ulonglong) usize;
|
|
||||||
pub const ZSTD_reset_session_only: c_int = 1;
|
|
||||||
pub const ZSTD_reset_parameters: c_int = 2;
|
|
||||||
pub const ZSTD_reset_session_and_parameters: c_int = 3;
|
|
||||||
pub const ZSTD_ResetDirective = c_uint;
|
|
||||||
pub extern fn ZSTD_CCtx_reset(cctx: ?*ZSTD_CCtx, reset: ZSTD_ResetDirective) usize;
|
|
||||||
pub extern fn ZSTD_compress2(cctx: ?*ZSTD_CCtx, dst: ?*anyopaque, dstCapacity: usize, src: ?*const anyopaque, srcSize: usize) usize;
|
|
||||||
pub const ZSTD_d_windowLogMax: c_int = 100;
|
|
||||||
pub const ZSTD_d_experimentalParam1: c_int = 1000;
|
|
||||||
pub const ZSTD_d_experimentalParam2: c_int = 1001;
|
|
||||||
pub const ZSTD_d_experimentalParam3: c_int = 1002;
|
|
||||||
pub const ZSTD_d_experimentalParam4: c_int = 1003;
|
|
||||||
pub const ZSTD_d_experimentalParam5: c_int = 1004;
|
|
||||||
pub const ZSTD_dParameter = c_uint;
|
|
||||||
pub extern fn ZSTD_dParam_getBounds(dParam: ZSTD_dParameter) ZSTD_bounds;
|
|
||||||
pub extern fn ZSTD_DCtx_setParameter(dctx: ?*ZSTD_DCtx, param: ZSTD_dParameter, value: c_int) usize;
|
|
||||||
pub extern fn ZSTD_DCtx_reset(dctx: ?*ZSTD_DCtx, reset: ZSTD_ResetDirective) usize;
|
|
||||||
pub const struct_ZSTD_inBuffer_s = extern struct {
|
|
||||||
src: ?*const anyopaque,
|
|
||||||
size: usize,
|
|
||||||
pos: usize,
|
|
||||||
};
|
|
||||||
pub const ZSTD_inBuffer = struct_ZSTD_inBuffer_s;
|
|
||||||
pub const struct_ZSTD_outBuffer_s = extern struct {
|
|
||||||
dst: ?*anyopaque,
|
|
||||||
size: usize,
|
|
||||||
pos: usize,
|
|
||||||
};
|
|
||||||
pub const ZSTD_outBuffer = struct_ZSTD_outBuffer_s;
|
|
||||||
pub const ZSTD_CStream = ZSTD_CCtx;
|
|
||||||
pub extern fn ZSTD_createCStream() ?*ZSTD_CStream;
|
|
||||||
pub extern fn ZSTD_freeCStream(zcs: ?*ZSTD_CStream) usize;
|
|
||||||
pub const ZSTD_e_continue: c_int = 0;
|
|
||||||
pub const ZSTD_e_flush: c_int = 1;
|
|
||||||
pub const ZSTD_e_end: c_int = 2;
|
|
||||||
pub const ZSTD_EndDirective = c_uint;
|
|
||||||
pub extern fn ZSTD_compressStream2(cctx: ?*ZSTD_CCtx, output: [*c]ZSTD_outBuffer, input: [*c]ZSTD_inBuffer, endOp: ZSTD_EndDirective) usize;
|
|
||||||
pub extern fn ZSTD_CStreamInSize() usize;
|
|
||||||
pub extern fn ZSTD_CStreamOutSize() usize;
|
|
||||||
pub extern fn ZSTD_initCStream(zcs: ?*ZSTD_CStream, compressionLevel: c_int) usize;
|
|
||||||
pub extern fn ZSTD_compressStream(zcs: ?*ZSTD_CStream, output: [*c]ZSTD_outBuffer, input: [*c]ZSTD_inBuffer) usize;
|
|
||||||
pub extern fn ZSTD_flushStream(zcs: ?*ZSTD_CStream, output: [*c]ZSTD_outBuffer) usize;
|
|
||||||
pub extern fn ZSTD_endStream(zcs: ?*ZSTD_CStream, output: [*c]ZSTD_outBuffer) usize;
|
|
||||||
pub const ZSTD_DStream = ZSTD_DCtx;
|
|
||||||
pub extern fn ZSTD_createDStream() ?*ZSTD_DStream;
|
|
||||||
pub extern fn ZSTD_freeDStream(zds: ?*ZSTD_DStream) usize;
|
|
||||||
pub extern fn ZSTD_initDStream(zds: ?*ZSTD_DStream) usize;
|
|
||||||
pub extern fn ZSTD_decompressStream(zds: ?*ZSTD_DStream, output: [*c]ZSTD_outBuffer, input: [*c]ZSTD_inBuffer) usize;
|
|
||||||
pub extern fn ZSTD_DStreamInSize() usize;
|
|
||||||
pub extern fn ZSTD_DStreamOutSize() usize;
|
|
||||||
pub extern fn ZSTD_compress_usingDict(ctx: ?*ZSTD_CCtx, dst: ?*anyopaque, dstCapacity: usize, src: ?*const anyopaque, srcSize: usize, dict: ?*const anyopaque, dictSize: usize, compressionLevel: c_int) usize;
|
|
||||||
pub extern fn ZSTD_decompress_usingDict(dctx: ?*ZSTD_DCtx, dst: ?*anyopaque, dstCapacity: usize, src: ?*const anyopaque, srcSize: usize, dict: ?*const anyopaque, dictSize: usize) usize;
|
|
||||||
pub const struct_ZSTD_CDict_s = opaque {};
|
|
||||||
pub const ZSTD_CDict = struct_ZSTD_CDict_s;
|
|
||||||
pub extern fn ZSTD_createCDict(dictBuffer: ?*const anyopaque, dictSize: usize, compressionLevel: c_int) ?*ZSTD_CDict;
|
|
||||||
pub extern fn ZSTD_freeCDict(CDict: ?*ZSTD_CDict) usize;
|
|
||||||
pub extern fn ZSTD_compress_usingCDict(cctx: ?*ZSTD_CCtx, dst: ?*anyopaque, dstCapacity: usize, src: ?*const anyopaque, srcSize: usize, cdict: ?*const ZSTD_CDict) usize;
|
|
||||||
pub const struct_ZSTD_DDict_s = opaque {};
|
|
||||||
pub const ZSTD_DDict = struct_ZSTD_DDict_s;
|
|
||||||
pub extern fn ZSTD_createDDict(dictBuffer: ?*const anyopaque, dictSize: usize) ?*ZSTD_DDict;
|
|
||||||
pub extern fn ZSTD_freeDDict(ddict: ?*ZSTD_DDict) usize;
|
|
||||||
pub extern fn ZSTD_decompress_usingDDict(dctx: ?*ZSTD_DCtx, dst: ?*anyopaque, dstCapacity: usize, src: ?*const anyopaque, srcSize: usize, ddict: ?*const ZSTD_DDict) usize;
|
|
||||||
pub extern fn ZSTD_getDictID_fromDict(dict: ?*const anyopaque, dictSize: usize) c_uint;
|
|
||||||
pub extern fn ZSTD_getDictID_fromCDict(cdict: ?*const ZSTD_CDict) c_uint;
|
|
||||||
pub extern fn ZSTD_getDictID_fromDDict(ddict: ?*const ZSTD_DDict) c_uint;
|
|
||||||
pub extern fn ZSTD_getDictID_fromFrame(src: ?*const anyopaque, srcSize: usize) c_uint;
|
|
||||||
pub extern fn ZSTD_CCtx_loadDictionary(cctx: ?*ZSTD_CCtx, dict: ?*const anyopaque, dictSize: usize) usize;
|
|
||||||
pub extern fn ZSTD_CCtx_refCDict(cctx: ?*ZSTD_CCtx, cdict: ?*const ZSTD_CDict) usize;
|
|
||||||
pub extern fn ZSTD_CCtx_refPrefix(cctx: ?*ZSTD_CCtx, prefix: ?*const anyopaque, prefixSize: usize) usize;
|
|
||||||
pub extern fn ZSTD_DCtx_loadDictionary(dctx: ?*ZSTD_DCtx, dict: ?*const anyopaque, dictSize: usize) usize;
|
|
||||||
pub extern fn ZSTD_DCtx_refDDict(dctx: ?*ZSTD_DCtx, ddict: ?*const ZSTD_DDict) usize;
|
|
||||||
pub extern fn ZSTD_DCtx_refPrefix(dctx: ?*ZSTD_DCtx, prefix: ?*const anyopaque, prefixSize: usize) usize;
|
|
||||||
pub extern fn ZSTD_sizeof_CCtx(cctx: ?*const ZSTD_CCtx) usize;
|
|
||||||
pub extern fn ZSTD_sizeof_DCtx(dctx: ?*const ZSTD_DCtx) usize;
|
|
||||||
pub extern fn ZSTD_sizeof_CStream(zcs: ?*const ZSTD_CStream) usize;
|
|
||||||
pub extern fn ZSTD_sizeof_DStream(zds: ?*const ZSTD_DStream) usize;
|
|
||||||
pub extern fn ZSTD_sizeof_CDict(cdict: ?*const ZSTD_CDict) usize;
|
|
||||||
pub extern fn ZSTD_sizeof_DDict(ddict: ?*const ZSTD_DDict) usize;
|
|
||||||
pub const ZSTD_VERSION_MAJOR = @as(c_int, 1);
|
|
||||||
pub const ZSTD_VERSION_MINOR = @as(c_int, 5);
|
|
||||||
pub const ZSTD_VERSION_RELEASE = @as(c_int, 5);
|
|
||||||
pub const ZSTD_VERSION_NUMBER = (((ZSTD_VERSION_MAJOR * @as(c_int, 100)) * @as(c_int, 100)) + (ZSTD_VERSION_MINOR * @as(c_int, 100))) + ZSTD_VERSION_RELEASE;
|
|
||||||
pub const ZSTD_LIB_VERSION = ZSTD_VERSION_MAJOR.ZSTD_VERSION_MINOR.ZSTD_VERSION_RELEASE;
|
|
||||||
pub const ZSTD_CLEVEL_DEFAULT = @as(c_int, 3);
|
|
||||||
pub const ZSTD_MAGICNUMBER = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0xFD2FB528, .hex);
|
|
||||||
pub const ZSTD_MAGIC_DICTIONARY = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0xEC30A437, .hex);
|
|
||||||
pub const ZSTD_MAGIC_SKIPPABLE_START = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x184D2A50, .hex);
|
|
||||||
pub const ZSTD_MAGIC_SKIPPABLE_MASK = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0xFFFFFFF0, .hex);
|
|
||||||
pub const ZSTD_BLOCKSIZELOG_MAX = @as(c_int, 17);
|
|
||||||
pub const ZSTD_BLOCKSIZE_MAX = @as(c_int, 1) << ZSTD_BLOCKSIZELOG_MAX;
|
|
||||||
pub const ZSTD_CONTENTSIZE_UNKNOWN = @as(c_ulonglong, 0) - @as(c_int, 1);
|
|
||||||
pub const ZSTD_CONTENTSIZE_ERROR = @as(c_ulonglong, 0) - @as(c_int, 2);
|
|
||||||
pub const ZSTD_MAX_INPUT_SIZE = if (@import("std").zig.c_translation.sizeof(usize) == @as(c_int, 8)) @as(c_ulonglong, 0xFF00FF00FF00FF00) else @import("std").zig.c_translation.promoteIntLiteral(c_uint, 0xFF00FF00, .hex);
|
|
||||||
pub inline fn ZSTD_COMPRESSBOUND(srcSize: anytype) @TypeOf(if (@import("std").zig.c_translation.cast(usize, srcSize) >= ZSTD_MAX_INPUT_SIZE) @as(c_int, 0) else (srcSize + (srcSize >> @as(c_int, 8))) + (if (srcSize < (@as(c_int, 128) << @as(c_int, 10))) ((@as(c_int, 128) << @as(c_int, 10)) - srcSize) >> @as(c_int, 11) else @as(c_int, 0))) {
|
|
||||||
return if (@import("std").zig.c_translation.cast(usize, srcSize) >= ZSTD_MAX_INPUT_SIZE) @as(c_int, 0) else (srcSize + (srcSize >> @as(c_int, 8))) + (if (srcSize < (@as(c_int, 128) << @as(c_int, 10))) ((@as(c_int, 128) << @as(c_int, 10)) - srcSize) >> @as(c_int, 11) else @as(c_int, 0));
|
|
||||||
}
|
|
||||||
pub const ZSTD_CCtx_s = struct_ZSTD_CCtx_s;
|
|
||||||
pub const ZSTD_DCtx_s = struct_ZSTD_DCtx_s;
|
|
||||||
pub const ZSTD_inBuffer_s = struct_ZSTD_inBuffer_s;
|
|
||||||
pub const ZSTD_outBuffer_s = struct_ZSTD_outBuffer_s;
|
|
||||||
pub const ZSTD_CDict_s = struct_ZSTD_CDict_s;
|
|
||||||
pub const ZSTD_DDict_s = struct_ZSTD_DDict_s;
|
|
||||||
|
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
|
|
||||||
@@ -194,13 +14,13 @@ pub const ZSTD_DDict_s = struct_ZSTD_DDict_s;
|
|||||||
// const void* src, size_t srcSize,
|
// const void* src, size_t srcSize,
|
||||||
// int compressionLevel);
|
// int compressionLevel);
|
||||||
pub fn compress(dest: []u8, src: []const u8, level: ?i32) Result {
|
pub fn compress(dest: []u8, src: []const u8, level: ?i32) Result {
|
||||||
const result = ZSTD_compress(dest.ptr, dest.len, src.ptr, src.len, level orelse ZSTD_defaultCLevel());
|
const result = c.ZSTD_compress(dest.ptr, dest.len, src.ptr, src.len, level orelse c.ZSTD_defaultCLevel());
|
||||||
if (ZSTD_isError(result) != 0) return .{ .err = bun.sliceTo(ZSTD_getErrorName(result), 0) };
|
if (c.ZSTD_isError(result) != 0) return .{ .err = bun.sliceTo(c.ZSTD_getErrorName(result), 0) };
|
||||||
return .{ .success = result };
|
return .{ .success = result };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compressBound(srcSize: usize) usize {
|
pub fn compressBound(srcSize: usize) usize {
|
||||||
return ZSTD_compressBound(srcSize);
|
return c.ZSTD_compressBound(srcSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ZSTD_decompress() :
|
/// ZSTD_decompress() :
|
||||||
@@ -212,8 +32,8 @@ pub fn compressBound(srcSize: usize) usize {
|
|||||||
// ZSTDLIB_API size_t ZSTD_decompress( void* dst, size_t dstCapacity,
|
// ZSTDLIB_API size_t ZSTD_decompress( void* dst, size_t dstCapacity,
|
||||||
// const void* src, size_t compressedSize);
|
// const void* src, size_t compressedSize);
|
||||||
pub fn decompress(dest: []u8, src: []const u8) Result {
|
pub fn decompress(dest: []u8, src: []const u8) Result {
|
||||||
const result = ZSTD_decompress(dest.ptr, dest.len, src.ptr, src.len);
|
const result = c.ZSTD_decompress(dest.ptr, dest.len, src.ptr, src.len);
|
||||||
if (ZSTD_isError(result) != 0) return .{ .err = bun.sliceTo(ZSTD_getErrorName(result), 0) };
|
if (c.ZSTD_isError(result) != 0) return .{ .err = bun.sliceTo(c.ZSTD_getErrorName(result), 0) };
|
||||||
return .{ .success = result };
|
return .{ .success = result };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,7 +82,7 @@ pub const ZstdReaderArrayList = struct {
|
|||||||
list_allocator: std.mem.Allocator,
|
list_allocator: std.mem.Allocator,
|
||||||
list_ptr: *std.ArrayListUnmanaged(u8),
|
list_ptr: *std.ArrayListUnmanaged(u8),
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
zstd: *ZSTD_DStream,
|
zstd: *c.ZSTD_DStream,
|
||||||
state: State = State.Uninitialized,
|
state: State = State.Uninitialized,
|
||||||
total_out: usize = 0,
|
total_out: usize = 0,
|
||||||
total_in: usize = 0,
|
total_in: usize = 0,
|
||||||
@@ -293,17 +113,17 @@ pub const ZstdReaderArrayList = struct {
|
|||||||
.zstd = undefined,
|
.zstd = undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
reader.zstd = ZSTD_createDStream() orelse {
|
reader.zstd = c.ZSTD_createDStream() orelse {
|
||||||
allocator.destroy(reader);
|
allocator.destroy(reader);
|
||||||
return error.ZstdFailedToCreateInstance;
|
return error.ZstdFailedToCreateInstance;
|
||||||
};
|
};
|
||||||
_ = ZSTD_initDStream(reader.zstd);
|
_ = c.ZSTD_initDStream(reader.zstd);
|
||||||
return reader;
|
return reader;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn end(this: *ZstdReaderArrayList) void {
|
pub fn end(this: *ZstdReaderArrayList) void {
|
||||||
if (this.state != .End) {
|
if (this.state != .End) {
|
||||||
_ = ZSTD_freeDStream(this.zstd);
|
_ = c.ZSTD_freeDStream(this.zstd);
|
||||||
this.state = .End;
|
this.state = .End;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -327,19 +147,19 @@ pub const ZstdReaderArrayList = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const next_in = this.input[this.total_in..];
|
const next_in = this.input[this.total_in..];
|
||||||
var in_buf = ZSTD_inBuffer{
|
var in_buf: c.ZSTD_inBuffer = .{
|
||||||
.src = if (next_in.len > 0) next_in.ptr else null,
|
.src = if (next_in.len > 0) next_in.ptr else null,
|
||||||
.size = next_in.len,
|
.size = next_in.len,
|
||||||
.pos = 0,
|
.pos = 0,
|
||||||
};
|
};
|
||||||
var out_buf = ZSTD_outBuffer{
|
var out_buf: c.ZSTD_outBuffer = .{
|
||||||
.dst = if (unused.len > 0) unused.ptr else null,
|
.dst = if (unused.len > 0) unused.ptr else null,
|
||||||
.size = unused.len,
|
.size = unused.len,
|
||||||
.pos = 0,
|
.pos = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
const rc = ZSTD_decompressStream(this.zstd, &out_buf, &in_buf);
|
const rc = c.ZSTD_decompressStream(this.zstd, &out_buf, &in_buf);
|
||||||
if (ZSTD_isError(rc) != 0) {
|
if (c.ZSTD_isError(rc) != 0) {
|
||||||
this.state = .Error;
|
this.state = .Error;
|
||||||
return error.ZstdDecompressionError;
|
return error.ZstdDecompressionError;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ const BufferModule = require("node:buffer");
|
|||||||
const crc32 = $newZigFunction("node_zlib_binding.zig", "crc32", 1);
|
const crc32 = $newZigFunction("node_zlib_binding.zig", "crc32", 1);
|
||||||
const NativeZlib = $zig("node_zlib_binding.zig", "NativeZlib");
|
const NativeZlib = $zig("node_zlib_binding.zig", "NativeZlib");
|
||||||
const NativeBrotli = $zig("node_zlib_binding.zig", "NativeBrotli");
|
const NativeBrotli = $zig("node_zlib_binding.zig", "NativeBrotli");
|
||||||
|
const NativeZstd = $zig("node_zlib_binding.zig", "NativeZstd");
|
||||||
|
|
||||||
const ObjectKeys = Object.keys;
|
const ObjectKeys = Object.keys;
|
||||||
const ArrayPrototypePush = Array.prototype.push;
|
const ArrayPrototypePush = Array.prototype.push;
|
||||||
@@ -15,6 +16,7 @@ const ObjectFreeze = Object.freeze;
|
|||||||
const TypedArrayPrototypeFill = Uint8Array.prototype.fill;
|
const TypedArrayPrototypeFill = Uint8Array.prototype.fill;
|
||||||
const ArrayPrototypeForEach = Array.prototype.forEach;
|
const ArrayPrototypeForEach = Array.prototype.forEach;
|
||||||
const NumberIsNaN = Number.isNaN;
|
const NumberIsNaN = Number.isNaN;
|
||||||
|
const MathMax = Math.max;
|
||||||
|
|
||||||
const ArrayBufferIsView = ArrayBuffer.isView;
|
const ArrayBufferIsView = ArrayBuffer.isView;
|
||||||
const isArrayBufferView = ArrayBufferIsView;
|
const isArrayBufferView = ArrayBufferIsView;
|
||||||
@@ -37,9 +39,11 @@ const {
|
|||||||
Z_MIN_CHUNK, Z_MIN_WINDOWBITS, Z_MAX_WINDOWBITS, Z_MIN_LEVEL, Z_MAX_LEVEL, Z_MIN_MEMLEVEL, Z_MAX_MEMLEVEL,
|
Z_MIN_CHUNK, Z_MIN_WINDOWBITS, Z_MAX_WINDOWBITS, Z_MIN_LEVEL, Z_MAX_LEVEL, Z_MIN_MEMLEVEL, Z_MAX_MEMLEVEL,
|
||||||
Z_DEFAULT_CHUNK, Z_DEFAULT_COMPRESSION, Z_DEFAULT_STRATEGY, Z_DEFAULT_WINDOWBITS, Z_DEFAULT_MEMLEVEL, Z_FIXED,
|
Z_DEFAULT_CHUNK, Z_DEFAULT_COMPRESSION, Z_DEFAULT_STRATEGY, Z_DEFAULT_WINDOWBITS, Z_DEFAULT_MEMLEVEL, Z_FIXED,
|
||||||
// Node's compression stream modes (node_zlib_mode)
|
// Node's compression stream modes (node_zlib_mode)
|
||||||
DEFLATE, DEFLATERAW, INFLATE, INFLATERAW, GZIP, GUNZIP, UNZIP, BROTLI_DECODE, BROTLI_ENCODE,
|
DEFLATE, DEFLATERAW, INFLATE, INFLATERAW, GZIP, GUNZIP, UNZIP, BROTLI_DECODE, BROTLI_ENCODE, ZSTD_COMPRESS, ZSTD_DECOMPRESS,
|
||||||
// Brotli operations (~flush levels)
|
// Brotli operations (~flush levels)
|
||||||
BROTLI_OPERATION_PROCESS, BROTLI_OPERATION_FLUSH, BROTLI_OPERATION_FINISH, BROTLI_OPERATION_EMIT_METADATA,
|
BROTLI_OPERATION_PROCESS, BROTLI_OPERATION_FLUSH, BROTLI_OPERATION_FINISH, BROTLI_OPERATION_EMIT_METADATA,
|
||||||
|
// Zstd end directives (~flush levels)
|
||||||
|
ZSTD_e_continue, ZSTD_e_flush, ZSTD_e_end,
|
||||||
} = constants;
|
} = constants;
|
||||||
|
|
||||||
// Translation table for return codes.
|
// Translation table for return codes.
|
||||||
@@ -132,9 +136,11 @@ function zlibOnError(message, errno, code) {
|
|||||||
const FLUSH_BOUND = [
|
const FLUSH_BOUND = [
|
||||||
[Z_NO_FLUSH, Z_BLOCK],
|
[Z_NO_FLUSH, Z_BLOCK],
|
||||||
[BROTLI_OPERATION_PROCESS, BROTLI_OPERATION_EMIT_METADATA],
|
[BROTLI_OPERATION_PROCESS, BROTLI_OPERATION_EMIT_METADATA],
|
||||||
|
[ZSTD_e_continue, ZSTD_e_end],
|
||||||
];
|
];
|
||||||
const FLUSH_BOUND_IDX_NORMAL = 0;
|
const FLUSH_BOUND_IDX_NORMAL = 0;
|
||||||
const FLUSH_BOUND_IDX_BROTLI = 1;
|
const FLUSH_BOUND_IDX_BROTLI = 1;
|
||||||
|
const FLUSH_BOUND_IDX_ZSTD = 2;
|
||||||
|
|
||||||
// The base class for all Zlib-style streams.
|
// The base class for all Zlib-style streams.
|
||||||
function ZlibBase(opts, mode, handle, { flush, finishFlush, fullFlush }) {
|
function ZlibBase(opts, mode, handle, { flush, finishFlush, fullFlush }) {
|
||||||
@@ -142,13 +148,15 @@ function ZlibBase(opts, mode, handle, { flush, finishFlush, fullFlush }) {
|
|||||||
let maxOutputLength = kMaxLength;
|
let maxOutputLength = kMaxLength;
|
||||||
// The ZlibBase class is not exported to user land, the mode should only be passed in by us.
|
// The ZlibBase class is not exported to user land, the mode should only be passed in by us.
|
||||||
assert(typeof mode === "number");
|
assert(typeof mode === "number");
|
||||||
assert(mode >= DEFLATE && mode <= BROTLI_ENCODE);
|
assert(mode >= DEFLATE && mode <= ZSTD_DECOMPRESS);
|
||||||
|
|
||||||
let flushBoundIdx;
|
let flushBoundIdx;
|
||||||
if (mode !== BROTLI_ENCODE && mode !== BROTLI_DECODE) {
|
if (mode === BROTLI_ENCODE || mode === BROTLI_DECODE) {
|
||||||
flushBoundIdx = FLUSH_BOUND_IDX_NORMAL;
|
|
||||||
} else {
|
|
||||||
flushBoundIdx = FLUSH_BOUND_IDX_BROTLI;
|
flushBoundIdx = FLUSH_BOUND_IDX_BROTLI;
|
||||||
|
} else if (mode === ZSTD_COMPRESS || mode === ZSTD_DECOMPRESS) {
|
||||||
|
flushBoundIdx = FLUSH_BOUND_IDX_ZSTD;
|
||||||
|
} else {
|
||||||
|
flushBoundIdx = FLUSH_BOUND_IDX_NORMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts) {
|
if (opts) {
|
||||||
@@ -592,44 +600,44 @@ Zlib.prototype.params = function params(level, strategy, callback) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function Deflate(opts) {
|
function Deflate(opts): void {
|
||||||
if (!(this instanceof Deflate)) return new Deflate(opts);
|
if (!(this instanceof Deflate)) return new Deflate(opts);
|
||||||
Zlib.$apply(this, [opts, DEFLATE]);
|
Zlib.$apply(this, [opts, DEFLATE]);
|
||||||
}
|
}
|
||||||
$toClass(Deflate, "Deflate", Zlib);
|
$toClass(Deflate, "Deflate", Zlib);
|
||||||
|
|
||||||
function Inflate(opts) {
|
function Inflate(opts): void {
|
||||||
if (!(this instanceof Inflate)) return new Inflate(opts);
|
if (!(this instanceof Inflate)) return new Inflate(opts);
|
||||||
Zlib.$apply(this, [opts, INFLATE]);
|
Zlib.$apply(this, [opts, INFLATE]);
|
||||||
}
|
}
|
||||||
$toClass(Inflate, "Inflate", Zlib);
|
$toClass(Inflate, "Inflate", Zlib);
|
||||||
|
|
||||||
function Gzip(opts) {
|
function Gzip(opts): void {
|
||||||
if (!(this instanceof Gzip)) return new Gzip(opts);
|
if (!(this instanceof Gzip)) return new Gzip(opts);
|
||||||
Zlib.$apply(this, [opts, GZIP]);
|
Zlib.$apply(this, [opts, GZIP]);
|
||||||
}
|
}
|
||||||
$toClass(Gzip, "Gzip", Zlib);
|
$toClass(Gzip, "Gzip", Zlib);
|
||||||
|
|
||||||
function Gunzip(opts) {
|
function Gunzip(opts): void {
|
||||||
if (!(this instanceof Gunzip)) return new Gunzip(opts);
|
if (!(this instanceof Gunzip)) return new Gunzip(opts);
|
||||||
Zlib.$apply(this, [opts, GUNZIP]);
|
Zlib.$apply(this, [opts, GUNZIP]);
|
||||||
}
|
}
|
||||||
$toClass(Gunzip, "Gunzip", Zlib);
|
$toClass(Gunzip, "Gunzip", Zlib);
|
||||||
|
|
||||||
function DeflateRaw(opts) {
|
function DeflateRaw(opts): void {
|
||||||
if (opts && opts.windowBits === 8) opts.windowBits = 9;
|
if (opts && opts.windowBits === 8) opts.windowBits = 9;
|
||||||
if (!(this instanceof DeflateRaw)) return new DeflateRaw(opts);
|
if (!(this instanceof DeflateRaw)) return new DeflateRaw(opts);
|
||||||
Zlib.$apply(this, [opts, DEFLATERAW]);
|
Zlib.$apply(this, [opts, DEFLATERAW]);
|
||||||
}
|
}
|
||||||
$toClass(DeflateRaw, "DeflateRaw", Zlib);
|
$toClass(DeflateRaw, "DeflateRaw", Zlib);
|
||||||
|
|
||||||
function InflateRaw(opts) {
|
function InflateRaw(opts): void {
|
||||||
if (!(this instanceof InflateRaw)) return new InflateRaw(opts);
|
if (!(this instanceof InflateRaw)) return new InflateRaw(opts);
|
||||||
Zlib.$apply(this, [opts, INFLATERAW]);
|
Zlib.$apply(this, [opts, INFLATERAW]);
|
||||||
}
|
}
|
||||||
$toClass(InflateRaw, "InflateRaw", Zlib);
|
$toClass(InflateRaw, "InflateRaw", Zlib);
|
||||||
|
|
||||||
function Unzip(opts) {
|
function Unzip(opts): void {
|
||||||
if (!(this instanceof Unzip)) return new Unzip(opts);
|
if (!(this instanceof Unzip)) return new Unzip(opts);
|
||||||
Zlib.$apply(this, [opts, UNZIP]);
|
Zlib.$apply(this, [opts, UNZIP]);
|
||||||
}
|
}
|
||||||
@@ -694,18 +702,75 @@ function Brotli(opts, mode) {
|
|||||||
}
|
}
|
||||||
$toClass(Brotli, "Brotli", Zlib);
|
$toClass(Brotli, "Brotli", Zlib);
|
||||||
|
|
||||||
function BrotliCompress(opts) {
|
function BrotliCompress(opts): void {
|
||||||
if (!(this instanceof BrotliCompress)) return new BrotliCompress(opts);
|
if (!(this instanceof BrotliCompress)) return new BrotliCompress(opts);
|
||||||
Brotli.$apply(this, [opts, BROTLI_ENCODE]);
|
Brotli.$apply(this, [opts, BROTLI_ENCODE]);
|
||||||
}
|
}
|
||||||
$toClass(BrotliCompress, "BrotliCompress", Brotli);
|
$toClass(BrotliCompress, "BrotliCompress", Brotli);
|
||||||
|
|
||||||
function BrotliDecompress(opts) {
|
function BrotliDecompress(opts): void {
|
||||||
if (!(this instanceof BrotliDecompress)) return new BrotliDecompress(opts);
|
if (!(this instanceof BrotliDecompress)) return new BrotliDecompress(opts);
|
||||||
Brotli.$apply(this, [opts, BROTLI_DECODE]);
|
Brotli.$apply(this, [opts, BROTLI_DECODE]);
|
||||||
}
|
}
|
||||||
$toClass(BrotliDecompress, "BrotliDecompress", Brotli);
|
$toClass(BrotliDecompress, "BrotliDecompress", Brotli);
|
||||||
|
|
||||||
|
const zstdDefaultOpts = {
|
||||||
|
flush: ZSTD_e_continue,
|
||||||
|
finishFlush: ZSTD_e_end,
|
||||||
|
fullFlush: ZSTD_e_flush,
|
||||||
|
};
|
||||||
|
|
||||||
|
class Zstd extends ZlibBase {
|
||||||
|
constructor(opts, mode, initParamsArray, maxParam) {
|
||||||
|
assert(mode === ZSTD_COMPRESS || mode === ZSTD_DECOMPRESS);
|
||||||
|
|
||||||
|
initParamsArray.fill(-1);
|
||||||
|
if (opts?.params) {
|
||||||
|
ObjectKeys(opts.params).forEach(origKey => {
|
||||||
|
const key = +origKey;
|
||||||
|
if (NumberIsNaN(key) || key < 0 || key > maxParam || (initParamsArray[key] | 0) !== -1) {
|
||||||
|
throw $ERR_ZSTD_INVALID_PARAM(origKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
const value = opts.params[origKey];
|
||||||
|
if (typeof value !== "number" && typeof value !== "boolean") {
|
||||||
|
throw $ERR_INVALID_ARG_TYPE("options.params[key]", "number", opts.params[origKey]);
|
||||||
|
}
|
||||||
|
initParamsArray[key] = value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const handle = new NativeZstd(mode);
|
||||||
|
|
||||||
|
const pledgedSrcSize = opts?.pledgedSrcSize ?? undefined;
|
||||||
|
|
||||||
|
const writeState = new Uint32Array(2);
|
||||||
|
handle.init(initParamsArray, pledgedSrcSize, writeState, processCallback);
|
||||||
|
super(opts, mode, handle, zstdDefaultOpts);
|
||||||
|
this._writeState = writeState;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const kMaxZstdCParam = MathMax(...ObjectKeys(constants).map(key => (key.startsWith("ZSTD_c_") ? constants[key] : 0)));
|
||||||
|
|
||||||
|
const zstdInitCParamsArray = new Uint32Array(kMaxZstdCParam + 1);
|
||||||
|
|
||||||
|
class ZstdCompress extends Zstd {
|
||||||
|
constructor(opts) {
|
||||||
|
super(opts, ZSTD_COMPRESS, zstdInitCParamsArray, kMaxZstdCParam);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const kMaxZstdDParam = MathMax(...ObjectKeys(constants).map(key => (key.startsWith("ZSTD_d_") ? constants[key] : 0)));
|
||||||
|
|
||||||
|
const zstdInitDParamsArray = new Uint32Array(kMaxZstdDParam + 1);
|
||||||
|
|
||||||
|
class ZstdDecompress extends Zstd {
|
||||||
|
constructor(opts) {
|
||||||
|
super(opts, ZSTD_DECOMPRESS, zstdInitDParamsArray, kMaxZstdDParam);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Legacy alias on the C++ wrapper object.
|
// Legacy alias on the C++ wrapper object.
|
||||||
ObjectDefineProperty(NativeZlib.prototype, "jsref", {
|
ObjectDefineProperty(NativeZlib.prototype, "jsref", {
|
||||||
__proto__: null,
|
__proto__: null,
|
||||||
@@ -728,6 +793,8 @@ const zlib = {
|
|||||||
Unzip,
|
Unzip,
|
||||||
BrotliCompress,
|
BrotliCompress,
|
||||||
BrotliDecompress,
|
BrotliDecompress,
|
||||||
|
ZstdCompress,
|
||||||
|
ZstdDecompress,
|
||||||
|
|
||||||
deflate: createConvenienceMethod(Deflate, false, "deflate"),
|
deflate: createConvenienceMethod(Deflate, false, "deflate"),
|
||||||
deflateSync: createConvenienceMethod(Deflate, true, "deflateSync"),
|
deflateSync: createConvenienceMethod(Deflate, true, "deflateSync"),
|
||||||
@@ -747,6 +814,10 @@ const zlib = {
|
|||||||
brotliCompressSync: createConvenienceMethod(BrotliCompress, true, "brotliCompressSync"),
|
brotliCompressSync: createConvenienceMethod(BrotliCompress, true, "brotliCompressSync"),
|
||||||
brotliDecompress: createConvenienceMethod(BrotliDecompress, false, "brotliDecompress"),
|
brotliDecompress: createConvenienceMethod(BrotliDecompress, false, "brotliDecompress"),
|
||||||
brotliDecompressSync: createConvenienceMethod(BrotliDecompress, true, "brotliDecompressSync"),
|
brotliDecompressSync: createConvenienceMethod(BrotliDecompress, true, "brotliDecompressSync"),
|
||||||
|
zstdCompress: createConvenienceMethod(ZstdCompress, false, "zstdCompress"),
|
||||||
|
zstdCompressSync: createConvenienceMethod(ZstdCompress, true, "zstdCompressSync"),
|
||||||
|
zstdDecompress: createConvenienceMethod(ZstdDecompress, false, "zstdDecompress"),
|
||||||
|
zstdDecompressSync: createConvenienceMethod(ZstdDecompress, true, "zstdDecompressSync"),
|
||||||
|
|
||||||
createDeflate: function (options) {
|
createDeflate: function (options) {
|
||||||
return new Deflate(options);
|
return new Deflate(options);
|
||||||
@@ -775,6 +846,12 @@ const zlib = {
|
|||||||
createBrotliDecompress: function (options) {
|
createBrotliDecompress: function (options) {
|
||||||
return new BrotliDecompress(options);
|
return new BrotliDecompress(options);
|
||||||
},
|
},
|
||||||
|
createZstdCompress: function (options) {
|
||||||
|
return new ZstdCompress(options);
|
||||||
|
},
|
||||||
|
createZstdDecompress: function (options) {
|
||||||
|
return new ZstdDecompress(options);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
ObjectDefineProperties(zlib, {
|
ObjectDefineProperties(zlib, {
|
||||||
|
|||||||
@@ -737,6 +737,8 @@ pub const NodeMode = enum(u8) {
|
|||||||
UNZIP = 7,
|
UNZIP = 7,
|
||||||
BROTLI_DECODE = 8,
|
BROTLI_DECODE = 8,
|
||||||
BROTLI_ENCODE = 9,
|
BROTLI_ENCODE = 9,
|
||||||
|
ZSTD_COMPRESS = 10,
|
||||||
|
ZSTD_DECOMPRESS = 11,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Not for streaming!
|
/// Not for streaming!
|
||||||
|
|||||||
BIN
test/js/node/test/fixtures/person.jpg.zst
vendored
Normal file
BIN
test/js/node/test/fixtures/person.jpg.zst
vendored
Normal file
Binary file not shown.
@@ -54,6 +54,8 @@ for (const [type, expect] of [
|
|||||||
['deflateRaw', 'inflateRaw', 'DeflateRaw', 'InflateRaw'],
|
['deflateRaw', 'inflateRaw', 'DeflateRaw', 'InflateRaw'],
|
||||||
['brotliCompress', 'brotliDecompress',
|
['brotliCompress', 'brotliDecompress',
|
||||||
'BrotliCompress', 'BrotliDecompress'],
|
'BrotliCompress', 'BrotliDecompress'],
|
||||||
|
['zstdCompress', 'zstdDecompress',
|
||||||
|
'ZstdCompress', 'ZstdDecompress'],
|
||||||
]) {
|
]) {
|
||||||
zlib[method[0]](expect, opts, common.mustCall((err, result) => {
|
zlib[method[0]](expect, opts, common.mustCall((err, result) => {
|
||||||
zlib[method[1]](result, opts, common.mustCall((err, result) => {
|
zlib[method[1]](result, opts, common.mustCall((err, result) => {
|
||||||
|
|||||||
@@ -11,10 +11,12 @@ const emptyBuffer = Buffer.alloc(0);
|
|||||||
[ zlib.deflateSync, zlib.inflateSync, 'deflate sync' ],
|
[ zlib.deflateSync, zlib.inflateSync, 'deflate sync' ],
|
||||||
[ zlib.gzipSync, zlib.gunzipSync, 'gzip sync' ],
|
[ zlib.gzipSync, zlib.gunzipSync, 'gzip sync' ],
|
||||||
[ zlib.brotliCompressSync, zlib.brotliDecompressSync, 'br sync' ],
|
[ zlib.brotliCompressSync, zlib.brotliDecompressSync, 'br sync' ],
|
||||||
|
[ zlib.zstdCompressSync, zlib.zstdDecompressSync, 'zstd sync' ],
|
||||||
[ promisify(zlib.deflateRaw), promisify(zlib.inflateRaw), 'raw' ],
|
[ promisify(zlib.deflateRaw), promisify(zlib.inflateRaw), 'raw' ],
|
||||||
[ promisify(zlib.deflate), promisify(zlib.inflate), 'deflate' ],
|
[ promisify(zlib.deflate), promisify(zlib.inflate), 'deflate' ],
|
||||||
[ promisify(zlib.gzip), promisify(zlib.gunzip), 'gzip' ],
|
[ promisify(zlib.gzip), promisify(zlib.gunzip), 'gzip' ],
|
||||||
[ promisify(zlib.brotliCompress), promisify(zlib.brotliDecompress), 'br' ],
|
[ promisify(zlib.brotliCompress), promisify(zlib.brotliDecompress), 'br' ],
|
||||||
|
[ promisify(zlib.zstdCompress), promisify(zlib.zstdDecompress), 'zstd' ],
|
||||||
]) {
|
]) {
|
||||||
const compressed = await compress(emptyBuffer);
|
const compressed = await compress(emptyBuffer);
|
||||||
const decompressed = await decompress(compressed);
|
const decompressed = await decompress(compressed);
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ const unzips = [
|
|||||||
zlib.Inflate(),
|
zlib.Inflate(),
|
||||||
zlib.InflateRaw(),
|
zlib.InflateRaw(),
|
||||||
zlib.BrotliDecompress(),
|
zlib.BrotliDecompress(),
|
||||||
|
new zlib.ZstdDecompress(),
|
||||||
];
|
];
|
||||||
|
|
||||||
nonStringInputs.forEach(common.mustCall((input) => {
|
nonStringInputs.forEach(common.mustCall((input) => {
|
||||||
|
|||||||
@@ -144,6 +144,7 @@ class HashStream extends Stream {
|
|||||||
for (const [ createCompress, createDecompress ] of [
|
for (const [ createCompress, createDecompress ] of [
|
||||||
[ zlib.createGzip, zlib.createGunzip ],
|
[ zlib.createGzip, zlib.createGunzip ],
|
||||||
[ zlib.createBrotliCompress, zlib.createBrotliDecompress ],
|
[ zlib.createBrotliCompress, zlib.createBrotliDecompress ],
|
||||||
|
[ zlib.createZstdCompress, zlib.createZstdDecompress ],
|
||||||
]) {
|
]) {
|
||||||
const inp = new RandomReadStream({ total: 1024, block: 256, jitter: 16 });
|
const inp = new RandomReadStream({ total: 1024, block: 256, jitter: 16 });
|
||||||
const out = new HashStream();
|
const out = new HashStream();
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ const zlib = require('zlib');
|
|||||||
for (const [ createCompress, createDecompress ] of [
|
for (const [ createCompress, createDecompress ] of [
|
||||||
[ zlib.createGzip, zlib.createGunzip ],
|
[ zlib.createGzip, zlib.createGunzip ],
|
||||||
[ zlib.createBrotliCompress, zlib.createBrotliDecompress ],
|
[ zlib.createBrotliCompress, zlib.createBrotliDecompress ],
|
||||||
|
[ zlib.createZstdCompress, zlib.createZstdDecompress ],
|
||||||
]) {
|
]) {
|
||||||
const gzip = createCompress();
|
const gzip = createCompress();
|
||||||
const gunz = createDecompress();
|
const gunz = createDecompress();
|
||||||
|
|||||||
@@ -24,8 +24,14 @@ const common = require('../common');
|
|||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
const zlib = require('zlib');
|
const zlib = require('zlib');
|
||||||
|
|
||||||
for (const Compressor of [ zlib.Gzip, zlib.BrotliCompress ]) {
|
const compressors = [
|
||||||
const gz = Compressor();
|
[zlib.Gzip, 20],
|
||||||
|
[zlib.BrotliCompress, 1],
|
||||||
|
[zlib.ZstdCompress, 9],
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const [Compressor, expected] of compressors) {
|
||||||
|
const gz = new Compressor();
|
||||||
const emptyBuffer = Buffer.alloc(0);
|
const emptyBuffer = Buffer.alloc(0);
|
||||||
let received = 0;
|
let received = 0;
|
||||||
gz.on('data', function(c) {
|
gz.on('data', function(c) {
|
||||||
@@ -33,7 +39,6 @@ for (const Compressor of [ zlib.Gzip, zlib.BrotliCompress ]) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
gz.on('end', common.mustCall(function() {
|
gz.on('end', common.mustCall(function() {
|
||||||
const expected = Compressor === zlib.Gzip ? 20 : 1;
|
|
||||||
assert.strictEqual(received, expected,
|
assert.strictEqual(received, expected,
|
||||||
`${received}, ${expected}, ${Compressor.name}`);
|
`${received}, ${expected}, ${Compressor.name}`);
|
||||||
}));
|
}));
|
||||||
|
|||||||
28
test/js/node/test/parallel/test-zlib-zstd-flush.js
Normal file
28
test/js/node/test/parallel/test-zlib-zstd-flush.js
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
'use strict';
|
||||||
|
require('../common');
|
||||||
|
const assert = require('assert');
|
||||||
|
const zlib = require('zlib');
|
||||||
|
const fixtures = require('../common/fixtures');
|
||||||
|
|
||||||
|
const file = fixtures.readSync('person.jpg');
|
||||||
|
const chunkSize = 16;
|
||||||
|
const compress = new zlib.ZstdCompress();
|
||||||
|
|
||||||
|
const chunk = file.slice(0, chunkSize);
|
||||||
|
const expectedFull = Buffer.from('KLUv/QBYgAAA/9j/4AAQSkZJRgABAQEASA==', 'base64');
|
||||||
|
let actualFull;
|
||||||
|
|
||||||
|
compress.write(chunk, function() {
|
||||||
|
compress.flush(function() {
|
||||||
|
const bufs = [];
|
||||||
|
let buf;
|
||||||
|
while ((buf = compress.read()) !== null)
|
||||||
|
bufs.push(buf);
|
||||||
|
actualFull = Buffer.concat(bufs);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
process.once('exit', function() {
|
||||||
|
assert.deepStrictEqual(actualFull.toString('base64'), expectedFull.toString('base64'));
|
||||||
|
assert.deepStrictEqual(actualFull, expectedFull);
|
||||||
|
});
|
||||||
38
test/js/node/test/parallel/test-zlib-zstd-from-string.js
Normal file
38
test/js/node/test/parallel/test-zlib-zstd-from-string.js
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
'use strict';
|
||||||
|
// Test compressing and uncompressing a string with zstd
|
||||||
|
|
||||||
|
const common = require('../common');
|
||||||
|
const assert = require('assert');
|
||||||
|
const zlib = require('zlib');
|
||||||
|
|
||||||
|
const inputString = 'ΩΩLorem ipsum dolor sit amet, consectetur adipiscing eli' +
|
||||||
|
't. Morbi faucibus, purus at gravida dictum, libero arcu ' +
|
||||||
|
'convallis lacus, in commodo libero metus eu nisi. Nullam' +
|
||||||
|
' commodo, neque nec porta placerat, nisi est fermentum a' +
|
||||||
|
'ugue, vitae gravida tellus sapien sit amet tellus. Aenea' +
|
||||||
|
'n non diam orci. Proin quis elit turpis. Suspendisse non' +
|
||||||
|
' diam ipsum. Suspendisse nec ullamcorper odio. Vestibulu' +
|
||||||
|
'm arcu mi, sodales non suscipit id, ultrices ut massa. S' +
|
||||||
|
'ed ac sem sit amet arcu malesuada fermentum. Nunc sed. ';
|
||||||
|
const compressedString = 'KLUv/QRYRQkA9tc9H6AlhTb/z/7/gbTI3kaWLKnbCtkZu/hXm0j' +
|
||||||
|
'FpNz/VQM2ADMANQBHTuQOpIYzfVv7XGwXrpoIfgXNAB98xW4wV3' +
|
||||||
|
'vnCF2bjcvWZF2wIZ1vr1mSHHvPHU0TgMGBwUFrF0xqReWcWPO8z' +
|
||||||
|
'Ny6wMwFUilN+Lg987Zvs2GSRMy6uYvtovK9Uuhgst6l9FQrXLnA' +
|
||||||
|
'5gpZL7PdI8bO9sDH3tHm73XBzaUK+LjSPNKRmzQ3ZMYEPozdof1' +
|
||||||
|
'2KcZGfIcLa0PTsdkYqhGcAx/E9mWa8EGEeq0Qou2LTmzgg3YJz/' +
|
||||||
|
'21OuXSF+TOd662d60Qyb04xC5dOF4b8JFH8mpHAxAAELu3tg1oa' +
|
||||||
|
'bBEIWaRHdE0l/+0RdEWWIVMAku8TgbiX/4bU+OpLo4UuY1FKDR8' +
|
||||||
|
'RgBc';
|
||||||
|
|
||||||
|
zlib.zstdCompress(inputString, common.mustCall((err, buffer) => {
|
||||||
|
assert(inputString.length > buffer.length);
|
||||||
|
|
||||||
|
zlib.zstdDecompress(buffer, common.mustCall((err, buffer) => {
|
||||||
|
assert.strictEqual(buffer.toString(), inputString);
|
||||||
|
}));
|
||||||
|
}));
|
||||||
|
|
||||||
|
const buffer = Buffer.from(compressedString, 'base64');
|
||||||
|
zlib.zstdDecompress(buffer, common.mustCall((err, buffer) => {
|
||||||
|
assert.strictEqual(buffer.toString(), inputString);
|
||||||
|
}));
|
||||||
34
test/js/node/test/parallel/test-zlib-zstd-from-zstd.js
Normal file
34
test/js/node/test/parallel/test-zlib-zstd-from-zstd.js
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
'use strict';
|
||||||
|
// Test unzipping a file that was created with a non-node zstd lib,
|
||||||
|
// piped in as fast as possible.
|
||||||
|
//
|
||||||
|
// The compressed fixture was created using the reference CLI:
|
||||||
|
// $ zstd -19 test/fixtures/person.jpg -o test/fixtures/person.jpg.zst
|
||||||
|
|
||||||
|
const common = require('../common');
|
||||||
|
const assert = require('assert');
|
||||||
|
const zlib = require('zlib');
|
||||||
|
const fixtures = require('../common/fixtures');
|
||||||
|
|
||||||
|
const tmpdir = require('../common/tmpdir');
|
||||||
|
tmpdir.refresh();
|
||||||
|
|
||||||
|
const decompress = new zlib.ZstdDecompress();
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
|
const fixture = fixtures.path('person.jpg.zst');
|
||||||
|
const unzippedFixture = fixtures.path('person.jpg');
|
||||||
|
const outputFile = tmpdir.resolve('person.jpg');
|
||||||
|
const expect = fs.readFileSync(unzippedFixture);
|
||||||
|
const inp = fs.createReadStream(fixture);
|
||||||
|
const out = fs.createWriteStream(outputFile);
|
||||||
|
|
||||||
|
inp.pipe(decompress).pipe(out);
|
||||||
|
out.on('close', common.mustCall(() => {
|
||||||
|
const actual = fs.readFileSync(outputFile);
|
||||||
|
assert.strictEqual(actual.length, expect.length);
|
||||||
|
for (let i = 0, l = actual.length; i < l; i++) {
|
||||||
|
assert.strictEqual(actual[i], expect[i], `byte[${i}]`);
|
||||||
|
}
|
||||||
|
}));
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
'use strict';
|
||||||
|
require('../common');
|
||||||
|
|
||||||
|
// This test ensures that zlib throws a RangeError if the final buffer needs to
|
||||||
|
// be larger than kMaxLength and concatenation fails.
|
||||||
|
// https://github.com/nodejs/node/pull/1811
|
||||||
|
|
||||||
|
const assert = require('assert');
|
||||||
|
|
||||||
|
// Change kMaxLength for zlib to trigger the error without having to allocate
|
||||||
|
// large Buffers.
|
||||||
|
const buffer = require('buffer');
|
||||||
|
const oldkMaxLength = buffer.kMaxLength;
|
||||||
|
buffer.kMaxLength = 64;
|
||||||
|
const zlib = require('zlib');
|
||||||
|
buffer.kMaxLength = oldkMaxLength;
|
||||||
|
|
||||||
|
// "a".repeat(128), compressed using zstd.
|
||||||
|
const encoded = Buffer.from('KLUv/SCARQAAEGFhAQA7BVg=', 'base64');
|
||||||
|
|
||||||
|
// Async
|
||||||
|
zlib.zstdDecompress(encoded, function(err) {
|
||||||
|
assert.ok(err instanceof RangeError);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Sync
|
||||||
|
assert.throws(function() {
|
||||||
|
zlib.zstdDecompressSync(encoded);
|
||||||
|
}, RangeError);
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
'use strict';
|
||||||
|
const common = require('../common');
|
||||||
|
const assert = require('assert');
|
||||||
|
const zlib = require('zlib');
|
||||||
|
|
||||||
|
function compressWithPledgedSrcSize({ pledgedSrcSize, actualSrcSize }) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const compressor = zlib.createZstdCompress({ pledgedSrcSize });
|
||||||
|
compressor.on('error', (e) => {
|
||||||
|
reject(e);
|
||||||
|
});
|
||||||
|
compressor.on('end', resolve);
|
||||||
|
compressor.write('x'.repeat(actualSrcSize), () => {
|
||||||
|
compressor.end();
|
||||||
|
compressor.resume();
|
||||||
|
});
|
||||||
|
}).then(() => {
|
||||||
|
// Compression should only succeed if sizes match
|
||||||
|
assert.strictEqual(pledgedSrcSize, actualSrcSize);
|
||||||
|
}, (error) => {
|
||||||
|
assert.strictEqual(error.code, 'ZSTD_error_srcSize_wrong');
|
||||||
|
// Size error should only happen when sizes do not match
|
||||||
|
assert.notStrictEqual(pledgedSrcSize, actualSrcSize);
|
||||||
|
}).then(common.mustCall());
|
||||||
|
}
|
||||||
|
|
||||||
|
compressWithPledgedSrcSize({ pledgedSrcSize: 0, actualSrcSize: 0 });
|
||||||
|
|
||||||
|
compressWithPledgedSrcSize({ pledgedSrcSize: 0, actualSrcSize: 42 });
|
||||||
|
|
||||||
|
compressWithPledgedSrcSize({ pledgedSrcSize: 13, actualSrcSize: 42 });
|
||||||
|
|
||||||
|
compressWithPledgedSrcSize({ pledgedSrcSize: 42, actualSrcSize: 0 });
|
||||||
|
|
||||||
|
compressWithPledgedSrcSize({ pledgedSrcSize: 42, actualSrcSize: 13 });
|
||||||
|
|
||||||
|
compressWithPledgedSrcSize({ pledgedSrcSize: 42, actualSrcSize: 42 });
|
||||||
134
test/js/node/test/parallel/test-zlib-zstd.js
Normal file
134
test/js/node/test/parallel/test-zlib-zstd.js
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
'use strict';
|
||||||
|
require('../common');
|
||||||
|
const fixtures = require('../common/fixtures');
|
||||||
|
const assert = require('assert');
|
||||||
|
const zlib = require('zlib');
|
||||||
|
|
||||||
|
// Test some zstd-specific properties of the zstd streams that can not
|
||||||
|
// be easily covered through expanding zlib-only tests.
|
||||||
|
|
||||||
|
const sampleBuffer = fixtures.readSync('/pss-vectors.json');
|
||||||
|
|
||||||
|
{
|
||||||
|
// Test setting the quality parameter at stream creation:
|
||||||
|
const sizes = [];
|
||||||
|
for (let quality = 1;
|
||||||
|
quality <= 22;
|
||||||
|
quality++) {
|
||||||
|
const encoded = zlib.zstdCompressSync(sampleBuffer, {
|
||||||
|
params: {
|
||||||
|
[zlib.constants.ZSTD_c_compressionLevel]: quality
|
||||||
|
}
|
||||||
|
});
|
||||||
|
sizes.push(encoded.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Increasing quality should roughly correspond to decreasing compressed size:
|
||||||
|
for (let i = 0; i < sizes.length - 1; i++) {
|
||||||
|
assert(sizes[i + 1] <= sizes[i] * 1.05, sizes); // 5 % margin of error.
|
||||||
|
}
|
||||||
|
assert(sizes[0] > sizes[sizes.length - 1], sizes);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Test that setting out-of-bounds option values or keys fails.
|
||||||
|
assert.throws(() => {
|
||||||
|
zlib.createZstdCompress({
|
||||||
|
params: {
|
||||||
|
10000: 0
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, {
|
||||||
|
code: 'ERR_ZSTD_INVALID_PARAM',
|
||||||
|
name: 'RangeError',
|
||||||
|
message: '10000 is not a valid zstd parameter'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test that accidentally using duplicate keys fails.
|
||||||
|
assert.throws(() => {
|
||||||
|
zlib.createZstdCompress({
|
||||||
|
params: {
|
||||||
|
'0': 0,
|
||||||
|
'00': 0
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, {
|
||||||
|
code: 'ERR_ZSTD_INVALID_PARAM',
|
||||||
|
name: 'RangeError',
|
||||||
|
message: '00 is not a valid zstd parameter'
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.throws(() => {
|
||||||
|
zlib.createZstdCompress({
|
||||||
|
params: {
|
||||||
|
// This param must be a valid ZSTD_strategy value.
|
||||||
|
[zlib.constants.ZSTD_c_strategy]: 130
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, {
|
||||||
|
code: 'ERR_ZLIB_INITIALIZATION_FAILED',
|
||||||
|
name: 'Error',
|
||||||
|
message: 'Setting parameter failed'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test that setting out-of-bounds option values or keys fails.
|
||||||
|
assert.throws(() => {
|
||||||
|
zlib.createZstdDecompress({
|
||||||
|
params: {
|
||||||
|
10000: 0
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, {
|
||||||
|
code: 'ERR_ZSTD_INVALID_PARAM',
|
||||||
|
name: 'RangeError',
|
||||||
|
message: '10000 is not a valid zstd parameter'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test that accidentally using duplicate keys fails.
|
||||||
|
assert.throws(() => {
|
||||||
|
zlib.createZstdDecompress({
|
||||||
|
params: {
|
||||||
|
'0': 0,
|
||||||
|
'00': 0
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, {
|
||||||
|
code: 'ERR_ZSTD_INVALID_PARAM',
|
||||||
|
name: 'RangeError',
|
||||||
|
message: '00 is not a valid zstd parameter'
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.throws(() => {
|
||||||
|
zlib.createZstdDecompress({
|
||||||
|
params: {
|
||||||
|
// This param must be >= 10 (ZSTD_WINDOWLOG_ABSOLUTEMIN).
|
||||||
|
[zlib.constants.ZSTD_d_windowLogMax]: 1
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, {
|
||||||
|
code: 'ERR_ZLIB_INITIALIZATION_FAILED',
|
||||||
|
name: 'Error',
|
||||||
|
message: 'Setting parameter failed'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Test options.flush range
|
||||||
|
assert.throws(() => {
|
||||||
|
zlib.zstdCompressSync('', { flush: zlib.constants.Z_FINISH });
|
||||||
|
}, {
|
||||||
|
code: 'ERR_OUT_OF_RANGE',
|
||||||
|
name: 'RangeError',
|
||||||
|
message: 'The value of "options.flush" is out of range. It must be >= 0 ' +
|
||||||
|
'and <= 2. Received 4',
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.throws(() => {
|
||||||
|
zlib.zstdCompressSync('', { finishFlush: zlib.constants.Z_FINISH });
|
||||||
|
}, {
|
||||||
|
code: 'ERR_OUT_OF_RANGE',
|
||||||
|
name: 'RangeError',
|
||||||
|
message: 'The value of "options.finishFlush" is out of range. It must be ' +
|
||||||
|
'>= 0 and <= 2. Received 4',
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -42,6 +42,7 @@ let zlibPairs = [
|
|||||||
[zlib.Gzip, zlib.Unzip],
|
[zlib.Gzip, zlib.Unzip],
|
||||||
[zlib.DeflateRaw, zlib.InflateRaw],
|
[zlib.DeflateRaw, zlib.InflateRaw],
|
||||||
[zlib.BrotliCompress, zlib.BrotliDecompress],
|
[zlib.BrotliCompress, zlib.BrotliDecompress],
|
||||||
|
[zlib.ZstdCompress, zlib.ZstdDecompress],
|
||||||
];
|
];
|
||||||
|
|
||||||
// How fast to trickle through the slowstream
|
// How fast to trickle through the slowstream
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
import { beforeAll, describe, expect, test } from "bun:test";
|
import { beforeAll, describe, expect, test } from "bun:test";
|
||||||
|
import { isASAN } from "harness";
|
||||||
import { promisify } from "node:util";
|
import { promisify } from "node:util";
|
||||||
import zlib from "node:zlib";
|
import zlib from "node:zlib";
|
||||||
|
|
||||||
const input = Buffer.alloc(50000);
|
const input = Buffer.alloc(50000);
|
||||||
for (let i = 0; i < input.length; i++) input[i] = Math.random();
|
for (let i = 0; i < input.length; i++) input[i] = Math.random();
|
||||||
|
|
||||||
|
const upper = 1024 * 1024 * (isASAN ? 15 : 10);
|
||||||
|
|
||||||
describe("zlib compression does not leak memory", () => {
|
describe("zlib compression does not leak memory", () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
for (let index = 0; index < 10_000; index++) {
|
for (let index = 0; index < 10_000; index++) {
|
||||||
@@ -30,8 +33,8 @@ describe("zlib compression does not leak memory", () => {
|
|||||||
const after = process.memoryUsage.rss();
|
const after = process.memoryUsage.rss();
|
||||||
console.log(after);
|
console.log(after);
|
||||||
console.log("-", after - baseline);
|
console.log("-", after - baseline);
|
||||||
console.log("-", 1024 * 1024 * 10);
|
console.log("-", upper);
|
||||||
expect(after - baseline).toBeLessThan(1024 * 1024 * 10);
|
expect(after - baseline).toBeLessThan(upper);
|
||||||
},
|
},
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
@@ -53,8 +56,8 @@ describe("zlib compression does not leak memory", () => {
|
|||||||
const after = process.memoryUsage.rss();
|
const after = process.memoryUsage.rss();
|
||||||
console.log(after);
|
console.log(after);
|
||||||
console.log("-", after - baseline);
|
console.log("-", after - baseline);
|
||||||
console.log("-", 1024 * 1024 * 10);
|
console.log("-", upper);
|
||||||
expect(after - baseline).toBeLessThan(1024 * 1024 * 10);
|
expect(after - baseline).toBeLessThan(upper);
|
||||||
},
|
},
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
@@ -73,8 +76,8 @@ describe("zlib compression does not leak memory", () => {
|
|||||||
const after = process.memoryUsage.rss();
|
const after = process.memoryUsage.rss();
|
||||||
console.log(after);
|
console.log(after);
|
||||||
console.log("-", after - baseline);
|
console.log("-", after - baseline);
|
||||||
console.log("-", 1024 * 1024 * 10);
|
console.log("-", upper);
|
||||||
expect(after - baseline).toBeLessThan(1024 * 1024 * 10);
|
expect(after - baseline).toBeLessThan(upper);
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
test("brotliCompressSync", async () => {
|
test("brotliCompressSync", async () => {
|
||||||
@@ -90,7 +93,41 @@ describe("zlib compression does not leak memory", () => {
|
|||||||
const after = process.memoryUsage.rss();
|
const after = process.memoryUsage.rss();
|
||||||
console.log(after);
|
console.log(after);
|
||||||
console.log("-", after - baseline);
|
console.log("-", after - baseline);
|
||||||
console.log("-", 1024 * 1024 * 10);
|
console.log("-", upper);
|
||||||
expect(after - baseline).toBeLessThan(1024 * 1024 * 10);
|
expect(after - baseline).toBeLessThan(upper);
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
test("zstdCompress", async () => {
|
||||||
|
for (let index = 0; index < 1_000; index++) {
|
||||||
|
await promisify(zlib.zstdCompress)(input);
|
||||||
|
}
|
||||||
|
const baseline = process.memoryUsage.rss();
|
||||||
|
console.log(baseline);
|
||||||
|
for (let index = 0; index < 1_000; index++) {
|
||||||
|
await promisify(zlib.zstdCompress)(input);
|
||||||
|
}
|
||||||
|
Bun.gc(true);
|
||||||
|
const after = process.memoryUsage.rss();
|
||||||
|
console.log(after);
|
||||||
|
console.log("-", after - baseline);
|
||||||
|
console.log("-", upper);
|
||||||
|
expect(after - baseline).toBeLessThan(upper);
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
test("zstdCompressSync", async () => {
|
||||||
|
for (let index = 0; index < 1_000; index++) {
|
||||||
|
zlib.zstdCompressSync(input);
|
||||||
|
}
|
||||||
|
const baseline = process.memoryUsage.rss();
|
||||||
|
console.log(baseline);
|
||||||
|
for (let index = 0; index < 1_000; index++) {
|
||||||
|
zlib.zstdCompressSync(input);
|
||||||
|
}
|
||||||
|
Bun.gc(true);
|
||||||
|
const after = process.memoryUsage.rss();
|
||||||
|
console.log(after);
|
||||||
|
console.log("-", after - baseline);
|
||||||
|
console.log("-", upper);
|
||||||
|
expect(after - baseline).toBeLessThan(upper);
|
||||||
}, 0);
|
}, 0);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -51,6 +51,26 @@ describe("prototype and name and constructor", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (let [name, Class] of [
|
||||||
|
["ZstdCompress", zlib.ZstdCompress],
|
||||||
|
["ZstdDecompress", zlib.ZstdDecompress],
|
||||||
|
]) {
|
||||||
|
describe(`${name}`, () => {
|
||||||
|
it(`${name}.prototype should be instanceof ${name}.__proto__`, () => {
|
||||||
|
expect(Class.prototype).toBeInstanceOf(Class.__proto__);
|
||||||
|
});
|
||||||
|
it(`${name}.prototype.constructor should be ${name}`, () => {
|
||||||
|
expect(Class.prototype.constructor).toBe(Class);
|
||||||
|
});
|
||||||
|
it(`${name}.name should be ${name}`, () => {
|
||||||
|
expect(Class.name).toBe(name);
|
||||||
|
});
|
||||||
|
it(`${name}.prototype.__proto__.constructor.name should be Zstd`, () => {
|
||||||
|
expect(Class.prototype.__proto__.constructor.name).toBe("Zstd");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("zlib", () => {
|
describe("zlib", () => {
|
||||||
@@ -198,21 +218,23 @@ describe("zlib.brotli", () => {
|
|||||||
const out_path_d = resolve(x_dir, "this.js");
|
const out_path_d = resolve(x_dir, "this.js");
|
||||||
|
|
||||||
{
|
{
|
||||||
const { resolve, promise } = Promise.withResolvers();
|
const { resolve, reject, promise } = Promise.withResolvers();
|
||||||
const readStream = fs.createReadStream(import.meta.filename);
|
const readStream = fs.createReadStream(import.meta.filename);
|
||||||
const writeStream = fs.createWriteStream(out_path_c);
|
const writeStream = fs.createWriteStream(out_path_c);
|
||||||
const brStream = zlib.createBrotliCompress();
|
const brStream = zlib.createBrotliCompress();
|
||||||
const the_stream = readStream.pipe(brStream).pipe(writeStream);
|
const the_stream = readStream.pipe(brStream).pipe(writeStream);
|
||||||
the_stream.on("finish", resolve);
|
the_stream.on("finish", resolve);
|
||||||
|
the_stream.on("error", reject);
|
||||||
await promise;
|
await promise;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const { resolve, promise } = Promise.withResolvers();
|
const { resolve, reject, promise } = Promise.withResolvers();
|
||||||
const readStream = fs.createReadStream(out_path_c);
|
const readStream = fs.createReadStream(out_path_c);
|
||||||
const writeStream = fs.createWriteStream(out_path_d);
|
const writeStream = fs.createWriteStream(out_path_d);
|
||||||
const brStream = zlib.createBrotliDecompress();
|
const brStream = zlib.createBrotliDecompress();
|
||||||
const the_stream = readStream.pipe(brStream).pipe(writeStream);
|
const the_stream = readStream.pipe(brStream).pipe(writeStream);
|
||||||
the_stream.on("finish", resolve);
|
the_stream.on("finish", resolve);
|
||||||
|
the_stream.on("error", reject);
|
||||||
await promise;
|
await promise;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
@@ -232,8 +254,10 @@ describe("zlib.brotli", () => {
|
|||||||
const rand = createPRNG(1);
|
const rand = createPRNG(1);
|
||||||
let all = [];
|
let all = [];
|
||||||
|
|
||||||
|
const { promise, resolve, reject } = Promise.withResolvers();
|
||||||
brotliStream.on("data", chunk => all.push(chunk.length));
|
brotliStream.on("data", chunk => all.push(chunk.length));
|
||||||
brotliStream.on("end", () => expect(all).toEqual([11180, 13, 14, 13, 13, 13, 14]));
|
brotliStream.on("end", resolve);
|
||||||
|
brotliStream.on("error", reject);
|
||||||
|
|
||||||
for (let i = 0; i < 50; i++) {
|
for (let i = 0; i < 50; i++) {
|
||||||
let buf = Buffer.alloc(1024 * 1024);
|
let buf = Buffer.alloc(1024 * 1024);
|
||||||
@@ -242,6 +266,8 @@ describe("zlib.brotli", () => {
|
|||||||
}
|
}
|
||||||
readStream.push(null);
|
readStream.push(null);
|
||||||
readStream.pipe(brotliStream);
|
readStream.pipe(brotliStream);
|
||||||
|
await promise;
|
||||||
|
expect(all.length).toBeGreaterThanOrEqual(7);
|
||||||
}, 15_000);
|
}, 15_000);
|
||||||
|
|
||||||
it("should accept params", async () => {
|
it("should accept params", async () => {
|
||||||
@@ -337,6 +363,7 @@ for (const [compress, decompressor] of [
|
|||||||
[zlib.deflateRawSync, zlib.createInflateRaw],
|
[zlib.deflateRawSync, zlib.createInflateRaw],
|
||||||
[zlib.deflateSync, zlib.createInflate],
|
[zlib.deflateSync, zlib.createInflate],
|
||||||
[zlib.brotliCompressSync, zlib.createBrotliDecompress],
|
[zlib.brotliCompressSync, zlib.createBrotliDecompress],
|
||||||
|
[zlib.zstdCompressSync, zlib.createZstdDecompress],
|
||||||
// [zlib.gzipSync, zlib.createGunzip],
|
// [zlib.gzipSync, zlib.createGunzip],
|
||||||
// [zlib.gzipSync, zlib.createUnzip],
|
// [zlib.gzipSync, zlib.createUnzip],
|
||||||
]) {
|
]) {
|
||||||
@@ -364,7 +391,11 @@ for (const [compress, decompressor] of [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
for (const i in variants) {
|
for (const i in variants) {
|
||||||
it(`premature end handles bytesWritten properly: ${compress.name} + ${decompressor.name}: variant ${i}`, async () => {
|
let should_skip = false;
|
||||||
|
if (decompressor === zlib.createZstdDecompress && i == 1) should_skip = true; // fails in node too
|
||||||
|
if (decompressor === zlib.createZstdDecompress && i == 2) should_skip = true; // fails in node too
|
||||||
|
// prettier-ignore
|
||||||
|
it.skipIf(should_skip)(`premature end handles bytesWritten properly: ${compress.name} + ${decompressor.name}: variant ${i}`, async () => {
|
||||||
const variant = variants[i];
|
const variant = variants[i];
|
||||||
const { promise, resolve, reject } = Promise.withResolvers();
|
const { promise, resolve, reject } = Promise.withResolvers();
|
||||||
let output = "";
|
let output = "";
|
||||||
@@ -469,3 +500,137 @@ for (const C of [zlib.BrotliCompress, zlib.BrotliDecompress]) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
describe("zlib.zstd", () => {
|
||||||
|
const inputString =
|
||||||
|
"ΩΩLorem ipsum dolor sit amet, consectetur adipiscing eli" +
|
||||||
|
"t. Morbi faucibus, purus at gravida dictum, libero arcu " +
|
||||||
|
"convallis lacus, in commodo libero metus eu nisi. Nullam" +
|
||||||
|
" commodo, neque nec porta placerat, nisi est fermentum a" +
|
||||||
|
"ugue, vitae gravida tellus sapien sit amet tellus. Aenea" +
|
||||||
|
"n non diam orci. Proin quis elit turpis. Suspendisse non" +
|
||||||
|
" diam ipsum. Suspendisse nec ullamcorper odio. Vestibulu" +
|
||||||
|
"m arcu mi, sodales non suscipit id, ultrices ut massa. S" +
|
||||||
|
"ed ac sem sit amet arcu malesuada fermentum. Nunc sed. ";
|
||||||
|
const compressedString =
|
||||||
|
"KLUv/WD5AF0JAGbXPCCgJUkH/8+rqgA3KaVsW+6LfK3JLcnP+I/" +
|
||||||
|
"Gy1/3Qv9XDTQAMwA0AK+Ch9LCub6tnT62C7QuwrHQHDhhNPcCQl" +
|
||||||
|
"tMWOrafGy3KO2D79QZ95omy09vwp/TFEAkEIlHOO99cOlZmfRiz" +
|
||||||
|
"XQ79GvDoY9TxrTgBBfR+77Nd7LkOWlHaGW+aEwd2rSeegWaj9Ns" +
|
||||||
|
"WAJJ0253u1jQpe3ByWLS5i+24QhTAZygaf4UlqNER3XoAk7QYar" +
|
||||||
|
"9tjHHV4yHj+tC108zuqMBJ+X2hlpwUqX6vE3r3N7q5QYntVvn3N" +
|
||||||
|
"8zVDb9UfCMCW1790yV3A88pgvkvQAniSWvFxMAELvECFu0tC1R9" +
|
||||||
|
"Ijsri5bt2kE/2mLoi2wCpkElnidDMS//DemxlNdHClyl6KeNTCugmAG";
|
||||||
|
const compressedBuffer = Buffer.from(compressedString, "base64");
|
||||||
|
|
||||||
|
it("zstdDecompress", async () => {
|
||||||
|
const roundtrip = await util.promisify(zlib.zstdDecompress)(compressedBuffer);
|
||||||
|
expect(roundtrip.toString()).toEqual(inputString);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("zstdCompressSync", () => {
|
||||||
|
const compressed = zlib.zstdCompressSync(inputString);
|
||||||
|
expect(compressed.toString("base64")).toEqual(compressedString);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("zstdDecompressSync", () => {
|
||||||
|
const roundtrip = zlib.zstdDecompressSync(compressedBuffer);
|
||||||
|
expect(roundtrip.toString()).toEqual(inputString);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("can compress streaming", async () => {
|
||||||
|
const encoder = zlib.createZstdCompress();
|
||||||
|
for (const chunk of window(inputString, 55)) {
|
||||||
|
encoder.push(chunk);
|
||||||
|
}
|
||||||
|
encoder.push(null);
|
||||||
|
const buf = await new Response(encoder).text();
|
||||||
|
expect(buf).toEqual(inputString);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("can decompress streaming", async () => {
|
||||||
|
const decoder = zlib.createZstdDecompress();
|
||||||
|
for (const chunk of window(compressedBuffer, 10)) {
|
||||||
|
decoder.push(chunk);
|
||||||
|
}
|
||||||
|
decoder.push(null);
|
||||||
|
const buf = await new Response(decoder).bytes();
|
||||||
|
expect(buf).toEqual(compressedBuffer);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("can roundtrip an empty string", async () => {
|
||||||
|
const input = "";
|
||||||
|
const compressed = await util.promisify(zlib.zstdCompress)(input);
|
||||||
|
const roundtrip = await util.promisify(zlib.zstdDecompress)(compressed);
|
||||||
|
expect(roundtrip.toString()).toEqual(input);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("can compress streaming big", async () => {
|
||||||
|
const encoder = zlib.createZstdCompress();
|
||||||
|
const input = inputString + inputString + inputString + inputString;
|
||||||
|
for (const chunk of window(input, 65)) {
|
||||||
|
encoder.push(chunk);
|
||||||
|
}
|
||||||
|
encoder.push(null);
|
||||||
|
const buf = await new Response(encoder).text();
|
||||||
|
expect(buf).toEqual(input);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fully works as a stream.Transform", async () => {
|
||||||
|
const x_dir = tmpdirSync();
|
||||||
|
const out_path_c = resolve(x_dir, "this.js.br");
|
||||||
|
const out_path_d = resolve(x_dir, "this.js");
|
||||||
|
|
||||||
|
{
|
||||||
|
const { resolve, reject, promise } = Promise.withResolvers();
|
||||||
|
const readStream = fs.createReadStream(import.meta.filename);
|
||||||
|
const writeStream = fs.createWriteStream(out_path_c);
|
||||||
|
const brStream = zlib.createZstdCompress();
|
||||||
|
const the_stream = readStream.pipe(brStream).pipe(writeStream);
|
||||||
|
the_stream.on("finish", resolve);
|
||||||
|
the_stream.on("error", reject);
|
||||||
|
await promise;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const { resolve, reject, promise } = Promise.withResolvers();
|
||||||
|
const readStream = fs.createReadStream(out_path_c);
|
||||||
|
const writeStream = fs.createWriteStream(out_path_d);
|
||||||
|
const brStream = zlib.createZstdDecompress();
|
||||||
|
const the_stream = readStream.pipe(brStream).pipe(writeStream);
|
||||||
|
the_stream.on("finish", resolve);
|
||||||
|
the_stream.on("error", reject);
|
||||||
|
await promise;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const expected = await Bun.file(import.meta.filename).text();
|
||||||
|
const actual = await Bun.file(out_path_d).text();
|
||||||
|
expect(actual).toEqual(expected);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("streaming encode doesn't wait for entire input", async () => {
|
||||||
|
const createPRNG = seed => {
|
||||||
|
let state = seed ?? Math.floor(Math.random() * 0x7fffffff);
|
||||||
|
return () => (state = (1103515245 * state + 12345) % 0x80000000) / 0x7fffffff;
|
||||||
|
};
|
||||||
|
const readStream = new stream.Readable();
|
||||||
|
const zstdStream = zlib.createZstdCompress();
|
||||||
|
const rand = createPRNG(1);
|
||||||
|
let all = [];
|
||||||
|
|
||||||
|
const { promise, resolve, reject } = Promise.withResolvers();
|
||||||
|
zstdStream.on("data", chunk => all.push(chunk.length));
|
||||||
|
zstdStream.on("end", resolve);
|
||||||
|
zstdStream.on("error", reject);
|
||||||
|
|
||||||
|
for (let i = 0; i < 50; i++) {
|
||||||
|
let buf = Buffer.alloc(1024 * 1024);
|
||||||
|
for (let j = 0; j < buf.length; j++) buf[j] = (rand() * 256) | 0;
|
||||||
|
readStream.push(buf);
|
||||||
|
}
|
||||||
|
readStream.push(null);
|
||||||
|
readStream.pipe(zstdStream);
|
||||||
|
await promise;
|
||||||
|
expect(all.length).toBeGreaterThanOrEqual(7);
|
||||||
|
}, 15_000);
|
||||||
|
});
|
||||||
|
|||||||
@@ -657,6 +657,7 @@ describe("fetch() with streaming", () => {
|
|||||||
{ headers: { "Content-Encoding": "deflate" }, compression: "deflate-libdeflate" },
|
{ headers: { "Content-Encoding": "deflate" }, compression: "deflate-libdeflate" },
|
||||||
{ headers: { "Content-Encoding": "deflate" }, compression: "deflate_with_headers" },
|
{ headers: { "Content-Encoding": "deflate" }, compression: "deflate_with_headers" },
|
||||||
{ headers: { "Content-Encoding": "br" }, compression: "br" },
|
{ headers: { "Content-Encoding": "br" }, compression: "br" },
|
||||||
|
{ headers: { "Content-Encoding": "zstd" }, compression: "zstd" },
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
function compress(compression, data: Uint8Array) {
|
function compress(compression, data: Uint8Array) {
|
||||||
@@ -685,6 +686,8 @@ describe("fetch() with streaming", () => {
|
|||||||
[zlib.constants.BROTLI_PARAM_SIZE_HINT]: 0,
|
[zlib.constants.BROTLI_PARAM_SIZE_HINT]: 0,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
case "zstd":
|
||||||
|
return zlib.zstdCompressSync(data, {});
|
||||||
default:
|
default:
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
@@ -1241,9 +1244,11 @@ describe("fetch() with streaming", () => {
|
|||||||
expect((err as Error).name).toBe("Error");
|
expect((err as Error).name).toBe("Error");
|
||||||
expect((err as Error).code).toBe("BrotliDecompressionError");
|
expect((err as Error).code).toBe("BrotliDecompressionError");
|
||||||
} else if (compression === "deflate-libdeflate") {
|
} else if (compression === "deflate-libdeflate") {
|
||||||
// Since the compressed data is different, the error ends up different.
|
|
||||||
expect((err as Error).name).toBe("Error");
|
expect((err as Error).name).toBe("Error");
|
||||||
expect((err as Error).code).toBe("ShortRead");
|
expect((err as Error).code).toBe("ShortRead");
|
||||||
|
} else if (compression === "zstd") {
|
||||||
|
expect((err as Error).name).toBe("Error");
|
||||||
|
expect((err as Error).code).toBe("ZstdDecompressionError");
|
||||||
} else {
|
} else {
|
||||||
expect((err as Error).name).toBe("Error");
|
expect((err as Error).name).toBe("Error");
|
||||||
expect((err as Error).code).toBe("ZlibError");
|
expect((err as Error).code).toBe("ZlibError");
|
||||||
|
|||||||
Reference in New Issue
Block a user