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