1 // SPDX-License-Identifier: 0BSD
3 ///////////////////////////////////////////////////////////////////////////////
6 /// \brief Common functions needed in many places in liblzma
8 // Author: Lasse Collin
10 ///////////////////////////////////////////////////////////////////////////////
19 extern LZMA_API(uint32_t)
20 lzma_version_number(void)
26 extern LZMA_API(const char *)
27 lzma_version_string(void)
29 return LZMA_VERSION_STRING
;
33 ///////////////////////
34 // Memory allocation //
35 ///////////////////////
37 lzma_attr_alloc_size(1)
39 lzma_alloc(size_t size
, const lzma_allocator
*allocator
)
41 // Some malloc() variants return NULL if called with size == 0.
47 if (allocator
!= NULL
&& allocator
->alloc
!= NULL
)
48 ptr
= allocator
->alloc(allocator
->opaque
, 1, size
);
56 lzma_attr_alloc_size(1)
58 lzma_alloc_zero(size_t size
, const lzma_allocator
*allocator
)
60 // Some calloc() variants return NULL if called with size == 0.
66 if (allocator
!= NULL
&& allocator
->alloc
!= NULL
) {
67 ptr
= allocator
->alloc(allocator
->opaque
, 1, size
);
71 ptr
= calloc(1, size
);
79 lzma_free(void *ptr
, const lzma_allocator
*allocator
)
81 if (allocator
!= NULL
&& allocator
->free
!= NULL
)
82 allocator
->free(allocator
->opaque
, ptr
);
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
)
99 const size_t in_avail
= in_size
- *in_pos
;
100 const size_t out_avail
= out_size
- *out_pos
;
101 const size_t copy_size
= my_min(in_avail
, out_avail
);
103 // Call memcpy() only if there is something to copy. If there is
104 // nothing to copy, in or out might be NULL and then the memcpy()
105 // call would trigger undefined behavior.
107 memcpy(out
+ *out_pos
, in
+ *in_pos
, copy_size
);
109 *in_pos
+= copy_size
;
110 *out_pos
+= copy_size
;
117 lzma_next_filter_init(lzma_next_coder
*next
, const lzma_allocator
*allocator
,
118 const lzma_filter_info
*filters
)
120 lzma_next_coder_init(filters
[0].init
, next
, allocator
);
121 next
->id
= filters
[0].id
;
122 return filters
[0].init
== NULL
123 ? LZMA_OK
: filters
[0].init(next
, allocator
, filters
);
128 lzma_next_filter_update(lzma_next_coder
*next
, const lzma_allocator
*allocator
,
129 const lzma_filter
*reversed_filters
)
131 // Check that the application isn't trying to change the Filter ID.
132 // End of filters is indicated with LZMA_VLI_UNKNOWN in both
133 // reversed_filters[0].id and next->id.
134 if (reversed_filters
[0].id
!= next
->id
)
135 return LZMA_PROG_ERROR
;
137 if (reversed_filters
[0].id
== LZMA_VLI_UNKNOWN
)
140 assert(next
->update
!= NULL
);
141 return next
->update(next
->coder
, allocator
, NULL
, reversed_filters
);
146 lzma_next_end(lzma_next_coder
*next
, const lzma_allocator
*allocator
)
148 if (next
->init
!= (uintptr_t)(NULL
)) {
149 // To avoid tiny end functions that simply call
150 // lzma_free(coder, allocator), we allow leaving next->end
151 // NULL and call lzma_free() here.
152 if (next
->end
!= NULL
)
153 next
->end(next
->coder
, allocator
);
155 lzma_free(next
->coder
, allocator
);
157 // Reset the variables so the we don't accidentally think
158 // that it is an already initialized coder.
159 *next
= LZMA_NEXT_CODER_INIT
;
166 //////////////////////////////////////
167 // External to internal API wrapper //
168 //////////////////////////////////////
171 lzma_strm_init(lzma_stream
*strm
)
174 return LZMA_PROG_ERROR
;
176 if (strm
->internal
== NULL
) {
177 strm
->internal
= lzma_alloc(sizeof(lzma_internal
),
179 if (strm
->internal
== NULL
)
180 return LZMA_MEM_ERROR
;
182 strm
->internal
->next
= LZMA_NEXT_CODER_INIT
;
185 memzero(strm
->internal
->supported_actions
,
186 sizeof(strm
->internal
->supported_actions
));
187 strm
->internal
->sequence
= ISEQ_RUN
;
188 strm
->internal
->allow_buf_error
= false;
197 extern LZMA_API(lzma_ret
)
198 lzma_code(lzma_stream
*strm
, lzma_action action
)
201 if ((strm
->next_in
== NULL
&& strm
->avail_in
!= 0)
202 || (strm
->next_out
== NULL
&& strm
->avail_out
!= 0)
203 || strm
->internal
== NULL
204 || strm
->internal
->next
.code
== NULL
205 || (unsigned int)(action
) > LZMA_ACTION_MAX
206 || !strm
->internal
->supported_actions
[action
])
207 return LZMA_PROG_ERROR
;
209 // Check if unsupported members have been set to non-zero or non-NULL,
210 // which would indicate that some new feature is wanted.
211 if (strm
->reserved_ptr1
!= NULL
212 || strm
->reserved_ptr2
!= NULL
213 || strm
->reserved_ptr3
!= NULL
214 || strm
->reserved_ptr4
!= NULL
215 || strm
->reserved_int2
!= 0
216 || strm
->reserved_int3
!= 0
217 || strm
->reserved_int4
!= 0
218 || strm
->reserved_enum1
!= LZMA_RESERVED_ENUM
219 || strm
->reserved_enum2
!= LZMA_RESERVED_ENUM
)
220 return LZMA_OPTIONS_ERROR
;
222 switch (strm
->internal
->sequence
) {
228 case LZMA_SYNC_FLUSH
:
229 strm
->internal
->sequence
= ISEQ_SYNC_FLUSH
;
232 case LZMA_FULL_FLUSH
:
233 strm
->internal
->sequence
= ISEQ_FULL_FLUSH
;
237 strm
->internal
->sequence
= ISEQ_FINISH
;
240 case LZMA_FULL_BARRIER
:
241 strm
->internal
->sequence
= ISEQ_FULL_BARRIER
;
247 case ISEQ_SYNC_FLUSH
:
248 // The same action must be used until we return
249 // LZMA_STREAM_END, and the amount of input must not change.
250 if (action
!= LZMA_SYNC_FLUSH
251 || strm
->internal
->avail_in
!= strm
->avail_in
)
252 return LZMA_PROG_ERROR
;
256 case ISEQ_FULL_FLUSH
:
257 if (action
!= LZMA_FULL_FLUSH
258 || strm
->internal
->avail_in
!= strm
->avail_in
)
259 return LZMA_PROG_ERROR
;
264 if (action
!= LZMA_FINISH
265 || strm
->internal
->avail_in
!= strm
->avail_in
)
266 return LZMA_PROG_ERROR
;
270 case ISEQ_FULL_BARRIER
:
271 if (action
!= LZMA_FULL_BARRIER
272 || strm
->internal
->avail_in
!= strm
->avail_in
)
273 return LZMA_PROG_ERROR
;
278 return LZMA_STREAM_END
;
282 return LZMA_PROG_ERROR
;
287 lzma_ret ret
= strm
->internal
->next
.code(
288 strm
->internal
->next
.coder
, strm
->allocator
,
289 strm
->next_in
, &in_pos
, strm
->avail_in
,
290 strm
->next_out
, &out_pos
, strm
->avail_out
, action
);
292 // Updating next_in and next_out has to be skipped when they are NULL
293 // to avoid null pointer + 0 (undefined behavior). Do this by checking
294 // in_pos > 0 and out_pos > 0 because this way NULL + non-zero (a bug)
295 // will get caught one way or other.
297 strm
->next_in
+= in_pos
;
298 strm
->avail_in
-= in_pos
;
299 strm
->total_in
+= in_pos
;
303 strm
->next_out
+= out_pos
;
304 strm
->avail_out
-= out_pos
;
305 strm
->total_out
+= out_pos
;
308 strm
->internal
->avail_in
= strm
->avail_in
;
312 // Don't return LZMA_BUF_ERROR when it happens the first time.
313 // This is to avoid returning LZMA_BUF_ERROR when avail_out
314 // was zero but still there was no more data left to written
316 if (out_pos
== 0 && in_pos
== 0) {
317 if (strm
->internal
->allow_buf_error
)
318 ret
= LZMA_BUF_ERROR
;
320 strm
->internal
->allow_buf_error
= true;
322 strm
->internal
->allow_buf_error
= false;
327 strm
->internal
->allow_buf_error
= false;
331 case LZMA_SEEK_NEEDED
:
332 strm
->internal
->allow_buf_error
= false;
334 // If LZMA_FINISH was used, reset it back to the
335 // LZMA_RUN-based state so that new input can be supplied
336 // by the application.
337 if (strm
->internal
->sequence
== ISEQ_FINISH
)
338 strm
->internal
->sequence
= ISEQ_RUN
;
342 case LZMA_STREAM_END
:
343 if (strm
->internal
->sequence
== ISEQ_SYNC_FLUSH
344 || strm
->internal
->sequence
== ISEQ_FULL_FLUSH
345 || strm
->internal
->sequence
346 == ISEQ_FULL_BARRIER
)
347 strm
->internal
->sequence
= ISEQ_RUN
;
349 strm
->internal
->sequence
= ISEQ_END
;
354 case LZMA_UNSUPPORTED_CHECK
:
356 case LZMA_MEMLIMIT_ERROR
:
357 // Something else than LZMA_OK, but not a fatal error,
358 // that is, coding may be continued (except if ISEQ_END).
359 strm
->internal
->allow_buf_error
= false;
363 // All the other errors are fatal; coding cannot be continued.
364 assert(ret
!= LZMA_BUF_ERROR
);
365 strm
->internal
->sequence
= ISEQ_ERROR
;
373 extern LZMA_API(void)
374 lzma_end(lzma_stream
*strm
)
376 if (strm
!= NULL
&& strm
->internal
!= NULL
) {
377 lzma_next_end(&strm
->internal
->next
, strm
->allocator
);
378 lzma_free(strm
->internal
, strm
->allocator
);
379 strm
->internal
= NULL
;
386 #ifdef HAVE_SYMBOL_VERSIONS_LINUX
387 // This is for compatibility with binaries linked against liblzma that
388 // has been patched with xz-5.2.2-compat-libs.patch from RHEL/CentOS 7.
389 LZMA_SYMVER_API("lzma_get_progress@XZ_5.2.2",
390 void, lzma_get_progress_522
)(lzma_stream
*strm
,
391 uint64_t *progress_in
, uint64_t *progress_out
) lzma_nothrow
392 __attribute__((__alias__("lzma_get_progress_52")));
394 LZMA_SYMVER_API("lzma_get_progress@@XZ_5.2",
395 void, lzma_get_progress_52
)(lzma_stream
*strm
,
396 uint64_t *progress_in
, uint64_t *progress_out
) lzma_nothrow
;
398 #define lzma_get_progress lzma_get_progress_52
400 extern LZMA_API(void)
401 lzma_get_progress(lzma_stream
*strm
,
402 uint64_t *progress_in
, uint64_t *progress_out
)
404 if (strm
->internal
->next
.get_progress
!= NULL
) {
405 strm
->internal
->next
.get_progress(strm
->internal
->next
.coder
,
406 progress_in
, progress_out
);
408 *progress_in
= strm
->total_in
;
409 *progress_out
= strm
->total_out
;
416 extern LZMA_API(lzma_check
)
417 lzma_get_check(const lzma_stream
*strm
)
419 // Return LZMA_CHECK_NONE if we cannot know the check type.
420 // It's a bug in the application if this happens.
421 if (strm
->internal
->next
.get_check
== NULL
)
422 return LZMA_CHECK_NONE
;
424 return strm
->internal
->next
.get_check(strm
->internal
->next
.coder
);
428 extern LZMA_API(uint64_t)
429 lzma_memusage(const lzma_stream
*strm
)
432 uint64_t old_memlimit
;
434 if (strm
== NULL
|| strm
->internal
== NULL
435 || strm
->internal
->next
.memconfig
== NULL
436 || strm
->internal
->next
.memconfig(
437 strm
->internal
->next
.coder
,
438 &memusage
, &old_memlimit
, 0) != LZMA_OK
)
445 extern LZMA_API(uint64_t)
446 lzma_memlimit_get(const lzma_stream
*strm
)
448 uint64_t old_memlimit
;
451 if (strm
== NULL
|| strm
->internal
== NULL
452 || strm
->internal
->next
.memconfig
== NULL
453 || strm
->internal
->next
.memconfig(
454 strm
->internal
->next
.coder
,
455 &memusage
, &old_memlimit
, 0) != LZMA_OK
)
462 extern LZMA_API(lzma_ret
)
463 lzma_memlimit_set(lzma_stream
*strm
, uint64_t new_memlimit
)
465 // Dummy variables to simplify memconfig functions
466 uint64_t old_memlimit
;
469 if (strm
== NULL
|| strm
->internal
== NULL
470 || strm
->internal
->next
.memconfig
== NULL
)
471 return LZMA_PROG_ERROR
;
473 // Zero is a special value that cannot be used as an actual limit.
474 // If 0 was specified, use 1 instead.
475 if (new_memlimit
== 0)
478 return strm
->internal
->next
.memconfig(strm
->internal
->next
.coder
,
479 &memusage
, &old_memlimit
, new_memlimit
);