17db96d56Sopenharmony_ci/* _lzma - Low-level Python interface to liblzma.
27db96d56Sopenharmony_ci
37db96d56Sopenharmony_ci   Initial implementation by Per Øyvind Karlsen.
47db96d56Sopenharmony_ci   Rewritten by Nadeem Vawda.
57db96d56Sopenharmony_ci
67db96d56Sopenharmony_ci*/
77db96d56Sopenharmony_ci
87db96d56Sopenharmony_ci#define PY_SSIZE_T_CLEAN
97db96d56Sopenharmony_ci
107db96d56Sopenharmony_ci#include "Python.h"
117db96d56Sopenharmony_ci#include "structmember.h"         // PyMemberDef
127db96d56Sopenharmony_ci
137db96d56Sopenharmony_ci#include <stdlib.h>               // free()
147db96d56Sopenharmony_ci#include <string.h>
157db96d56Sopenharmony_ci
167db96d56Sopenharmony_ci#include <lzma.h>
177db96d56Sopenharmony_ci
187db96d56Sopenharmony_ci// Blocks output buffer wrappers
197db96d56Sopenharmony_ci#include "pycore_blocks_output_buffer.h"
207db96d56Sopenharmony_ci
217db96d56Sopenharmony_ci#if OUTPUT_BUFFER_MAX_BLOCK_SIZE > SIZE_MAX
227db96d56Sopenharmony_ci    #error "The maximum block size accepted by liblzma is SIZE_MAX."
237db96d56Sopenharmony_ci#endif
247db96d56Sopenharmony_ci
257db96d56Sopenharmony_ci/* On success, return value >= 0
267db96d56Sopenharmony_ci   On failure, return -1 */
277db96d56Sopenharmony_cistatic inline Py_ssize_t
287db96d56Sopenharmony_ciOutputBuffer_InitAndGrow(_BlocksOutputBuffer *buffer, Py_ssize_t max_length,
297db96d56Sopenharmony_ci                         uint8_t **next_out, size_t *avail_out)
307db96d56Sopenharmony_ci{
317db96d56Sopenharmony_ci    Py_ssize_t allocated;
327db96d56Sopenharmony_ci
337db96d56Sopenharmony_ci    allocated = _BlocksOutputBuffer_InitAndGrow(
347db96d56Sopenharmony_ci                    buffer, max_length, (void**) next_out);
357db96d56Sopenharmony_ci    *avail_out = (size_t) allocated;
367db96d56Sopenharmony_ci    return allocated;
377db96d56Sopenharmony_ci}
387db96d56Sopenharmony_ci
397db96d56Sopenharmony_ci/* On success, return value >= 0
407db96d56Sopenharmony_ci   On failure, return -1 */
417db96d56Sopenharmony_cistatic inline Py_ssize_t
427db96d56Sopenharmony_ciOutputBuffer_Grow(_BlocksOutputBuffer *buffer,
437db96d56Sopenharmony_ci                  uint8_t **next_out, size_t *avail_out)
447db96d56Sopenharmony_ci{
457db96d56Sopenharmony_ci    Py_ssize_t allocated;
467db96d56Sopenharmony_ci
477db96d56Sopenharmony_ci    allocated = _BlocksOutputBuffer_Grow(
487db96d56Sopenharmony_ci                    buffer, (void**) next_out, (Py_ssize_t) *avail_out);
497db96d56Sopenharmony_ci    *avail_out = (size_t) allocated;
507db96d56Sopenharmony_ci    return allocated;
517db96d56Sopenharmony_ci}
527db96d56Sopenharmony_ci
537db96d56Sopenharmony_cistatic inline Py_ssize_t
547db96d56Sopenharmony_ciOutputBuffer_GetDataSize(_BlocksOutputBuffer *buffer, size_t avail_out)
557db96d56Sopenharmony_ci{
567db96d56Sopenharmony_ci    return _BlocksOutputBuffer_GetDataSize(buffer, (Py_ssize_t) avail_out);
577db96d56Sopenharmony_ci}
587db96d56Sopenharmony_ci
597db96d56Sopenharmony_cistatic inline PyObject *
607db96d56Sopenharmony_ciOutputBuffer_Finish(_BlocksOutputBuffer *buffer, size_t avail_out)
617db96d56Sopenharmony_ci{
627db96d56Sopenharmony_ci    return _BlocksOutputBuffer_Finish(buffer, (Py_ssize_t) avail_out);
637db96d56Sopenharmony_ci}
647db96d56Sopenharmony_ci
657db96d56Sopenharmony_cistatic inline void
667db96d56Sopenharmony_ciOutputBuffer_OnError(_BlocksOutputBuffer *buffer)
677db96d56Sopenharmony_ci{
687db96d56Sopenharmony_ci    _BlocksOutputBuffer_OnError(buffer);
697db96d56Sopenharmony_ci}
707db96d56Sopenharmony_ci
717db96d56Sopenharmony_ci
727db96d56Sopenharmony_ci#define ACQUIRE_LOCK(obj) do { \
737db96d56Sopenharmony_ci    if (!PyThread_acquire_lock((obj)->lock, 0)) { \
747db96d56Sopenharmony_ci        Py_BEGIN_ALLOW_THREADS \
757db96d56Sopenharmony_ci        PyThread_acquire_lock((obj)->lock, 1); \
767db96d56Sopenharmony_ci        Py_END_ALLOW_THREADS \
777db96d56Sopenharmony_ci    } } while (0)
787db96d56Sopenharmony_ci#define RELEASE_LOCK(obj) PyThread_release_lock((obj)->lock)
797db96d56Sopenharmony_ci
807db96d56Sopenharmony_citypedef struct {
817db96d56Sopenharmony_ci    PyTypeObject *lzma_compressor_type;
827db96d56Sopenharmony_ci    PyTypeObject *lzma_decompressor_type;
837db96d56Sopenharmony_ci    PyObject *error;
847db96d56Sopenharmony_ci    PyObject *empty_tuple;
857db96d56Sopenharmony_ci} _lzma_state;
867db96d56Sopenharmony_ci
877db96d56Sopenharmony_cistatic inline _lzma_state*
887db96d56Sopenharmony_ciget_lzma_state(PyObject *module)
897db96d56Sopenharmony_ci{
907db96d56Sopenharmony_ci    void *state = PyModule_GetState(module);
917db96d56Sopenharmony_ci    assert(state != NULL);
927db96d56Sopenharmony_ci    return (_lzma_state *)state;
937db96d56Sopenharmony_ci}
947db96d56Sopenharmony_ci
957db96d56Sopenharmony_ci/* Container formats: */
967db96d56Sopenharmony_cienum {
977db96d56Sopenharmony_ci    FORMAT_AUTO,
987db96d56Sopenharmony_ci    FORMAT_XZ,
997db96d56Sopenharmony_ci    FORMAT_ALONE,
1007db96d56Sopenharmony_ci    FORMAT_RAW,
1017db96d56Sopenharmony_ci};
1027db96d56Sopenharmony_ci
1037db96d56Sopenharmony_ci#define LZMA_CHECK_UNKNOWN (LZMA_CHECK_ID_MAX + 1)
1047db96d56Sopenharmony_ci
1057db96d56Sopenharmony_ci
1067db96d56Sopenharmony_citypedef struct {
1077db96d56Sopenharmony_ci    PyObject_HEAD
1087db96d56Sopenharmony_ci    lzma_allocator alloc;
1097db96d56Sopenharmony_ci    lzma_stream lzs;
1107db96d56Sopenharmony_ci    int flushed;
1117db96d56Sopenharmony_ci    PyThread_type_lock lock;
1127db96d56Sopenharmony_ci} Compressor;
1137db96d56Sopenharmony_ci
1147db96d56Sopenharmony_citypedef struct {
1157db96d56Sopenharmony_ci    PyObject_HEAD
1167db96d56Sopenharmony_ci    lzma_allocator alloc;
1177db96d56Sopenharmony_ci    lzma_stream lzs;
1187db96d56Sopenharmony_ci    int check;
1197db96d56Sopenharmony_ci    char eof;
1207db96d56Sopenharmony_ci    PyObject *unused_data;
1217db96d56Sopenharmony_ci    char needs_input;
1227db96d56Sopenharmony_ci    uint8_t *input_buffer;
1237db96d56Sopenharmony_ci    size_t input_buffer_size;
1247db96d56Sopenharmony_ci    PyThread_type_lock lock;
1257db96d56Sopenharmony_ci} Decompressor;
1267db96d56Sopenharmony_ci
1277db96d56Sopenharmony_ci/* Helper functions. */
1287db96d56Sopenharmony_ci
1297db96d56Sopenharmony_cistatic int
1307db96d56Sopenharmony_cicatch_lzma_error(_lzma_state *state, lzma_ret lzret)
1317db96d56Sopenharmony_ci{
1327db96d56Sopenharmony_ci    switch (lzret) {
1337db96d56Sopenharmony_ci        case LZMA_OK:
1347db96d56Sopenharmony_ci        case LZMA_GET_CHECK:
1357db96d56Sopenharmony_ci        case LZMA_NO_CHECK:
1367db96d56Sopenharmony_ci        case LZMA_STREAM_END:
1377db96d56Sopenharmony_ci            return 0;
1387db96d56Sopenharmony_ci        case LZMA_UNSUPPORTED_CHECK:
1397db96d56Sopenharmony_ci            PyErr_SetString(state->error, "Unsupported integrity check");
1407db96d56Sopenharmony_ci            return 1;
1417db96d56Sopenharmony_ci        case LZMA_MEM_ERROR:
1427db96d56Sopenharmony_ci            PyErr_NoMemory();
1437db96d56Sopenharmony_ci            return 1;
1447db96d56Sopenharmony_ci        case LZMA_MEMLIMIT_ERROR:
1457db96d56Sopenharmony_ci            PyErr_SetString(state->error, "Memory usage limit exceeded");
1467db96d56Sopenharmony_ci            return 1;
1477db96d56Sopenharmony_ci        case LZMA_FORMAT_ERROR:
1487db96d56Sopenharmony_ci            PyErr_SetString(state->error, "Input format not supported by decoder");
1497db96d56Sopenharmony_ci            return 1;
1507db96d56Sopenharmony_ci        case LZMA_OPTIONS_ERROR:
1517db96d56Sopenharmony_ci            PyErr_SetString(state->error, "Invalid or unsupported options");
1527db96d56Sopenharmony_ci            return 1;
1537db96d56Sopenharmony_ci        case LZMA_DATA_ERROR:
1547db96d56Sopenharmony_ci            PyErr_SetString(state->error, "Corrupt input data");
1557db96d56Sopenharmony_ci            return 1;
1567db96d56Sopenharmony_ci        case LZMA_BUF_ERROR:
1577db96d56Sopenharmony_ci            PyErr_SetString(state->error, "Insufficient buffer space");
1587db96d56Sopenharmony_ci            return 1;
1597db96d56Sopenharmony_ci        case LZMA_PROG_ERROR:
1607db96d56Sopenharmony_ci            PyErr_SetString(state->error, "Internal error");
1617db96d56Sopenharmony_ci            return 1;
1627db96d56Sopenharmony_ci        default:
1637db96d56Sopenharmony_ci            PyErr_Format(state->error, "Unrecognized error from liblzma: %d", lzret);
1647db96d56Sopenharmony_ci            return 1;
1657db96d56Sopenharmony_ci    }
1667db96d56Sopenharmony_ci}
1677db96d56Sopenharmony_ci
1687db96d56Sopenharmony_cistatic void*
1697db96d56Sopenharmony_ciPyLzma_Malloc(void *opaque, size_t items, size_t size)
1707db96d56Sopenharmony_ci{
1717db96d56Sopenharmony_ci    if (size != 0 && items > (size_t)PY_SSIZE_T_MAX / size) {
1727db96d56Sopenharmony_ci        return NULL;
1737db96d56Sopenharmony_ci    }
1747db96d56Sopenharmony_ci    /* PyMem_Malloc() cannot be used:
1757db96d56Sopenharmony_ci       the GIL is not held when lzma_code() is called */
1767db96d56Sopenharmony_ci    return PyMem_RawMalloc(items * size);
1777db96d56Sopenharmony_ci}
1787db96d56Sopenharmony_ci
1797db96d56Sopenharmony_cistatic void
1807db96d56Sopenharmony_ciPyLzma_Free(void *opaque, void *ptr)
1817db96d56Sopenharmony_ci{
1827db96d56Sopenharmony_ci    PyMem_RawFree(ptr);
1837db96d56Sopenharmony_ci}
1847db96d56Sopenharmony_ci
1857db96d56Sopenharmony_ci
1867db96d56Sopenharmony_ci/* Some custom type conversions for PyArg_ParseTupleAndKeywords(),
1877db96d56Sopenharmony_ci   since the predefined conversion specifiers do not suit our needs:
1887db96d56Sopenharmony_ci
1897db96d56Sopenharmony_ci      uint32_t - the "I" (unsigned int) specifier is the right size, but
1907db96d56Sopenharmony_ci      silently ignores overflows on conversion.
1917db96d56Sopenharmony_ci
1927db96d56Sopenharmony_ci      lzma_vli - the "K" (unsigned long long) specifier is the right
1937db96d56Sopenharmony_ci      size, but like "I" it silently ignores overflows on conversion.
1947db96d56Sopenharmony_ci
1957db96d56Sopenharmony_ci      lzma_mode and lzma_match_finder - these are enumeration types, and
1967db96d56Sopenharmony_ci      so the size of each is implementation-defined. Worse, different
1977db96d56Sopenharmony_ci      enum types can be of different sizes within the same program, so
1987db96d56Sopenharmony_ci      to be strictly correct, we need to define two separate converters.
1997db96d56Sopenharmony_ci */
2007db96d56Sopenharmony_ci
2017db96d56Sopenharmony_ci#define INT_TYPE_CONVERTER_FUNC(TYPE, FUNCNAME) \
2027db96d56Sopenharmony_ci    static int \
2037db96d56Sopenharmony_ci    FUNCNAME(PyObject *obj, void *ptr) \
2047db96d56Sopenharmony_ci    { \
2057db96d56Sopenharmony_ci        unsigned long long val; \
2067db96d56Sopenharmony_ci        \
2077db96d56Sopenharmony_ci        val = PyLong_AsUnsignedLongLong(obj); \
2087db96d56Sopenharmony_ci        if (PyErr_Occurred()) \
2097db96d56Sopenharmony_ci            return 0; \
2107db96d56Sopenharmony_ci        if ((unsigned long long)(TYPE)val != val) { \
2117db96d56Sopenharmony_ci            PyErr_SetString(PyExc_OverflowError, \
2127db96d56Sopenharmony_ci                            "Value too large for " #TYPE " type"); \
2137db96d56Sopenharmony_ci            return 0; \
2147db96d56Sopenharmony_ci        } \
2157db96d56Sopenharmony_ci        *(TYPE *)ptr = (TYPE)val; \
2167db96d56Sopenharmony_ci        return 1; \
2177db96d56Sopenharmony_ci    }
2187db96d56Sopenharmony_ci
2197db96d56Sopenharmony_ciINT_TYPE_CONVERTER_FUNC(uint32_t, uint32_converter)
2207db96d56Sopenharmony_ciINT_TYPE_CONVERTER_FUNC(lzma_vli, lzma_vli_converter)
2217db96d56Sopenharmony_ciINT_TYPE_CONVERTER_FUNC(lzma_mode, lzma_mode_converter)
2227db96d56Sopenharmony_ciINT_TYPE_CONVERTER_FUNC(lzma_match_finder, lzma_mf_converter)
2237db96d56Sopenharmony_ci
2247db96d56Sopenharmony_ci#undef INT_TYPE_CONVERTER_FUNC
2257db96d56Sopenharmony_ci
2267db96d56Sopenharmony_ci
2277db96d56Sopenharmony_ci/* Filter specifier parsing.
2287db96d56Sopenharmony_ci
2297db96d56Sopenharmony_ci   This code handles converting filter specifiers (Python dicts) into
2307db96d56Sopenharmony_ci   the C lzma_filter structs expected by liblzma. */
2317db96d56Sopenharmony_ci
2327db96d56Sopenharmony_cistatic void *
2337db96d56Sopenharmony_ciparse_filter_spec_lzma(_lzma_state *state, PyObject *spec)
2347db96d56Sopenharmony_ci{
2357db96d56Sopenharmony_ci    static char *optnames[] = {"id", "preset", "dict_size", "lc", "lp",
2367db96d56Sopenharmony_ci                               "pb", "mode", "nice_len", "mf", "depth", NULL};
2377db96d56Sopenharmony_ci    PyObject *id;
2387db96d56Sopenharmony_ci    PyObject *preset_obj;
2397db96d56Sopenharmony_ci    uint32_t preset = LZMA_PRESET_DEFAULT;
2407db96d56Sopenharmony_ci    lzma_options_lzma *options;
2417db96d56Sopenharmony_ci
2427db96d56Sopenharmony_ci    /* First, fill in default values for all the options using a preset.
2437db96d56Sopenharmony_ci       Then, override the defaults with any values given by the caller. */
2447db96d56Sopenharmony_ci
2457db96d56Sopenharmony_ci    preset_obj = PyMapping_GetItemString(spec, "preset");
2467db96d56Sopenharmony_ci    if (preset_obj == NULL) {
2477db96d56Sopenharmony_ci        if (PyErr_ExceptionMatches(PyExc_KeyError)) {
2487db96d56Sopenharmony_ci            PyErr_Clear();
2497db96d56Sopenharmony_ci        }
2507db96d56Sopenharmony_ci        else {
2517db96d56Sopenharmony_ci            return NULL;
2527db96d56Sopenharmony_ci        }
2537db96d56Sopenharmony_ci    } else {
2547db96d56Sopenharmony_ci        int ok = uint32_converter(preset_obj, &preset);
2557db96d56Sopenharmony_ci        Py_DECREF(preset_obj);
2567db96d56Sopenharmony_ci        if (!ok) {
2577db96d56Sopenharmony_ci            return NULL;
2587db96d56Sopenharmony_ci        }
2597db96d56Sopenharmony_ci    }
2607db96d56Sopenharmony_ci
2617db96d56Sopenharmony_ci    options = (lzma_options_lzma *)PyMem_Calloc(1, sizeof *options);
2627db96d56Sopenharmony_ci    if (options == NULL) {
2637db96d56Sopenharmony_ci        return PyErr_NoMemory();
2647db96d56Sopenharmony_ci    }
2657db96d56Sopenharmony_ci
2667db96d56Sopenharmony_ci    if (lzma_lzma_preset(options, preset)) {
2677db96d56Sopenharmony_ci        PyMem_Free(options);
2687db96d56Sopenharmony_ci        PyErr_Format(state->error, "Invalid compression preset: %u", preset);
2697db96d56Sopenharmony_ci        return NULL;
2707db96d56Sopenharmony_ci    }
2717db96d56Sopenharmony_ci
2727db96d56Sopenharmony_ci    if (!PyArg_ParseTupleAndKeywords(state->empty_tuple, spec,
2737db96d56Sopenharmony_ci                                     "|OOO&O&O&O&O&O&O&O&", optnames,
2747db96d56Sopenharmony_ci                                     &id, &preset_obj,
2757db96d56Sopenharmony_ci                                     uint32_converter, &options->dict_size,
2767db96d56Sopenharmony_ci                                     uint32_converter, &options->lc,
2777db96d56Sopenharmony_ci                                     uint32_converter, &options->lp,
2787db96d56Sopenharmony_ci                                     uint32_converter, &options->pb,
2797db96d56Sopenharmony_ci                                     lzma_mode_converter, &options->mode,
2807db96d56Sopenharmony_ci                                     uint32_converter, &options->nice_len,
2817db96d56Sopenharmony_ci                                     lzma_mf_converter, &options->mf,
2827db96d56Sopenharmony_ci                                     uint32_converter, &options->depth)) {
2837db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError,
2847db96d56Sopenharmony_ci                        "Invalid filter specifier for LZMA filter");
2857db96d56Sopenharmony_ci        PyMem_Free(options);
2867db96d56Sopenharmony_ci        return NULL;
2877db96d56Sopenharmony_ci    }
2887db96d56Sopenharmony_ci
2897db96d56Sopenharmony_ci    return options;
2907db96d56Sopenharmony_ci}
2917db96d56Sopenharmony_ci
2927db96d56Sopenharmony_cistatic void *
2937db96d56Sopenharmony_ciparse_filter_spec_delta(_lzma_state *state, PyObject *spec)
2947db96d56Sopenharmony_ci{
2957db96d56Sopenharmony_ci    static char *optnames[] = {"id", "dist", NULL};
2967db96d56Sopenharmony_ci    PyObject *id;
2977db96d56Sopenharmony_ci    uint32_t dist = 1;
2987db96d56Sopenharmony_ci    lzma_options_delta *options;
2997db96d56Sopenharmony_ci
3007db96d56Sopenharmony_ci    if (!PyArg_ParseTupleAndKeywords(state->empty_tuple, spec, "|OO&", optnames,
3017db96d56Sopenharmony_ci                                     &id, uint32_converter, &dist)) {
3027db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError,
3037db96d56Sopenharmony_ci                        "Invalid filter specifier for delta filter");
3047db96d56Sopenharmony_ci        return NULL;
3057db96d56Sopenharmony_ci    }
3067db96d56Sopenharmony_ci
3077db96d56Sopenharmony_ci    options = (lzma_options_delta *)PyMem_Calloc(1, sizeof *options);
3087db96d56Sopenharmony_ci    if (options == NULL) {
3097db96d56Sopenharmony_ci        return PyErr_NoMemory();
3107db96d56Sopenharmony_ci    }
3117db96d56Sopenharmony_ci    options->type = LZMA_DELTA_TYPE_BYTE;
3127db96d56Sopenharmony_ci    options->dist = dist;
3137db96d56Sopenharmony_ci    return options;
3147db96d56Sopenharmony_ci}
3157db96d56Sopenharmony_ci
3167db96d56Sopenharmony_cistatic void *
3177db96d56Sopenharmony_ciparse_filter_spec_bcj(_lzma_state *state, PyObject *spec)
3187db96d56Sopenharmony_ci{
3197db96d56Sopenharmony_ci    static char *optnames[] = {"id", "start_offset", NULL};
3207db96d56Sopenharmony_ci    PyObject *id;
3217db96d56Sopenharmony_ci    uint32_t start_offset = 0;
3227db96d56Sopenharmony_ci    lzma_options_bcj *options;
3237db96d56Sopenharmony_ci
3247db96d56Sopenharmony_ci    if (!PyArg_ParseTupleAndKeywords(state->empty_tuple, spec, "|OO&", optnames,
3257db96d56Sopenharmony_ci                                     &id, uint32_converter, &start_offset)) {
3267db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError,
3277db96d56Sopenharmony_ci                        "Invalid filter specifier for BCJ filter");
3287db96d56Sopenharmony_ci        return NULL;
3297db96d56Sopenharmony_ci    }
3307db96d56Sopenharmony_ci
3317db96d56Sopenharmony_ci    options = (lzma_options_bcj *)PyMem_Calloc(1, sizeof *options);
3327db96d56Sopenharmony_ci    if (options == NULL) {
3337db96d56Sopenharmony_ci        return PyErr_NoMemory();
3347db96d56Sopenharmony_ci    }
3357db96d56Sopenharmony_ci    options->start_offset = start_offset;
3367db96d56Sopenharmony_ci    return options;
3377db96d56Sopenharmony_ci}
3387db96d56Sopenharmony_ci
3397db96d56Sopenharmony_cistatic int
3407db96d56Sopenharmony_cilzma_filter_converter(_lzma_state *state, PyObject *spec, void *ptr)
3417db96d56Sopenharmony_ci{
3427db96d56Sopenharmony_ci    lzma_filter *f = (lzma_filter *)ptr;
3437db96d56Sopenharmony_ci    PyObject *id_obj;
3447db96d56Sopenharmony_ci
3457db96d56Sopenharmony_ci    if (!PyMapping_Check(spec)) {
3467db96d56Sopenharmony_ci        PyErr_SetString(PyExc_TypeError,
3477db96d56Sopenharmony_ci                        "Filter specifier must be a dict or dict-like object");
3487db96d56Sopenharmony_ci        return 0;
3497db96d56Sopenharmony_ci    }
3507db96d56Sopenharmony_ci    id_obj = PyMapping_GetItemString(spec, "id");
3517db96d56Sopenharmony_ci    if (id_obj == NULL) {
3527db96d56Sopenharmony_ci        if (PyErr_ExceptionMatches(PyExc_KeyError))
3537db96d56Sopenharmony_ci            PyErr_SetString(PyExc_ValueError,
3547db96d56Sopenharmony_ci                            "Filter specifier must have an \"id\" entry");
3557db96d56Sopenharmony_ci        return 0;
3567db96d56Sopenharmony_ci    }
3577db96d56Sopenharmony_ci    f->id = PyLong_AsUnsignedLongLong(id_obj);
3587db96d56Sopenharmony_ci    Py_DECREF(id_obj);
3597db96d56Sopenharmony_ci    if (PyErr_Occurred()) {
3607db96d56Sopenharmony_ci        return 0;
3617db96d56Sopenharmony_ci    }
3627db96d56Sopenharmony_ci
3637db96d56Sopenharmony_ci    switch (f->id) {
3647db96d56Sopenharmony_ci        case LZMA_FILTER_LZMA1:
3657db96d56Sopenharmony_ci        case LZMA_FILTER_LZMA2:
3667db96d56Sopenharmony_ci            f->options = parse_filter_spec_lzma(state, spec);
3677db96d56Sopenharmony_ci            return f->options != NULL;
3687db96d56Sopenharmony_ci        case LZMA_FILTER_DELTA:
3697db96d56Sopenharmony_ci            f->options = parse_filter_spec_delta(state, spec);
3707db96d56Sopenharmony_ci            return f->options != NULL;
3717db96d56Sopenharmony_ci        case LZMA_FILTER_X86:
3727db96d56Sopenharmony_ci        case LZMA_FILTER_POWERPC:
3737db96d56Sopenharmony_ci        case LZMA_FILTER_IA64:
3747db96d56Sopenharmony_ci        case LZMA_FILTER_ARM:
3757db96d56Sopenharmony_ci        case LZMA_FILTER_ARMTHUMB:
3767db96d56Sopenharmony_ci        case LZMA_FILTER_SPARC:
3777db96d56Sopenharmony_ci            f->options = parse_filter_spec_bcj(state, spec);
3787db96d56Sopenharmony_ci            return f->options != NULL;
3797db96d56Sopenharmony_ci        default:
3807db96d56Sopenharmony_ci            PyErr_Format(PyExc_ValueError, "Invalid filter ID: %llu", f->id);
3817db96d56Sopenharmony_ci            return 0;
3827db96d56Sopenharmony_ci    }
3837db96d56Sopenharmony_ci}
3847db96d56Sopenharmony_ci
3857db96d56Sopenharmony_cistatic void
3867db96d56Sopenharmony_cifree_filter_chain(lzma_filter filters[])
3877db96d56Sopenharmony_ci{
3887db96d56Sopenharmony_ci    for (int i = 0; filters[i].id != LZMA_VLI_UNKNOWN; i++) {
3897db96d56Sopenharmony_ci        PyMem_Free(filters[i].options);
3907db96d56Sopenharmony_ci    }
3917db96d56Sopenharmony_ci}
3927db96d56Sopenharmony_ci
3937db96d56Sopenharmony_cistatic int
3947db96d56Sopenharmony_ciparse_filter_chain_spec(_lzma_state *state, lzma_filter filters[], PyObject *filterspecs)
3957db96d56Sopenharmony_ci{
3967db96d56Sopenharmony_ci    Py_ssize_t i, num_filters;
3977db96d56Sopenharmony_ci
3987db96d56Sopenharmony_ci    num_filters = PySequence_Length(filterspecs);
3997db96d56Sopenharmony_ci    if (num_filters == -1) {
4007db96d56Sopenharmony_ci        return -1;
4017db96d56Sopenharmony_ci    }
4027db96d56Sopenharmony_ci    if (num_filters > LZMA_FILTERS_MAX) {
4037db96d56Sopenharmony_ci        PyErr_Format(PyExc_ValueError,
4047db96d56Sopenharmony_ci                     "Too many filters - liblzma supports a maximum of %d",
4057db96d56Sopenharmony_ci                     LZMA_FILTERS_MAX);
4067db96d56Sopenharmony_ci        return -1;
4077db96d56Sopenharmony_ci    }
4087db96d56Sopenharmony_ci
4097db96d56Sopenharmony_ci    for (i = 0; i < num_filters; i++) {
4107db96d56Sopenharmony_ci        int ok = 1;
4117db96d56Sopenharmony_ci        PyObject *spec = PySequence_GetItem(filterspecs, i);
4127db96d56Sopenharmony_ci        if (spec == NULL || !lzma_filter_converter(state, spec, &filters[i])) {
4137db96d56Sopenharmony_ci            ok = 0;
4147db96d56Sopenharmony_ci        }
4157db96d56Sopenharmony_ci        Py_XDECREF(spec);
4167db96d56Sopenharmony_ci        if (!ok) {
4177db96d56Sopenharmony_ci            filters[i].id = LZMA_VLI_UNKNOWN;
4187db96d56Sopenharmony_ci            free_filter_chain(filters);
4197db96d56Sopenharmony_ci            return -1;
4207db96d56Sopenharmony_ci        }
4217db96d56Sopenharmony_ci    }
4227db96d56Sopenharmony_ci    filters[num_filters].id = LZMA_VLI_UNKNOWN;
4237db96d56Sopenharmony_ci    return 0;
4247db96d56Sopenharmony_ci}
4257db96d56Sopenharmony_ci
4267db96d56Sopenharmony_ci
4277db96d56Sopenharmony_ci/* Filter specifier construction.
4287db96d56Sopenharmony_ci
4297db96d56Sopenharmony_ci   This code handles converting C lzma_filter structs into
4307db96d56Sopenharmony_ci   Python-level filter specifiers (represented as dicts). */
4317db96d56Sopenharmony_ci
4327db96d56Sopenharmony_cistatic int
4337db96d56Sopenharmony_cispec_add_field(PyObject *spec, const char *key, unsigned long long value)
4347db96d56Sopenharmony_ci{
4357db96d56Sopenharmony_ci    PyObject *value_object = PyLong_FromUnsignedLongLong(value);
4367db96d56Sopenharmony_ci    if (value_object == NULL) {
4377db96d56Sopenharmony_ci        return -1;
4387db96d56Sopenharmony_ci    }
4397db96d56Sopenharmony_ci    PyObject *key_object = PyUnicode_InternFromString(key);
4407db96d56Sopenharmony_ci    if (key_object == NULL) {
4417db96d56Sopenharmony_ci        Py_DECREF(value_object);
4427db96d56Sopenharmony_ci        return -1;
4437db96d56Sopenharmony_ci    }
4447db96d56Sopenharmony_ci    int status = PyDict_SetItem(spec, key_object, value_object);
4457db96d56Sopenharmony_ci    Py_DECREF(key_object);
4467db96d56Sopenharmony_ci    Py_DECREF(value_object);
4477db96d56Sopenharmony_ci    return status;
4487db96d56Sopenharmony_ci}
4497db96d56Sopenharmony_ci
4507db96d56Sopenharmony_cistatic PyObject *
4517db96d56Sopenharmony_cibuild_filter_spec(const lzma_filter *f)
4527db96d56Sopenharmony_ci{
4537db96d56Sopenharmony_ci    PyObject *spec;
4547db96d56Sopenharmony_ci
4557db96d56Sopenharmony_ci    spec = PyDict_New();
4567db96d56Sopenharmony_ci    if (spec == NULL) {
4577db96d56Sopenharmony_ci        return NULL;
4587db96d56Sopenharmony_ci    }
4597db96d56Sopenharmony_ci
4607db96d56Sopenharmony_ci#define ADD_FIELD(SOURCE, FIELD) \
4617db96d56Sopenharmony_ci    do { \
4627db96d56Sopenharmony_ci        if (spec_add_field(spec, #FIELD, SOURCE->FIELD) == -1) \
4637db96d56Sopenharmony_ci            goto error;\
4647db96d56Sopenharmony_ci    } while (0)
4657db96d56Sopenharmony_ci
4667db96d56Sopenharmony_ci    ADD_FIELD(f, id);
4677db96d56Sopenharmony_ci
4687db96d56Sopenharmony_ci    switch (f->id) {
4697db96d56Sopenharmony_ci        /* For LZMA1 filters, lzma_properties_{encode,decode}() only look at the
4707db96d56Sopenharmony_ci           lc, lp, pb, and dict_size fields. For LZMA2 filters, only the
4717db96d56Sopenharmony_ci           dict_size field is used. */
4727db96d56Sopenharmony_ci        case LZMA_FILTER_LZMA1: {
4737db96d56Sopenharmony_ci            lzma_options_lzma *options = f->options;
4747db96d56Sopenharmony_ci            ADD_FIELD(options, lc);
4757db96d56Sopenharmony_ci            ADD_FIELD(options, lp);
4767db96d56Sopenharmony_ci            ADD_FIELD(options, pb);
4777db96d56Sopenharmony_ci            ADD_FIELD(options, dict_size);
4787db96d56Sopenharmony_ci            break;
4797db96d56Sopenharmony_ci        }
4807db96d56Sopenharmony_ci        case LZMA_FILTER_LZMA2: {
4817db96d56Sopenharmony_ci            lzma_options_lzma *options = f->options;
4827db96d56Sopenharmony_ci            ADD_FIELD(options, dict_size);
4837db96d56Sopenharmony_ci            break;
4847db96d56Sopenharmony_ci        }
4857db96d56Sopenharmony_ci        case LZMA_FILTER_DELTA: {
4867db96d56Sopenharmony_ci            lzma_options_delta *options = f->options;
4877db96d56Sopenharmony_ci            ADD_FIELD(options, dist);
4887db96d56Sopenharmony_ci            break;
4897db96d56Sopenharmony_ci        }
4907db96d56Sopenharmony_ci        case LZMA_FILTER_X86:
4917db96d56Sopenharmony_ci        case LZMA_FILTER_POWERPC:
4927db96d56Sopenharmony_ci        case LZMA_FILTER_IA64:
4937db96d56Sopenharmony_ci        case LZMA_FILTER_ARM:
4947db96d56Sopenharmony_ci        case LZMA_FILTER_ARMTHUMB:
4957db96d56Sopenharmony_ci        case LZMA_FILTER_SPARC: {
4967db96d56Sopenharmony_ci            lzma_options_bcj *options = f->options;
4977db96d56Sopenharmony_ci            ADD_FIELD(options, start_offset);
4987db96d56Sopenharmony_ci            break;
4997db96d56Sopenharmony_ci        }
5007db96d56Sopenharmony_ci        default:
5017db96d56Sopenharmony_ci            PyErr_Format(PyExc_ValueError, "Invalid filter ID: %llu", f->id);
5027db96d56Sopenharmony_ci            goto error;
5037db96d56Sopenharmony_ci    }
5047db96d56Sopenharmony_ci
5057db96d56Sopenharmony_ci#undef ADD_FIELD
5067db96d56Sopenharmony_ci
5077db96d56Sopenharmony_ci    return spec;
5087db96d56Sopenharmony_ci
5097db96d56Sopenharmony_cierror:
5107db96d56Sopenharmony_ci    Py_DECREF(spec);
5117db96d56Sopenharmony_ci    return NULL;
5127db96d56Sopenharmony_ci}
5137db96d56Sopenharmony_ci
5147db96d56Sopenharmony_ci
5157db96d56Sopenharmony_ci/*[clinic input]
5167db96d56Sopenharmony_cimodule _lzma
5177db96d56Sopenharmony_ciclass _lzma.LZMACompressor "Compressor *" "&Compressor_type"
5187db96d56Sopenharmony_ciclass _lzma.LZMADecompressor "Decompressor *" "&Decompressor_type"
5197db96d56Sopenharmony_ci[clinic start generated code]*/
5207db96d56Sopenharmony_ci/*[clinic end generated code: output=da39a3ee5e6b4b0d input=2c14bbe05ff0c147]*/
5217db96d56Sopenharmony_ci
5227db96d56Sopenharmony_ci#include "clinic/_lzmamodule.c.h"
5237db96d56Sopenharmony_ci
5247db96d56Sopenharmony_ci/*[python input]
5257db96d56Sopenharmony_ci
5267db96d56Sopenharmony_ciclass lzma_vli_converter(CConverter):
5277db96d56Sopenharmony_ci    type = 'lzma_vli'
5287db96d56Sopenharmony_ci    converter = 'lzma_vli_converter'
5297db96d56Sopenharmony_ci
5307db96d56Sopenharmony_ciclass lzma_filter_converter(CConverter):
5317db96d56Sopenharmony_ci    type = 'lzma_filter'
5327db96d56Sopenharmony_ci    converter = 'lzma_filter_converter'
5337db96d56Sopenharmony_ci    c_default = c_ignored_default = "{LZMA_VLI_UNKNOWN, NULL}"
5347db96d56Sopenharmony_ci
5357db96d56Sopenharmony_ci    def cleanup(self):
5367db96d56Sopenharmony_ci        name = ensure_legal_c_identifier(self.name)
5377db96d56Sopenharmony_ci        return ('if (%(name)s.id != LZMA_VLI_UNKNOWN)\n'
5387db96d56Sopenharmony_ci                '   PyMem_Free(%(name)s.options);\n') % {'name': name}
5397db96d56Sopenharmony_ci
5407db96d56Sopenharmony_ci[python start generated code]*/
5417db96d56Sopenharmony_ci/*[python end generated code: output=da39a3ee5e6b4b0d input=74fe7631ce377a94]*/
5427db96d56Sopenharmony_ci
5437db96d56Sopenharmony_ci
5447db96d56Sopenharmony_ci/* LZMACompressor class. */
5457db96d56Sopenharmony_ci
5467db96d56Sopenharmony_cistatic PyObject *
5477db96d56Sopenharmony_cicompress(Compressor *c, uint8_t *data, size_t len, lzma_action action)
5487db96d56Sopenharmony_ci{
5497db96d56Sopenharmony_ci    PyObject *result;
5507db96d56Sopenharmony_ci    _BlocksOutputBuffer buffer = {.list = NULL};
5517db96d56Sopenharmony_ci    _lzma_state *state = PyType_GetModuleState(Py_TYPE(c));
5527db96d56Sopenharmony_ci    assert(state != NULL);
5537db96d56Sopenharmony_ci
5547db96d56Sopenharmony_ci    if (OutputBuffer_InitAndGrow(&buffer, -1, &c->lzs.next_out, &c->lzs.avail_out) < 0) {
5557db96d56Sopenharmony_ci        goto error;
5567db96d56Sopenharmony_ci    }
5577db96d56Sopenharmony_ci    c->lzs.next_in = data;
5587db96d56Sopenharmony_ci    c->lzs.avail_in = len;
5597db96d56Sopenharmony_ci
5607db96d56Sopenharmony_ci    for (;;) {
5617db96d56Sopenharmony_ci        lzma_ret lzret;
5627db96d56Sopenharmony_ci
5637db96d56Sopenharmony_ci        Py_BEGIN_ALLOW_THREADS
5647db96d56Sopenharmony_ci        lzret = lzma_code(&c->lzs, action);
5657db96d56Sopenharmony_ci        Py_END_ALLOW_THREADS
5667db96d56Sopenharmony_ci
5677db96d56Sopenharmony_ci        if (lzret == LZMA_BUF_ERROR && len == 0 && c->lzs.avail_out > 0) {
5687db96d56Sopenharmony_ci            lzret = LZMA_OK; /* That wasn't a real error */
5697db96d56Sopenharmony_ci        }
5707db96d56Sopenharmony_ci        if (catch_lzma_error(state, lzret)) {
5717db96d56Sopenharmony_ci            goto error;
5727db96d56Sopenharmony_ci        }
5737db96d56Sopenharmony_ci        if ((action == LZMA_RUN && c->lzs.avail_in == 0) ||
5747db96d56Sopenharmony_ci            (action == LZMA_FINISH && lzret == LZMA_STREAM_END)) {
5757db96d56Sopenharmony_ci            break;
5767db96d56Sopenharmony_ci        } else if (c->lzs.avail_out == 0) {
5777db96d56Sopenharmony_ci            if (OutputBuffer_Grow(&buffer, &c->lzs.next_out, &c->lzs.avail_out) < 0) {
5787db96d56Sopenharmony_ci                goto error;
5797db96d56Sopenharmony_ci            }
5807db96d56Sopenharmony_ci        }
5817db96d56Sopenharmony_ci    }
5827db96d56Sopenharmony_ci
5837db96d56Sopenharmony_ci    result = OutputBuffer_Finish(&buffer, c->lzs.avail_out);
5847db96d56Sopenharmony_ci    if (result != NULL) {
5857db96d56Sopenharmony_ci        return result;
5867db96d56Sopenharmony_ci    }
5877db96d56Sopenharmony_ci
5887db96d56Sopenharmony_cierror:
5897db96d56Sopenharmony_ci    OutputBuffer_OnError(&buffer);
5907db96d56Sopenharmony_ci    return NULL;
5917db96d56Sopenharmony_ci}
5927db96d56Sopenharmony_ci
5937db96d56Sopenharmony_ci/*[clinic input]
5947db96d56Sopenharmony_ci_lzma.LZMACompressor.compress
5957db96d56Sopenharmony_ci
5967db96d56Sopenharmony_ci    data: Py_buffer
5977db96d56Sopenharmony_ci    /
5987db96d56Sopenharmony_ci
5997db96d56Sopenharmony_ciProvide data to the compressor object.
6007db96d56Sopenharmony_ci
6017db96d56Sopenharmony_ciReturns a chunk of compressed data if possible, or b'' otherwise.
6027db96d56Sopenharmony_ci
6037db96d56Sopenharmony_ciWhen you have finished providing data to the compressor, call the
6047db96d56Sopenharmony_ciflush() method to finish the compression process.
6057db96d56Sopenharmony_ci[clinic start generated code]*/
6067db96d56Sopenharmony_ci
6077db96d56Sopenharmony_cistatic PyObject *
6087db96d56Sopenharmony_ci_lzma_LZMACompressor_compress_impl(Compressor *self, Py_buffer *data)
6097db96d56Sopenharmony_ci/*[clinic end generated code: output=31f615136963e00f input=64019eac7f2cc8d0]*/
6107db96d56Sopenharmony_ci{
6117db96d56Sopenharmony_ci    PyObject *result = NULL;
6127db96d56Sopenharmony_ci
6137db96d56Sopenharmony_ci    ACQUIRE_LOCK(self);
6147db96d56Sopenharmony_ci    if (self->flushed) {
6157db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError, "Compressor has been flushed");
6167db96d56Sopenharmony_ci    }
6177db96d56Sopenharmony_ci    else {
6187db96d56Sopenharmony_ci        result = compress(self, data->buf, data->len, LZMA_RUN);
6197db96d56Sopenharmony_ci    }
6207db96d56Sopenharmony_ci    RELEASE_LOCK(self);
6217db96d56Sopenharmony_ci    return result;
6227db96d56Sopenharmony_ci}
6237db96d56Sopenharmony_ci
6247db96d56Sopenharmony_ci/*[clinic input]
6257db96d56Sopenharmony_ci_lzma.LZMACompressor.flush
6267db96d56Sopenharmony_ci
6277db96d56Sopenharmony_ciFinish the compression process.
6287db96d56Sopenharmony_ci
6297db96d56Sopenharmony_ciReturns the compressed data left in internal buffers.
6307db96d56Sopenharmony_ci
6317db96d56Sopenharmony_ciThe compressor object may not be used after this method is called.
6327db96d56Sopenharmony_ci[clinic start generated code]*/
6337db96d56Sopenharmony_ci
6347db96d56Sopenharmony_cistatic PyObject *
6357db96d56Sopenharmony_ci_lzma_LZMACompressor_flush_impl(Compressor *self)
6367db96d56Sopenharmony_ci/*[clinic end generated code: output=fec21f3e22504f50 input=6b369303f67ad0a8]*/
6377db96d56Sopenharmony_ci{
6387db96d56Sopenharmony_ci    PyObject *result = NULL;
6397db96d56Sopenharmony_ci
6407db96d56Sopenharmony_ci    ACQUIRE_LOCK(self);
6417db96d56Sopenharmony_ci    if (self->flushed) {
6427db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError, "Repeated call to flush()");
6437db96d56Sopenharmony_ci    } else {
6447db96d56Sopenharmony_ci        self->flushed = 1;
6457db96d56Sopenharmony_ci        result = compress(self, NULL, 0, LZMA_FINISH);
6467db96d56Sopenharmony_ci    }
6477db96d56Sopenharmony_ci    RELEASE_LOCK(self);
6487db96d56Sopenharmony_ci    return result;
6497db96d56Sopenharmony_ci}
6507db96d56Sopenharmony_ci
6517db96d56Sopenharmony_cistatic int
6527db96d56Sopenharmony_ciCompressor_init_xz(_lzma_state *state, lzma_stream *lzs,
6537db96d56Sopenharmony_ci                   int check, uint32_t preset, PyObject *filterspecs)
6547db96d56Sopenharmony_ci{
6557db96d56Sopenharmony_ci    lzma_ret lzret;
6567db96d56Sopenharmony_ci
6577db96d56Sopenharmony_ci    if (filterspecs == Py_None) {
6587db96d56Sopenharmony_ci        lzret = lzma_easy_encoder(lzs, preset, check);
6597db96d56Sopenharmony_ci    } else {
6607db96d56Sopenharmony_ci        lzma_filter filters[LZMA_FILTERS_MAX + 1];
6617db96d56Sopenharmony_ci
6627db96d56Sopenharmony_ci        if (parse_filter_chain_spec(state, filters, filterspecs) == -1)
6637db96d56Sopenharmony_ci            return -1;
6647db96d56Sopenharmony_ci        lzret = lzma_stream_encoder(lzs, filters, check);
6657db96d56Sopenharmony_ci        free_filter_chain(filters);
6667db96d56Sopenharmony_ci    }
6677db96d56Sopenharmony_ci    if (catch_lzma_error(state, lzret)) {
6687db96d56Sopenharmony_ci        return -1;
6697db96d56Sopenharmony_ci    }
6707db96d56Sopenharmony_ci    else {
6717db96d56Sopenharmony_ci        return 0;
6727db96d56Sopenharmony_ci    }
6737db96d56Sopenharmony_ci}
6747db96d56Sopenharmony_ci
6757db96d56Sopenharmony_cistatic int
6767db96d56Sopenharmony_ciCompressor_init_alone(_lzma_state *state, lzma_stream *lzs, uint32_t preset, PyObject *filterspecs)
6777db96d56Sopenharmony_ci{
6787db96d56Sopenharmony_ci    lzma_ret lzret;
6797db96d56Sopenharmony_ci
6807db96d56Sopenharmony_ci    if (filterspecs == Py_None) {
6817db96d56Sopenharmony_ci        lzma_options_lzma options;
6827db96d56Sopenharmony_ci
6837db96d56Sopenharmony_ci        if (lzma_lzma_preset(&options, preset)) {
6847db96d56Sopenharmony_ci            PyErr_Format(state->error, "Invalid compression preset: %u", preset);
6857db96d56Sopenharmony_ci            return -1;
6867db96d56Sopenharmony_ci        }
6877db96d56Sopenharmony_ci        lzret = lzma_alone_encoder(lzs, &options);
6887db96d56Sopenharmony_ci    } else {
6897db96d56Sopenharmony_ci        lzma_filter filters[LZMA_FILTERS_MAX + 1];
6907db96d56Sopenharmony_ci
6917db96d56Sopenharmony_ci        if (parse_filter_chain_spec(state, filters, filterspecs) == -1)
6927db96d56Sopenharmony_ci            return -1;
6937db96d56Sopenharmony_ci        if (filters[0].id == LZMA_FILTER_LZMA1 &&
6947db96d56Sopenharmony_ci            filters[1].id == LZMA_VLI_UNKNOWN) {
6957db96d56Sopenharmony_ci            lzret = lzma_alone_encoder(lzs, filters[0].options);
6967db96d56Sopenharmony_ci        } else {
6977db96d56Sopenharmony_ci            PyErr_SetString(PyExc_ValueError,
6987db96d56Sopenharmony_ci                            "Invalid filter chain for FORMAT_ALONE - "
6997db96d56Sopenharmony_ci                            "must be a single LZMA1 filter");
7007db96d56Sopenharmony_ci            lzret = LZMA_PROG_ERROR;
7017db96d56Sopenharmony_ci        }
7027db96d56Sopenharmony_ci        free_filter_chain(filters);
7037db96d56Sopenharmony_ci    }
7047db96d56Sopenharmony_ci    if (PyErr_Occurred() || catch_lzma_error(state, lzret)) {
7057db96d56Sopenharmony_ci        return -1;
7067db96d56Sopenharmony_ci    }
7077db96d56Sopenharmony_ci    else {
7087db96d56Sopenharmony_ci        return 0;
7097db96d56Sopenharmony_ci    }
7107db96d56Sopenharmony_ci}
7117db96d56Sopenharmony_ci
7127db96d56Sopenharmony_cistatic int
7137db96d56Sopenharmony_ciCompressor_init_raw(_lzma_state *state, lzma_stream *lzs, PyObject *filterspecs)
7147db96d56Sopenharmony_ci{
7157db96d56Sopenharmony_ci    lzma_filter filters[LZMA_FILTERS_MAX + 1];
7167db96d56Sopenharmony_ci    lzma_ret lzret;
7177db96d56Sopenharmony_ci
7187db96d56Sopenharmony_ci    if (filterspecs == Py_None) {
7197db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError,
7207db96d56Sopenharmony_ci                        "Must specify filters for FORMAT_RAW");
7217db96d56Sopenharmony_ci        return -1;
7227db96d56Sopenharmony_ci    }
7237db96d56Sopenharmony_ci    if (parse_filter_chain_spec(state, filters, filterspecs) == -1) {
7247db96d56Sopenharmony_ci        return -1;
7257db96d56Sopenharmony_ci    }
7267db96d56Sopenharmony_ci    lzret = lzma_raw_encoder(lzs, filters);
7277db96d56Sopenharmony_ci    free_filter_chain(filters);
7287db96d56Sopenharmony_ci    if (catch_lzma_error(state, lzret)) {
7297db96d56Sopenharmony_ci        return -1;
7307db96d56Sopenharmony_ci    }
7317db96d56Sopenharmony_ci    else {
7327db96d56Sopenharmony_ci        return 0;
7337db96d56Sopenharmony_ci    }
7347db96d56Sopenharmony_ci}
7357db96d56Sopenharmony_ci
7367db96d56Sopenharmony_ci/*[-clinic input]
7377db96d56Sopenharmony_ci_lzma.LZMACompressor.__init__
7387db96d56Sopenharmony_ci
7397db96d56Sopenharmony_ci    format: int(c_default="FORMAT_XZ") = FORMAT_XZ
7407db96d56Sopenharmony_ci        The container format to use for the output.  This can
7417db96d56Sopenharmony_ci        be FORMAT_XZ (default), FORMAT_ALONE, or FORMAT_RAW.
7427db96d56Sopenharmony_ci
7437db96d56Sopenharmony_ci    check: int(c_default="-1") = unspecified
7447db96d56Sopenharmony_ci        The integrity check to use.  For FORMAT_XZ, the default
7457db96d56Sopenharmony_ci        is CHECK_CRC64.  FORMAT_ALONE and FORMAT_RAW do not support integrity
7467db96d56Sopenharmony_ci        checks; for these formats, check must be omitted, or be CHECK_NONE.
7477db96d56Sopenharmony_ci
7487db96d56Sopenharmony_ci    preset: object = None
7497db96d56Sopenharmony_ci        If provided should be an integer in the range 0-9, optionally
7507db96d56Sopenharmony_ci        OR-ed with the constant PRESET_EXTREME.
7517db96d56Sopenharmony_ci
7527db96d56Sopenharmony_ci    filters: object = None
7537db96d56Sopenharmony_ci        If provided should be a sequence of dicts.  Each dict should
7547db96d56Sopenharmony_ci        have an entry for "id" indicating the ID of the filter, plus
7557db96d56Sopenharmony_ci        additional entries for options to the filter.
7567db96d56Sopenharmony_ci
7577db96d56Sopenharmony_ciCreate a compressor object for compressing data incrementally.
7587db96d56Sopenharmony_ci
7597db96d56Sopenharmony_ciThe settings used by the compressor can be specified either as a
7607db96d56Sopenharmony_cipreset compression level (with the 'preset' argument), or in detail
7617db96d56Sopenharmony_cias a custom filter chain (with the 'filters' argument).  For FORMAT_XZ
7627db96d56Sopenharmony_ciand FORMAT_ALONE, the default is to use the PRESET_DEFAULT preset
7637db96d56Sopenharmony_cilevel.  For FORMAT_RAW, the caller must always specify a filter chain;
7647db96d56Sopenharmony_cithe raw compressor does not support preset compression levels.
7657db96d56Sopenharmony_ci
7667db96d56Sopenharmony_ciFor one-shot compression, use the compress() function instead.
7677db96d56Sopenharmony_ci[-clinic start generated code]*/
7687db96d56Sopenharmony_cistatic int
7697db96d56Sopenharmony_ciCompressor_init(Compressor *self, PyObject *args, PyObject *kwargs)
7707db96d56Sopenharmony_ci{
7717db96d56Sopenharmony_ci    static char *arg_names[] = {"format", "check", "preset", "filters", NULL};
7727db96d56Sopenharmony_ci    int format = FORMAT_XZ;
7737db96d56Sopenharmony_ci    int check = -1;
7747db96d56Sopenharmony_ci    uint32_t preset = LZMA_PRESET_DEFAULT;
7757db96d56Sopenharmony_ci    PyObject *preset_obj = Py_None;
7767db96d56Sopenharmony_ci    PyObject *filterspecs = Py_None;
7777db96d56Sopenharmony_ci    _lzma_state *state = PyType_GetModuleState(Py_TYPE(self));
7787db96d56Sopenharmony_ci    assert(state != NULL);
7797db96d56Sopenharmony_ci    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
7807db96d56Sopenharmony_ci                                     "|iiOO:LZMACompressor", arg_names,
7817db96d56Sopenharmony_ci                                     &format, &check, &preset_obj,
7827db96d56Sopenharmony_ci                                     &filterspecs)) {
7837db96d56Sopenharmony_ci        return -1;
7847db96d56Sopenharmony_ci    }
7857db96d56Sopenharmony_ci
7867db96d56Sopenharmony_ci    if (format != FORMAT_XZ && check != -1 && check != LZMA_CHECK_NONE) {
7877db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError,
7887db96d56Sopenharmony_ci                        "Integrity checks are only supported by FORMAT_XZ");
7897db96d56Sopenharmony_ci        return -1;
7907db96d56Sopenharmony_ci    }
7917db96d56Sopenharmony_ci
7927db96d56Sopenharmony_ci    if (preset_obj != Py_None && filterspecs != Py_None) {
7937db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError,
7947db96d56Sopenharmony_ci                        "Cannot specify both preset and filter chain");
7957db96d56Sopenharmony_ci        return -1;
7967db96d56Sopenharmony_ci    }
7977db96d56Sopenharmony_ci
7987db96d56Sopenharmony_ci    if (preset_obj != Py_None) {
7997db96d56Sopenharmony_ci        if (!uint32_converter(preset_obj, &preset)) {
8007db96d56Sopenharmony_ci            return -1;
8017db96d56Sopenharmony_ci        }
8027db96d56Sopenharmony_ci    }
8037db96d56Sopenharmony_ci
8047db96d56Sopenharmony_ci    self->alloc.opaque = NULL;
8057db96d56Sopenharmony_ci    self->alloc.alloc = PyLzma_Malloc;
8067db96d56Sopenharmony_ci    self->alloc.free = PyLzma_Free;
8077db96d56Sopenharmony_ci    self->lzs.allocator = &self->alloc;
8087db96d56Sopenharmony_ci
8097db96d56Sopenharmony_ci    self->lock = PyThread_allocate_lock();
8107db96d56Sopenharmony_ci    if (self->lock == NULL) {
8117db96d56Sopenharmony_ci        PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock");
8127db96d56Sopenharmony_ci        return -1;
8137db96d56Sopenharmony_ci    }
8147db96d56Sopenharmony_ci
8157db96d56Sopenharmony_ci    self->flushed = 0;
8167db96d56Sopenharmony_ci    switch (format) {
8177db96d56Sopenharmony_ci        case FORMAT_XZ:
8187db96d56Sopenharmony_ci            if (check == -1) {
8197db96d56Sopenharmony_ci                check = LZMA_CHECK_CRC64;
8207db96d56Sopenharmony_ci            }
8217db96d56Sopenharmony_ci            if (Compressor_init_xz(state, &self->lzs, check, preset, filterspecs) != 0) {
8227db96d56Sopenharmony_ci                break;
8237db96d56Sopenharmony_ci            }
8247db96d56Sopenharmony_ci            return 0;
8257db96d56Sopenharmony_ci
8267db96d56Sopenharmony_ci        case FORMAT_ALONE:
8277db96d56Sopenharmony_ci            if (Compressor_init_alone(state, &self->lzs, preset, filterspecs) != 0) {
8287db96d56Sopenharmony_ci                break;
8297db96d56Sopenharmony_ci            }
8307db96d56Sopenharmony_ci            return 0;
8317db96d56Sopenharmony_ci
8327db96d56Sopenharmony_ci        case FORMAT_RAW:
8337db96d56Sopenharmony_ci            if (Compressor_init_raw(state, &self->lzs, filterspecs) != 0) {
8347db96d56Sopenharmony_ci                break;
8357db96d56Sopenharmony_ci            }
8367db96d56Sopenharmony_ci            return 0;
8377db96d56Sopenharmony_ci
8387db96d56Sopenharmony_ci        default:
8397db96d56Sopenharmony_ci            PyErr_Format(PyExc_ValueError,
8407db96d56Sopenharmony_ci                         "Invalid container format: %d", format);
8417db96d56Sopenharmony_ci            break;
8427db96d56Sopenharmony_ci    }
8437db96d56Sopenharmony_ci
8447db96d56Sopenharmony_ci    PyThread_free_lock(self->lock);
8457db96d56Sopenharmony_ci    self->lock = NULL;
8467db96d56Sopenharmony_ci    return -1;
8477db96d56Sopenharmony_ci}
8487db96d56Sopenharmony_ci
8497db96d56Sopenharmony_cistatic void
8507db96d56Sopenharmony_ciCompressor_dealloc(Compressor *self)
8517db96d56Sopenharmony_ci{
8527db96d56Sopenharmony_ci    lzma_end(&self->lzs);
8537db96d56Sopenharmony_ci    if (self->lock != NULL) {
8547db96d56Sopenharmony_ci        PyThread_free_lock(self->lock);
8557db96d56Sopenharmony_ci    }
8567db96d56Sopenharmony_ci    PyTypeObject *tp = Py_TYPE(self);
8577db96d56Sopenharmony_ci    tp->tp_free((PyObject *)self);
8587db96d56Sopenharmony_ci    Py_DECREF(tp);
8597db96d56Sopenharmony_ci}
8607db96d56Sopenharmony_ci
8617db96d56Sopenharmony_cistatic PyMethodDef Compressor_methods[] = {
8627db96d56Sopenharmony_ci    _LZMA_LZMACOMPRESSOR_COMPRESS_METHODDEF
8637db96d56Sopenharmony_ci    _LZMA_LZMACOMPRESSOR_FLUSH_METHODDEF
8647db96d56Sopenharmony_ci    {NULL}
8657db96d56Sopenharmony_ci};
8667db96d56Sopenharmony_ci
8677db96d56Sopenharmony_cistatic int
8687db96d56Sopenharmony_ciCompressor_traverse(Compressor *self, visitproc visit, void *arg)
8697db96d56Sopenharmony_ci{
8707db96d56Sopenharmony_ci    Py_VISIT(Py_TYPE(self));
8717db96d56Sopenharmony_ci    return 0;
8727db96d56Sopenharmony_ci}
8737db96d56Sopenharmony_ci
8747db96d56Sopenharmony_ciPyDoc_STRVAR(Compressor_doc,
8757db96d56Sopenharmony_ci"LZMACompressor(format=FORMAT_XZ, check=-1, preset=None, filters=None)\n"
8767db96d56Sopenharmony_ci"\n"
8777db96d56Sopenharmony_ci"Create a compressor object for compressing data incrementally.\n"
8787db96d56Sopenharmony_ci"\n"
8797db96d56Sopenharmony_ci"format specifies the container format to use for the output. This can\n"
8807db96d56Sopenharmony_ci"be FORMAT_XZ (default), FORMAT_ALONE, or FORMAT_RAW.\n"
8817db96d56Sopenharmony_ci"\n"
8827db96d56Sopenharmony_ci"check specifies the integrity check to use. For FORMAT_XZ, the default\n"
8837db96d56Sopenharmony_ci"is CHECK_CRC64. FORMAT_ALONE and FORMAT_RAW do not support integrity\n"
8847db96d56Sopenharmony_ci"checks; for these formats, check must be omitted, or be CHECK_NONE.\n"
8857db96d56Sopenharmony_ci"\n"
8867db96d56Sopenharmony_ci"The settings used by the compressor can be specified either as a\n"
8877db96d56Sopenharmony_ci"preset compression level (with the 'preset' argument), or in detail\n"
8887db96d56Sopenharmony_ci"as a custom filter chain (with the 'filters' argument). For FORMAT_XZ\n"
8897db96d56Sopenharmony_ci"and FORMAT_ALONE, the default is to use the PRESET_DEFAULT preset\n"
8907db96d56Sopenharmony_ci"level. For FORMAT_RAW, the caller must always specify a filter chain;\n"
8917db96d56Sopenharmony_ci"the raw compressor does not support preset compression levels.\n"
8927db96d56Sopenharmony_ci"\n"
8937db96d56Sopenharmony_ci"preset (if provided) should be an integer in the range 0-9, optionally\n"
8947db96d56Sopenharmony_ci"OR-ed with the constant PRESET_EXTREME.\n"
8957db96d56Sopenharmony_ci"\n"
8967db96d56Sopenharmony_ci"filters (if provided) should be a sequence of dicts. Each dict should\n"
8977db96d56Sopenharmony_ci"have an entry for \"id\" indicating the ID of the filter, plus\n"
8987db96d56Sopenharmony_ci"additional entries for options to the filter.\n"
8997db96d56Sopenharmony_ci"\n"
9007db96d56Sopenharmony_ci"For one-shot compression, use the compress() function instead.\n");
9017db96d56Sopenharmony_ci
9027db96d56Sopenharmony_cistatic PyType_Slot lzma_compressor_type_slots[] = {
9037db96d56Sopenharmony_ci    {Py_tp_dealloc, Compressor_dealloc},
9047db96d56Sopenharmony_ci    {Py_tp_methods, Compressor_methods},
9057db96d56Sopenharmony_ci    {Py_tp_init, Compressor_init},
9067db96d56Sopenharmony_ci    {Py_tp_new, PyType_GenericNew},
9077db96d56Sopenharmony_ci    {Py_tp_doc, (char *)Compressor_doc},
9087db96d56Sopenharmony_ci    {Py_tp_traverse, Compressor_traverse},
9097db96d56Sopenharmony_ci    {0, 0}
9107db96d56Sopenharmony_ci};
9117db96d56Sopenharmony_ci
9127db96d56Sopenharmony_cistatic PyType_Spec lzma_compressor_type_spec = {
9137db96d56Sopenharmony_ci    .name = "_lzma.LZMACompressor",
9147db96d56Sopenharmony_ci    .basicsize = sizeof(Compressor),
9157db96d56Sopenharmony_ci    // Calling PyType_GetModuleState() on a subclass is not safe.
9167db96d56Sopenharmony_ci    // lzma_compressor_type_spec does not have Py_TPFLAGS_BASETYPE flag
9177db96d56Sopenharmony_ci    // which prevents to create a subclass.
9187db96d56Sopenharmony_ci    // So calling PyType_GetModuleState() in this file is always safe.
9197db96d56Sopenharmony_ci    .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE),
9207db96d56Sopenharmony_ci    .slots = lzma_compressor_type_slots,
9217db96d56Sopenharmony_ci};
9227db96d56Sopenharmony_ci
9237db96d56Sopenharmony_ci/* LZMADecompressor class. */
9247db96d56Sopenharmony_ci
9257db96d56Sopenharmony_ci/* Decompress data of length d->lzs.avail_in in d->lzs.next_in.  The output
9267db96d56Sopenharmony_ci   buffer is allocated dynamically and returned.  At most max_length bytes are
9277db96d56Sopenharmony_ci   returned, so some of the input may not be consumed. d->lzs.next_in and
9287db96d56Sopenharmony_ci   d->lzs.avail_in are updated to reflect the consumed input. */
9297db96d56Sopenharmony_cistatic PyObject*
9307db96d56Sopenharmony_cidecompress_buf(Decompressor *d, Py_ssize_t max_length)
9317db96d56Sopenharmony_ci{
9327db96d56Sopenharmony_ci    PyObject *result;
9337db96d56Sopenharmony_ci    lzma_stream *lzs = &d->lzs;
9347db96d56Sopenharmony_ci    _BlocksOutputBuffer buffer = {.list = NULL};
9357db96d56Sopenharmony_ci    _lzma_state *state = PyType_GetModuleState(Py_TYPE(d));
9367db96d56Sopenharmony_ci    assert(state != NULL);
9377db96d56Sopenharmony_ci
9387db96d56Sopenharmony_ci    if (OutputBuffer_InitAndGrow(&buffer, max_length, &lzs->next_out, &lzs->avail_out) < 0) {
9397db96d56Sopenharmony_ci        goto error;
9407db96d56Sopenharmony_ci    }
9417db96d56Sopenharmony_ci
9427db96d56Sopenharmony_ci    for (;;) {
9437db96d56Sopenharmony_ci        lzma_ret lzret;
9447db96d56Sopenharmony_ci
9457db96d56Sopenharmony_ci        Py_BEGIN_ALLOW_THREADS
9467db96d56Sopenharmony_ci        lzret = lzma_code(lzs, LZMA_RUN);
9477db96d56Sopenharmony_ci        Py_END_ALLOW_THREADS
9487db96d56Sopenharmony_ci
9497db96d56Sopenharmony_ci        if (lzret == LZMA_BUF_ERROR && lzs->avail_in == 0 && lzs->avail_out > 0) {
9507db96d56Sopenharmony_ci            lzret = LZMA_OK; /* That wasn't a real error */
9517db96d56Sopenharmony_ci        }
9527db96d56Sopenharmony_ci        if (catch_lzma_error(state, lzret)) {
9537db96d56Sopenharmony_ci            goto error;
9547db96d56Sopenharmony_ci        }
9557db96d56Sopenharmony_ci        if (lzret == LZMA_GET_CHECK || lzret == LZMA_NO_CHECK) {
9567db96d56Sopenharmony_ci            d->check = lzma_get_check(&d->lzs);
9577db96d56Sopenharmony_ci        }
9587db96d56Sopenharmony_ci        if (lzret == LZMA_STREAM_END) {
9597db96d56Sopenharmony_ci            d->eof = 1;
9607db96d56Sopenharmony_ci            break;
9617db96d56Sopenharmony_ci        } else if (lzs->avail_out == 0) {
9627db96d56Sopenharmony_ci            /* Need to check lzs->avail_out before lzs->avail_in.
9637db96d56Sopenharmony_ci               Maybe lzs's internal state still have a few bytes
9647db96d56Sopenharmony_ci               can be output, grow the output buffer and continue
9657db96d56Sopenharmony_ci               if max_lengh < 0. */
9667db96d56Sopenharmony_ci            if (OutputBuffer_GetDataSize(&buffer, lzs->avail_out) == max_length) {
9677db96d56Sopenharmony_ci                break;
9687db96d56Sopenharmony_ci            }
9697db96d56Sopenharmony_ci            if (OutputBuffer_Grow(&buffer, &lzs->next_out, &lzs->avail_out) < 0) {
9707db96d56Sopenharmony_ci                goto error;
9717db96d56Sopenharmony_ci            }
9727db96d56Sopenharmony_ci        } else if (lzs->avail_in == 0) {
9737db96d56Sopenharmony_ci            break;
9747db96d56Sopenharmony_ci        }
9757db96d56Sopenharmony_ci    }
9767db96d56Sopenharmony_ci
9777db96d56Sopenharmony_ci    result = OutputBuffer_Finish(&buffer, lzs->avail_out);
9787db96d56Sopenharmony_ci    if (result != NULL) {
9797db96d56Sopenharmony_ci        return result;
9807db96d56Sopenharmony_ci    }
9817db96d56Sopenharmony_ci
9827db96d56Sopenharmony_cierror:
9837db96d56Sopenharmony_ci    OutputBuffer_OnError(&buffer);
9847db96d56Sopenharmony_ci    return NULL;
9857db96d56Sopenharmony_ci}
9867db96d56Sopenharmony_ci
9877db96d56Sopenharmony_cistatic PyObject *
9887db96d56Sopenharmony_cidecompress(Decompressor *d, uint8_t *data, size_t len, Py_ssize_t max_length)
9897db96d56Sopenharmony_ci{
9907db96d56Sopenharmony_ci    char input_buffer_in_use;
9917db96d56Sopenharmony_ci    PyObject *result;
9927db96d56Sopenharmony_ci    lzma_stream *lzs = &d->lzs;
9937db96d56Sopenharmony_ci
9947db96d56Sopenharmony_ci    /* Prepend unconsumed input if necessary */
9957db96d56Sopenharmony_ci    if (lzs->next_in != NULL) {
9967db96d56Sopenharmony_ci        size_t avail_now, avail_total;
9977db96d56Sopenharmony_ci
9987db96d56Sopenharmony_ci        /* Number of bytes we can append to input buffer */
9997db96d56Sopenharmony_ci        avail_now = (d->input_buffer + d->input_buffer_size)
10007db96d56Sopenharmony_ci            - (lzs->next_in + lzs->avail_in);
10017db96d56Sopenharmony_ci
10027db96d56Sopenharmony_ci        /* Number of bytes we can append if we move existing
10037db96d56Sopenharmony_ci           contents to beginning of buffer (overwriting
10047db96d56Sopenharmony_ci           consumed input) */
10057db96d56Sopenharmony_ci        avail_total = d->input_buffer_size - lzs->avail_in;
10067db96d56Sopenharmony_ci
10077db96d56Sopenharmony_ci        if (avail_total < len) {
10087db96d56Sopenharmony_ci            size_t offset = lzs->next_in - d->input_buffer;
10097db96d56Sopenharmony_ci            uint8_t *tmp;
10107db96d56Sopenharmony_ci            size_t new_size = d->input_buffer_size + len - avail_now;
10117db96d56Sopenharmony_ci
10127db96d56Sopenharmony_ci            /* Assign to temporary variable first, so we don't
10137db96d56Sopenharmony_ci               lose address of allocated buffer if realloc fails */
10147db96d56Sopenharmony_ci            tmp = PyMem_Realloc(d->input_buffer, new_size);
10157db96d56Sopenharmony_ci            if (tmp == NULL) {
10167db96d56Sopenharmony_ci                PyErr_SetNone(PyExc_MemoryError);
10177db96d56Sopenharmony_ci                return NULL;
10187db96d56Sopenharmony_ci            }
10197db96d56Sopenharmony_ci            d->input_buffer = tmp;
10207db96d56Sopenharmony_ci            d->input_buffer_size = new_size;
10217db96d56Sopenharmony_ci
10227db96d56Sopenharmony_ci            lzs->next_in = d->input_buffer + offset;
10237db96d56Sopenharmony_ci        }
10247db96d56Sopenharmony_ci        else if (avail_now < len) {
10257db96d56Sopenharmony_ci            memmove(d->input_buffer, lzs->next_in,
10267db96d56Sopenharmony_ci                    lzs->avail_in);
10277db96d56Sopenharmony_ci            lzs->next_in = d->input_buffer;
10287db96d56Sopenharmony_ci        }
10297db96d56Sopenharmony_ci        memcpy((void*)(lzs->next_in + lzs->avail_in), data, len);
10307db96d56Sopenharmony_ci        lzs->avail_in += len;
10317db96d56Sopenharmony_ci        input_buffer_in_use = 1;
10327db96d56Sopenharmony_ci    }
10337db96d56Sopenharmony_ci    else {
10347db96d56Sopenharmony_ci        lzs->next_in = data;
10357db96d56Sopenharmony_ci        lzs->avail_in = len;
10367db96d56Sopenharmony_ci        input_buffer_in_use = 0;
10377db96d56Sopenharmony_ci    }
10387db96d56Sopenharmony_ci
10397db96d56Sopenharmony_ci    result = decompress_buf(d, max_length);
10407db96d56Sopenharmony_ci    if (result == NULL) {
10417db96d56Sopenharmony_ci        lzs->next_in = NULL;
10427db96d56Sopenharmony_ci        return NULL;
10437db96d56Sopenharmony_ci    }
10447db96d56Sopenharmony_ci
10457db96d56Sopenharmony_ci    if (d->eof) {
10467db96d56Sopenharmony_ci        d->needs_input = 0;
10477db96d56Sopenharmony_ci        if (lzs->avail_in > 0) {
10487db96d56Sopenharmony_ci            Py_XSETREF(d->unused_data,
10497db96d56Sopenharmony_ci                      PyBytes_FromStringAndSize((char *)lzs->next_in, lzs->avail_in));
10507db96d56Sopenharmony_ci            if (d->unused_data == NULL) {
10517db96d56Sopenharmony_ci                goto error;
10527db96d56Sopenharmony_ci            }
10537db96d56Sopenharmony_ci        }
10547db96d56Sopenharmony_ci    }
10557db96d56Sopenharmony_ci    else if (lzs->avail_in == 0) {
10567db96d56Sopenharmony_ci        lzs->next_in = NULL;
10577db96d56Sopenharmony_ci
10587db96d56Sopenharmony_ci        if (lzs->avail_out == 0) {
10597db96d56Sopenharmony_ci            /* (avail_in==0 && avail_out==0)
10607db96d56Sopenharmony_ci               Maybe lzs's internal state still have a few bytes can
10617db96d56Sopenharmony_ci               be output, try to output them next time. */
10627db96d56Sopenharmony_ci            d->needs_input = 0;
10637db96d56Sopenharmony_ci
10647db96d56Sopenharmony_ci            /* If max_length < 0, lzs->avail_out always > 0 */
10657db96d56Sopenharmony_ci            assert(max_length >= 0);
10667db96d56Sopenharmony_ci        } else {
10677db96d56Sopenharmony_ci            /* Input buffer exhausted, output buffer has space. */
10687db96d56Sopenharmony_ci            d->needs_input = 1;
10697db96d56Sopenharmony_ci        }
10707db96d56Sopenharmony_ci    }
10717db96d56Sopenharmony_ci    else {
10727db96d56Sopenharmony_ci        d->needs_input = 0;
10737db96d56Sopenharmony_ci
10747db96d56Sopenharmony_ci        /* If we did not use the input buffer, we now have
10757db96d56Sopenharmony_ci           to copy the tail from the caller's buffer into the
10767db96d56Sopenharmony_ci           input buffer */
10777db96d56Sopenharmony_ci        if (!input_buffer_in_use) {
10787db96d56Sopenharmony_ci
10797db96d56Sopenharmony_ci            /* Discard buffer if it's too small
10807db96d56Sopenharmony_ci               (resizing it may needlessly copy the current contents) */
10817db96d56Sopenharmony_ci            if (d->input_buffer != NULL &&
10827db96d56Sopenharmony_ci                d->input_buffer_size < lzs->avail_in) {
10837db96d56Sopenharmony_ci                PyMem_Free(d->input_buffer);
10847db96d56Sopenharmony_ci                d->input_buffer = NULL;
10857db96d56Sopenharmony_ci            }
10867db96d56Sopenharmony_ci
10877db96d56Sopenharmony_ci            /* Allocate if necessary */
10887db96d56Sopenharmony_ci            if (d->input_buffer == NULL) {
10897db96d56Sopenharmony_ci                d->input_buffer = PyMem_Malloc(lzs->avail_in);
10907db96d56Sopenharmony_ci                if (d->input_buffer == NULL) {
10917db96d56Sopenharmony_ci                    PyErr_SetNone(PyExc_MemoryError);
10927db96d56Sopenharmony_ci                    goto error;
10937db96d56Sopenharmony_ci                }
10947db96d56Sopenharmony_ci                d->input_buffer_size = lzs->avail_in;
10957db96d56Sopenharmony_ci            }
10967db96d56Sopenharmony_ci
10977db96d56Sopenharmony_ci            /* Copy tail */
10987db96d56Sopenharmony_ci            memcpy(d->input_buffer, lzs->next_in, lzs->avail_in);
10997db96d56Sopenharmony_ci            lzs->next_in = d->input_buffer;
11007db96d56Sopenharmony_ci        }
11017db96d56Sopenharmony_ci    }
11027db96d56Sopenharmony_ci
11037db96d56Sopenharmony_ci    return result;
11047db96d56Sopenharmony_ci
11057db96d56Sopenharmony_cierror:
11067db96d56Sopenharmony_ci    Py_XDECREF(result);
11077db96d56Sopenharmony_ci    return NULL;
11087db96d56Sopenharmony_ci}
11097db96d56Sopenharmony_ci
11107db96d56Sopenharmony_ci/*[clinic input]
11117db96d56Sopenharmony_ci_lzma.LZMADecompressor.decompress
11127db96d56Sopenharmony_ci
11137db96d56Sopenharmony_ci    data: Py_buffer
11147db96d56Sopenharmony_ci    max_length: Py_ssize_t=-1
11157db96d56Sopenharmony_ci
11167db96d56Sopenharmony_ciDecompress *data*, returning uncompressed data as bytes.
11177db96d56Sopenharmony_ci
11187db96d56Sopenharmony_ciIf *max_length* is nonnegative, returns at most *max_length* bytes of
11197db96d56Sopenharmony_cidecompressed data. If this limit is reached and further output can be
11207db96d56Sopenharmony_ciproduced, *self.needs_input* will be set to ``False``. In this case, the next
11217db96d56Sopenharmony_cicall to *decompress()* may provide *data* as b'' to obtain more of the output.
11227db96d56Sopenharmony_ci
11237db96d56Sopenharmony_ciIf all of the input data was decompressed and returned (either because this
11247db96d56Sopenharmony_ciwas less than *max_length* bytes, or because *max_length* was negative),
11257db96d56Sopenharmony_ci*self.needs_input* will be set to True.
11267db96d56Sopenharmony_ci
11277db96d56Sopenharmony_ciAttempting to decompress data after the end of stream is reached raises an
11287db96d56Sopenharmony_ciEOFError.  Any data found after the end of the stream is ignored and saved in
11297db96d56Sopenharmony_cithe unused_data attribute.
11307db96d56Sopenharmony_ci[clinic start generated code]*/
11317db96d56Sopenharmony_ci
11327db96d56Sopenharmony_cistatic PyObject *
11337db96d56Sopenharmony_ci_lzma_LZMADecompressor_decompress_impl(Decompressor *self, Py_buffer *data,
11347db96d56Sopenharmony_ci                                       Py_ssize_t max_length)
11357db96d56Sopenharmony_ci/*[clinic end generated code: output=ef4e20ec7122241d input=60c1f135820e309d]*/
11367db96d56Sopenharmony_ci{
11377db96d56Sopenharmony_ci    PyObject *result = NULL;
11387db96d56Sopenharmony_ci
11397db96d56Sopenharmony_ci    ACQUIRE_LOCK(self);
11407db96d56Sopenharmony_ci    if (self->eof)
11417db96d56Sopenharmony_ci        PyErr_SetString(PyExc_EOFError, "Already at end of stream");
11427db96d56Sopenharmony_ci    else
11437db96d56Sopenharmony_ci        result = decompress(self, data->buf, data->len, max_length);
11447db96d56Sopenharmony_ci    RELEASE_LOCK(self);
11457db96d56Sopenharmony_ci    return result;
11467db96d56Sopenharmony_ci}
11477db96d56Sopenharmony_ci
11487db96d56Sopenharmony_cistatic int
11497db96d56Sopenharmony_ciDecompressor_init_raw(_lzma_state *state, lzma_stream *lzs, PyObject *filterspecs)
11507db96d56Sopenharmony_ci{
11517db96d56Sopenharmony_ci    lzma_filter filters[LZMA_FILTERS_MAX + 1];
11527db96d56Sopenharmony_ci    lzma_ret lzret;
11537db96d56Sopenharmony_ci
11547db96d56Sopenharmony_ci    if (parse_filter_chain_spec(state, filters, filterspecs) == -1) {
11557db96d56Sopenharmony_ci        return -1;
11567db96d56Sopenharmony_ci    }
11577db96d56Sopenharmony_ci    lzret = lzma_raw_decoder(lzs, filters);
11587db96d56Sopenharmony_ci    free_filter_chain(filters);
11597db96d56Sopenharmony_ci    if (catch_lzma_error(state, lzret)) {
11607db96d56Sopenharmony_ci        return -1;
11617db96d56Sopenharmony_ci    }
11627db96d56Sopenharmony_ci    else {
11637db96d56Sopenharmony_ci        return 0;
11647db96d56Sopenharmony_ci    }
11657db96d56Sopenharmony_ci}
11667db96d56Sopenharmony_ci
11677db96d56Sopenharmony_ci/*[clinic input]
11687db96d56Sopenharmony_ci_lzma.LZMADecompressor.__init__
11697db96d56Sopenharmony_ci
11707db96d56Sopenharmony_ci    format: int(c_default="FORMAT_AUTO") = FORMAT_AUTO
11717db96d56Sopenharmony_ci        Specifies the container format of the input stream.  If this is
11727db96d56Sopenharmony_ci        FORMAT_AUTO (the default), the decompressor will automatically detect
11737db96d56Sopenharmony_ci        whether the input is FORMAT_XZ or FORMAT_ALONE.  Streams created with
11747db96d56Sopenharmony_ci        FORMAT_RAW cannot be autodetected.
11757db96d56Sopenharmony_ci
11767db96d56Sopenharmony_ci    memlimit: object = None
11777db96d56Sopenharmony_ci        Limit the amount of memory used by the decompressor.  This will cause
11787db96d56Sopenharmony_ci        decompression to fail if the input cannot be decompressed within the
11797db96d56Sopenharmony_ci        given limit.
11807db96d56Sopenharmony_ci
11817db96d56Sopenharmony_ci    filters: object = None
11827db96d56Sopenharmony_ci        A custom filter chain.  This argument is required for FORMAT_RAW, and
11837db96d56Sopenharmony_ci        not accepted with any other format.  When provided, this should be a
11847db96d56Sopenharmony_ci        sequence of dicts, each indicating the ID and options for a single
11857db96d56Sopenharmony_ci        filter.
11867db96d56Sopenharmony_ci
11877db96d56Sopenharmony_ciCreate a decompressor object for decompressing data incrementally.
11887db96d56Sopenharmony_ci
11897db96d56Sopenharmony_ciFor one-shot decompression, use the decompress() function instead.
11907db96d56Sopenharmony_ci[clinic start generated code]*/
11917db96d56Sopenharmony_ci
11927db96d56Sopenharmony_cistatic int
11937db96d56Sopenharmony_ci_lzma_LZMADecompressor___init___impl(Decompressor *self, int format,
11947db96d56Sopenharmony_ci                                     PyObject *memlimit, PyObject *filters)
11957db96d56Sopenharmony_ci/*[clinic end generated code: output=3e1821f8aa36564c input=81fe684a6c2f8a27]*/
11967db96d56Sopenharmony_ci{
11977db96d56Sopenharmony_ci    const uint32_t decoder_flags = LZMA_TELL_ANY_CHECK | LZMA_TELL_NO_CHECK;
11987db96d56Sopenharmony_ci    uint64_t memlimit_ = UINT64_MAX;
11997db96d56Sopenharmony_ci    lzma_ret lzret;
12007db96d56Sopenharmony_ci    _lzma_state *state = PyType_GetModuleState(Py_TYPE(self));
12017db96d56Sopenharmony_ci    assert(state != NULL);
12027db96d56Sopenharmony_ci
12037db96d56Sopenharmony_ci    if (memlimit != Py_None) {
12047db96d56Sopenharmony_ci        if (format == FORMAT_RAW) {
12057db96d56Sopenharmony_ci            PyErr_SetString(PyExc_ValueError,
12067db96d56Sopenharmony_ci                            "Cannot specify memory limit with FORMAT_RAW");
12077db96d56Sopenharmony_ci            return -1;
12087db96d56Sopenharmony_ci        }
12097db96d56Sopenharmony_ci        memlimit_ = PyLong_AsUnsignedLongLong(memlimit);
12107db96d56Sopenharmony_ci        if (PyErr_Occurred()) {
12117db96d56Sopenharmony_ci            return -1;
12127db96d56Sopenharmony_ci        }
12137db96d56Sopenharmony_ci    }
12147db96d56Sopenharmony_ci
12157db96d56Sopenharmony_ci    if (format == FORMAT_RAW && filters == Py_None) {
12167db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError,
12177db96d56Sopenharmony_ci                        "Must specify filters for FORMAT_RAW");
12187db96d56Sopenharmony_ci        return -1;
12197db96d56Sopenharmony_ci    } else if (format != FORMAT_RAW && filters != Py_None) {
12207db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError,
12217db96d56Sopenharmony_ci                        "Cannot specify filters except with FORMAT_RAW");
12227db96d56Sopenharmony_ci        return -1;
12237db96d56Sopenharmony_ci    }
12247db96d56Sopenharmony_ci
12257db96d56Sopenharmony_ci    self->alloc.opaque = NULL;
12267db96d56Sopenharmony_ci    self->alloc.alloc = PyLzma_Malloc;
12277db96d56Sopenharmony_ci    self->alloc.free = PyLzma_Free;
12287db96d56Sopenharmony_ci    self->lzs.allocator = &self->alloc;
12297db96d56Sopenharmony_ci    self->lzs.next_in = NULL;
12307db96d56Sopenharmony_ci
12317db96d56Sopenharmony_ci    PyThread_type_lock lock = PyThread_allocate_lock();
12327db96d56Sopenharmony_ci    if (lock == NULL) {
12337db96d56Sopenharmony_ci        PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock");
12347db96d56Sopenharmony_ci        return -1;
12357db96d56Sopenharmony_ci    }
12367db96d56Sopenharmony_ci    if (self->lock != NULL) {
12377db96d56Sopenharmony_ci        PyThread_free_lock(self->lock);
12387db96d56Sopenharmony_ci    }
12397db96d56Sopenharmony_ci    self->lock = lock;
12407db96d56Sopenharmony_ci
12417db96d56Sopenharmony_ci    self->check = LZMA_CHECK_UNKNOWN;
12427db96d56Sopenharmony_ci    self->needs_input = 1;
12437db96d56Sopenharmony_ci    self->input_buffer = NULL;
12447db96d56Sopenharmony_ci    self->input_buffer_size = 0;
12457db96d56Sopenharmony_ci    Py_XSETREF(self->unused_data, PyBytes_FromStringAndSize(NULL, 0));
12467db96d56Sopenharmony_ci    if (self->unused_data == NULL) {
12477db96d56Sopenharmony_ci        goto error;
12487db96d56Sopenharmony_ci    }
12497db96d56Sopenharmony_ci
12507db96d56Sopenharmony_ci    switch (format) {
12517db96d56Sopenharmony_ci        case FORMAT_AUTO:
12527db96d56Sopenharmony_ci            lzret = lzma_auto_decoder(&self->lzs, memlimit_, decoder_flags);
12537db96d56Sopenharmony_ci            if (catch_lzma_error(state, lzret)) {
12547db96d56Sopenharmony_ci                break;
12557db96d56Sopenharmony_ci            }
12567db96d56Sopenharmony_ci            return 0;
12577db96d56Sopenharmony_ci
12587db96d56Sopenharmony_ci        case FORMAT_XZ:
12597db96d56Sopenharmony_ci            lzret = lzma_stream_decoder(&self->lzs, memlimit_, decoder_flags);
12607db96d56Sopenharmony_ci            if (catch_lzma_error(state, lzret)) {
12617db96d56Sopenharmony_ci                break;
12627db96d56Sopenharmony_ci            }
12637db96d56Sopenharmony_ci            return 0;
12647db96d56Sopenharmony_ci
12657db96d56Sopenharmony_ci        case FORMAT_ALONE:
12667db96d56Sopenharmony_ci            self->check = LZMA_CHECK_NONE;
12677db96d56Sopenharmony_ci            lzret = lzma_alone_decoder(&self->lzs, memlimit_);
12687db96d56Sopenharmony_ci            if (catch_lzma_error(state, lzret)) {
12697db96d56Sopenharmony_ci                break;
12707db96d56Sopenharmony_ci            }
12717db96d56Sopenharmony_ci            return 0;
12727db96d56Sopenharmony_ci
12737db96d56Sopenharmony_ci        case FORMAT_RAW:
12747db96d56Sopenharmony_ci            self->check = LZMA_CHECK_NONE;
12757db96d56Sopenharmony_ci            if (Decompressor_init_raw(state, &self->lzs, filters) == -1) {
12767db96d56Sopenharmony_ci                break;
12777db96d56Sopenharmony_ci            }
12787db96d56Sopenharmony_ci            return 0;
12797db96d56Sopenharmony_ci
12807db96d56Sopenharmony_ci        default:
12817db96d56Sopenharmony_ci            PyErr_Format(PyExc_ValueError,
12827db96d56Sopenharmony_ci                         "Invalid container format: %d", format);
12837db96d56Sopenharmony_ci            break;
12847db96d56Sopenharmony_ci    }
12857db96d56Sopenharmony_ci
12867db96d56Sopenharmony_cierror:
12877db96d56Sopenharmony_ci    Py_CLEAR(self->unused_data);
12887db96d56Sopenharmony_ci    PyThread_free_lock(self->lock);
12897db96d56Sopenharmony_ci    self->lock = NULL;
12907db96d56Sopenharmony_ci    return -1;
12917db96d56Sopenharmony_ci}
12927db96d56Sopenharmony_ci
12937db96d56Sopenharmony_cistatic void
12947db96d56Sopenharmony_ciDecompressor_dealloc(Decompressor *self)
12957db96d56Sopenharmony_ci{
12967db96d56Sopenharmony_ci    if(self->input_buffer != NULL)
12977db96d56Sopenharmony_ci        PyMem_Free(self->input_buffer);
12987db96d56Sopenharmony_ci
12997db96d56Sopenharmony_ci    lzma_end(&self->lzs);
13007db96d56Sopenharmony_ci    Py_CLEAR(self->unused_data);
13017db96d56Sopenharmony_ci    if (self->lock != NULL) {
13027db96d56Sopenharmony_ci        PyThread_free_lock(self->lock);
13037db96d56Sopenharmony_ci    }
13047db96d56Sopenharmony_ci    PyTypeObject *tp = Py_TYPE(self);
13057db96d56Sopenharmony_ci    tp->tp_free((PyObject *)self);
13067db96d56Sopenharmony_ci    Py_DECREF(tp);
13077db96d56Sopenharmony_ci}
13087db96d56Sopenharmony_ci
13097db96d56Sopenharmony_cistatic int
13107db96d56Sopenharmony_ciDecompressor_traverse(Decompressor *self, visitproc visit, void *arg)
13117db96d56Sopenharmony_ci{
13127db96d56Sopenharmony_ci    Py_VISIT(Py_TYPE(self));
13137db96d56Sopenharmony_ci    return 0;
13147db96d56Sopenharmony_ci}
13157db96d56Sopenharmony_ci
13167db96d56Sopenharmony_cistatic PyMethodDef Decompressor_methods[] = {
13177db96d56Sopenharmony_ci    _LZMA_LZMADECOMPRESSOR_DECOMPRESS_METHODDEF
13187db96d56Sopenharmony_ci    {NULL}
13197db96d56Sopenharmony_ci};
13207db96d56Sopenharmony_ci
13217db96d56Sopenharmony_ciPyDoc_STRVAR(Decompressor_check_doc,
13227db96d56Sopenharmony_ci"ID of the integrity check used by the input stream.");
13237db96d56Sopenharmony_ci
13247db96d56Sopenharmony_ciPyDoc_STRVAR(Decompressor_eof_doc,
13257db96d56Sopenharmony_ci"True if the end-of-stream marker has been reached.");
13267db96d56Sopenharmony_ci
13277db96d56Sopenharmony_ciPyDoc_STRVAR(Decompressor_needs_input_doc,
13287db96d56Sopenharmony_ci"True if more input is needed before more decompressed data can be produced.");
13297db96d56Sopenharmony_ci
13307db96d56Sopenharmony_ciPyDoc_STRVAR(Decompressor_unused_data_doc,
13317db96d56Sopenharmony_ci"Data found after the end of the compressed stream.");
13327db96d56Sopenharmony_ci
13337db96d56Sopenharmony_cistatic PyMemberDef Decompressor_members[] = {
13347db96d56Sopenharmony_ci    {"check", T_INT, offsetof(Decompressor, check), READONLY,
13357db96d56Sopenharmony_ci     Decompressor_check_doc},
13367db96d56Sopenharmony_ci    {"eof", T_BOOL, offsetof(Decompressor, eof), READONLY,
13377db96d56Sopenharmony_ci     Decompressor_eof_doc},
13387db96d56Sopenharmony_ci    {"needs_input", T_BOOL, offsetof(Decompressor, needs_input), READONLY,
13397db96d56Sopenharmony_ci     Decompressor_needs_input_doc},
13407db96d56Sopenharmony_ci    {"unused_data", T_OBJECT_EX, offsetof(Decompressor, unused_data), READONLY,
13417db96d56Sopenharmony_ci     Decompressor_unused_data_doc},
13427db96d56Sopenharmony_ci    {NULL}
13437db96d56Sopenharmony_ci};
13447db96d56Sopenharmony_ci
13457db96d56Sopenharmony_cistatic PyType_Slot lzma_decompressor_type_slots[] = {
13467db96d56Sopenharmony_ci    {Py_tp_dealloc, Decompressor_dealloc},
13477db96d56Sopenharmony_ci    {Py_tp_methods, Decompressor_methods},
13487db96d56Sopenharmony_ci    {Py_tp_init, _lzma_LZMADecompressor___init__},
13497db96d56Sopenharmony_ci    {Py_tp_new, PyType_GenericNew},
13507db96d56Sopenharmony_ci    {Py_tp_doc, (char *)_lzma_LZMADecompressor___init____doc__},
13517db96d56Sopenharmony_ci    {Py_tp_traverse, Decompressor_traverse},
13527db96d56Sopenharmony_ci    {Py_tp_members, Decompressor_members},
13537db96d56Sopenharmony_ci    {0, 0}
13547db96d56Sopenharmony_ci};
13557db96d56Sopenharmony_ci
13567db96d56Sopenharmony_cistatic PyType_Spec lzma_decompressor_type_spec = {
13577db96d56Sopenharmony_ci    .name = "_lzma.LZMADecompressor",
13587db96d56Sopenharmony_ci    .basicsize = sizeof(Decompressor),
13597db96d56Sopenharmony_ci    // Calling PyType_GetModuleState() on a subclass is not safe.
13607db96d56Sopenharmony_ci    // lzma_decompressor_type_spec does not have Py_TPFLAGS_BASETYPE flag
13617db96d56Sopenharmony_ci    // which prevents to create a subclass.
13627db96d56Sopenharmony_ci    // So calling PyType_GetModuleState() in this file is always safe.
13637db96d56Sopenharmony_ci    .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE),
13647db96d56Sopenharmony_ci    .slots = lzma_decompressor_type_slots,
13657db96d56Sopenharmony_ci};
13667db96d56Sopenharmony_ci
13677db96d56Sopenharmony_ci
13687db96d56Sopenharmony_ci/* Module-level functions. */
13697db96d56Sopenharmony_ci
13707db96d56Sopenharmony_ci/*[clinic input]
13717db96d56Sopenharmony_ci_lzma.is_check_supported
13727db96d56Sopenharmony_ci    check_id: int
13737db96d56Sopenharmony_ci    /
13747db96d56Sopenharmony_ci
13757db96d56Sopenharmony_ciTest whether the given integrity check is supported.
13767db96d56Sopenharmony_ci
13777db96d56Sopenharmony_ciAlways returns True for CHECK_NONE and CHECK_CRC32.
13787db96d56Sopenharmony_ci[clinic start generated code]*/
13797db96d56Sopenharmony_ci
13807db96d56Sopenharmony_cistatic PyObject *
13817db96d56Sopenharmony_ci_lzma_is_check_supported_impl(PyObject *module, int check_id)
13827db96d56Sopenharmony_ci/*[clinic end generated code: output=e4f14ba3ce2ad0a5 input=5518297b97b2318f]*/
13837db96d56Sopenharmony_ci{
13847db96d56Sopenharmony_ci    return PyBool_FromLong(lzma_check_is_supported(check_id));
13857db96d56Sopenharmony_ci}
13867db96d56Sopenharmony_ci
13877db96d56Sopenharmony_ciPyDoc_STRVAR(_lzma__encode_filter_properties__doc__,
13887db96d56Sopenharmony_ci"_encode_filter_properties($module, filter, /)\n"
13897db96d56Sopenharmony_ci"--\n"
13907db96d56Sopenharmony_ci"\n"
13917db96d56Sopenharmony_ci"Return a bytes object encoding the options (properties) of the filter specified by *filter* (a dict).\n"
13927db96d56Sopenharmony_ci"\n"
13937db96d56Sopenharmony_ci"The result does not include the filter ID itself, only the options.");
13947db96d56Sopenharmony_ci
13957db96d56Sopenharmony_ci#define _LZMA__ENCODE_FILTER_PROPERTIES_METHODDEF    \
13967db96d56Sopenharmony_ci    {"_encode_filter_properties", (PyCFunction)_lzma__encode_filter_properties, METH_O, _lzma__encode_filter_properties__doc__},
13977db96d56Sopenharmony_ci
13987db96d56Sopenharmony_cistatic PyObject *
13997db96d56Sopenharmony_ci_lzma__encode_filter_properties_impl(PyObject *module, lzma_filter filter);
14007db96d56Sopenharmony_ci
14017db96d56Sopenharmony_cistatic PyObject *
14027db96d56Sopenharmony_ci_lzma__encode_filter_properties(PyObject *module, PyObject *arg)
14037db96d56Sopenharmony_ci{
14047db96d56Sopenharmony_ci    PyObject *return_value = NULL;
14057db96d56Sopenharmony_ci    lzma_filter filter = {LZMA_VLI_UNKNOWN, NULL};
14067db96d56Sopenharmony_ci    _lzma_state *state = get_lzma_state(module);
14077db96d56Sopenharmony_ci    assert(state != NULL);
14087db96d56Sopenharmony_ci    if (!lzma_filter_converter(state, arg, &filter)) {
14097db96d56Sopenharmony_ci        goto exit;
14107db96d56Sopenharmony_ci    }
14117db96d56Sopenharmony_ci    return_value = _lzma__encode_filter_properties_impl(module, filter);
14127db96d56Sopenharmony_ci
14137db96d56Sopenharmony_ciexit:
14147db96d56Sopenharmony_ci    /* Cleanup for filter */
14157db96d56Sopenharmony_ci    if (filter.id != LZMA_VLI_UNKNOWN) {
14167db96d56Sopenharmony_ci       PyMem_Free(filter.options);
14177db96d56Sopenharmony_ci    }
14187db96d56Sopenharmony_ci
14197db96d56Sopenharmony_ci    return return_value;
14207db96d56Sopenharmony_ci}
14217db96d56Sopenharmony_ci
14227db96d56Sopenharmony_cistatic PyObject *
14237db96d56Sopenharmony_ci_lzma__encode_filter_properties_impl(PyObject *module, lzma_filter filter)
14247db96d56Sopenharmony_ci{
14257db96d56Sopenharmony_ci    lzma_ret lzret;
14267db96d56Sopenharmony_ci    uint32_t encoded_size;
14277db96d56Sopenharmony_ci    PyObject *result = NULL;
14287db96d56Sopenharmony_ci    _lzma_state *state = get_lzma_state(module);
14297db96d56Sopenharmony_ci    assert(state != NULL);
14307db96d56Sopenharmony_ci
14317db96d56Sopenharmony_ci    lzret = lzma_properties_size(&encoded_size, &filter);
14327db96d56Sopenharmony_ci    if (catch_lzma_error(state, lzret))
14337db96d56Sopenharmony_ci        goto error;
14347db96d56Sopenharmony_ci
14357db96d56Sopenharmony_ci    result = PyBytes_FromStringAndSize(NULL, encoded_size);
14367db96d56Sopenharmony_ci    if (result == NULL)
14377db96d56Sopenharmony_ci        goto error;
14387db96d56Sopenharmony_ci
14397db96d56Sopenharmony_ci    lzret = lzma_properties_encode(
14407db96d56Sopenharmony_ci            &filter, (uint8_t *)PyBytes_AS_STRING(result));
14417db96d56Sopenharmony_ci    if (catch_lzma_error(state, lzret)) {
14427db96d56Sopenharmony_ci        goto error;
14437db96d56Sopenharmony_ci    }
14447db96d56Sopenharmony_ci
14457db96d56Sopenharmony_ci    return result;
14467db96d56Sopenharmony_ci
14477db96d56Sopenharmony_cierror:
14487db96d56Sopenharmony_ci    Py_XDECREF(result);
14497db96d56Sopenharmony_ci    return NULL;
14507db96d56Sopenharmony_ci}
14517db96d56Sopenharmony_ci
14527db96d56Sopenharmony_ci
14537db96d56Sopenharmony_ci/*[clinic input]
14547db96d56Sopenharmony_ci_lzma._decode_filter_properties
14557db96d56Sopenharmony_ci    filter_id: lzma_vli
14567db96d56Sopenharmony_ci    encoded_props: Py_buffer
14577db96d56Sopenharmony_ci    /
14587db96d56Sopenharmony_ci
14597db96d56Sopenharmony_ciReturn a bytes object encoding the options (properties) of the filter specified by *filter* (a dict).
14607db96d56Sopenharmony_ci
14617db96d56Sopenharmony_ciThe result does not include the filter ID itself, only the options.
14627db96d56Sopenharmony_ci[clinic start generated code]*/
14637db96d56Sopenharmony_ci
14647db96d56Sopenharmony_cistatic PyObject *
14657db96d56Sopenharmony_ci_lzma__decode_filter_properties_impl(PyObject *module, lzma_vli filter_id,
14667db96d56Sopenharmony_ci                                     Py_buffer *encoded_props)
14677db96d56Sopenharmony_ci/*[clinic end generated code: output=714fd2ef565d5c60 input=246410800782160c]*/
14687db96d56Sopenharmony_ci{
14697db96d56Sopenharmony_ci    lzma_filter filter;
14707db96d56Sopenharmony_ci    lzma_ret lzret;
14717db96d56Sopenharmony_ci    PyObject *result = NULL;
14727db96d56Sopenharmony_ci    filter.id = filter_id;
14737db96d56Sopenharmony_ci    _lzma_state *state = get_lzma_state(module);
14747db96d56Sopenharmony_ci    assert(state != NULL);
14757db96d56Sopenharmony_ci
14767db96d56Sopenharmony_ci    lzret = lzma_properties_decode(
14777db96d56Sopenharmony_ci            &filter, NULL, encoded_props->buf, encoded_props->len);
14787db96d56Sopenharmony_ci    if (catch_lzma_error(state, lzret)) {
14797db96d56Sopenharmony_ci        return NULL;
14807db96d56Sopenharmony_ci    }
14817db96d56Sopenharmony_ci
14827db96d56Sopenharmony_ci    result = build_filter_spec(&filter);
14837db96d56Sopenharmony_ci
14847db96d56Sopenharmony_ci    /* We use vanilla free() here instead of PyMem_Free() - filter.options was
14857db96d56Sopenharmony_ci       allocated by lzma_properties_decode() using the default allocator. */
14867db96d56Sopenharmony_ci    free(filter.options);
14877db96d56Sopenharmony_ci    return result;
14887db96d56Sopenharmony_ci}
14897db96d56Sopenharmony_ci
14907db96d56Sopenharmony_ci/* Some of our constants are more than 32 bits wide, so PyModule_AddIntConstant
14917db96d56Sopenharmony_ci   would not work correctly on platforms with 32-bit longs. */
14927db96d56Sopenharmony_cistatic int
14937db96d56Sopenharmony_cimodule_add_int_constant(PyObject *m, const char *name, long long value)
14947db96d56Sopenharmony_ci{
14957db96d56Sopenharmony_ci    PyObject *o = PyLong_FromLongLong(value);
14967db96d56Sopenharmony_ci    if (o == NULL) {
14977db96d56Sopenharmony_ci        return -1;
14987db96d56Sopenharmony_ci    }
14997db96d56Sopenharmony_ci    if (PyModule_AddObject(m, name, o) == 0) {
15007db96d56Sopenharmony_ci        return 0;
15017db96d56Sopenharmony_ci    }
15027db96d56Sopenharmony_ci    Py_DECREF(o);
15037db96d56Sopenharmony_ci    return -1;
15047db96d56Sopenharmony_ci}
15057db96d56Sopenharmony_ci
15067db96d56Sopenharmony_cistatic int
15077db96d56Sopenharmony_cilzma_exec(PyObject *module)
15087db96d56Sopenharmony_ci{
15097db96d56Sopenharmony_ci#define ADD_INT_PREFIX_MACRO(module, macro)                                 \
15107db96d56Sopenharmony_ci    do {                                                                    \
15117db96d56Sopenharmony_ci        if (module_add_int_constant(module, #macro, LZMA_ ## macro) < 0) {  \
15127db96d56Sopenharmony_ci            return -1;                                                      \
15137db96d56Sopenharmony_ci        }                                                                   \
15147db96d56Sopenharmony_ci    } while(0)
15157db96d56Sopenharmony_ci
15167db96d56Sopenharmony_ci#define ADD_INT_MACRO(module, macro)                                        \
15177db96d56Sopenharmony_ci    do {                                                                    \
15187db96d56Sopenharmony_ci        if (PyModule_AddIntMacro(module, macro) < 0) {                      \
15197db96d56Sopenharmony_ci            return -1;                                                      \
15207db96d56Sopenharmony_ci        }                                                                   \
15217db96d56Sopenharmony_ci    } while (0)
15227db96d56Sopenharmony_ci
15237db96d56Sopenharmony_ci
15247db96d56Sopenharmony_ci    _lzma_state *state = get_lzma_state(module);
15257db96d56Sopenharmony_ci
15267db96d56Sopenharmony_ci    state->empty_tuple = PyTuple_New(0);
15277db96d56Sopenharmony_ci    if (state->empty_tuple == NULL) {
15287db96d56Sopenharmony_ci        return -1;
15297db96d56Sopenharmony_ci    }
15307db96d56Sopenharmony_ci
15317db96d56Sopenharmony_ci    ADD_INT_MACRO(module, FORMAT_AUTO);
15327db96d56Sopenharmony_ci    ADD_INT_MACRO(module, FORMAT_XZ);
15337db96d56Sopenharmony_ci    ADD_INT_MACRO(module, FORMAT_ALONE);
15347db96d56Sopenharmony_ci    ADD_INT_MACRO(module, FORMAT_RAW);
15357db96d56Sopenharmony_ci    ADD_INT_PREFIX_MACRO(module, CHECK_NONE);
15367db96d56Sopenharmony_ci    ADD_INT_PREFIX_MACRO(module, CHECK_CRC32);
15377db96d56Sopenharmony_ci    ADD_INT_PREFIX_MACRO(module, CHECK_CRC64);
15387db96d56Sopenharmony_ci    ADD_INT_PREFIX_MACRO(module, CHECK_SHA256);
15397db96d56Sopenharmony_ci    ADD_INT_PREFIX_MACRO(module, CHECK_ID_MAX);
15407db96d56Sopenharmony_ci    ADD_INT_PREFIX_MACRO(module, CHECK_UNKNOWN);
15417db96d56Sopenharmony_ci    ADD_INT_PREFIX_MACRO(module, FILTER_LZMA1);
15427db96d56Sopenharmony_ci    ADD_INT_PREFIX_MACRO(module, FILTER_LZMA2);
15437db96d56Sopenharmony_ci    ADD_INT_PREFIX_MACRO(module, FILTER_DELTA);
15447db96d56Sopenharmony_ci    ADD_INT_PREFIX_MACRO(module, FILTER_X86);
15457db96d56Sopenharmony_ci    ADD_INT_PREFIX_MACRO(module, FILTER_IA64);
15467db96d56Sopenharmony_ci    ADD_INT_PREFIX_MACRO(module, FILTER_ARM);
15477db96d56Sopenharmony_ci    ADD_INT_PREFIX_MACRO(module, FILTER_ARMTHUMB);
15487db96d56Sopenharmony_ci    ADD_INT_PREFIX_MACRO(module, FILTER_SPARC);
15497db96d56Sopenharmony_ci    ADD_INT_PREFIX_MACRO(module, FILTER_POWERPC);
15507db96d56Sopenharmony_ci    ADD_INT_PREFIX_MACRO(module, MF_HC3);
15517db96d56Sopenharmony_ci    ADD_INT_PREFIX_MACRO(module, MF_HC4);
15527db96d56Sopenharmony_ci    ADD_INT_PREFIX_MACRO(module, MF_BT2);
15537db96d56Sopenharmony_ci    ADD_INT_PREFIX_MACRO(module, MF_BT3);
15547db96d56Sopenharmony_ci    ADD_INT_PREFIX_MACRO(module, MF_BT4);
15557db96d56Sopenharmony_ci    ADD_INT_PREFIX_MACRO(module, MODE_FAST);
15567db96d56Sopenharmony_ci    ADD_INT_PREFIX_MACRO(module, MODE_NORMAL);
15577db96d56Sopenharmony_ci    ADD_INT_PREFIX_MACRO(module, PRESET_DEFAULT);
15587db96d56Sopenharmony_ci    ADD_INT_PREFIX_MACRO(module, PRESET_EXTREME);
15597db96d56Sopenharmony_ci
15607db96d56Sopenharmony_ci    state->error = PyErr_NewExceptionWithDoc("_lzma.LZMAError", "Call to liblzma failed.", NULL, NULL);
15617db96d56Sopenharmony_ci    if (state->error == NULL) {
15627db96d56Sopenharmony_ci        return -1;
15637db96d56Sopenharmony_ci    }
15647db96d56Sopenharmony_ci
15657db96d56Sopenharmony_ci    if (PyModule_AddType(module, (PyTypeObject *)state->error) < 0) {
15667db96d56Sopenharmony_ci        return -1;
15677db96d56Sopenharmony_ci    }
15687db96d56Sopenharmony_ci
15697db96d56Sopenharmony_ci
15707db96d56Sopenharmony_ci    state->lzma_compressor_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
15717db96d56Sopenharmony_ci                                                            &lzma_compressor_type_spec, NULL);
15727db96d56Sopenharmony_ci    if (state->lzma_compressor_type == NULL) {
15737db96d56Sopenharmony_ci        return -1;
15747db96d56Sopenharmony_ci    }
15757db96d56Sopenharmony_ci
15767db96d56Sopenharmony_ci    if (PyModule_AddType(module, state->lzma_compressor_type) < 0) {
15777db96d56Sopenharmony_ci        return -1;
15787db96d56Sopenharmony_ci    }
15797db96d56Sopenharmony_ci
15807db96d56Sopenharmony_ci    state->lzma_decompressor_type = (PyTypeObject *)PyType_FromModuleAndSpec(module,
15817db96d56Sopenharmony_ci                                                         &lzma_decompressor_type_spec, NULL);
15827db96d56Sopenharmony_ci    if (state->lzma_decompressor_type == NULL) {
15837db96d56Sopenharmony_ci        return -1;
15847db96d56Sopenharmony_ci    }
15857db96d56Sopenharmony_ci
15867db96d56Sopenharmony_ci    if (PyModule_AddType(module, state->lzma_decompressor_type) < 0) {
15877db96d56Sopenharmony_ci        return -1;
15887db96d56Sopenharmony_ci    }
15897db96d56Sopenharmony_ci
15907db96d56Sopenharmony_ci    return 0;
15917db96d56Sopenharmony_ci}
15927db96d56Sopenharmony_ci
15937db96d56Sopenharmony_cistatic PyMethodDef lzma_methods[] = {
15947db96d56Sopenharmony_ci    _LZMA_IS_CHECK_SUPPORTED_METHODDEF
15957db96d56Sopenharmony_ci    _LZMA__ENCODE_FILTER_PROPERTIES_METHODDEF
15967db96d56Sopenharmony_ci    _LZMA__DECODE_FILTER_PROPERTIES_METHODDEF
15977db96d56Sopenharmony_ci    {NULL}
15987db96d56Sopenharmony_ci};
15997db96d56Sopenharmony_ci
16007db96d56Sopenharmony_cistatic PyModuleDef_Slot lzma_slots[] = {
16017db96d56Sopenharmony_ci    {Py_mod_exec, lzma_exec},
16027db96d56Sopenharmony_ci    {0, NULL}
16037db96d56Sopenharmony_ci};
16047db96d56Sopenharmony_ci
16057db96d56Sopenharmony_cistatic int
16067db96d56Sopenharmony_cilzma_traverse(PyObject *module, visitproc visit, void *arg)
16077db96d56Sopenharmony_ci{
16087db96d56Sopenharmony_ci    _lzma_state *state = get_lzma_state(module);
16097db96d56Sopenharmony_ci    Py_VISIT(state->lzma_compressor_type);
16107db96d56Sopenharmony_ci    Py_VISIT(state->lzma_decompressor_type);
16117db96d56Sopenharmony_ci    Py_VISIT(state->error);
16127db96d56Sopenharmony_ci    Py_VISIT(state->empty_tuple);
16137db96d56Sopenharmony_ci    return 0;
16147db96d56Sopenharmony_ci}
16157db96d56Sopenharmony_ci
16167db96d56Sopenharmony_cistatic int
16177db96d56Sopenharmony_cilzma_clear(PyObject *module)
16187db96d56Sopenharmony_ci{
16197db96d56Sopenharmony_ci    _lzma_state *state = get_lzma_state(module);
16207db96d56Sopenharmony_ci    Py_CLEAR(state->lzma_compressor_type);
16217db96d56Sopenharmony_ci    Py_CLEAR(state->lzma_decompressor_type);
16227db96d56Sopenharmony_ci    Py_CLEAR(state->error);
16237db96d56Sopenharmony_ci    Py_CLEAR(state->empty_tuple);
16247db96d56Sopenharmony_ci    return 0;
16257db96d56Sopenharmony_ci}
16267db96d56Sopenharmony_ci
16277db96d56Sopenharmony_cistatic void
16287db96d56Sopenharmony_cilzma_free(void *module)
16297db96d56Sopenharmony_ci{
16307db96d56Sopenharmony_ci    lzma_clear((PyObject *)module);
16317db96d56Sopenharmony_ci}
16327db96d56Sopenharmony_ci
16337db96d56Sopenharmony_cistatic PyModuleDef _lzmamodule = {
16347db96d56Sopenharmony_ci    PyModuleDef_HEAD_INIT,
16357db96d56Sopenharmony_ci    .m_name = "_lzma",
16367db96d56Sopenharmony_ci    .m_size = sizeof(_lzma_state),
16377db96d56Sopenharmony_ci    .m_methods = lzma_methods,
16387db96d56Sopenharmony_ci    .m_slots = lzma_slots,
16397db96d56Sopenharmony_ci    .m_traverse = lzma_traverse,
16407db96d56Sopenharmony_ci    .m_clear = lzma_clear,
16417db96d56Sopenharmony_ci    .m_free = lzma_free,
16427db96d56Sopenharmony_ci};
16437db96d56Sopenharmony_ci
16447db96d56Sopenharmony_ciPyMODINIT_FUNC
16457db96d56Sopenharmony_ciPyInit__lzma(void)
16467db96d56Sopenharmony_ci{
16477db96d56Sopenharmony_ci    return PyModuleDef_Init(&_lzmamodule);
16487db96d56Sopenharmony_ci}
1649