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