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