From ba229f1007b82e614c62e106ba32cb628c45e378 Mon Sep 17 00:00:00 2001 From: gamblor21 Date: Sat, 19 Feb 2022 10:41:42 -0600 Subject: [PATCH] Initial commit of uzlib module --- lib/uzlib/uzlib.h | 2 + py/circuitpy_defns.mk | 16 +++++ py/circuitpy_mpconfig.mk | 4 ++ shared-bindings/uzlib/DecompIO.c | 86 ++++++++++++++++++++++++++ shared-bindings/uzlib/DecompIO.h | 37 +++++++++++ shared-bindings/uzlib/__init__.c | 72 ++++++++++++++++++++++ shared-bindings/uzlib/__init__.h | 32 ++++++++++ shared-module/uzlib/DecompIO.c | 101 +++++++++++++++++++++++++++++++ shared-module/uzlib/DecompIO.h | 44 ++++++++++++++ shared-module/uzlib/__init__.c | 100 ++++++++++++++++++++++++++++++ 10 files changed, 494 insertions(+) create mode 100644 shared-bindings/uzlib/DecompIO.c create mode 100644 shared-bindings/uzlib/DecompIO.h create mode 100644 shared-bindings/uzlib/__init__.c create mode 100644 shared-bindings/uzlib/__init__.h create mode 100644 shared-module/uzlib/DecompIO.c create mode 100644 shared-module/uzlib/DecompIO.h create mode 100644 shared-module/uzlib/__init__.c diff --git a/lib/uzlib/uzlib.h b/lib/uzlib/uzlib.h index 3a4a1ad160..7d8949543e 100644 --- a/lib/uzlib/uzlib.h +++ b/lib/uzlib/uzlib.h @@ -83,6 +83,8 @@ typedef struct { } TINF_TREE; struct uzlib_uncomp { + /* Point to the CircuitPython object that owns this decompression stream */ + void *self; /* Pointer to the next byte in the input buffer */ const unsigned char *source; /* Pointer to the next byte past the input buffer (source_limit = source + len) */ diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 15828f6616..044dc143c7 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -321,6 +321,9 @@ endif ifeq ($(CIRCUITPY_USTACK),1) SRC_PATTERNS += ustack/% endif +ifeq ($(CIRCUITPY_UZLIB),1) +SRC_PATTERNS += uzlib/% +endif ifeq ($(CIRCUITPY_VIDEOCORE),1) SRC_PATTERNS += videocore/% endif @@ -578,6 +581,8 @@ SRC_SHARED_MODULE_ALL = \ traceback/__init__.c \ uheap/__init__.c \ ustack/__init__.c \ + uzlib/__init__.c \ + uzlib/DecompIO.c \ vectorio/Circle.c \ vectorio/Polygon.c \ vectorio/Rectangle.c \ @@ -634,6 +639,17 @@ SRC_MOD += $(addprefix lib/protomatter/src/, \ $(BUILD)/lib/protomatter/src/core.o: CFLAGS += -include "shared-module/rgbmatrix/allocator.h" -DCIRCUITPY -Wno-missing-braces -Wno-missing-prototypes endif +ifeq ($(CIRCUITPY_UZLIB),1) +SRC_MOD += $(addprefix lib/uzlib/, \ + tinflate.c \ + tinfzlib.c \ + tinfgzip.c \ + adler32.c \ + crc32.c \ +) +$(BUILD)/lib/uzlib/tinflate.o: CFLAGS += -Wno-missing-braces -Wno-missing-prototypes +endif + # All possible sources are listed here, and are filtered by SRC_PATTERNS. SRC_SHARED_MODULE_INTERNAL = \ $(filter $(SRC_PATTERNS), \ diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 14852580e5..b4b6b8ddd7 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -446,6 +446,10 @@ CFLAGS += -DUSB_NUM_ENDPOINT_PAIRS=$(USB_NUM_ENDPOINT_PAIRS) CIRCUITPY_USTACK ?= 0 CFLAGS += -DCIRCUITPY_USTACK=$(CIRCUITPY_USTACK) +# for decompressing utlities +CIRCUITPY_UZLIB ?= 1 +CFLAGS += -DCIRCUITPY_UZLIB=$(CIRCUITPY_UZLIB) + # ulab numerics library CIRCUITPY_ULAB ?= $(CIRCUITPY_FULL_BUILD) CFLAGS += -DCIRCUITPY_ULAB=$(CIRCUITPY_ULAB) diff --git a/shared-bindings/uzlib/DecompIO.c b/shared-bindings/uzlib/DecompIO.c new file mode 100644 index 0000000000..5151113385 --- /dev/null +++ b/shared-bindings/uzlib/DecompIO.c @@ -0,0 +1,86 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2022 Mark Komus + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include "py/obj.h" +#include "py/stream.h" +#include "py/runtime.h" +#include "shared-bindings/uzlib/DecompIO.h" +#include "shared-module/uzlib/DecompIO.h" + +STATIC mp_obj_t uzlib_decompio_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, 2, false); + mp_get_stream_raise(args[0], MP_STREAM_OP_READ); + + mp_obj_decompio_t *self = m_new_obj(mp_obj_decompio_t); + self->base.type = type; + memset(&self->decomp, 0, sizeof(self->decomp)); + + mp_int_t dict_opt = 0; + if (n_args > 1) { + dict_opt = mp_obj_get_int(args[1]); + } + + common_hal_uzlib_decompio_construct(self, args[0], dict_opt); + + return MP_OBJ_FROM_PTR(self); +} + +STATIC mp_uint_t uzlib_decompio_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) { + mp_obj_decompio_t *self = MP_OBJ_TO_PTR(self_in); + if (self->eof) { + return 0; + } + + return common_hal_uzlib_decompio_read(self, buf, size, errcode); +} + +STATIC const mp_rom_map_elem_t decompio_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(decompio_locals_dict, decompio_locals_dict_table); + +STATIC const mp_stream_p_t decompio_stream_p = { + MP_PROTO_IMPLEMENT(MP_QSTR_protocol_stream) + .read = uzlib_decompio_read, + .write = NULL, + .ioctl = NULL, + .is_text = false, +}; + +const mp_obj_type_t decompio_type = { + { &mp_type_type }, + .flags = MP_TYPE_FLAG_EXTENDED, + .name = MP_QSTR_DecompIO, + .make_new = uzlib_decompio_make_new, + .locals_dict = (void *)&decompio_locals_dict, + MP_TYPE_EXTENDED_FIELDS( + .protocol = &decompio_stream_p, + ), +}; diff --git a/shared-bindings/uzlib/DecompIO.h b/shared-bindings/uzlib/DecompIO.h new file mode 100644 index 0000000000..65f0c9d9ae --- /dev/null +++ b/shared-bindings/uzlib/DecompIO.h @@ -0,0 +1,37 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2022 Mark Komus + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_UZLIB_DECOMPIO_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_UZLIB_DECOMPIO_H + +#include "shared-module/uzlib/DecompIO.h" + +extern const mp_obj_type_t decompio_type; + +extern void common_hal_uzlib_decompio_construct(mp_obj_decompio_t *self, mp_obj_t src_stream, mp_int_t dict_opt); +extern mp_uint_t common_hal_uzlib_decompio_read(mp_obj_decompio_t *self, void *buf, mp_uint_t size, int *errcode); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_UZLIB_DECOMPIO_H diff --git a/shared-bindings/uzlib/__init__.c b/shared-bindings/uzlib/__init__.c new file mode 100644 index 0000000000..c8fad450fb --- /dev/null +++ b/shared-bindings/uzlib/__init__.c @@ -0,0 +1,72 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2022 Mark Komus + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/obj.h" +#include "py/runtime.h" +#include "py/stream.h" +#include "py/mperrno.h" +#include "py/builtin.h" +#include "py/objtuple.h" +#include "py/binary.h" +#include "py/parsenum.h" + +#include "shared-bindings/uzlib/DecompIO.h" + +#include "supervisor/shared/translate.h" + +#include "shared-bindings/uzlib/__init__.h" +#include "shared-bindings/uzlib/DecompIO.h" + +STATIC mp_obj_t uzlib_decompress(size_t n_args, const mp_obj_t *args) { + // TODO: Check number of args + + bool is_zlib = true; + if (n_args > 1 && MP_OBJ_SMALL_INT_VALUE(args[1]) < 0) { + is_zlib = false; + } + + return common_hal_uzlib_decompress(args[0], is_zlib); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(uzlib_decompress_obj, 1, 3, uzlib_decompress); + +STATIC const mp_rom_map_elem_t uzlib_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uzlib) }, + { MP_ROM_QSTR(MP_QSTR_decompress), MP_ROM_PTR(&uzlib_decompress_obj) }, + { MP_ROM_QSTR(MP_QSTR_DecompIO), MP_ROM_PTR(&decompio_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(uzlib_globals, uzlib_globals_table); + +const mp_obj_module_t uzlib_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&uzlib_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_uzlib, uzlib_module, CIRCUITPY_UZLIB); diff --git a/shared-bindings/uzlib/__init__.h b/shared-bindings/uzlib/__init__.h new file mode 100644 index 0000000000..b365317a94 --- /dev/null +++ b/shared-bindings/uzlib/__init__.h @@ -0,0 +1,32 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2022 Mark Komus + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_UZLIB___INIT___H +#define MICROPY_INCLUDED_SHARED_BINDINGS_UZLIB___INIT___H + +mp_obj_t common_hal_uzlib_decompress(mp_obj_t data, bool is_zlib); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_UZLIB___INIT___H diff --git a/shared-module/uzlib/DecompIO.c b/shared-module/uzlib/DecompIO.c new file mode 100644 index 0000000000..7df944f4e8 --- /dev/null +++ b/shared-module/uzlib/DecompIO.c @@ -0,0 +1,101 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2022 Mark Komus + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/obj.h" +#include "py/runtime.h" +#include "py/stream.h" +#include "py/mperrno.h" +#include "py/builtin.h" +#include "py/objtuple.h" +#include "py/binary.h" +#include "py/parsenum.h" + +#include "shared-bindings/uzlib/__init__.h" +#include "shared-bindings/uzlib/DecompIO.h" +#include "shared-module/uzlib/DecompIO.h" + +STATIC int read_src_stream(TINF_DATA *data) { + mp_obj_decompio_t *self = (mp_obj_decompio_t *)data->self; + + const mp_stream_p_t *stream = mp_get_stream_raise(self->src_stream, MP_STREAM_OP_READ); + int err; + byte c; + mp_uint_t out_sz = stream->read(self->src_stream, &c, 1, &err); + + if (out_sz == MP_STREAM_ERROR) { + mp_raise_OSError(err); + } + if (out_sz == 0) { + mp_raise_type(&mp_type_EOFError); + } + return c; +} + +void common_hal_uzlib_decompio_construct(mp_obj_decompio_t *self, mp_obj_t src_stream, mp_int_t dict_opt) { + self->decomp.self = self; + self->decomp.readSource = read_src_stream; + self->src_stream = src_stream; + self->eof = false; + + int dict_sz; + + if (dict_opt >= 16) { + int st = uzlib_gzip_parse_header(&self->decomp); + if (st != TINF_OK) { + goto header_error; + } + dict_sz = 1 << (dict_opt - 16); + } else if (dict_opt >= 0) { + dict_opt = uzlib_zlib_parse_header(&self->decomp); + if (dict_opt < 0) { + header_error: + mp_raise_ValueError(MP_ERROR_TEXT("compression header")); + } + dict_sz = 1 << dict_opt; + } else { + dict_sz = 1 << -dict_opt; + } + + uzlib_uncompress_init(&self->decomp, m_new(byte, dict_sz), dict_sz); +} + +mp_uint_t common_hal_uzlib_decompio_read(mp_obj_decompio_t *self, void *buf, mp_uint_t size, int *errcode) { + self->decomp.dest = buf; + self->decomp.dest_limit = (unsigned char *)buf + size; + int st = uzlib_uncompress_chksum(&self->decomp); + if (st == TINF_DONE) { + self->eof = true; + } + if (st < 0) { + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; + } + return self->decomp.dest - (byte *)buf; +} diff --git a/shared-module/uzlib/DecompIO.h b/shared-module/uzlib/DecompIO.h new file mode 100644 index 0000000000..9ca583dbb8 --- /dev/null +++ b/shared-module/uzlib/DecompIO.h @@ -0,0 +1,44 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2022 Mark Komus + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef SHARED_MODULE_UZLIB_DECOMPIO_H +#define SHARED_MODULE_UZLIB_DECOMPIO_H + +#include +#include + +#include "py/obj.h" +#define UZLIB_CONF_PARANOID_CHECKS (1) +#include "lib/uzlib/tinf.h" + +typedef struct _mp_obj_decompio_t { + mp_obj_base_t base; + mp_obj_t src_stream; + TINF_DATA decomp; + bool eof; +} mp_obj_decompio_t; + +#endif /* SHARED_MODULE_UZLIB_DECOMPIO_H */ diff --git a/shared-module/uzlib/__init__.c b/shared-module/uzlib/__init__.c new file mode 100644 index 0000000000..3fe75c69b1 --- /dev/null +++ b/shared-module/uzlib/__init__.c @@ -0,0 +1,100 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2022 Mark Komus + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/obj.h" +#include "py/runtime.h" +#include "py/stream.h" +#include "py/mperrno.h" +#include "py/builtin.h" +#include "py/objtuple.h" +#include "py/binary.h" +#include "py/parsenum.h" + +#include "shared-bindings/uzlib/__init__.h" + +#define UZLIB_CONF_PARANOID_CHECKS (1) +#include "lib/uzlib/tinf.h" + +#if 0 // print debugging info +#define DEBUG_printf DEBUG_printf +#else // don't print debugging info +#define DEBUG_printf(...) (void)0 +#endif + +mp_obj_t common_hal_uzlib_decompress(mp_obj_t data, bool is_zlib) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ); + + TINF_DATA *decomp = m_new_obj(TINF_DATA); + memset(decomp, 0, sizeof(*decomp)); + DEBUG_printf("sizeof(TINF_DATA)=" UINT_FMT "\n", sizeof(*decomp)); + uzlib_uncompress_init(decomp, NULL, 0); + mp_uint_t dest_buf_size = (bufinfo.len + 15) & ~15; + byte *dest_buf = m_new(byte, dest_buf_size); + + decomp->dest = dest_buf; + decomp->dest_limit = dest_buf + dest_buf_size; + DEBUG_printf("uzlib: Initial out buffer: " UINT_FMT " bytes\n", decomp->destSize); + decomp->source = bufinfo.buf; + decomp->source_limit = (unsigned char *)bufinfo.buf + bufinfo.len; + int st; + + if (is_zlib) { + st = uzlib_zlib_parse_header(decomp); + if (st < 0) { + goto error; + } + } + + while (1) { + st = uzlib_uncompress_chksum(decomp); + if (st < 0) { + goto error; + } + if (st == TINF_DONE) { + break; + } + size_t offset = decomp->dest - dest_buf; + dest_buf = m_renew(byte, dest_buf, dest_buf_size, dest_buf_size + 256); + dest_buf_size += 256; + decomp->dest = dest_buf + offset; + decomp->dest_limit = dest_buf + offset + 256; + } + + mp_uint_t final_sz = decomp->dest - dest_buf; + DEBUG_printf("uzlib: Resizing from " UINT_FMT " to final size: " UINT_FMT " bytes\n", dest_buf_size, final_sz); + dest_buf = (byte *)m_renew(byte, dest_buf, dest_buf_size, final_sz); + mp_obj_t res = mp_obj_new_bytearray_by_ref(final_sz, dest_buf); + m_del_obj(TINF_DATA, decomp); + return res; + +error: + mp_raise_type_arg(&mp_type_ValueError, MP_OBJ_NEW_SMALL_INT(st)); +}