/src/libzip/lib/zip_algorithm_deflate.c
Line  | Count  | Source  | 
1  |  | /*  | 
2  |  |   zip_algorithm_deflate.c -- deflate (de)compression routines  | 
3  |  |   Copyright (C) 2017-2023 Dieter Baron and Thomas Klausner  | 
4  |  |  | 
5  |  |   This file is part of libzip, a library to manipulate ZIP archives.  | 
6  |  |   The authors can be contacted at <info@libzip.org>  | 
7  |  |  | 
8  |  |   Redistribution and use in source and binary forms, with or without  | 
9  |  |   modification, are permitted provided that the following conditions  | 
10  |  |   are met:  | 
11  |  |   1. Redistributions of source code must retain the above copyright  | 
12  |  |      notice, this list of conditions and the following disclaimer.  | 
13  |  |   2. Redistributions in binary form must reproduce the above copyright  | 
14  |  |      notice, this list of conditions and the following disclaimer in  | 
15  |  |      the documentation and/or other materials provided with the  | 
16  |  |      distribution.  | 
17  |  |   3. The names of the authors may not be used to endorse or promote  | 
18  |  |      products derived from this software without specific prior  | 
19  |  |      written permission.  | 
20  |  |  | 
21  |  |   THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS  | 
22  |  |   OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED  | 
23  |  |   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE  | 
24  |  |   ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY  | 
25  |  |   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL  | 
26  |  |   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE  | 
27  |  |   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  | 
28  |  |   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER  | 
29  |  |   IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR  | 
30  |  |   OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN  | 
31  |  |   IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  | 
32  |  | */  | 
33  |  |  | 
34  |  | #include "zipint.h"  | 
35  |  |  | 
36  |  | #include <limits.h>  | 
37  |  | #include <stdlib.h>  | 
38  |  | #include <zlib.h>  | 
39  |  |  | 
40  |  | struct ctx { | 
41  |  |     zip_error_t *error;  | 
42  |  |     bool compress;  | 
43  |  |     int level;  | 
44  |  |     int mem_level;  | 
45  |  |     bool end_of_input;  | 
46  |  |     z_stream zstr;  | 
47  |  | };  | 
48  |  |  | 
49  |  |  | 
50  |  | static zip_uint64_t  | 
51  | 939  | maximum_compressed_size(zip_uint64_t uncompressed_size) { | 
52  |  |     /* max deflate size increase: size + ceil(size/16k)*5+6 */  | 
53  |  |  | 
54  | 939  |     zip_uint64_t compressed_size = uncompressed_size + (uncompressed_size + 16383) / 16384 * 5 + 6;  | 
55  |  |  | 
56  | 939  |     if (compressed_size < uncompressed_size) { | 
57  | 0  |         return ZIP_UINT64_MAX;  | 
58  | 0  |     }  | 
59  | 939  |     return compressed_size;  | 
60  | 939  | }  | 
61  |  |  | 
62  |  |  | 
63  |  | static void *  | 
64  | 19.7k  | allocate(bool compress, zip_uint32_t compression_flags, zip_error_t *error) { | 
65  | 19.7k  |     struct ctx *ctx;  | 
66  |  |  | 
67  | 19.7k  |     if ((ctx = (struct ctx *)malloc(sizeof(*ctx))) == NULL) { | 
68  | 0  |         zip_error_set(error, ZIP_ET_SYS, errno);  | 
69  | 0  |         return NULL;  | 
70  | 0  |     }  | 
71  |  |  | 
72  | 19.7k  |     ctx->error = error;  | 
73  | 19.7k  |     ctx->compress = compress;  | 
74  | 19.7k  |     if (compression_flags >= 1 && compression_flags <= 9) { | 
75  | 0  |         ctx->level = (int)compression_flags;  | 
76  | 0  |     }  | 
77  | 19.7k  |     else { | 
78  | 19.7k  |         ctx->level = Z_BEST_COMPRESSION;  | 
79  | 19.7k  |     }  | 
80  | 19.7k  |     ctx->mem_level = compression_flags == TORRENTZIP_COMPRESSION_FLAGS ? TORRENTZIP_MEM_LEVEL : MAX_MEM_LEVEL;  | 
81  | 19.7k  |     ctx->end_of_input = false;  | 
82  |  |  | 
83  | 19.7k  |     ctx->zstr.zalloc = Z_NULL;  | 
84  | 19.7k  |     ctx->zstr.zfree = Z_NULL;  | 
85  | 19.7k  |     ctx->zstr.opaque = NULL;  | 
86  |  |  | 
87  | 19.7k  |     return ctx;  | 
88  | 19.7k  | }  | 
89  |  |  | 
90  |  |  | 
91  |  | static void *  | 
92  | 939  | compress_allocate(zip_uint16_t method, zip_uint32_t compression_flags, zip_error_t *error) { | 
93  | 939  |     (void)method;  | 
94  | 939  |     return allocate(true, compression_flags, error);  | 
95  | 939  | }  | 
96  |  |  | 
97  |  |  | 
98  |  | static void *  | 
99  | 18.7k  | decompress_allocate(zip_uint16_t method, zip_uint32_t compression_flags, zip_error_t *error) { | 
100  | 18.7k  |     (void)method;  | 
101  | 18.7k  |     return allocate(false, compression_flags, error);  | 
102  | 18.7k  | }  | 
103  |  |  | 
104  |  |  | 
105  |  | static void  | 
106  | 19.7k  | deallocate(void *ud) { | 
107  | 19.7k  |     struct ctx *ctx = (struct ctx *)ud;  | 
108  |  |  | 
109  | 19.7k  |     free(ctx);  | 
110  | 19.7k  | }  | 
111  |  |  | 
112  |  |  | 
113  |  | static zip_uint16_t  | 
114  | 1.61k  | general_purpose_bit_flags(void *ud) { | 
115  | 1.61k  |     struct ctx *ctx = (struct ctx *)ud;  | 
116  |  |  | 
117  | 1.61k  |     if (!ctx->compress) { | 
118  | 0  |         return 0;  | 
119  | 0  |     }  | 
120  |  |  | 
121  | 1.61k  |     if (ctx->level < 3) { | 
122  | 0  |         return 2 << 1;  | 
123  | 0  |     }  | 
124  | 1.61k  |     else if (ctx->level > 7) { | 
125  | 1.61k  |         return 1 << 1;  | 
126  | 1.61k  |     }  | 
127  | 0  |     return 0;  | 
128  | 1.61k  | }  | 
129  |  |  | 
130  |  |  | 
131  |  | static bool  | 
132  | 17.0k  | start(void *ud, zip_stat_t *st, zip_file_attributes_t *attributes) { | 
133  | 17.0k  |     struct ctx *ctx = (struct ctx *)ud;  | 
134  | 17.0k  |     int ret;  | 
135  |  |  | 
136  | 17.0k  |     (void)st;  | 
137  | 17.0k  |     (void)attributes;  | 
138  |  |  | 
139  | 17.0k  |     ctx->zstr.avail_in = 0;  | 
140  | 17.0k  |     ctx->zstr.next_in = NULL;  | 
141  | 17.0k  |     ctx->zstr.avail_out = 0;  | 
142  | 17.0k  |     ctx->zstr.next_out = NULL;  | 
143  |  |  | 
144  | 17.0k  |     if (ctx->compress) { | 
145  |  |         /* negative value to tell zlib not to write a header */  | 
146  | 939  |         ret = deflateInit2(&ctx->zstr, ctx->level, Z_DEFLATED, -MAX_WBITS, ctx->mem_level, Z_DEFAULT_STRATEGY);  | 
147  | 939  |     }  | 
148  | 16.0k  |     else { | 
149  | 16.0k  |         ret = inflateInit2(&ctx->zstr, -MAX_WBITS);  | 
150  | 16.0k  |     }  | 
151  |  |  | 
152  | 17.0k  |     if (ret != Z_OK) { | 
153  | 0  |         zip_error_set(ctx->error, ZIP_ER_ZLIB, ret);  | 
154  | 0  |         return false;  | 
155  | 0  |     }  | 
156  |  |  | 
157  |  |  | 
158  | 17.0k  |     return true;  | 
159  | 17.0k  | }  | 
160  |  |  | 
161  |  |  | 
162  |  | static bool  | 
163  | 17.0k  | end(void *ud) { | 
164  | 17.0k  |     struct ctx *ctx = (struct ctx *)ud;  | 
165  | 17.0k  |     int err;  | 
166  |  |  | 
167  | 17.0k  |     if (ctx->compress) { | 
168  | 939  |         err = deflateEnd(&ctx->zstr);  | 
169  | 939  |     }  | 
170  | 16.0k  |     else { | 
171  | 16.0k  |         err = inflateEnd(&ctx->zstr);  | 
172  | 16.0k  |     }  | 
173  |  |  | 
174  | 17.0k  |     if (err != Z_OK) { | 
175  | 0  |         zip_error_set(ctx->error, ZIP_ER_ZLIB, err);  | 
176  | 0  |         return false;  | 
177  | 0  |     }  | 
178  |  |  | 
179  | 17.0k  |     return true;  | 
180  | 17.0k  | }  | 
181  |  |  | 
182  |  |  | 
183  |  | static bool  | 
184  | 37.0k  | input(void *ud, zip_uint8_t *data, zip_uint64_t length) { | 
185  | 37.0k  |     struct ctx *ctx = (struct ctx *)ud;  | 
186  |  |  | 
187  | 37.0k  |     if (length > UINT_MAX || ctx->zstr.avail_in > 0) { | 
188  | 0  |         zip_error_set(ctx->error, ZIP_ER_INVAL, 0);  | 
189  | 0  |         return false;  | 
190  | 0  |     }  | 
191  |  |  | 
192  | 37.0k  |     ctx->zstr.avail_in = (uInt)length;  | 
193  | 37.0k  |     ctx->zstr.next_in = (Bytef *)data;  | 
194  |  |  | 
195  | 37.0k  |     return true;  | 
196  | 37.0k  | }  | 
197  |  |  | 
198  |  |  | 
199  | 4.74k  | static bool end_of_input(void *ud) { | 
200  | 4.74k  |     struct ctx *ctx = (struct ctx *)ud;  | 
201  |  |  | 
202  | 4.74k  |     ctx->end_of_input = true;  | 
203  | 4.74k  |     return ctx->zstr.avail_in != 0;  | 
204  | 4.74k  | }  | 
205  |  |  | 
206  |  |  | 
207  |  | static zip_compression_status_t  | 
208  | 99.0k  | process(void *ud, zip_uint8_t *data, zip_uint64_t *length) { | 
209  | 99.0k  |     struct ctx *ctx = (struct ctx *)ud;  | 
210  | 99.0k  |     uInt avail_out;  | 
211  |  |  | 
212  | 99.0k  |     int ret;  | 
213  |  |  | 
214  | 99.0k  |     avail_out = (uInt)ZIP_MIN(UINT_MAX, *length);  | 
215  | 99.0k  |     ctx->zstr.avail_out = avail_out;  | 
216  | 99.0k  |     ctx->zstr.next_out = (Bytef *)data;  | 
217  |  |  | 
218  | 99.0k  |     if (ctx->compress) { | 
219  | 64.6k  |         ret = deflate(&ctx->zstr, ctx->end_of_input ? Z_FINISH : 0);  | 
220  | 64.6k  |     }  | 
221  | 34.3k  |     else { | 
222  | 34.3k  |         ret = inflate(&ctx->zstr, Z_SYNC_FLUSH);  | 
223  | 34.3k  |     }  | 
224  |  |  | 
225  | 99.0k  |     *length = avail_out - ctx->zstr.avail_out;  | 
226  |  |  | 
227  | 99.0k  |     switch (ret) { | 
228  | 42.2k  |     case Z_OK:  | 
229  | 42.2k  |         return ZIP_COMPRESSION_OK;  | 
230  |  |  | 
231  | 4.36k  |     case Z_STREAM_END:  | 
232  | 4.36k  |         return ZIP_COMPRESSION_END;  | 
233  |  |  | 
234  | 42.3k  |     case Z_BUF_ERROR:  | 
235  | 42.3k  |         if (ctx->zstr.avail_in == 0) { | 
236  | 42.3k  |             return ZIP_COMPRESSION_NEED_DATA;  | 
237  | 42.3k  |         }  | 
238  |  |  | 
239  |  |         /* fallthrough */  | 
240  |  |  | 
241  | 10.0k  |     default:  | 
242  | 10.0k  |         zip_error_set(ctx->error, ZIP_ER_ZLIB, ret);  | 
243  | 10.0k  |         return ZIP_COMPRESSION_ERROR;  | 
244  | 99.0k  |     }  | 
245  | 99.0k  | }  | 
246  |  |  | 
247  |  | /* clang-format off */  | 
248  |  |  | 
249  |  | zip_compression_algorithm_t zip_algorithm_deflate_compress = { | 
250  |  |     maximum_compressed_size,  | 
251  |  |     compress_allocate,  | 
252  |  |     deallocate,  | 
253  |  |     general_purpose_bit_flags,  | 
254  |  |     20,  | 
255  |  |     start,  | 
256  |  |     end,  | 
257  |  |     input,  | 
258  |  |     end_of_input,  | 
259  |  |     process  | 
260  |  | };  | 
261  |  |  | 
262  |  |  | 
263  |  | zip_compression_algorithm_t zip_algorithm_deflate_decompress = { | 
264  |  |     maximum_compressed_size,  | 
265  |  |     decompress_allocate,  | 
266  |  |     deallocate,  | 
267  |  |     general_purpose_bit_flags,  | 
268  |  |     20,  | 
269  |  |     start,  | 
270  |  |     end,  | 
271  |  |     input,  | 
272  |  |     end_of_input,  | 
273  |  |     process  | 
274  |  | };  | 
275  |  |  | 
276  |  | /* clang-format on */  |