1 /*
2  * This file is part of the MicroPython project, http://micropython.org/
3  *
4  * The MIT License (MIT)
5  *
6  * Copyright (c) 2019-2020 Damien P. George
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a copy
9  * of this software and associated documentation files (the "Software"), to deal
10  * in the Software without restriction, including without limitation the rights
11  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12  * copies of the Software, and to permit persons to whom the Software is
13  * furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24  * THE SOFTWARE.
25  */
26 
27 #include <string.h>
28 
29 #include "py/mphal.h"
30 #include "lib/uzlib/uzlib.h"
31 #include "gzstream.h"
32 #include "mboot.h"
33 
34 #if MBOOT_FSLOAD || MBOOT_ENABLE_PACKING
35 
36 #define DICT_SIZE (1 << 15)
37 
38 typedef struct _gz_stream_t {
39     void *stream_data;
40     stream_read_t stream_read;
41     struct uzlib_uncomp tinf;
42     uint8_t buf[512];
43     uint8_t dict[DICT_SIZE];
44 } gz_stream_t;
45 
46 static gz_stream_t gz_stream SECTION_NOZERO_BSS;
47 
gz_stream_read_src(TINF_DATA * tinf)48 static int gz_stream_read_src(TINF_DATA *tinf) {
49     int n = gz_stream.stream_read(gz_stream.stream_data, gz_stream.buf, sizeof(gz_stream.buf));
50     if (n < 0) {
51         // Stream error
52         return -1;
53     }
54     if (n == 0) {
55         // No data / EOF
56         return -1;
57     }
58 
59     tinf->source = gz_stream.buf + 1;
60     tinf->source_limit = gz_stream.buf + n;
61     return gz_stream.buf[0];
62 }
63 
gz_stream_init_from_raw_data(const uint8_t * data,size_t len)64 int gz_stream_init_from_raw_data(const uint8_t *data, size_t len) {
65     memset(&gz_stream.tinf, 0, sizeof(gz_stream.tinf));
66     gz_stream.tinf.source = data;
67     gz_stream.tinf.source_limit = data + len;
68 
69     uzlib_uncompress_init(&gz_stream.tinf, gz_stream.dict, DICT_SIZE);
70 
71     return 0;
72 }
73 
gz_stream_init_from_stream(void * stream_data,stream_read_t stream_read)74 int gz_stream_init_from_stream(void *stream_data, stream_read_t stream_read) {
75     gz_stream.stream_data = stream_data;
76     gz_stream.stream_read = stream_read;
77 
78     memset(&gz_stream.tinf, 0, sizeof(gz_stream.tinf));
79     gz_stream.tinf.source_read_cb = gz_stream_read_src;
80 
81     int st = uzlib_gzip_parse_header(&gz_stream.tinf);
82     if (st != TINF_OK) {
83         return -MBOOT_ERRNO_GUNZIP_FAILED;
84     }
85 
86     uzlib_uncompress_init(&gz_stream.tinf, gz_stream.dict, DICT_SIZE);
87 
88     return 0;
89 }
90 
gz_stream_read(size_t len,uint8_t * buf)91 int gz_stream_read(size_t len, uint8_t *buf) {
92     if (gz_stream.tinf.source == NULL && gz_stream.tinf.source_read_cb == NULL) {
93         // End of stream.
94         return 0;
95     }
96     gz_stream.tinf.dest = buf;
97     gz_stream.tinf.dest_limit = buf + len;
98     int st = uzlib_uncompress_chksum(&gz_stream.tinf);
99     if (st < 0) {
100         return st;
101     }
102     if (st == TINF_DONE) {
103         // Indicate end-of-stream for subsequent calls.
104         gz_stream.tinf.source = NULL;
105         gz_stream.tinf.source_read_cb = NULL;
106     }
107     return gz_stream.tinf.dest - buf;
108 }
109 
110 #endif // MBOOT_FSLOAD || MBOOT_ENABLE_PACKING
111