1 ///////////////////////////////////////////////////////////////////////////////
4 /// \brief Common functions needed in many places in liblzma
6 // Author: Lasse Collin
8 // This file has been put into the public domain.
9 // You can do whatever you want with this file.
11 ///////////////////////////////////////////////////////////////////////////////
20 extern LZMA_API(uint32_t)
21 lzma_version_number(void)
27 extern LZMA_API(const char *)
28 lzma_version_string(void)
30 return LZMA_VERSION_STRING
;
34 ///////////////////////
35 // Memory allocation //
36 ///////////////////////
38 extern void * lzma_attribute((__malloc__
)) 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 extern void * lzma_attribute((__malloc__
)) lzma_attr_alloc_size(1)
57 lzma_alloc_zero(size_t size
, const lzma_allocator
*allocator
)
59 // Some calloc() variants return NULL if called with size == 0.
65 if (allocator
!= NULL
&& allocator
->alloc
!= NULL
) {
66 ptr
= allocator
->alloc(allocator
->opaque
, 1, size
);
70 ptr
= calloc(1, size
);
78 lzma_free(void *ptr
, const lzma_allocator
*allocator
)
80 if (allocator
!= NULL
&& allocator
->free
!= NULL
)
81 allocator
->free(allocator
->opaque
, ptr
);
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
)
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
);
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.
106 memcpy(out
+ *out_pos
, in
+ *in_pos
, copy_size
);
108 *in_pos
+= copy_size
;
109 *out_pos
+= copy_size
;
116 lzma_next_filter_init(lzma_next_coder
*next
, const lzma_allocator
*allocator
,
117 const lzma_filter_info
*filters
)
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
);
127 lzma_next_filter_update(lzma_next_coder
*next
, const lzma_allocator
*allocator
,
128 const lzma_filter
*reversed_filters
)
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
;
136 if (reversed_filters
[0].id
== LZMA_VLI_UNKNOWN
)
139 assert(next
->update
!= NULL
);
140 return next
->update(next
->coder
, allocator
, NULL
, reversed_filters
);
145 lzma_next_end(lzma_next_coder
*next
, const lzma_allocator
*allocator
)
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
);
154 lzma_free(next
->coder
, allocator
);
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
;
165 //////////////////////////////////////
166 // External to internal API wrapper //
167 //////////////////////////////////////
170 lzma_strm_init(lzma_stream
*strm
)
173 return LZMA_PROG_ERROR
;
175 if (strm
->internal
== NULL
) {
176 strm
->internal
= lzma_alloc(sizeof(lzma_internal
),
178 if (strm
->internal
== NULL
)
179 return LZMA_MEM_ERROR
;
181 strm
->internal
->next
= LZMA_NEXT_CODER_INIT
;
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;
196 extern LZMA_API(lzma_ret
)
197 lzma_code(lzma_stream
*strm
, lzma_action action
)
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
;
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
;
221 switch (strm
->internal
->sequence
) {
227 case LZMA_SYNC_FLUSH
:
228 strm
->internal
->sequence
= ISEQ_SYNC_FLUSH
;
231 case LZMA_FULL_FLUSH
:
232 strm
->internal
->sequence
= ISEQ_FULL_FLUSH
;
236 strm
->internal
->sequence
= ISEQ_FINISH
;
239 case LZMA_FULL_BARRIER
:
240 strm
->internal
->sequence
= ISEQ_FULL_BARRIER
;
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
;
255 case ISEQ_FULL_FLUSH
:
256 if (action
!= LZMA_FULL_FLUSH
257 || strm
->internal
->avail_in
!= strm
->avail_in
)
258 return LZMA_PROG_ERROR
;
263 if (action
!= LZMA_FINISH
264 || strm
->internal
->avail_in
!= strm
->avail_in
)
265 return LZMA_PROG_ERROR
;
269 case ISEQ_FULL_BARRIER
:
270 if (action
!= LZMA_FULL_BARRIER
271 || strm
->internal
->avail_in
!= strm
->avail_in
)
272 return LZMA_PROG_ERROR
;
277 return LZMA_STREAM_END
;
281 return LZMA_PROG_ERROR
;
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
);
291 // Updating next_in and next_out has to be skipped when they are NULL
292 // to avoid null pointer + 0 (undefined behavior). Do this by checking
293 // in_pos > 0 and out_pos > 0 because this way NULL + non-zero (a bug)
294 // will get caught one way or other.
296 strm
->next_in
+= in_pos
;
297 strm
->avail_in
-= in_pos
;
298 strm
->total_in
+= in_pos
;
302 strm
->next_out
+= out_pos
;
303 strm
->avail_out
-= out_pos
;
304 strm
->total_out
+= out_pos
;
307 strm
->internal
->avail_in
= strm
->avail_in
;
311 // Don't return LZMA_BUF_ERROR when it happens the first time.
312 // This is to avoid returning LZMA_BUF_ERROR when avail_out
313 // was zero but still there was no more data left to written
315 if (out_pos
== 0 && in_pos
== 0) {
316 if (strm
->internal
->allow_buf_error
)
317 ret
= LZMA_BUF_ERROR
;
319 strm
->internal
->allow_buf_error
= true;
321 strm
->internal
->allow_buf_error
= false;
326 strm
->internal
->allow_buf_error
= false;
330 case LZMA_SEEK_NEEDED
:
331 strm
->internal
->allow_buf_error
= false;
333 // If LZMA_FINISH was used, reset it back to the
334 // LZMA_RUN-based state so that new input can be supplied
335 // by the application.
336 if (strm
->internal
->sequence
== ISEQ_FINISH
)
337 strm
->internal
->sequence
= ISEQ_RUN
;
341 case LZMA_STREAM_END
:
342 if (strm
->internal
->sequence
== ISEQ_SYNC_FLUSH
343 || strm
->internal
->sequence
== ISEQ_FULL_FLUSH
344 || strm
->internal
->sequence
345 == ISEQ_FULL_BARRIER
)
346 strm
->internal
->sequence
= ISEQ_RUN
;
348 strm
->internal
->sequence
= ISEQ_END
;
353 case LZMA_UNSUPPORTED_CHECK
:
355 case LZMA_MEMLIMIT_ERROR
:
356 // Something else than LZMA_OK, but not a fatal error,
357 // that is, coding may be continued (except if ISEQ_END).
358 strm
->internal
->allow_buf_error
= false;
362 // All the other errors are fatal; coding cannot be continued.
363 assert(ret
!= LZMA_BUF_ERROR
);
364 strm
->internal
->sequence
= ISEQ_ERROR
;
372 extern LZMA_API(void)
373 lzma_end(lzma_stream
*strm
)
375 if (strm
!= NULL
&& strm
->internal
!= NULL
) {
376 lzma_next_end(&strm
->internal
->next
, strm
->allocator
);
377 lzma_free(strm
->internal
, strm
->allocator
);
378 strm
->internal
= NULL
;
385 #ifdef HAVE_SYMBOL_VERSIONS_LINUX
386 // This is for compatibility with binaries linked against liblzma that
387 // has been patched with xz-5.2.2-compat-libs.patch from RHEL/CentOS 7.
388 LZMA_SYMVER_API("lzma_get_progress@XZ_5.2.2",
389 void, lzma_get_progress_522
)(lzma_stream
*strm
,
390 uint64_t *progress_in
, uint64_t *progress_out
) lzma_nothrow
391 __attribute__((__alias__("lzma_get_progress_52")));
393 LZMA_SYMVER_API("lzma_get_progress@@XZ_5.2",
394 void, lzma_get_progress_52
)(lzma_stream
*strm
,
395 uint64_t *progress_in
, uint64_t *progress_out
) lzma_nothrow
;
397 #define lzma_get_progress lzma_get_progress_52
399 extern LZMA_API(void)
400 lzma_get_progress(lzma_stream
*strm
,
401 uint64_t *progress_in
, uint64_t *progress_out
)
403 if (strm
->internal
->next
.get_progress
!= NULL
) {
404 strm
->internal
->next
.get_progress(strm
->internal
->next
.coder
,
405 progress_in
, progress_out
);
407 *progress_in
= strm
->total_in
;
408 *progress_out
= strm
->total_out
;
415 extern LZMA_API(lzma_check
)
416 lzma_get_check(const lzma_stream
*strm
)
418 // Return LZMA_CHECK_NONE if we cannot know the check type.
419 // It's a bug in the application if this happens.
420 if (strm
->internal
->next
.get_check
== NULL
)
421 return LZMA_CHECK_NONE
;
423 return strm
->internal
->next
.get_check(strm
->internal
->next
.coder
);
427 extern LZMA_API(uint64_t)
428 lzma_memusage(const lzma_stream
*strm
)
431 uint64_t old_memlimit
;
433 if (strm
== NULL
|| strm
->internal
== NULL
434 || strm
->internal
->next
.memconfig
== NULL
435 || strm
->internal
->next
.memconfig(
436 strm
->internal
->next
.coder
,
437 &memusage
, &old_memlimit
, 0) != LZMA_OK
)
444 extern LZMA_API(uint64_t)
445 lzma_memlimit_get(const lzma_stream
*strm
)
447 uint64_t old_memlimit
;
450 if (strm
== NULL
|| strm
->internal
== NULL
451 || strm
->internal
->next
.memconfig
== NULL
452 || strm
->internal
->next
.memconfig(
453 strm
->internal
->next
.coder
,
454 &memusage
, &old_memlimit
, 0) != LZMA_OK
)
461 extern LZMA_API(lzma_ret
)
462 lzma_memlimit_set(lzma_stream
*strm
, uint64_t new_memlimit
)
464 // Dummy variables to simplify memconfig functions
465 uint64_t old_memlimit
;
468 if (strm
== NULL
|| strm
->internal
== NULL
469 || strm
->internal
->next
.memconfig
== NULL
)
470 return LZMA_PROG_ERROR
;
472 // Zero is a special value that cannot be used as an actual limit.
473 // If 0 was specified, use 1 instead.
474 if (new_memlimit
== 0)
477 return strm
->internal
->next
.memconfig(strm
->internal
->next
.coder
,
478 &memusage
, &old_memlimit
, new_memlimit
);