GitHub Viewer
/* Low level interface to the Zstandard algorithm & the zstd library. */
#ifndef Py_BUILD_CORE_BUILTIN
# define Py_BUILD_CORE_MODULE 1
#endif
#include "Python.h"
#include "_zstdmodule.h"
#include // ZSTD_*()
#include // ZDICT_*()
/*[clinic input]
module _zstd
[clinic start generated code]*/
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=4b5f5587aac15c14]*/
#include "clinic/_zstdmodule.c.h"
ZstdDict *
_Py_parse_zstd_dict(const _zstd_state *state, PyObject *dict, int *ptype)
{
if (state == NULL) {
return NULL;
}
/* Check ZstdDict */
if (PyObject_TypeCheck(dict, state->ZstdDict_type)) {
return (ZstdDict*)dict;
}
/* Check (ZstdDict, type) */
if (PyTuple_CheckExact(dict) && PyTuple_GET_SIZE(dict) == 2
&& PyObject_TypeCheck(PyTuple_GET_ITEM(dict, 0), state->ZstdDict_type)
&& PyLong_Check(PyTuple_GET_ITEM(dict, 1)))
{
int type = PyLong_AsInt(PyTuple_GET_ITEM(dict, 1));
if (type == -1 && PyErr_Occurred()) {
return NULL;
}
if (type == DICT_TYPE_DIGESTED
|| type == DICT_TYPE_UNDIGESTED
|| type == DICT_TYPE_PREFIX)
{
*ptype = type;
return (ZstdDict*)PyTuple_GET_ITEM(dict, 0);
}
}
/* Wrong type */
PyErr_SetString(PyExc_TypeError,
"zstd_dict argument should be a ZstdDict object.");
return NULL;
}
/* Format error message and set ZstdError. */
void
set_zstd_error(const _zstd_state *state, error_type type, size_t zstd_ret)
{
const char *msg;
assert(ZSTD_isError(zstd_ret));
if (state == NULL) {
return;
}
switch (type) {
case ERR_DECOMPRESS:
msg = "Unable to decompress Zstandard data: %s";
break;
case ERR_COMPRESS:
msg = "Unable to compress Zstandard data: %s";
break;
case ERR_SET_PLEDGED_INPUT_SIZE:
msg = "Unable to set pledged uncompressed content size: %s";
break;
case ERR_LOAD_D_DICT:
msg = "Unable to load Zstandard dictionary or prefix for "
"decompression: %s";
break;
case ERR_LOAD_C_DICT:
msg = "Unable to load Zstandard dictionary or prefix for "
"compression: %s";
break;
case ERR_GET_C_BOUNDS:
msg = "Unable to get zstd compression parameter bounds: %s";
break;
case ERR_GET_D_BOUNDS:
msg = "Unable to get zstd decompression parameter bounds: %s";
break;
case ERR_SET_C_LEVEL:
msg = "Unable to set zstd compression level: %s";
break;
case ERR_TRAIN_DICT:
msg = "Unable to train the Zstandard dictionary: %s";
break;
case ERR_FINALIZE_DICT:
msg = "Unable to finalize the Zstandard dictionary: %s";
break;
default:
Py_UNREACHABLE();
}
PyErr_Format(state->ZstdError, msg, ZSTD_getErrorName(zstd_ret));
}
typedef struct {
int parameter;
char parameter_name[32];
} ParameterInfo;
static const ParameterInfo cp_list[] = {
{ZSTD_c_compressionLevel, "compression_level"},
{ZSTD_c_windowLog, "window_log"},
{ZSTD_c_hashLog, "hash_log"},
{ZSTD_c_chainLog, "chain_log"},
{ZSTD_c_searchLog, "search_log"},
{ZSTD_c_minMatch, "min_match"},
{ZSTD_c_targetLength, "target_length"},
{ZSTD_c_strategy, "strategy"},
{ZSTD_c_enableLongDistanceMatching, "enable_long_distance_matching"},
{ZSTD_c_ldmHashLog, "ldm_hash_log"},
{ZSTD_c_ldmMinMatch, "ldm_min_match"},
{ZSTD_c_ldmBucketSizeLog, "ldm_bucket_size_log"},
{ZSTD_c_ldmHashRateLog, "ldm_hash_rate_log"},
{ZSTD_c_contentSizeFlag, "content_size_flag"},
{ZSTD_c_checksumFlag, "checksum_flag"},
{ZSTD_c_dictIDFlag, "dict_id_flag"},
{ZSTD_c_nbWorkers, "nb_workers"},
{ZSTD_c_jobSize, "job_size"},
{ZSTD_c_overlapLog, "overlap_log"}
};
static const ParameterInfo dp_list[] = {
{ZSTD_d_windowLogMax, "window_log_max"}
};
void
set_parameter_error(int is_compress, int key_v, int value_v)
{
ParameterInfo const *list;
int list_size;
char *type;
ZSTD_bounds bounds;
char pos_msg[64];
if (is_compress) {
list = cp_list;
list_size = Py_ARRAY_LENGTH(cp_list);
type = "compression";
}
else {
list = dp_list;
list_size = Py_ARRAY_LENGTH(dp_list);
type = "decompression";
}
/* Find parameter's name */
char const *name = NULL;
for (int i = 0; i < list_size; i++) {
if (key_v == (list+i)->parameter) {
name = (list+i)->parameter_name;
break;
}
}
/* Unknown parameter */
if (name == NULL) {
PyOS_snprintf(pos_msg, sizeof(pos_msg),
"unknown parameter (key %d)", key_v);
name = pos_msg;
}
/* Get parameter bounds */
if (is_compress) {
bounds = ZSTD_cParam_getBounds(key_v);
}
else {
bounds = ZSTD_dParam_getBounds(key_v);
}
if (ZSTD_isError(bounds.error)) {
PyErr_Format(PyExc_ValueError, "invalid %s parameter '%s'",
type, name);
return;
}
/* Error message */
PyErr_Format(PyExc_ValueError,
"%s parameter '%s' received an illegal value %d; "
"the valid range is [%d, %d]",
type, name, value_v, bounds.lowerBound, bounds.upperBound);
}
static inline _zstd_state*
get_zstd_state(PyObject *module)
{
void *state = PyModule_GetState(module);
assert(state != NULL);
return (_zstd_state *)state;
}
static Py_ssize_t
calculate_samples_stats(PyBytesObject *samples_bytes, PyObject *samples_sizes,
size_t **chunk_sizes)
{
Py_ssize_t chunks_number;
Py_ssize_t sizes_sum;
Py_ssize_t i;
chunks_number = PyTuple_GET_SIZE(samples_sizes);
if ((size_t) chunks_number > UINT32_MAX) {
PyErr_Format(PyExc_ValueError,
"The number of samples should be