Rizin
unix-like reverse engineering framework and cli tools
zip_algorithm_zstd.c
Go to the documentation of this file.
1 /*
2  zip_algorithm_zstd.c -- zstd (de)compression routines
3  Copyright (C) 2020-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 "zipint.h"
35 
36 #include <limits.h>
37 #include <stdlib.h>
38 #include <zstd.h>
39 #include <zstd_errors.h>
40 
41 struct ctx {
43  bool compress;
45  bool end_of_input;
46  ZSTD_DStream *zdstream;
47  ZSTD_CStream *zcstream;
48  ZSTD_outBuffer out;
49  ZSTD_inBuffer in;
50 };
51 
52 static zip_uint64_t
54  return ZSTD_compressBound(uncompressed_size);
55 }
56 
57 
58 static void *
59 allocate(bool compress, int compression_flags, zip_error_t *error) {
60  struct ctx *ctx;
61 
62  /* 0: let zstd choose */
63  if (compression_flags < ZSTD_minCLevel() || compression_flags > ZSTD_maxCLevel()) {
65  }
66 
67  if ((ctx = (struct ctx *)malloc(sizeof(*ctx))) == NULL) {
68  return NULL;
69  }
70 
71  ctx->error = error;
74  ctx->end_of_input = false;
75 
76  ctx->zdstream = NULL;
77  ctx->zcstream = NULL;
78  ctx->in.src = NULL;
79  ctx->in.pos = 0;
80  ctx->in.size = 0;
81  ctx->out.dst = NULL;
82  ctx->out.pos = 0;
83  ctx->out.size = 0;
84 
85  return ctx;
86 }
87 
88 
89 static void *
91  return allocate(true, compression_flags, error);
92 }
93 
94 
95 static void *
97  return allocate(false, compression_flags, error);
98 }
99 
100 
101 static void
102 deallocate(void *ud) {
103  struct ctx *ctx = (struct ctx *)ud;
104  free(ctx);
105 }
106 
107 
108 static zip_uint16_t
110  /* struct ctx *ctx = (struct ctx *)ud; */
111  return 0;
112 }
113 
114 static int
115 map_error(size_t ret) {
116  switch (ret) {
117  case ZSTD_error_no_error:
118  return ZIP_ER_OK;
119 
120  case ZSTD_error_corruption_detected:
121  case ZSTD_error_checksum_wrong:
122  case ZSTD_error_dictionary_corrupted:
123  case ZSTD_error_dictionary_wrong:
124  return ZIP_ER_COMPRESSED_DATA;
125 
126  case ZSTD_error_memory_allocation:
127  return ZIP_ER_MEMORY;
128 
129  case ZSTD_error_parameter_unsupported:
130  case ZSTD_error_parameter_outOfBound:
131  return ZIP_ER_INVAL;
132 
133  default:
134  return ZIP_ER_INTERNAL;
135  }
136 }
137 
138 
139 static bool
140 start(void *ud, zip_stat_t *st, zip_file_attributes_t *attributes) {
141  struct ctx *ctx = (struct ctx *)ud;
142  ctx->in.src = NULL;
143  ctx->in.pos = 0;
144  ctx->in.size = 0;
145  ctx->out.dst = NULL;
146  ctx->out.pos = 0;
147  ctx->out.size = 0;
148  if (ctx->compress) {
149  size_t ret;
150  ctx->zcstream = ZSTD_createCStream();
151  if (ctx->zcstream == NULL) {
153  return false;
154  }
155  ret = ZSTD_initCStream(ctx->zcstream, ctx->compression_flags);
156  if (ZSTD_isError(ret)) {
158  return false;
159  }
160  }
161  else {
162  ctx->zdstream = ZSTD_createDStream();
163  if (ctx->zdstream == NULL) {
165  return false;
166  }
167  }
168 
169  return true;
170 }
171 
172 
173 static bool
174 end(void *ud) {
175  struct ctx *ctx = (struct ctx *)ud;
176  size_t ret;
177 
178  if (ctx->compress) {
179  ret = ZSTD_freeCStream(ctx->zcstream);
180  ctx->zcstream = NULL;
181  }
182  else {
183  ret = ZSTD_freeDStream(ctx->zdstream);
184  ctx->zdstream = NULL;
185  }
186 
187  if (ZSTD_isError(ret)) {
188  zip_error_set(ctx->error, map_error(ret), 0);
189  return false;
190  }
191 
192  return true;
193 }
194 
195 
196 static bool
198  struct ctx *ctx = (struct ctx *)ud;
199  if (length > SIZE_MAX || ctx->in.pos != ctx->in.size) {
201  return false;
202  }
203  ctx->in.src = (const void *)data;
204  ctx->in.size = (size_t)length;
205  ctx->in.pos = 0;
206  return true;
207 }
208 
209 
210 static void
211 end_of_input(void *ud) {
212  struct ctx *ctx = (struct ctx *)ud;
213 
214  ctx->end_of_input = true;
215 }
216 
217 
220  struct ctx *ctx = (struct ctx *)ud;
221 
222  size_t ret;
223 
224  if (ctx->in.pos == ctx->in.size && !ctx->end_of_input) {
225  *length = 0;
227  }
228 
229  ctx->out.dst = data;
230  ctx->out.pos = 0;
231  ctx->out.size = ZIP_MIN(SIZE_MAX, *length);
232 
233  if (ctx->compress) {
234  if (ctx->in.pos == ctx->in.size && ctx->end_of_input) {
235  ret = ZSTD_endStream(ctx->zcstream, &ctx->out);
236  if (ret == 0) {
237  *length = ctx->out.pos;
238  return ZIP_COMPRESSION_END;
239  }
240  }
241  else {
242  ret = ZSTD_compressStream(ctx->zcstream, &ctx->out, &ctx->in);
243  }
244  }
245  else {
246  ret = ZSTD_decompressStream(ctx->zdstream, &ctx->out, &ctx->in);
247  }
248  if (ZSTD_isError(ret)) {
249  zip_error_set(ctx->error, map_error(ret), 0);
250  return ZIP_COMPRESSION_ERROR;
251  }
252 
253  *length = ctx->out.pos;
254  if (ctx->in.pos == ctx->in.size) {
256  }
257 
258  return ZIP_COMPRESSION_OK;
259 }
260 
261 /* Version Required should be set to 63 (6.3) because this compression
262  method was only defined in appnote.txt version 6.3.7, but Winzip
263  does not unpack it if the value is not 20. */
264 
265 /* clang-format off */
266 
270  deallocate,
272  20,
273  start,
274  end,
275  input,
276  end_of_input,
277  process
278 };
279 
280 
284  deallocate,
286  20,
287  start,
288  end,
289  input,
290  end_of_input,
291  process
292 };
293 
294 /* clang-format on */
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 static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void static offset struct stat static buf void long static basep static whence static length const void static len static semflg const void static shmflg const struct timespec struct timespec static rem const char static group const void length
Definition: sflib.h:133
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
#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_ER_COMPRESSED_DATA
Definition: zip.h:136
#define ZIP_ER_ZLIB
Definition: zip.h:118
#define ZIP_ER_MEMORY
Definition: zip.h:119
#define ZIP_ER_OK
Definition: zip.h:105
#define ZIP_ER_INVAL
Definition: zip.h:123
void * malloc(size_t size)
Definition: malloc.c:123
int size_t
Definition: sftypes.h:40
#define SIZE_MAX
ZSTD_CStream * zcstream
zip_uint16_t method
ZSTD_outBuffer out
bool end_of_input
ZSTD_DStream * zdstream
int compression_flags
bool compress
zip_error_t * error
ZSTD_inBuffer in
Definition: zip.h:284
Definition: zip.h:300
uint64_t uncompressed_size
Definition: list.c:106
void error(const char *msg)
Definition: untgz.c:593
static zip_uint64_t maximum_compressed_size(zip_uint64_t uncompressed_size)
static void deallocate(void *ud)
static int map_error(size_t ret)
zip_compression_algorithm_t zip_algorithm_zstd_compress
static void * decompress_allocate(zip_uint16_t method, int compression_flags, zip_error_t *error)
static void * allocate(bool compress, int compression_flags, zip_error_t *error)
zip_compression_algorithm_t zip_algorithm_zstd_decompress
static void * compress_allocate(zip_uint16_t method, int compression_flags, zip_error_t *error)
static bool start(void *ud, zip_stat_t *st, zip_file_attributes_t *attributes)
static bool end(void *ud)
static zip_uint16_t general_purpose_bit_flags(void *ud)
static void end_of_input(void *ud)
static bool input(void *ud, zip_uint8_t *data, zip_uint64_t length)
static zip_compression_status_t process(void *ud, zip_uint8_t *data, zip_uint64_t *length)
uint64_t zip_uint64_t
Definition: zipconf.h:39
uint8_t zip_uint8_t
Definition: zipconf.h:33
uint16_t zip_uint16_t
Definition: zipconf.h:35
enum zip_compression_status zip_compression_status_t
Definition: zipint.h:122
#define ZIP_MIN(a, b)
Definition: zipint.h:473
@ 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