Rizin
unix-like reverse engineering framework and cli tools
zip_source_compress.c
Go to the documentation of this file.
1 /*
2  zip_source_compress.c -- (de)compression routines
3  Copyright (C) 2017-2021 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 <stdlib.h>
35 #include <string.h>
36 
37 #include "zipint.h"
38 
39 struct context {
41 
44  bool can_store;
45  bool is_stored; /* only valid if end_of_stream is true */
46  bool compress;
48 
52 
54  void *ud;
55 };
56 
57 
62 };
63 
64 static struct implementation implementations[] = {
66 #if defined(HAVE_LIBBZ2)
68 #endif
69 #if defined(HAVE_LIBLZMA)
71  /* Disabled - because 7z isn't able to unpack ZIP+LZMA2
72  archives made this way - and vice versa.
73 
74  {ZIP_CM_LZMA2, &zip_algorithm_xz_compress, &zip_algorithm_xz_decompress},
75  */
77 #endif
78 #if defined(HAVE_LIBZSTD)
80 #endif
81 
82 };
83 
84 static size_t implementations_size = sizeof(implementations) / sizeof(implementations[0]);
85 
86 static zip_source_t *compression_source_new(zip_t *za, zip_source_t *src, zip_int32_t method, bool compress, int compression_flags);
88 static void context_free(struct context *ctx);
89 static struct context *context_new(zip_int32_t method, bool compress, int compression_flags, zip_compression_algorithm_t *algorithm);
90 static zip_int64_t compress_read(zip_source_t *, struct context *, void *, zip_uint64_t);
91 
94  size_t i;
95  zip_uint16_t real_method = ZIP_CM_ACTUAL(method);
96 
97  for (i = 0; i < implementations_size; i++) {
98  if (implementations[i].method == real_method) {
99  if (compress) {
100  return implementations[i].compress;
101  }
102  else {
103  return implementations[i].decompress;
104  }
105  }
106  }
107 
108  return NULL;
109 }
110 
111 ZIP_EXTERN int
113  if (method == ZIP_CM_STORE) {
114  return 1;
115  }
117 }
118 
119 zip_source_t *
121  return compression_source_new(za, src, method, true, compression_flags);
122 }
123 
124 zip_source_t *
126  return compression_source_new(za, src, method, false, 0);
127 }
128 
129 
130 static zip_source_t *
132  struct context *ctx;
133  zip_source_t *s2;
135 
136  if (src == NULL) {
138  return NULL;
139  }
140 
143  return NULL;
144  }
145 
146  if ((ctx = context_new(method, compress, compression_flags, algorithm)) == NULL) {
148  return NULL;
149  }
150 
152  context_free(ctx);
153  return NULL;
154  }
155 
156  return s2;
157 }
158 
159 
160 static struct context *
162  struct context *ctx;
163 
164  if ((ctx = (struct context *)malloc(sizeof(*ctx))) == NULL) {
165  return NULL;
166  }
168  ctx->can_store = compress ? ZIP_CM_IS_DEFAULT(method) : false;
169  ctx->algorithm = algorithm;
170  ctx->method = method;
171  ctx->compress = compress;
172  ctx->end_of_input = false;
173  ctx->end_of_stream = false;
174  ctx->is_stored = false;
175 
176  if ((ctx->ud = ctx->algorithm->allocate(ZIP_CM_ACTUAL(method), compression_flags, &ctx->error)) == NULL) {
178  free(ctx);
179  return NULL;
180  }
181 
182  return ctx;
183 }
184 
185 
186 static void
188  if (ctx == NULL) {
189  return;
190  }
191 
192  ctx->algorithm->deallocate(ctx->ud);
194 
195  free(ctx);
196 }
197 
198 
199 static zip_int64_t
202  bool end;
203  zip_int64_t n;
204  zip_uint64_t out_offset;
205  zip_uint64_t out_len;
206 
208  return -1;
209  }
210 
211  if (len == 0 || ctx->end_of_stream) {
212  return 0;
213  }
214 
215  out_offset = 0;
216 
217  end = false;
218  while (!end && out_offset < len) {
219  out_len = len - out_offset;
220  ret = ctx->algorithm->process(ctx->ud, (zip_uint8_t *)data + out_offset, &out_len);
221 
222  if (ret != ZIP_COMPRESSION_ERROR) {
223  out_offset += out_len;
224  }
225 
226  switch (ret) {
227  case ZIP_COMPRESSION_END:
228  ctx->end_of_stream = true;
229 
230  if (!ctx->end_of_input) {
231  /* TODO: garbage after stream, or compression ended before all data read */
232  }
233 
234  if (ctx->first_read < 0) {
235  /* we got end of processed stream before reading any input data */
237  end = true;
238  break;
239  }
240  if (ctx->can_store && (zip_uint64_t)ctx->first_read <= out_offset) {
241  ctx->is_stored = true;
242  ctx->size = (zip_uint64_t)ctx->first_read;
243  memcpy(data, ctx->buffer, ctx->size);
244  return (zip_int64_t)ctx->size;
245  }
246  end = true;
247  break;
248 
249  case ZIP_COMPRESSION_OK:
250  break;
251 
253  if (ctx->end_of_input) {
254  /* TODO: error: stream not ended, but no more input */
255  end = true;
256  break;
257  }
258 
259  if ((n = zip_source_read(src, ctx->buffer, sizeof(ctx->buffer))) < 0) {
261  end = true;
262  break;
263  }
264  else if (n == 0) {
265  ctx->end_of_input = true;
266  ctx->algorithm->end_of_input(ctx->ud);
267  if (ctx->first_read < 0) {
268  ctx->first_read = 0;
269  }
270  }
271  else {
272  if (ctx->first_read >= 0) {
273  /* we overwrote a previously filled ctx->buffer */
274  ctx->can_store = false;
275  }
276  else {
277  ctx->first_read = n;
278  }
279 
280  ctx->algorithm->input(ctx->ud, ctx->buffer, (zip_uint64_t)n);
281  }
282  break;
283 
285  /* error set by algorithm */
288  }
289  end = true;
290  break;
291  }
292  }
293 
294  if (out_offset > 0) {
295  ctx->can_store = false;
296  ctx->size += out_offset;
297  return (zip_int64_t)out_offset;
298  }
299 
300  return (zip_error_code_zip(&ctx->error) == ZIP_ER_OK) ? 0 : -1;
301 }
302 
303 
304 static zip_int64_t
306  struct context *ctx;
307 
308  ctx = (struct context *)ud;
309 
310  switch (cmd) {
311  case ZIP_SOURCE_OPEN: {
312  zip_stat_t st;
313  zip_file_attributes_t attributes;
314 
315  ctx->size = 0;
316  ctx->end_of_input = false;
317  ctx->end_of_stream = false;
318  ctx->is_stored = false;
319  ctx->first_read = -1;
320 
321  if (zip_source_stat(src, &st) < 0 || zip_source_get_file_attributes(src, &attributes) < 0) {
323  return -1;
324  }
325 
326  if (!ctx->algorithm->start(ctx->ud, &st, &attributes)) {
327  return -1;
328  }
329 
330  return 0;
331  }
332 
333  case ZIP_SOURCE_READ:
334  return compress_read(src, ctx, data, len);
335 
336  case ZIP_SOURCE_CLOSE:
337  if (!ctx->algorithm->end(ctx->ud)) {
338  return -1;
339  }
340  return 0;
341 
342  case ZIP_SOURCE_STAT: {
343  zip_stat_t *st;
344 
345  st = (zip_stat_t *)data;
346 
347  if (ctx->compress) {
348  if (ctx->end_of_stream) {
349  st->comp_method = ctx->is_stored ? ZIP_CM_STORE : ZIP_CM_ACTUAL(ctx->method);
350  st->comp_size = ctx->size;
352  }
353  else {
355  }
356  }
357  else {
360  if (ctx->end_of_stream) {
361  st->size = ctx->size;
362  st->valid |= ZIP_STAT_SIZE;
363  }
364  }
365  }
366  return 0;
367 
368  case ZIP_SOURCE_ERROR:
369  return zip_error_to_data(&ctx->error, data, len);
370 
371  case ZIP_SOURCE_FREE:
372  context_free(ctx);
373  return 0;
374 
376  zip_file_attributes_t *attributes = (zip_file_attributes_t *)data;
377 
378  if (len < sizeof(*attributes)) {
380  return -1;
381  }
382 
384  attributes->version_needed = ctx->algorithm->version_needed;
386  attributes->general_purpose_bit_flags = (ctx->is_stored ? 0 : ctx->algorithm->general_purpose_bit_flags(ctx->ud));
387 
388  return sizeof(*attributes);
389  }
390 
391  case ZIP_SOURCE_SUPPORTS:
393 
394  default:
396  return -1;
397  }
398 }
size_t len
Definition: 6502dis.c:15
lzma_index ** i
Definition: index.h:629
lzma_index * src
Definition: index.h:567
int ZEXPORT compress(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)
Definition: compress.c:68
#define NULL
Definition: cris-opc.c:27
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags cmd
Definition: sflib.h:79
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
#define ZIP_ER_INTERNAL
Definition: zip.h:125
ZIP_EXTERN void zip_error_set(zip_error_t *_Nullable, int, int)
Definition: zip_error.c:126
#define ZIP_CM_STORE
Definition: zip.h:149
#define ZIP_SOURCE_SUPPORTS_READABLE
Definition: zip.h:249
#define ZIP_ER_MEMORY
Definition: zip.h:119
ZIP_EXTERN zip_int64_t zip_source_read(zip_source_t *_Nonnull, void *_Nonnull, zip_uint64_t)
#define ZIP_STAT_SIZE
Definition: zip.h:292
#define ZIP_STAT_COMP_METHOD
Definition: zip.h:296
#define ZIP_CM_BZIP2
Definition: zip.h:161
#define ZIP_CM_ZSTD
Definition: zip.h:169
ZIP_EXTERN int zip_source_get_file_attributes(zip_source_t *_Nonnull, zip_file_attributes_t *_Nonnull)
ZIP_EXTERN void zip_error_init(zip_error_t *_Nonnull)
Definition: zip_error.c:59
#define ZIP_EXTERN
Definition: zip.h:54
#define ZIP_CM_XZ
Definition: zip.h:170
ZIP_EXTERN int zip_source_stat(zip_source_t *_Nonnull, zip_stat_t *_Nonnull)
#define ZIP_CM_LZMA
Definition: zip.h:163
enum zip_source_cmd zip_source_cmd_t
Definition: zip.h:241
#define ZIP_STAT_COMP_SIZE
Definition: zip.h:293
@ ZIP_SOURCE_CLOSE
Definition: zip.h:222
@ ZIP_SOURCE_READ
Definition: zip.h:221
@ ZIP_SOURCE_GET_FILE_ATTRIBUTES
Definition: zip.h:239
@ ZIP_SOURCE_FREE
Definition: zip.h:225
@ ZIP_SOURCE_SUPPORTS
Definition: zip.h:234
@ ZIP_SOURCE_STAT
Definition: zip.h:223
@ ZIP_SOURCE_OPEN
Definition: zip.h:220
@ ZIP_SOURCE_ERROR
Definition: zip.h:224
#define ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS
Definition: zip.h:333
#define ZIP_ER_OK
Definition: zip.h:105
ZIP_EXTERN void zip_error_fini(zip_error_t *_Nonnull)
Definition: zip_error.c:52
#define ZIP_ER_COMPNOTSUPP
Definition: zip.h:121
#define ZIP_ER_INVAL
Definition: zip.h:123
ZIP_EXTERN zip_int64_t zip_source_make_command_bitmap(zip_source_cmd_t,...)
#define ZIP_FILE_ATTRIBUTES_VERSION_NEEDED
Definition: zip.h:331
ZIP_EXTERN int zip_error_code_zip(const zip_error_t *_Nonnull)
Definition: zip_error.c:46
#define ZIP_CM_DEFLATE
Definition: zip.h:157
ZIP_EXTERN zip_int64_t zip_error_to_data(const zip_error_t *_Nonnull, void *_Nonnull, zip_uint64_t)
Definition: zip_error.c:141
void * malloc(size_t size)
Definition: malloc.c:123
int n
Definition: mipsasm.c:19
#define BUFSIZE
Definition: buffer.h:15
zip_compression_algorithm_t * algorithm
zip_int64_t first_read
zip_int32_t method
zip_error_t error
zip_uint64_t size
zip_uint16_t method
bool end_of_input
bool compress
zip_error_t * error
zip_uint16_t method
zip_compression_algorithm_t * compress
zip_compression_algorithm_t * decompress
Definition: zip.h:284
zip_uint16_t general_purpose_bit_mask
Definition: zip.h:326
zip_uint16_t general_purpose_bit_flags
Definition: zip.h:325
zip_uint8_t version_needed
Definition: zip.h:323
zip_uint64_t valid
Definition: zip.h:319
Definition: zip.h:300
zip_uint64_t valid
Definition: zip.h:301
zip_uint16_t comp_method
Definition: zip.h:308
zip_uint64_t comp_size
Definition: zip.h:305
zip_uint64_t size
Definition: zip.h:304
Definition: zipint.h:278
zip_error_t error
Definition: zipint.h:281
zip_compression_algorithm_t zip_algorithm_bzip2_decompress
zip_compression_algorithm_t zip_algorithm_bzip2_compress
zip_compression_algorithm_t zip_algorithm_deflate_decompress
zip_compression_algorithm_t zip_algorithm_deflate_compress
zip_compression_algorithm_t zip_algorithm_xz_compress
zip_compression_algorithm_t zip_algorithm_xz_decompress
zip_compression_algorithm_t zip_algorithm_zstd_compress
zip_compression_algorithm_t zip_algorithm_zstd_decompress
void _zip_error_set_from_source(zip_error_t *err, zip_source_t *src)
Definition: zip_error.c:135
ZIP_EXTERN int zip_compression_method_supported(zip_int32_t method, int compress)
zip_compression_algorithm_t * _zip_get_compression_algorithm(zip_int32_t method, bool compress)
static struct implementation implementations[]
static zip_int64_t compress_callback(zip_source_t *, void *, void *, zip_uint64_t, zip_source_cmd_t)
static zip_source_t * compression_source_new(zip_t *za, zip_source_t *src, zip_int32_t method, bool compress, int compression_flags)
zip_source_t * zip_source_decompress(zip_t *za, zip_source_t *src, zip_int32_t method)
zip_source_t * zip_source_compress(zip_t *za, zip_source_t *src, zip_int32_t method, int compression_flags)
static zip_int64_t compress_read(zip_source_t *, struct context *, void *, zip_uint64_t)
static struct context * context_new(zip_int32_t method, bool compress, int compression_flags, zip_compression_algorithm_t *algorithm)
static void context_free(struct context *ctx)
static size_t implementations_size
zip_source_t * zip_source_layered(zip_t *za, zip_source_t *src, zip_source_layered_callback cb, void *ud)
uint64_t zip_uint64_t
Definition: zipconf.h:39
uint8_t zip_uint8_t
Definition: zipconf.h:33
int32_t zip_int32_t
Definition: zipconf.h:36
uint16_t zip_uint16_t
Definition: zipconf.h:35
int64_t zip_int64_t
Definition: zipconf.h:38
#define ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS_ALLOWED_MASK
Definition: zipint.h:97
enum zip_compression_status zip_compression_status_t
Definition: zipint.h:122
#define ZIP_CM_IS_DEFAULT(x)
Definition: zipint.h:82
@ ZIP_COMPRESSION_NEED_DATA
Definition: zipint.h:119
@ ZIP_COMPRESSION_ERROR
Definition: zipint.h:118
@ ZIP_COMPRESSION_END
Definition: zipint.h:117
@ ZIP_COMPRESSION_OK
Definition: zipint.h:116
#define ZIP_CM_ACTUAL(x)
Definition: zipint.h:83
zip_t * za
Definition: ziptool.c:79