/* * Decoder orchestration is implemented in rust/src/zstd_decompress.rs. * * `ZSTD_DCtx_s` is intentionally still allocated and laid out by C: its * optional members vary with the build configuration and the block decoder * shares that object. This translation unit is therefore a deliberately * narrow ABI adapter. It projects field addresses to Rust, keeps allocation * ownership in the C allocator domain, and retains the configuration-bound * legacy and trace leaves. */ #define ZSTD_STATIC_LINKING_ONLY #include "../common/zstd_deps.h" #include "../common/allocations.h" #include "../common/error_private.h" #include "../common/mem.h" #include "../common/zstd_internal.h" #include "zstd_decompress_internal.h" #include "zstd_ddict.h" #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1) # include "../legacy/zstd_legacy.h" #endif /* Keep the three public build-time tuning knobs in the C configuration domain. * Rust queries them through the small leaves below rather than baking a second * set of defaults into its source. */ #ifndef ZSTD_HEAPMODE # define ZSTD_HEAPMODE 1 #endif #ifndef ZSTD_MAXWINDOWSIZE_DEFAULT # define ZSTD_MAXWINDOWSIZE_DEFAULT (((U32)1 << ZSTD_WINDOWLOG_LIMIT_DEFAULT) + 1) #endif #ifndef ZSTD_NO_FORWARD_PROGRESS_MAX # define ZSTD_NO_FORWARD_PROGRESS_MAX 16 #endif /* Keep this in lock-step with ZSTD_rustDctxView in zstd_decompress.rs. * Every pointer that names a scalar is the address of that scalar; array and * embedded-object entries name their first byte. */ typedef struct { void* dctx; void* llt_ptr; void* mlt_ptr; void* oft_ptr; void* huf_ptr; void* entropy; void* workspace; size_t workspace_size; void* previous_dst_end; void* prefix_start; void* virtual_start; void* dict_end; void* expected; void* f_params; void* processed_c_size; void* decoded_size; void* b_type; void* stage; void* lit_entropy; void* fse_entropy; void* xxh_state; void* header_size; void* format; void* force_ignore_checksum; void* validate_checksum; void* lit_ptr; void* custom_mem; void* lit_size; void* rle_size; void* static_size; void* is_frame_decompression; void* ddict_local; void* ddict; void* dict_id; void* ddict_is_cold; void* dict_uses; void* ddict_set; void* ref_multiple_ddicts; void* disable_huf_asm; void* max_block_size_param; void* stream_stage; void* in_buff; void* in_buff_size; void* in_pos; void* max_window_size; void* out_buff; void* out_buff_size; void* out_start; void* out_end; void* lh_size; void* legacy_context; void* previous_legacy_version; void* legacy_version; void* hostage_byte; void* no_forward_progress; void* out_buffer_mode; void* expected_out_buffer; void* lit_buffer; void* lit_buffer_end; void* lit_buffer_location; void* lit_extra_buffer; size_t lit_extra_buffer_size; void* header_buffer; size_t header_buffer_size; void* oversized_duration; void* fuzz_begin; void* fuzz_end; size_t dctx_size; } ZSTD_rustDctxView; void ZSTD_rust_dctx_view(ZSTD_DCtx* dctx, ZSTD_rustDctxView* out); size_t ZSTD_rust_dctx_sizeof(void); ZSTD_DCtx* ZSTD_rust_dctx_alloc(ZSTD_customMem customMem); void ZSTD_rust_dctx_free_storage(ZSTD_DCtx* dctx, ZSTD_customMem customMem); void ZSTD_rust_dctx_init_platform(ZSTD_DCtx* dctx); size_t ZSTD_rust_dctx_default_max_window_size(void); int ZSTD_rust_no_forward_progress_max(void); int ZSTD_rust_heapmode(void); size_t ZSTD_rust_decompress_stack(void* dst, size_t dstCapacity, const void* src, size_t srcSize); void* ZSTD_rust_custom_malloc(size_t size, ZSTD_customMem customMem); void* ZSTD_rust_custom_calloc(size_t size, ZSTD_customMem customMem); void ZSTD_rust_custom_free(void* allocation, ZSTD_customMem customMem); ZSTD_DDict* ZSTD_rust_create_ddict(const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType, ZSTD_customMem customMem); void ZSTD_rust_dctx_copy_prefix(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx); void ZSTD_rust_dctx_trace_begin(ZSTD_DCtx* dctx); void ZSTD_rust_dctx_trace_end(ZSTD_DCtx* dctx, U64 uncompressedSize, U64 compressedSize, int streaming); unsigned ZSTD_rust_legacy_is(const void* src, size_t srcSize); unsigned long long ZSTD_rust_legacy_get_decompressed_size(const void* src, size_t srcSize); size_t ZSTD_rust_legacy_find_compressed_size(const void* src, size_t srcSize); size_t ZSTD_rust_legacy_frame_size_info(const void* src, size_t srcSize, size_t* compressedSize, unsigned long long* decompressedBound, size_t* nbBlocks); size_t ZSTD_rust_legacy_decompress(void* dst, size_t dstCapacity, const void* src, size_t srcSize, const void* dict, size_t dictSize); size_t ZSTD_rust_legacy_decompress_stream(ZSTD_DCtx* dctx, ZSTD_outBuffer* output, ZSTD_inBuffer* input, const void* dict, size_t dictSize); void ZSTD_rust_legacy_free_stream(ZSTD_DCtx* dctx); void ZSTD_rust_dctx_view(ZSTD_DCtx* dctx, ZSTD_rustDctxView* out) { ZSTD_memset(out, 0, sizeof(*out)); if (dctx == NULL) return; out->dctx = dctx; out->llt_ptr = &dctx->LLTptr; out->mlt_ptr = &dctx->MLTptr; out->oft_ptr = &dctx->OFTptr; out->huf_ptr = &dctx->HUFptr; out->entropy = &dctx->entropy; out->workspace = dctx->workspace; out->workspace_size = sizeof(dctx->workspace); out->previous_dst_end = &dctx->previousDstEnd; out->prefix_start = &dctx->prefixStart; out->virtual_start = &dctx->virtualStart; out->dict_end = &dctx->dictEnd; out->expected = &dctx->expected; out->f_params = &dctx->fParams; out->processed_c_size = &dctx->processedCSize; out->decoded_size = &dctx->decodedSize; out->b_type = &dctx->bType; out->stage = &dctx->stage; out->lit_entropy = &dctx->litEntropy; out->fse_entropy = &dctx->fseEntropy; out->xxh_state = &dctx->xxhState; out->header_size = &dctx->headerSize; out->format = &dctx->format; out->force_ignore_checksum = &dctx->forceIgnoreChecksum; out->validate_checksum = &dctx->validateChecksum; out->lit_ptr = &dctx->litPtr; out->custom_mem = &dctx->customMem; out->lit_size = &dctx->litSize; out->rle_size = &dctx->rleSize; out->static_size = &dctx->staticSize; out->is_frame_decompression = &dctx->isFrameDecompression; out->ddict_local = &dctx->ddictLocal; out->ddict = &dctx->ddict; out->dict_id = &dctx->dictID; out->ddict_is_cold = &dctx->ddictIsCold; out->dict_uses = &dctx->dictUses; out->ddict_set = &dctx->ddictSet; out->ref_multiple_ddicts = &dctx->refMultipleDDicts; out->disable_huf_asm = &dctx->disableHufAsm; out->max_block_size_param = &dctx->maxBlockSizeParam; out->stream_stage = &dctx->streamStage; out->in_buff = &dctx->inBuff; out->in_buff_size = &dctx->inBuffSize; out->in_pos = &dctx->inPos; out->max_window_size = &dctx->maxWindowSize; out->out_buff = &dctx->outBuff; out->out_buff_size = &dctx->outBuffSize; out->out_start = &dctx->outStart; out->out_end = &dctx->outEnd; out->lh_size = &dctx->lhSize; #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1) out->legacy_context = &dctx->legacyContext; out->previous_legacy_version = &dctx->previousLegacyVersion; out->legacy_version = &dctx->legacyVersion; #endif out->hostage_byte = &dctx->hostageByte; out->no_forward_progress = &dctx->noForwardProgress; out->out_buffer_mode = &dctx->outBufferMode; out->expected_out_buffer = &dctx->expectedOutBuffer; out->lit_buffer = &dctx->litBuffer; out->lit_buffer_end = &dctx->litBufferEnd; out->lit_buffer_location = &dctx->litBufferLocation; out->lit_extra_buffer = dctx->litExtraBuffer; out->lit_extra_buffer_size = sizeof(dctx->litExtraBuffer); out->header_buffer = dctx->headerBuffer; out->header_buffer_size = sizeof(dctx->headerBuffer); out->oversized_duration = &dctx->oversizedDuration; #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION out->fuzz_begin = &dctx->dictContentBeginForFuzzing; out->fuzz_end = &dctx->dictContentEndForFuzzing; #endif out->dctx_size = sizeof(*dctx); } size_t ZSTD_rust_dctx_sizeof(void) { return sizeof(ZSTD_DCtx); } ZSTD_DCtx* ZSTD_rust_dctx_alloc(ZSTD_customMem customMem) { if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL; return (ZSTD_DCtx*)ZSTD_customMalloc(sizeof(ZSTD_DCtx), customMem); } void ZSTD_rust_dctx_free_storage(ZSTD_DCtx* dctx, ZSTD_customMem customMem) { ZSTD_customFree(dctx, customMem); } void ZSTD_rust_dctx_init_platform(ZSTD_DCtx* dctx) { #if DYNAMIC_BMI2 dctx->bmi2 = ZSTD_cpuSupportsBmi2(); #else (void)dctx; #endif } size_t ZSTD_rust_dctx_default_max_window_size(void) { return ZSTD_MAXWINDOWSIZE_DEFAULT; } int ZSTD_rust_no_forward_progress_max(void) { return ZSTD_NO_FORWARD_PROGRESS_MAX; } int ZSTD_rust_heapmode(void) { return ZSTD_HEAPMODE; } size_t ZSTD_rust_decompress_stack(void* dst, size_t dstCapacity, const void* src, size_t srcSize) { #if ZSTD_HEAPMODE >= 1 (void)dst; (void)dstCapacity; (void)src; (void)srcSize; return ERROR(GENERIC); #else ZSTD_DCtx dctx; ZSTD_DCtx* const initialized = ZSTD_initStaticDCtx(&dctx, sizeof(dctx)); if (initialized == NULL) return ERROR(memory_allocation); /* This is a stack DCtx, not a user-provided static workspace. Keep the * original heapmode=0 semantics so legacy decoding is permitted and no * static-context allocation restrictions leak into the one-shot API. */ initialized->staticSize = 0; return ZSTD_decompressDCtx(initialized, dst, dstCapacity, src, srcSize); #endif } void* ZSTD_rust_custom_malloc(size_t size, ZSTD_customMem customMem) { return ZSTD_customMalloc(size, customMem); } void* ZSTD_rust_custom_calloc(size_t size, ZSTD_customMem customMem) { return ZSTD_customCalloc(size, customMem); } void ZSTD_rust_custom_free(void* allocation, ZSTD_customMem customMem) { ZSTD_customFree(allocation, customMem); } ZSTD_DDict* ZSTD_rust_create_ddict(const void* dict, size_t dictSize, ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType, ZSTD_customMem customMem) { return ZSTD_createDDict_advanced(dict, dictSize, dictLoadMethod, dictContentType, customMem); } void ZSTD_rust_dctx_copy_prefix(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx) { size_t const toCopy = (size_t)((const char*)(&dstDCtx->inBuff) - (const char*)dstDCtx); ZSTD_memcpy(dstDCtx, srcDCtx, toCopy); } void ZSTD_rust_dctx_trace_begin(ZSTD_DCtx* dctx) { #if ZSTD_TRACE dctx->traceCtx = (ZSTD_trace_decompress_begin != NULL) ? ZSTD_trace_decompress_begin(dctx) : 0; #else (void)dctx; #endif } void ZSTD_rust_dctx_trace_end(ZSTD_DCtx* dctx, U64 uncompressedSize, U64 compressedSize, int streaming) { #if ZSTD_TRACE if (dctx->traceCtx && ZSTD_trace_decompress_end != NULL) { ZSTD_Trace trace; ZSTD_memset(&trace, 0, sizeof(trace)); trace.version = ZSTD_VERSION_NUMBER; trace.streaming = streaming; if (dctx->ddict) { trace.dictionaryID = ZSTD_getDictID_fromDDict(dctx->ddict); trace.dictionarySize = ZSTD_DDict_dictSize(dctx->ddict); trace.dictionaryIsCold = dctx->ddictIsCold; } trace.uncompressedSize = (size_t)uncompressedSize; trace.compressedSize = (size_t)compressedSize; trace.dctx = dctx; ZSTD_trace_decompress_end(dctx->traceCtx, &trace); } #else (void)dctx; (void)uncompressedSize; (void)compressedSize; (void)streaming; #endif } unsigned ZSTD_rust_legacy_is(const void* src, size_t srcSize) { #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1) return ZSTD_isLegacy(src, srcSize); #else (void)src; (void)srcSize; return 0; #endif } unsigned long long ZSTD_rust_legacy_get_decompressed_size(const void* src, size_t srcSize) { #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1) return ZSTD_getDecompressedSize_legacy(src, srcSize); #else (void)src; (void)srcSize; return 0; #endif } size_t ZSTD_rust_legacy_find_compressed_size(const void* src, size_t srcSize) { #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1) return ZSTD_findFrameCompressedSizeLegacy(src, srcSize); #else (void)src; (void)srcSize; return ERROR(prefix_unknown); #endif } size_t ZSTD_rust_legacy_frame_size_info(const void* src, size_t srcSize, size_t* compressedSize, unsigned long long* decompressedBound, size_t* nbBlocks) { #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1) ZSTD_frameSizeInfo const info = ZSTD_findFrameSizeInfoLegacy(src, srcSize); *compressedSize = info.compressedSize; *decompressedBound = info.decompressedBound; *nbBlocks = info.decompressedBound == ZSTD_CONTENTSIZE_ERROR ? 0 : (size_t)(info.decompressedBound / ZSTD_BLOCKSIZE_MAX); return ZSTD_isError(info.compressedSize) ? info.compressedSize : 0; #else (void)src; (void)srcSize; *compressedSize = ERROR(prefix_unknown); *decompressedBound = ZSTD_CONTENTSIZE_ERROR; *nbBlocks = 0; return ERROR(prefix_unknown); #endif } size_t ZSTD_rust_legacy_decompress(void* dst, size_t dstCapacity, const void* src, size_t srcSize, const void* dict, size_t dictSize) { #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1) return ZSTD_decompressLegacy(dst, dstCapacity, src, srcSize, dict, dictSize); #else (void)dst; (void)dstCapacity; (void)src; (void)srcSize; (void)dict; (void)dictSize; return ERROR(prefix_unknown); #endif } size_t ZSTD_rust_legacy_decompress_stream(ZSTD_DCtx* dctx, ZSTD_outBuffer* output, ZSTD_inBuffer* input, const void* dict, size_t dictSize) { #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1) size_t hint; if (dctx->legacyVersion) { hint = ZSTD_decompressLegacyStream(dctx->legacyContext, dctx->legacyVersion, output, input); if (hint == 0) dctx->streamStage = zdss_init; return hint; } { const char* const istart = input->pos != 0 ? (const char*)input->src + input->pos : (const char*)input->src; size_t const inputSize = input->size - input->pos; U32 const legacyVersion = ZSTD_isLegacy(istart, inputSize); if (!legacyVersion) return ERROR(prefix_unknown); if (dctx->staticSize) return ERROR(memory_allocation); FORWARD_IF_ERROR(ZSTD_initLegacyStream(&dctx->legacyContext, dctx->previousLegacyVersion, legacyVersion, dict, dictSize), ""); dctx->legacyVersion = dctx->previousLegacyVersion = legacyVersion; hint = ZSTD_decompressLegacyStream(dctx->legacyContext, legacyVersion, output, input); if (hint == 0) dctx->streamStage = zdss_init; return hint; } #else (void)dctx; (void)output; (void)input; (void)dict; (void)dictSize; return ERROR(prefix_unknown); #endif } void ZSTD_rust_legacy_free_stream(ZSTD_DCtx* dctx) { #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1) if (dctx->legacyContext) { ZSTD_freeLegacyStreamContext(dctx->legacyContext, dctx->previousLegacyVersion); dctx->legacyContext = NULL; } #else (void)dctx; #endif }