LCOV - code coverage report
Current view: top level - extmod - moddeflate.c (source / functions) Hit Total Coverage
Test: unix_coverage_v1.22.0-344-ge60e8079a.info Lines: 147 149 98.7 %
Date: 2024-04-26 14:58:11 Functions: 8 8 100.0 %
Branches: 78 82 95.1 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * This file is part of the MicroPython project, http://micropython.org/
       3                 :            :  *
       4                 :            :  * The MIT License (MIT)
       5                 :            :  *
       6                 :            :  * Copyright (c) 2023 Jim Mussared
       7                 :            :  *
       8                 :            :  * Based on extmod/modzlib.c
       9                 :            :  * Copyright (c) 2014-2016 Paul Sokolovsky
      10                 :            :  * Copyright (c) 2021-2023 Damien P. George
      11                 :            :  *
      12                 :            :  * Permission is hereby granted, free of charge, to any person obtaining a copy
      13                 :            :  * of this software and associated documentation files (the "Software"), to deal
      14                 :            :  * in the Software without restriction, including without limitation the rights
      15                 :            :  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      16                 :            :  * copies of the Software, and to permit persons to whom the Software is
      17                 :            :  * furnished to do so, subject to the following conditions:
      18                 :            :  *
      19                 :            :  * The above copyright notice and this permission notice shall be included in
      20                 :            :  * all copies or substantial portions of the Software.
      21                 :            :  *
      22                 :            :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      23                 :            :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      24                 :            :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      25                 :            :  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      26                 :            :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      27                 :            :  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      28                 :            :  * THE SOFTWARE.
      29                 :            :  */
      30                 :            : 
      31                 :            : #include <stdio.h>
      32                 :            : #include <string.h>
      33                 :            : 
      34                 :            : #include "py/runtime.h"
      35                 :            : #include "py/stream.h"
      36                 :            : #include "py/mperrno.h"
      37                 :            : 
      38                 :            : #if MICROPY_PY_DEFLATE
      39                 :            : 
      40                 :            : #include "lib/uzlib/uzlib.h"
      41                 :            : 
      42                 :            : #if 0 // print debugging info
      43                 :            : #define DEBUG_printf DEBUG_printf
      44                 :            : #else // don't print debugging info
      45                 :            : #define DEBUG_printf(...) (void)0
      46                 :            : #endif
      47                 :            : 
      48                 :            : typedef enum {
      49                 :            :     DEFLATEIO_FORMAT_MIN = 0,
      50                 :            :     DEFLATEIO_FORMAT_AUTO = DEFLATEIO_FORMAT_MIN, // Read mode this means auto-detect zlib/gzip, write mode this means RAW.
      51                 :            :     DEFLATEIO_FORMAT_RAW = 1,
      52                 :            :     DEFLATEIO_FORMAT_ZLIB = 2,
      53                 :            :     DEFLATEIO_FORMAT_GZIP = 3,
      54                 :            :     DEFLATEIO_FORMAT_MAX = DEFLATEIO_FORMAT_GZIP,
      55                 :            : } deflateio_format_t;
      56                 :            : 
      57                 :            : // This is used when the wbits is unset in the DeflateIO constructor. Default
      58                 :            : // to the smallest window size (faster compression, less RAM usage, etc).
      59                 :            : const int DEFLATEIO_DEFAULT_WBITS = 8;
      60                 :            : 
      61                 :            : typedef struct {
      62                 :            :     void *window;
      63                 :            :     uzlib_uncomp_t decomp;
      64                 :            :     bool eof;
      65                 :            : } mp_obj_deflateio_read_t;
      66                 :            : 
      67                 :            : #if MICROPY_PY_DEFLATE_COMPRESS
      68                 :            : typedef struct {
      69                 :            :     void *window;
      70                 :            :     size_t input_len;
      71                 :            :     uint32_t input_checksum;
      72                 :            :     uzlib_lz77_state_t lz77;
      73                 :            : } mp_obj_deflateio_write_t;
      74                 :            : #endif
      75                 :            : 
      76                 :            : typedef struct {
      77                 :            :     mp_obj_base_t base;
      78                 :            :     mp_obj_t stream;
      79                 :            :     uint8_t format : 2;
      80                 :            :     uint8_t window_bits : 4;
      81                 :            :     bool close : 1;
      82                 :            :     mp_obj_deflateio_read_t *read;
      83                 :            :     #if MICROPY_PY_DEFLATE_COMPRESS
      84                 :            :     mp_obj_deflateio_write_t *write;
      85                 :            :     #endif
      86                 :            : } mp_obj_deflateio_t;
      87                 :            : 
      88                 :      10500 : static int deflateio_read_stream(void *data) {
      89                 :      10500 :     mp_obj_deflateio_t *self = data;
      90                 :      10500 :     const mp_stream_p_t *stream = mp_get_stream(self->stream);
      91                 :      10500 :     int err;
      92                 :      10500 :     byte c;
      93                 :      10500 :     mp_uint_t out_sz = stream->read(self->stream, &c, 1, &err);
      94         [ +  + ]:      10498 :     if (out_sz == MP_STREAM_ERROR) {
      95                 :          2 :         mp_raise_OSError(err);
      96                 :            :     }
      97         [ +  + ]:      10496 :     if (out_sz == 0) {
      98                 :          2 :         mp_raise_type(&mp_type_EOFError);
      99                 :            :     }
     100                 :      10494 :     return c;
     101                 :            : }
     102                 :            : 
     103                 :        376 : static bool deflateio_init_read(mp_obj_deflateio_t *self) {
     104         [ +  + ]:        376 :     if (self->read) {
     105                 :            :         return true;
     106                 :            :     }
     107                 :            : 
     108                 :        142 :     mp_get_stream_raise(self->stream, MP_STREAM_OP_READ);
     109                 :            : 
     110                 :        142 :     self->read = m_new_obj(mp_obj_deflateio_read_t);
     111                 :        142 :     memset(&self->read->decomp, 0, sizeof(self->read->decomp));
     112                 :        142 :     self->read->decomp.source_read_data = self;
     113                 :        142 :     self->read->decomp.source_read_cb = deflateio_read_stream;
     114                 :        142 :     self->read->eof = false;
     115                 :            : 
     116                 :            :     // Don't modify self->window_bits as it may also be used for write.
     117                 :        142 :     int wbits = self->window_bits;
     118                 :            : 
     119         [ +  + ]:        142 :     if (self->format == DEFLATEIO_FORMAT_RAW) {
     120         [ +  + ]:         72 :         if (wbits == 0) {
     121                 :            :             // The docs recommends always setting wbits explicitly when using
     122                 :            :             // RAW, but we still allow a default.
     123                 :         26 :             wbits = DEFLATEIO_DEFAULT_WBITS;
     124                 :            :         }
     125                 :            :     } else {
     126                 :            :         // Parse the header if we're in NONE/ZLIB/GZIP modes.
     127                 :         70 :         int header_wbits;
     128                 :         70 :         int header_type = uzlib_parse_zlib_gzip_header(&self->read->decomp, &header_wbits);
     129         [ +  + ]:         68 :         if (header_type < 0) {
     130                 :            :             // Stream header was invalid.
     131                 :         10 :             return false;
     132                 :            :         }
     133   [ +  +  +  +  :         62 :         if ((self->format == DEFLATEIO_FORMAT_ZLIB && header_type != UZLIB_HEADER_ZLIB) || (self->format == DEFLATEIO_FORMAT_GZIP && header_type != UZLIB_HEADER_GZIP)) {
             +  +  +  + ]
     134                 :            :             // Not what we expected.
     135                 :            :             return false;
     136                 :            :         }
     137                 :            :         // header_wbits will either be 15 (gzip) or 8-15 (zlib).
     138   [ +  +  -  + ]:         58 :         if (wbits == 0 || header_wbits < wbits) {
     139                 :            :             // If the header specified something lower, then use that instead.
     140                 :            :             // No point doing a bigger allocation than we need to.
     141                 :         54 :             wbits = header_wbits;
     142                 :            :         }
     143                 :            :     }
     144                 :            : 
     145                 :        130 :     size_t window_len = 1 << wbits;
     146                 :        130 :     self->read->window = m_new(uint8_t, window_len);
     147                 :            : 
     148                 :        130 :     uzlib_uncompress_init(&self->read->decomp, self->read->window, window_len);
     149                 :            : 
     150                 :        130 :     return true;
     151                 :            : }
     152                 :            : 
     153                 :            : #if MICROPY_PY_DEFLATE_COMPRESS
     154                 :      10202 : static void deflateio_out_byte(void *data, uint8_t b) {
     155                 :      10202 :     mp_obj_deflateio_t *self = data;
     156                 :      10202 :     const mp_stream_p_t *stream = mp_get_stream(self->stream);
     157                 :      10202 :     int err;
     158                 :      10202 :     mp_uint_t ret = stream->write(self->stream, &b, 1, &err);
     159         [ +  + ]:      10200 :     if (ret == MP_STREAM_ERROR) {
     160                 :          2 :         mp_raise_OSError(err);
     161                 :            :     }
     162                 :      10198 : }
     163                 :            : 
     164                 :        118 : static bool deflateio_init_write(mp_obj_deflateio_t *self) {
     165         [ +  + ]:        118 :     if (self->write) {
     166                 :            :         return true;
     167                 :            :     }
     168                 :            : 
     169                 :         80 :     const mp_stream_p_t *stream = mp_get_stream_raise(self->stream, MP_STREAM_OP_WRITE);
     170                 :            : 
     171                 :         80 :     self->write = m_new_obj(mp_obj_deflateio_write_t);
     172                 :         80 :     self->write->input_len = 0;
     173                 :            : 
     174                 :         80 :     int wbits = self->window_bits;
     175         [ +  + ]:         80 :     if (wbits == 0) {
     176                 :            :         // Same default wbits for all formats.
     177                 :         42 :         wbits = DEFLATEIO_DEFAULT_WBITS;
     178                 :            :     }
     179                 :         80 :     size_t window_len = 1 << wbits;
     180                 :         80 :     self->write->window = m_new(uint8_t, window_len);
     181                 :            : 
     182                 :         80 :     uzlib_lz77_init(&self->write->lz77, self->write->window, window_len);
     183                 :         80 :     self->write->lz77.dest_write_data = self;
     184                 :         80 :     self->write->lz77.dest_write_cb = deflateio_out_byte;
     185                 :            : 
     186                 :            :     // Write header if needed.
     187                 :         80 :     mp_uint_t ret = 0;
     188                 :         80 :     int err;
     189         [ +  + ]:         80 :     if (self->format == DEFLATEIO_FORMAT_ZLIB) {
     190                 :            :         // -----CMF------  ----------FLG---------------
     191                 :            :         // CINFO(5) CM(3)  FLEVEL(2) FDICT(1) FCHECK(5)
     192                 :          8 :         uint8_t buf[] = { 0x08, 0x80 }; // CM=2 (deflate), FLEVEL=2 (default), FDICT=0 (no dictionary)
     193                 :          8 :         buf[0] |= MAX(wbits - 8, 1) << 4; // base-2 logarithm of the LZ77 window size, minus eight.
     194                 :          8 :         buf[1] |= 31 - ((buf[0] * 256 + buf[1]) % 31); // (CMF*256 + FLG) % 31 == 0.
     195                 :          8 :         ret = stream->write(self->stream, buf, sizeof(buf), &err);
     196                 :            : 
     197                 :          8 :         self->write->input_checksum = 1; // ADLER32
     198         [ +  + ]:         72 :     } else if (self->format == DEFLATEIO_FORMAT_GZIP) {
     199                 :            :         // ID1(8) ID2(8) CM(8) ---FLG--- MTIME(32) XFL(8) OS(8)
     200                 :            :         // FLG: x x x FCOMMENT FNAME FEXTRA FHCRC FTEXT
     201                 :          6 :         uint8_t buf[] = { 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03 }; // MTIME=0, XFL=4 (fastest), OS=3 (unix)
     202                 :          6 :         ret = stream->write(self->stream, buf, sizeof(buf), &err);
     203                 :            : 
     204                 :          6 :         self->write->input_checksum = ~0; // CRC32
     205                 :            :     }
     206         [ +  + ]:         14 :     if (ret == MP_STREAM_ERROR) {
     207                 :            :         return false;
     208                 :            :     }
     209                 :            : 
     210                 :            :     // Write starting block.
     211                 :         76 :     uzlib_start_block(&self->write->lz77);
     212                 :            : 
     213                 :         76 :     return true;
     214                 :            : }
     215                 :            : #endif
     216                 :            : 
     217                 :        248 : static mp_obj_t deflateio_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args_in) {
     218                 :            :     // args: stream, format=NONE, wbits=0, close=False
     219                 :        248 :     mp_arg_check_num(n_args, n_kw, 1, 4, false);
     220                 :            : 
     221         [ +  + ]:        248 :     mp_int_t format = n_args > 1 ? mp_obj_get_int(args_in[1]) : DEFLATEIO_FORMAT_AUTO;
     222         [ +  + ]:        206 :     mp_int_t wbits = n_args > 2 ? mp_obj_get_int(args_in[2]) : 0;
     223                 :            : 
     224         [ +  + ]:        248 :     if (format < DEFLATEIO_FORMAT_MIN || format > DEFLATEIO_FORMAT_MAX) {
     225                 :          8 :         mp_raise_ValueError(MP_ERROR_TEXT("format"));
     226                 :            :     }
     227         [ +  + ]:        240 :     if (wbits != 0 && (wbits < 5 || wbits > 15)) {
     228                 :         16 :         mp_raise_ValueError(MP_ERROR_TEXT("wbits"));
     229                 :            :     }
     230                 :            : 
     231                 :        224 :     mp_obj_deflateio_t *self = mp_obj_malloc(mp_obj_deflateio_t, type);
     232                 :        224 :     self->stream = args_in[0];
     233                 :        224 :     self->format = format;
     234                 :        224 :     self->window_bits = wbits;
     235                 :        224 :     self->read = NULL;
     236                 :            :     #if MICROPY_PY_DEFLATE_COMPRESS
     237                 :        224 :     self->write = NULL;
     238                 :            :     #endif
     239   [ +  +  -  + ]:        224 :     self->close = n_args > 3 ? mp_obj_is_true(args_in[3]) : false;
     240                 :            : 
     241                 :        224 :     return MP_OBJ_FROM_PTR(self);
     242                 :            : }
     243                 :            : 
     244                 :        378 : static mp_uint_t deflateio_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
     245                 :        378 :     mp_obj_deflateio_t *self = MP_OBJ_TO_PTR(o_in);
     246                 :            : 
     247   [ +  +  +  + ]:        378 :     if (self->stream == MP_OBJ_NULL || !deflateio_init_read(self)) {
     248                 :         12 :         *errcode = MP_EINVAL;
     249                 :         12 :         return MP_STREAM_ERROR;
     250                 :            :     }
     251                 :            : 
     252         [ +  + ]:        364 :     if (self->read->eof) {
     253                 :            :         return 0;
     254                 :            :     }
     255                 :            : 
     256                 :        272 :     self->read->decomp.dest = buf;
     257                 :        272 :     self->read->decomp.dest_limit = (uint8_t *)buf + size;
     258                 :        272 :     int st = uzlib_uncompress_chksum(&self->read->decomp);
     259         [ +  + ]:        268 :     if (st == UZLIB_DONE) {
     260                 :         98 :         self->read->eof = true;
     261                 :            :     }
     262         [ +  + ]:        268 :     if (st < 0) {
     263                 :         26 :         DEBUG_printf("uncompress error=" INT_FMT "\n", st);
     264                 :         26 :         *errcode = MP_EINVAL;
     265                 :         26 :         return MP_STREAM_ERROR;
     266                 :            :     }
     267                 :        242 :     return self->read->decomp.dest - (uint8_t *)buf;
     268                 :            : }
     269                 :            : 
     270                 :            : #if MICROPY_PY_DEFLATE_COMPRESS
     271                 :        122 : static mp_uint_t deflateio_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {
     272                 :        122 :     mp_obj_deflateio_t *self = MP_OBJ_TO_PTR(self_in);
     273                 :            : 
     274   [ +  +  +  + ]:        122 :     if (self->stream == MP_OBJ_NULL || !deflateio_init_write(self)) {
     275                 :          8 :         *errcode = MP_EINVAL;
     276                 :          8 :         return MP_STREAM_ERROR;
     277                 :            :     }
     278                 :            : 
     279                 :        114 :     self->write->input_len += size;
     280         [ +  + ]:        114 :     if (self->format == DEFLATEIO_FORMAT_ZLIB) {
     281                 :          6 :         self->write->input_checksum = uzlib_adler32(buf, size, self->write->input_checksum);
     282         [ +  + ]:        108 :     } else if (self->format == DEFLATEIO_FORMAT_GZIP) {
     283                 :          4 :         self->write->input_checksum = uzlib_crc32(buf, size, self->write->input_checksum);
     284                 :            :     }
     285                 :            : 
     286                 :        114 :     uzlib_lz77_compress(&self->write->lz77, buf, size);
     287                 :        114 :     return size;
     288                 :            : }
     289                 :            : 
     290                 :          4 : static inline void put_le32(char *buf, uint32_t value) {
     291                 :          4 :     buf[0] = value & 0xff;
     292                 :          4 :     buf[1] = value >> 8 & 0xff;
     293                 :          4 :     buf[2] = value >> 16 & 0xff;
     294                 :          4 :     buf[3] = value >> 24 & 0xff;
     295                 :            : }
     296                 :            : 
     297                 :          6 : static inline void put_be32(char *buf, uint32_t value) {
     298                 :          6 :     buf[3] = value & 0xff;
     299                 :          6 :     buf[2] = value >> 8 & 0xff;
     300                 :          6 :     buf[1] = value >> 16 & 0xff;
     301                 :          6 :     buf[0] = value >> 24 & 0xff;
     302                 :            : }
     303                 :            : #endif
     304                 :            : 
     305                 :        208 : static mp_uint_t deflateio_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
     306         [ +  - ]:        208 :     if (request == MP_STREAM_CLOSE) {
     307                 :        208 :         mp_obj_deflateio_t *self = MP_OBJ_TO_PTR(self_in);
     308                 :            : 
     309                 :        208 :         mp_uint_t ret = 0;
     310                 :            : 
     311         [ +  - ]:        208 :         if (self->stream != MP_OBJ_NULL) {
     312                 :            :             #if MICROPY_PY_DEFLATE_COMPRESS
     313         [ +  + ]:        208 :             if (self->write) {
     314                 :         72 :                 uzlib_finish_block(&self->write->lz77);
     315                 :            : 
     316         [ +  + ]:         72 :                 const mp_stream_p_t *stream = mp_get_stream(self->stream);
     317                 :            : 
     318                 :            :                 // Write footer if needed.
     319         [ +  + ]:         72 :                 if (self->format == DEFLATEIO_FORMAT_ZLIB || self->format == DEFLATEIO_FORMAT_GZIP) {
     320                 :         10 :                     char footer[8];
     321                 :         10 :                     size_t footer_len;
     322         [ +  + ]:         10 :                     if (self->format == DEFLATEIO_FORMAT_ZLIB) {
     323                 :          6 :                         put_be32(&footer[0], self->write->input_checksum);
     324                 :          6 :                         footer_len = 4;
     325                 :            :                     } else { // DEFLATEIO_FORMAT_GZIP
     326                 :          4 :                         put_le32(&footer[0], ~self->write->input_checksum);
     327                 :          4 :                         put_le32(&footer[4], self->write->input_len);
     328                 :          4 :                         footer_len = 8;
     329                 :            :                     }
     330         [ +  + ]:         10 :                     if (stream->write(self->stream, footer, footer_len, errcode) == MP_STREAM_ERROR) {
     331                 :          4 :                         ret = MP_STREAM_ERROR;
     332                 :            :                     }
     333                 :            :                 }
     334                 :            :             }
     335                 :            :             #endif
     336                 :            : 
     337                 :            :             // Only close the stream if required. e.g. when using io.BytesIO
     338                 :            :             // it needs to stay open so that getvalue() can be called.
     339         [ +  + ]:        208 :             if (self->close) {
     340                 :          2 :                 mp_stream_close(self->stream);
     341                 :            :             }
     342                 :            : 
     343                 :            :             // Either way, free the reference to the stream.
     344                 :        208 :             self->stream = MP_OBJ_NULL;
     345                 :            :         }
     346                 :            : 
     347                 :        208 :         return ret;
     348                 :            :     } else {
     349                 :          0 :         *errcode = MP_EINVAL;
     350                 :          0 :         return MP_STREAM_ERROR;
     351                 :            :     }
     352                 :            : }
     353                 :            : 
     354                 :            : static const mp_stream_p_t deflateio_stream_p = {
     355                 :            :     .read = deflateio_read,
     356                 :            :     #if MICROPY_PY_DEFLATE_COMPRESS
     357                 :            :     .write = deflateio_write,
     358                 :            :     #endif
     359                 :            :     .ioctl = deflateio_ioctl,
     360                 :            : };
     361                 :            : 
     362                 :            : #if !MICROPY_ENABLE_DYNRUNTIME
     363                 :            : static const mp_rom_map_elem_t deflateio_locals_dict_table[] = {
     364                 :            :     { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
     365                 :            :     { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
     366                 :            :     { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
     367                 :            :     #if MICROPY_PY_DEFLATE_COMPRESS
     368                 :            :     { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
     369                 :            :     #endif
     370                 :            :     { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
     371                 :            :     { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) },
     372                 :            :     { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&mp_stream___exit___obj) },
     373                 :            : };
     374                 :            : static MP_DEFINE_CONST_DICT(deflateio_locals_dict, deflateio_locals_dict_table);
     375                 :            : 
     376                 :            : static MP_DEFINE_CONST_OBJ_TYPE(
     377                 :            :     deflateio_type,
     378                 :            :     MP_QSTR_DeflateIO,
     379                 :            :     MP_TYPE_FLAG_NONE,
     380                 :            :     make_new, deflateio_make_new,
     381                 :            :     protocol, &deflateio_stream_p,
     382                 :            :     locals_dict, &deflateio_locals_dict
     383                 :            :     );
     384                 :            : 
     385                 :            : static const mp_rom_map_elem_t mp_module_deflate_globals_table[] = {
     386                 :            :     { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_deflate) },
     387                 :            :     { MP_ROM_QSTR(MP_QSTR_DeflateIO), MP_ROM_PTR(&deflateio_type) },
     388                 :            :     { MP_ROM_QSTR(MP_QSTR_AUTO), MP_ROM_INT(DEFLATEIO_FORMAT_AUTO) },
     389                 :            :     { MP_ROM_QSTR(MP_QSTR_RAW), MP_ROM_INT(DEFLATEIO_FORMAT_RAW) },
     390                 :            :     { MP_ROM_QSTR(MP_QSTR_ZLIB), MP_ROM_INT(DEFLATEIO_FORMAT_ZLIB) },
     391                 :            :     { MP_ROM_QSTR(MP_QSTR_GZIP), MP_ROM_INT(DEFLATEIO_FORMAT_GZIP) },
     392                 :            : };
     393                 :            : static MP_DEFINE_CONST_DICT(mp_module_deflate_globals, mp_module_deflate_globals_table);
     394                 :            : 
     395                 :            : const mp_obj_module_t mp_module_deflate = {
     396                 :            :     .base = { &mp_type_module },
     397                 :            :     .globals = (mp_obj_dict_t *)&mp_module_deflate_globals,
     398                 :            : };
     399                 :            : 
     400                 :            : MP_REGISTER_MODULE(MP_QSTR_deflate, mp_module_deflate);
     401                 :            : #endif // !MICROPY_ENABLE_DYNRUNTIME
     402                 :            : 
     403                 :            : // Source files #include'd here to make sure they're compiled in
     404                 :            : // only if the module is enabled.
     405                 :            : 
     406                 :            : #include "lib/uzlib/tinflate.c"
     407                 :            : #include "lib/uzlib/header.c"
     408                 :            : #include "lib/uzlib/adler32.c"
     409                 :            : #include "lib/uzlib/crc32.c"
     410                 :            : 
     411                 :            : #if MICROPY_PY_DEFLATE_COMPRESS
     412                 :            : #include "lib/uzlib/lz77.c"
     413                 :            : #endif
     414                 :            : 
     415                 :            : #endif // MICROPY_PY_DEFLATE

Generated by: LCOV version 1.15-5-g462f71d