Imported Upstream version 1.3.2
[platform/upstream/libzip.git] / lib / zip_algorithm_deflate.c
1 /*
2   zip_algorithm_deflate.c -- deflate (de)compression routines
3   Copyright (C) 2017 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 <libzip@nih.at>
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 compression_flags;
44     bool end_of_input;
45     z_stream zstr;
46 };
47
48
49 static void *
50 allocate(bool compress, int compression_flags, zip_error_t *error) {
51     struct ctx *ctx;
52
53     if ((ctx = (struct ctx *)malloc(sizeof(*ctx))) == NULL) {
54         return NULL;
55     }
56
57     ctx->error = error;
58     ctx->compress = compress;
59     ctx->compression_flags = compression_flags;
60     if (ctx->compression_flags < 1 || ctx->compression_flags > 9) {
61         ctx->compression_flags = Z_BEST_COMPRESSION;
62     }
63     ctx->end_of_input = false;
64
65     ctx->zstr.zalloc = Z_NULL;
66     ctx->zstr.zfree = Z_NULL;
67     ctx->zstr.opaque = NULL;
68
69     return ctx;
70 }
71
72
73 static void *
74 compress_allocate(zip_uint16_t method, int compression_flags, zip_error_t *error) {
75     return allocate(true, compression_flags, error);
76 }
77
78
79 static void *
80 decompress_allocate(zip_uint16_t method, int compression_flags, zip_error_t *error) {
81     return allocate(false, compression_flags, error);
82 }
83
84
85 static void
86 deallocate(void *ud) {
87     struct ctx *ctx = (struct ctx *)ud;
88
89     free(ctx);
90 }
91
92
93 static int
94 compression_flags(void *ud) {
95     struct ctx *ctx = (struct ctx *)ud;
96
97     if (!ctx->compress) {
98         return 0;
99     }
100
101     if (ctx->compression_flags < 3) {
102         return 2;
103     }
104     else if (ctx->compression_flags > 7) {
105         return 1;
106     }
107     return 0;
108 }
109
110
111 static bool
112 start(void *ud) {
113     struct ctx *ctx = (struct ctx *)ud;
114     int ret;
115
116     ctx->zstr.avail_in = 0;
117     ctx->zstr.next_in = NULL;
118     ctx->zstr.avail_out = 0;
119     ctx->zstr.next_out = NULL;
120
121     if (ctx->compress) {
122         /* negative value to tell zlib not to write a header */
123         ret = deflateInit2(&ctx->zstr, ctx->compression_flags, Z_DEFLATED, -MAX_WBITS, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
124     }
125     else {
126         ret = inflateInit2(&ctx->zstr, -MAX_WBITS);
127     }
128
129     if (ret != Z_OK) {
130         zip_error_set(ctx->error, ZIP_ER_ZLIB, ret);
131         return false;
132     }
133
134
135     return true;
136 }
137
138
139 static bool
140 end(void *ud) {
141     struct ctx *ctx = (struct ctx *)ud;
142     int err;
143
144     if (ctx->compress) {
145         err = deflateEnd(&ctx->zstr);
146     }
147     else {
148         err = inflateEnd(&ctx->zstr);
149     }
150
151     if (err != Z_OK) {
152         zip_error_set(ctx->error, ZIP_ER_ZLIB, err);
153         return false;
154     }
155
156     return true;
157 }
158
159
160 static bool input(void *ud, zip_uint8_t *data, zip_uint64_t length) {
161     struct ctx *ctx = (struct ctx *)ud;
162
163     if (length > UINT_MAX || ctx->zstr.avail_in > 0) {
164         zip_error_set(ctx->error, ZIP_ER_INVAL, 0);
165         return false;
166     }
167
168     ctx->zstr.avail_in = (uInt)length;
169     ctx->zstr.next_in = (Bytef *)data;
170
171     return true;
172 }
173
174
175 static void end_of_input(void *ud) {
176     struct ctx *ctx = (struct ctx *)ud;
177
178     ctx->end_of_input = true;
179 }
180
181
182 static zip_compression_status_t
183 process(void *ud, zip_uint8_t *data, zip_uint64_t *length) {
184     struct ctx *ctx = (struct ctx *)ud;
185
186     int ret;
187
188     ctx->zstr.avail_out = (uInt)ZIP_MIN(UINT_MAX, *length);
189     ctx->zstr.next_out = (Bytef *)data;
190
191     if (ctx->compress) {
192         ret = deflate(&ctx->zstr, ctx->end_of_input ? Z_FINISH : 0);
193     }
194     else {
195         ret = inflate(&ctx->zstr, Z_SYNC_FLUSH);
196     }
197
198     *length = *length - ctx->zstr.avail_out;
199
200     switch (ret) {
201     case Z_OK:
202         return ZIP_COMPRESSION_OK;
203
204     case Z_STREAM_END:
205         return ZIP_COMPRESSION_END;
206
207     case Z_BUF_ERROR:
208         if (ctx->zstr.avail_in == 0) {
209             return ZIP_COMPRESSION_NEED_DATA;
210         }
211
212         /* fallthrough */
213
214     default:
215         zip_error_set(ctx->error, ZIP_ER_ZLIB, ret);
216         return ZIP_COMPRESSION_ERROR;
217     }
218 }
219
220
221 zip_compression_algorithm_t zip_algorithm_deflate_compress = {
222     compress_allocate,
223     deallocate,
224     compression_flags,
225     start,
226     end,
227     input,
228     end_of_input,
229     process
230 };
231
232
233 zip_compression_algorithm_t zip_algorithm_deflate_decompress = {
234     decompress_allocate,
235     deallocate,
236     compression_flags,
237     start,
238     end,
239     input,
240     end_of_input,
241     process
242 };