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 strm
->next_in
+= in_pos
;
292 strm
->avail_in
-= in_pos
;
293 strm
->total_in
+= in_pos
;
295 strm
->next_out
+= out_pos
;
296 strm
->avail_out
-= out_pos
;
297 strm
->total_out
+= out_pos
;
299 strm
->internal
->avail_in
= strm
->avail_in
;
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
307 if (out_pos
== 0 && in_pos
== 0) {
308 if (strm
->internal
->allow_buf_error
)
309 ret
= LZMA_BUF_ERROR
;
311 strm
->internal
->allow_buf_error
= true;
313 strm
->internal
->allow_buf_error
= false;
318 strm
->internal
->allow_buf_error
= false;
322 case LZMA_SEEK_NEEDED
:
323 strm
->internal
->allow_buf_error
= false;
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
;
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
;
340 strm
->internal
->sequence
= ISEQ_END
;
345 case LZMA_UNSUPPORTED_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;
354 // All the other errors are fatal; coding cannot be continued.
355 assert(ret
!= LZMA_BUF_ERROR
);
356 strm
->internal
->sequence
= ISEQ_ERROR
;
364 extern LZMA_API(void)
365 lzma_end(lzma_stream
*strm
)
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
;
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")));
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
;
389 #define lzma_get_progress lzma_get_progress_52
391 extern LZMA_API(void)
392 lzma_get_progress(lzma_stream
*strm
,
393 uint64_t *progress_in
, uint64_t *progress_out
)
395 if (strm
->internal
->next
.get_progress
!= NULL
) {
396 strm
->internal
->next
.get_progress(strm
->internal
->next
.coder
,
397 progress_in
, progress_out
);
399 *progress_in
= strm
->total_in
;
400 *progress_out
= strm
->total_out
;
407 extern LZMA_API(lzma_check
)
408 lzma_get_check(const lzma_stream
*strm
)
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
;
415 return strm
->internal
->next
.get_check(strm
->internal
->next
.coder
);
419 extern LZMA_API(uint64_t)
420 lzma_memusage(const lzma_stream
*strm
)
423 uint64_t old_memlimit
;
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
)
436 extern LZMA_API(uint64_t)
437 lzma_memlimit_get(const lzma_stream
*strm
)
439 uint64_t old_memlimit
;
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
)
453 extern LZMA_API(lzma_ret
)
454 lzma_memlimit_set(lzma_stream
*strm
, uint64_t new_memlimit
)
456 // Dummy variables to simplify memconfig functions
457 uint64_t old_memlimit
;
460 if (strm
== NULL
|| strm
->internal
== NULL
461 || strm
->internal
->next
.memconfig
== NULL
)
462 return LZMA_PROG_ERROR
;
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)
469 return strm
->internal
->next
.memconfig(strm
->internal
->next
.coder
,
470 &memusage
, &old_memlimit
, new_memlimit
);