/src/xz/src/liblzma/common/common.c
Line | Count | Source |
1 | | // SPDX-License-Identifier: 0BSD |
2 | | |
3 | | /////////////////////////////////////////////////////////////////////////////// |
4 | | // |
5 | | /// \file common.c |
6 | | /// \brief Common functions needed in many places in liblzma |
7 | | // |
8 | | // Author: Lasse Collin |
9 | | // |
10 | | /////////////////////////////////////////////////////////////////////////////// |
11 | | |
12 | | #include "common.h" |
13 | | |
14 | | |
15 | | ///////////// |
16 | | // Version // |
17 | | ///////////// |
18 | | |
19 | | extern LZMA_API(uint32_t) |
20 | | lzma_version_number(void) |
21 | 0 | { |
22 | 0 | return LZMA_VERSION; |
23 | 0 | } |
24 | | |
25 | | |
26 | | extern LZMA_API(const char *) |
27 | | lzma_version_string(void) |
28 | 0 | { |
29 | 0 | return LZMA_VERSION_STRING; |
30 | 0 | } |
31 | | |
32 | | |
33 | | /////////////////////// |
34 | | // Memory allocation // |
35 | | /////////////////////// |
36 | | |
37 | | lzma_attr_alloc_size(1) |
38 | | extern void * |
39 | | lzma_alloc(size_t size, const lzma_allocator *allocator) |
40 | 165 | { |
41 | | // Some malloc() variants return NULL if called with size == 0. |
42 | 165 | if (size == 0) |
43 | 0 | size = 1; |
44 | | |
45 | 165 | void *ptr; |
46 | | |
47 | 165 | if (allocator != NULL && allocator->alloc != NULL) |
48 | 0 | ptr = allocator->alloc(allocator->opaque, 1, size); |
49 | 165 | else |
50 | 165 | ptr = malloc(size); |
51 | | |
52 | 165 | return ptr; |
53 | 165 | } |
54 | | |
55 | | |
56 | | lzma_attr_alloc_size(1) |
57 | | extern void * |
58 | | lzma_alloc_zero(size_t size, const lzma_allocator *allocator) |
59 | 0 | { |
60 | | // Some calloc() variants return NULL if called with size == 0. |
61 | 0 | if (size == 0) |
62 | 0 | size = 1; |
63 | |
|
64 | 0 | void *ptr; |
65 | |
|
66 | 0 | if (allocator != NULL && allocator->alloc != NULL) { |
67 | 0 | ptr = allocator->alloc(allocator->opaque, 1, size); |
68 | 0 | if (ptr != NULL) |
69 | 0 | memzero(ptr, size); |
70 | 0 | } else { |
71 | 0 | ptr = calloc(1, size); |
72 | 0 | } |
73 | |
|
74 | 0 | return ptr; |
75 | 0 | } |
76 | | |
77 | | |
78 | | extern void |
79 | | lzma_free(void *ptr, const lzma_allocator *allocator) |
80 | 192 | { |
81 | 192 | if (allocator != NULL && allocator->free != NULL) |
82 | 0 | allocator->free(allocator->opaque, ptr); |
83 | 192 | else |
84 | 192 | free(ptr); |
85 | | |
86 | 192 | return; |
87 | 192 | } |
88 | | |
89 | | |
90 | | ////////// |
91 | | // Misc // |
92 | | ////////// |
93 | | |
94 | | extern size_t |
95 | | lzma_bufcpy(const uint8_t *restrict in, size_t *restrict in_pos, |
96 | | size_t in_size, uint8_t *restrict out, |
97 | | size_t *restrict out_pos, size_t out_size) |
98 | 92 | { |
99 | 92 | assert(in != NULL || *in_pos == in_size); |
100 | 92 | assert(out != NULL || *out_pos == out_size); |
101 | | |
102 | 92 | assert(*in_pos <= in_size); |
103 | 92 | assert(*out_pos <= out_size); |
104 | | |
105 | 92 | const size_t in_avail = in_size - *in_pos; |
106 | 92 | const size_t out_avail = out_size - *out_pos; |
107 | 92 | const size_t copy_size = my_min(in_avail, out_avail); |
108 | | |
109 | | // Call memcpy() only if there is something to copy. If there is |
110 | | // nothing to copy, in or out might be NULL and then the memcpy() |
111 | | // call would trigger undefined behavior. |
112 | 92 | if (copy_size > 0) |
113 | 86 | memcpy(out + *out_pos, in + *in_pos, copy_size); |
114 | | |
115 | 92 | *in_pos += copy_size; |
116 | 92 | *out_pos += copy_size; |
117 | | |
118 | 92 | return copy_size; |
119 | 92 | } |
120 | | |
121 | | |
122 | | extern lzma_ret |
123 | | lzma_next_filter_init(lzma_next_coder *next, const lzma_allocator *allocator, |
124 | | const lzma_filter_info *filters) |
125 | 0 | { |
126 | 0 | lzma_next_coder_init(filters[0].init, next, allocator); |
127 | 0 | next->id = filters[0].id; |
128 | 0 | return filters[0].init == NULL |
129 | 0 | ? LZMA_OK : filters[0].init(next, allocator, filters); |
130 | 0 | } |
131 | | |
132 | | |
133 | | extern lzma_ret |
134 | | lzma_next_filter_update(lzma_next_coder *next, const lzma_allocator *allocator, |
135 | | const lzma_filter *reversed_filters) |
136 | 0 | { |
137 | | // Check that the application isn't trying to change the Filter ID. |
138 | | // End of filters is indicated with LZMA_VLI_UNKNOWN in both |
139 | | // reversed_filters[0].id and next->id. |
140 | 0 | if (reversed_filters[0].id != next->id) |
141 | 0 | return LZMA_PROG_ERROR; |
142 | | |
143 | 0 | if (reversed_filters[0].id == LZMA_VLI_UNKNOWN) |
144 | 0 | return LZMA_OK; |
145 | | |
146 | 0 | assert(next->update != NULL); |
147 | 0 | return next->update(next->coder, allocator, NULL, reversed_filters); |
148 | 0 | } |
149 | | |
150 | | |
151 | | extern void |
152 | | lzma_next_end(lzma_next_coder *next, const lzma_allocator *allocator) |
153 | 156 | { |
154 | 156 | if (next->init != (uintptr_t)(NULL)) { |
155 | | // To avoid tiny end functions that simply call |
156 | | // lzma_free(coder, allocator), we allow leaving next->end |
157 | | // NULL and call lzma_free() here. |
158 | 52 | if (next->end != NULL) |
159 | 52 | next->end(next->coder, allocator); |
160 | 0 | else |
161 | 0 | lzma_free(next->coder, allocator); |
162 | | |
163 | | // Reset the variables so the we don't accidentally think |
164 | | // that it is an already initialized coder. |
165 | 52 | *next = LZMA_NEXT_CODER_INIT; |
166 | 52 | } |
167 | | |
168 | 156 | return; |
169 | 156 | } |
170 | | |
171 | | |
172 | | ////////////////////////////////////// |
173 | | // External to internal API wrapper // |
174 | | ////////////////////////////////////// |
175 | | |
176 | | extern lzma_ret |
177 | | lzma_strm_init(lzma_stream *strm) |
178 | 52 | { |
179 | 52 | if (strm == NULL) |
180 | 0 | return LZMA_PROG_ERROR; |
181 | | |
182 | 52 | if (strm->internal == NULL) { |
183 | 52 | strm->internal = lzma_alloc(sizeof(lzma_internal), |
184 | 52 | strm->allocator); |
185 | 52 | if (strm->internal == NULL) |
186 | 0 | return LZMA_MEM_ERROR; |
187 | | |
188 | 52 | strm->internal->next = LZMA_NEXT_CODER_INIT; |
189 | 52 | } |
190 | | |
191 | 52 | memzero(strm->internal->supported_actions, |
192 | 52 | sizeof(strm->internal->supported_actions)); |
193 | 52 | strm->internal->sequence = ISEQ_RUN; |
194 | 52 | strm->internal->allow_buf_error = false; |
195 | | |
196 | 52 | strm->total_in = 0; |
197 | 52 | strm->total_out = 0; |
198 | | |
199 | 52 | return LZMA_OK; |
200 | 52 | } |
201 | | |
202 | | |
203 | | extern LZMA_API(lzma_ret) |
204 | | lzma_code(lzma_stream *strm, lzma_action action) |
205 | 62 | { |
206 | | // Sanity checks |
207 | 62 | if ((strm->next_in == NULL && strm->avail_in != 0) |
208 | 62 | || (strm->next_out == NULL && strm->avail_out != 0) |
209 | 62 | || strm->internal == NULL |
210 | 62 | || strm->internal->next.code == NULL |
211 | 62 | || (unsigned int)(action) > LZMA_ACTION_MAX |
212 | 62 | || !strm->internal->supported_actions[action]) |
213 | 0 | return LZMA_PROG_ERROR; |
214 | | |
215 | | // Check if unsupported members have been set to non-zero or non-NULL, |
216 | | // which would indicate that some new feature is wanted. |
217 | 62 | if (strm->reserved_ptr1 != NULL |
218 | 62 | || strm->reserved_ptr2 != NULL |
219 | 62 | || strm->reserved_ptr3 != NULL |
220 | 62 | || strm->reserved_ptr4 != NULL |
221 | 62 | || strm->reserved_int2 != 0 |
222 | 62 | || strm->reserved_int3 != 0 |
223 | 62 | || strm->reserved_int4 != 0 |
224 | 62 | || strm->reserved_enum1 != LZMA_RESERVED_ENUM |
225 | 62 | || strm->reserved_enum2 != LZMA_RESERVED_ENUM) |
226 | 0 | return LZMA_OPTIONS_ERROR; |
227 | | |
228 | 62 | switch (strm->internal->sequence) { |
229 | 62 | case ISEQ_RUN: |
230 | 62 | switch (action) { |
231 | 62 | case LZMA_RUN: |
232 | 62 | break; |
233 | | |
234 | 0 | case LZMA_SYNC_FLUSH: |
235 | 0 | strm->internal->sequence = ISEQ_SYNC_FLUSH; |
236 | 0 | break; |
237 | | |
238 | 0 | case LZMA_FULL_FLUSH: |
239 | 0 | strm->internal->sequence = ISEQ_FULL_FLUSH; |
240 | 0 | break; |
241 | | |
242 | 0 | case LZMA_FINISH: |
243 | 0 | strm->internal->sequence = ISEQ_FINISH; |
244 | 0 | break; |
245 | | |
246 | 0 | case LZMA_FULL_BARRIER: |
247 | 0 | strm->internal->sequence = ISEQ_FULL_BARRIER; |
248 | 0 | break; |
249 | 62 | } |
250 | | |
251 | 62 | break; |
252 | | |
253 | 62 | case ISEQ_SYNC_FLUSH: |
254 | | // The same action must be used until we return |
255 | | // LZMA_STREAM_END, and the amount of input must not change. |
256 | 0 | if (action != LZMA_SYNC_FLUSH |
257 | 0 | || strm->internal->avail_in != strm->avail_in) |
258 | 0 | return LZMA_PROG_ERROR; |
259 | | |
260 | 0 | break; |
261 | | |
262 | 0 | case ISEQ_FULL_FLUSH: |
263 | 0 | if (action != LZMA_FULL_FLUSH |
264 | 0 | || strm->internal->avail_in != strm->avail_in) |
265 | 0 | return LZMA_PROG_ERROR; |
266 | | |
267 | 0 | break; |
268 | | |
269 | 0 | case ISEQ_FINISH: |
270 | 0 | if (action != LZMA_FINISH |
271 | 0 | || strm->internal->avail_in != strm->avail_in) |
272 | 0 | return LZMA_PROG_ERROR; |
273 | | |
274 | 0 | break; |
275 | | |
276 | 0 | case ISEQ_FULL_BARRIER: |
277 | 0 | if (action != LZMA_FULL_BARRIER |
278 | 0 | || strm->internal->avail_in != strm->avail_in) |
279 | 0 | return LZMA_PROG_ERROR; |
280 | | |
281 | 0 | break; |
282 | | |
283 | 0 | case ISEQ_END: |
284 | 0 | return LZMA_STREAM_END; |
285 | | |
286 | 0 | case ISEQ_ERROR: |
287 | 0 | default: |
288 | 0 | return LZMA_PROG_ERROR; |
289 | 62 | } |
290 | | |
291 | 62 | size_t in_pos = 0; |
292 | 62 | size_t out_pos = 0; |
293 | 62 | lzma_ret ret = strm->internal->next.code( |
294 | 62 | strm->internal->next.coder, strm->allocator, |
295 | 62 | strm->next_in, &in_pos, strm->avail_in, |
296 | 62 | strm->next_out, &out_pos, strm->avail_out, action); |
297 | | |
298 | | // Updating next_in and next_out has to be skipped when they are NULL |
299 | | // to avoid null pointer + 0 (undefined behavior). Do this by checking |
300 | | // in_pos > 0 and out_pos > 0 because this way NULL + non-zero (a bug) |
301 | | // will get caught one way or other. |
302 | 62 | if (in_pos > 0) { |
303 | 52 | strm->next_in += in_pos; |
304 | 52 | strm->avail_in -= in_pos; |
305 | 52 | strm->total_in += in_pos; |
306 | 52 | } |
307 | | |
308 | 62 | if (out_pos > 0) { |
309 | 0 | strm->next_out += out_pos; |
310 | 0 | strm->avail_out -= out_pos; |
311 | 0 | strm->total_out += out_pos; |
312 | 0 | } |
313 | | |
314 | 62 | strm->internal->avail_in = strm->avail_in; |
315 | | |
316 | 62 | switch (ret) { |
317 | 15 | case LZMA_OK: |
318 | | // Don't return LZMA_BUF_ERROR when it happens the first time. |
319 | | // This is to avoid returning LZMA_BUF_ERROR when avail_out |
320 | | // was zero but still there was no more data left to written |
321 | | // to next_out. |
322 | 15 | if (out_pos == 0 && in_pos == 0) { |
323 | 10 | if (strm->internal->allow_buf_error) |
324 | 5 | ret = LZMA_BUF_ERROR; |
325 | 5 | else |
326 | 5 | strm->internal->allow_buf_error = true; |
327 | 10 | } else { |
328 | 5 | strm->internal->allow_buf_error = false; |
329 | 5 | } |
330 | 15 | break; |
331 | | |
332 | 0 | case LZMA_TIMED_OUT: |
333 | 0 | strm->internal->allow_buf_error = false; |
334 | 0 | ret = LZMA_OK; |
335 | 0 | break; |
336 | | |
337 | 0 | case LZMA_SEEK_NEEDED: |
338 | 0 | strm->internal->allow_buf_error = false; |
339 | | |
340 | | // If LZMA_FINISH was used, reset it back to the |
341 | | // LZMA_RUN-based state so that new input can be supplied |
342 | | // by the application. |
343 | 0 | if (strm->internal->sequence == ISEQ_FINISH) |
344 | 0 | strm->internal->sequence = ISEQ_RUN; |
345 | |
|
346 | 0 | break; |
347 | | |
348 | 0 | case LZMA_STREAM_END: |
349 | 0 | if (strm->internal->sequence == ISEQ_SYNC_FLUSH |
350 | 0 | || strm->internal->sequence == ISEQ_FULL_FLUSH |
351 | 0 | || strm->internal->sequence |
352 | 0 | == ISEQ_FULL_BARRIER) |
353 | 0 | strm->internal->sequence = ISEQ_RUN; |
354 | 0 | else |
355 | 0 | strm->internal->sequence = ISEQ_END; |
356 | |
|
357 | 0 | FALLTHROUGH; |
358 | |
|
359 | 0 | case LZMA_NO_CHECK: |
360 | 0 | case LZMA_UNSUPPORTED_CHECK: |
361 | 0 | case LZMA_GET_CHECK: |
362 | 0 | case LZMA_MEMLIMIT_ERROR: |
363 | | // Something else than LZMA_OK, but not a fatal error, |
364 | | // that is, coding may be continued (except if ISEQ_END). |
365 | 0 | strm->internal->allow_buf_error = false; |
366 | 0 | break; |
367 | | |
368 | 47 | default: |
369 | | // All the other errors are fatal; coding cannot be continued. |
370 | 47 | assert(ret != LZMA_BUF_ERROR); |
371 | 47 | strm->internal->sequence = ISEQ_ERROR; |
372 | 47 | break; |
373 | 62 | } |
374 | | |
375 | 62 | return ret; |
376 | 62 | } |
377 | | |
378 | | |
379 | | extern LZMA_API(void) |
380 | | lzma_end(lzma_stream *strm) |
381 | 55 | { |
382 | 55 | if (strm != NULL && strm->internal != NULL) { |
383 | 52 | lzma_next_end(&strm->internal->next, strm->allocator); |
384 | 52 | lzma_free(strm->internal, strm->allocator); |
385 | 52 | strm->internal = NULL; |
386 | 52 | } |
387 | | |
388 | 55 | return; |
389 | 55 | } |
390 | | |
391 | | |
392 | | #ifdef HAVE_SYMBOL_VERSIONS_LINUX |
393 | | // This is for compatibility with binaries linked against liblzma that |
394 | | // has been patched with xz-5.2.2-compat-libs.patch from RHEL/CentOS 7. |
395 | | LZMA_SYMVER_API("lzma_get_progress@XZ_5.2.2", |
396 | | void, lzma_get_progress_522)(lzma_stream *strm, |
397 | | uint64_t *progress_in, uint64_t *progress_out) lzma_nothrow |
398 | | __attribute__((__alias__("lzma_get_progress_52"))); |
399 | | |
400 | | LZMA_SYMVER_API("lzma_get_progress@@XZ_5.2", |
401 | | void, lzma_get_progress_52)(lzma_stream *strm, |
402 | | uint64_t *progress_in, uint64_t *progress_out) lzma_nothrow; |
403 | | |
404 | | #define lzma_get_progress lzma_get_progress_52 |
405 | | #endif |
406 | | extern LZMA_API(void) |
407 | | lzma_get_progress(lzma_stream *strm, |
408 | | uint64_t *progress_in, uint64_t *progress_out) |
409 | 0 | { |
410 | 0 | if (strm->internal->next.get_progress != NULL) { |
411 | 0 | strm->internal->next.get_progress(strm->internal->next.coder, |
412 | 0 | progress_in, progress_out); |
413 | 0 | } else { |
414 | 0 | *progress_in = strm->total_in; |
415 | 0 | *progress_out = strm->total_out; |
416 | 0 | } |
417 | |
|
418 | 0 | return; |
419 | 0 | } |
420 | | |
421 | | |
422 | | extern LZMA_API(lzma_check) |
423 | | lzma_get_check(const lzma_stream *strm) |
424 | 0 | { |
425 | | // Return LZMA_CHECK_NONE if we cannot know the check type. |
426 | | // It's a bug in the application if this happens. |
427 | 0 | if (strm->internal->next.get_check == NULL) |
428 | 0 | return LZMA_CHECK_NONE; |
429 | | |
430 | 0 | return strm->internal->next.get_check(strm->internal->next.coder); |
431 | 0 | } |
432 | | |
433 | | |
434 | | extern LZMA_API(uint64_t) |
435 | | lzma_memusage(const lzma_stream *strm) |
436 | 0 | { |
437 | 0 | uint64_t memusage; |
438 | 0 | uint64_t old_memlimit; |
439 | |
|
440 | 0 | if (strm == NULL || strm->internal == NULL |
441 | 0 | || strm->internal->next.memconfig == NULL |
442 | 0 | || strm->internal->next.memconfig( |
443 | 0 | strm->internal->next.coder, |
444 | 0 | &memusage, &old_memlimit, 0) != LZMA_OK) |
445 | 0 | return 0; |
446 | | |
447 | 0 | return memusage; |
448 | 0 | } |
449 | | |
450 | | |
451 | | extern LZMA_API(uint64_t) |
452 | | lzma_memlimit_get(const lzma_stream *strm) |
453 | 0 | { |
454 | 0 | uint64_t old_memlimit; |
455 | 0 | uint64_t memusage; |
456 | |
|
457 | 0 | if (strm == NULL || strm->internal == NULL |
458 | 0 | || strm->internal->next.memconfig == NULL |
459 | 0 | || strm->internal->next.memconfig( |
460 | 0 | strm->internal->next.coder, |
461 | 0 | &memusage, &old_memlimit, 0) != LZMA_OK) |
462 | 0 | return 0; |
463 | | |
464 | 0 | return old_memlimit; |
465 | 0 | } |
466 | | |
467 | | |
468 | | extern LZMA_API(lzma_ret) |
469 | | lzma_memlimit_set(lzma_stream *strm, uint64_t new_memlimit) |
470 | 0 | { |
471 | | // Dummy variables to simplify memconfig functions |
472 | 0 | uint64_t old_memlimit; |
473 | 0 | uint64_t memusage; |
474 | |
|
475 | 0 | if (strm == NULL || strm->internal == NULL |
476 | 0 | || strm->internal->next.memconfig == NULL) |
477 | 0 | return LZMA_PROG_ERROR; |
478 | | |
479 | | // Zero is a special value that cannot be used as an actual limit. |
480 | | // If 0 was specified, use 1 instead. |
481 | 0 | if (new_memlimit == 0) |
482 | 0 | new_memlimit = 1; |
483 | |
|
484 | 0 | return strm->internal->next.memconfig(strm->internal->next.coder, |
485 | 0 | &memusage, &old_memlimit, new_memlimit); |
486 | 0 | } |