1 ///////////////////////////////////////////////////////////////////////////////
3 /// \file auto_decoder.c
4 /// \brief Autodetect between .xz Stream and .lzma (LZMA_Alone) formats
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 ///////////////////////////////////////////////////////////////////////////////
13 #include "stream_decoder.h"
14 #include "alone_decoder.h"
18 /// Stream decoder or LZMA_Alone decoder
33 auto_decode(lzma_coder
*coder
, const lzma_allocator
*allocator
,
34 const uint8_t *restrict in
, size_t *restrict in_pos
,
35 size_t in_size
, uint8_t *restrict out
,
36 size_t *restrict out_pos
, size_t out_size
, lzma_action action
)
38 switch (coder
->sequence
) {
40 if (*in_pos
>= in_size
)
43 // Update the sequence now, because we want to continue from
44 // SEQ_CODE even if we return some LZMA_*_CHECK.
45 coder
->sequence
= SEQ_CODE
;
47 // Detect the file format. For now this is simple, since if
48 // it doesn't start with 0xFD (the first magic byte of the
49 // new format), it has to be LZMA_Alone, or something that
50 // we don't support at all.
51 if (in
[*in_pos
] == 0xFD) {
52 return_if_error(lzma_stream_decoder_init(
53 &coder
->next
, allocator
,
54 coder
->memlimit
, coder
->flags
));
56 return_if_error(lzma_alone_decoder_init(&coder
->next
,
57 allocator
, coder
->memlimit
, true));
59 // If the application wants to know about missing
60 // integrity check or about the check in general, we
61 // need to handle it here, because LZMA_Alone decoder
62 // doesn't accept any flags.
63 if (coder
->flags
& LZMA_TELL_NO_CHECK
)
66 if (coder
->flags
& LZMA_TELL_ANY_CHECK
)
67 return LZMA_GET_CHECK
;
73 const lzma_ret ret
= coder
->next
.code(
74 coder
->next
.coder
, allocator
,
76 out
, out_pos
, out_size
, action
);
77 if (ret
!= LZMA_STREAM_END
78 || (coder
->flags
& LZMA_CONCATENATED
) == 0)
81 coder
->sequence
= SEQ_FINISH
;
87 // When LZMA_DECODE_CONCATENATED was used and we were decoding
88 // LZMA_Alone file, we need to check check that there is no
89 // trailing garbage and wait for LZMA_FINISH.
90 if (*in_pos
< in_size
)
91 return LZMA_DATA_ERROR
;
93 return action
== LZMA_FINISH
? LZMA_STREAM_END
: LZMA_OK
;
97 return LZMA_PROG_ERROR
;
103 auto_decoder_end(lzma_coder
*coder
, const lzma_allocator
*allocator
)
105 lzma_next_end(&coder
->next
, allocator
);
106 lzma_free(coder
, allocator
);
112 auto_decoder_get_check(const lzma_coder
*coder
)
114 // It is LZMA_Alone if get_check is NULL.
115 return coder
->next
.get_check
== NULL
? LZMA_CHECK_NONE
116 : coder
->next
.get_check(coder
->next
.coder
);
121 auto_decoder_memconfig(lzma_coder
*coder
, uint64_t *memusage
,
122 uint64_t *old_memlimit
, uint64_t new_memlimit
)
126 if (coder
->next
.memconfig
!= NULL
) {
127 ret
= coder
->next
.memconfig(coder
->next
.coder
,
128 memusage
, old_memlimit
, new_memlimit
);
129 assert(*old_memlimit
== coder
->memlimit
);
131 // No coder is configured yet. Use the base value as
132 // the current memory usage.
133 *memusage
= LZMA_MEMUSAGE_BASE
;
134 *old_memlimit
= coder
->memlimit
;
138 if (ret
== LZMA_OK
&& new_memlimit
!= 0)
139 coder
->memlimit
= new_memlimit
;
146 auto_decoder_init(lzma_next_coder
*next
, const lzma_allocator
*allocator
,
147 uint64_t memlimit
, uint32_t flags
)
149 lzma_next_coder_init(&auto_decoder_init
, next
, allocator
);
152 return LZMA_PROG_ERROR
;
154 if (flags
& ~LZMA_SUPPORTED_FLAGS
)
155 return LZMA_OPTIONS_ERROR
;
157 if (next
->coder
== NULL
) {
158 next
->coder
= lzma_alloc(sizeof(lzma_coder
), allocator
);
159 if (next
->coder
== NULL
)
160 return LZMA_MEM_ERROR
;
162 next
->code
= &auto_decode
;
163 next
->end
= &auto_decoder_end
;
164 next
->get_check
= &auto_decoder_get_check
;
165 next
->memconfig
= &auto_decoder_memconfig
;
166 next
->coder
->next
= LZMA_NEXT_CODER_INIT
;
169 next
->coder
->memlimit
= memlimit
;
170 next
->coder
->flags
= flags
;
171 next
->coder
->sequence
= SEQ_INIT
;
177 extern LZMA_API(lzma_ret
)
178 lzma_auto_decoder(lzma_stream
*strm
, uint64_t memlimit
, uint32_t flags
)
180 lzma_next_strm_init(auto_decoder_init
, strm
, memlimit
, flags
);
182 strm
->internal
->supported_actions
[LZMA_RUN
] = true;
183 strm
->internal
->supported_actions
[LZMA_FINISH
] = true;