12940b44dSPeter Avalos ///////////////////////////////////////////////////////////////////////////////
22940b44dSPeter Avalos //
32940b44dSPeter Avalos /// \file auto_decoder.c
42940b44dSPeter Avalos /// \brief Autodetect between .xz Stream and .lzma (LZMA_Alone) formats
52940b44dSPeter Avalos //
62940b44dSPeter Avalos // Author: Lasse Collin
72940b44dSPeter Avalos //
82940b44dSPeter Avalos // This file has been put into the public domain.
92940b44dSPeter Avalos // You can do whatever you want with this file.
102940b44dSPeter Avalos //
112940b44dSPeter Avalos ///////////////////////////////////////////////////////////////////////////////
122940b44dSPeter Avalos
132940b44dSPeter Avalos #include "stream_decoder.h"
142940b44dSPeter Avalos #include "alone_decoder.h"
152940b44dSPeter Avalos
162940b44dSPeter Avalos
17*46a2189dSzrj typedef struct {
182940b44dSPeter Avalos /// Stream decoder or LZMA_Alone decoder
192940b44dSPeter Avalos lzma_next_coder next;
202940b44dSPeter Avalos
212940b44dSPeter Avalos uint64_t memlimit;
222940b44dSPeter Avalos uint32_t flags;
232940b44dSPeter Avalos
242940b44dSPeter Avalos enum {
252940b44dSPeter Avalos SEQ_INIT,
262940b44dSPeter Avalos SEQ_CODE,
272940b44dSPeter Avalos SEQ_FINISH,
282940b44dSPeter Avalos } sequence;
29*46a2189dSzrj } lzma_auto_coder;
302940b44dSPeter Avalos
312940b44dSPeter Avalos
322940b44dSPeter Avalos static lzma_ret
auto_decode(void * coder_ptr,const lzma_allocator * allocator,const uint8_t * restrict in,size_t * restrict in_pos,size_t in_size,uint8_t * restrict out,size_t * restrict out_pos,size_t out_size,lzma_action action)33*46a2189dSzrj auto_decode(void *coder_ptr, const lzma_allocator *allocator,
342940b44dSPeter Avalos const uint8_t *restrict in, size_t *restrict in_pos,
352940b44dSPeter Avalos size_t in_size, uint8_t *restrict out,
362940b44dSPeter Avalos size_t *restrict out_pos, size_t out_size, lzma_action action)
372940b44dSPeter Avalos {
38*46a2189dSzrj lzma_auto_coder *coder = coder_ptr;
39*46a2189dSzrj
402940b44dSPeter Avalos switch (coder->sequence) {
412940b44dSPeter Avalos case SEQ_INIT:
422940b44dSPeter Avalos if (*in_pos >= in_size)
432940b44dSPeter Avalos return LZMA_OK;
442940b44dSPeter Avalos
452940b44dSPeter Avalos // Update the sequence now, because we want to continue from
462940b44dSPeter Avalos // SEQ_CODE even if we return some LZMA_*_CHECK.
472940b44dSPeter Avalos coder->sequence = SEQ_CODE;
482940b44dSPeter Avalos
492940b44dSPeter Avalos // Detect the file format. For now this is simple, since if
502940b44dSPeter Avalos // it doesn't start with 0xFD (the first magic byte of the
512940b44dSPeter Avalos // new format), it has to be LZMA_Alone, or something that
522940b44dSPeter Avalos // we don't support at all.
532940b44dSPeter Avalos if (in[*in_pos] == 0xFD) {
542940b44dSPeter Avalos return_if_error(lzma_stream_decoder_init(
552940b44dSPeter Avalos &coder->next, allocator,
562940b44dSPeter Avalos coder->memlimit, coder->flags));
572940b44dSPeter Avalos } else {
582940b44dSPeter Avalos return_if_error(lzma_alone_decoder_init(&coder->next,
59a530a267SJohn Marino allocator, coder->memlimit, true));
602940b44dSPeter Avalos
612940b44dSPeter Avalos // If the application wants to know about missing
622940b44dSPeter Avalos // integrity check or about the check in general, we
632940b44dSPeter Avalos // need to handle it here, because LZMA_Alone decoder
642940b44dSPeter Avalos // doesn't accept any flags.
652940b44dSPeter Avalos if (coder->flags & LZMA_TELL_NO_CHECK)
662940b44dSPeter Avalos return LZMA_NO_CHECK;
672940b44dSPeter Avalos
682940b44dSPeter Avalos if (coder->flags & LZMA_TELL_ANY_CHECK)
692940b44dSPeter Avalos return LZMA_GET_CHECK;
702940b44dSPeter Avalos }
712940b44dSPeter Avalos
722940b44dSPeter Avalos // Fall through
732940b44dSPeter Avalos
742940b44dSPeter Avalos case SEQ_CODE: {
752940b44dSPeter Avalos const lzma_ret ret = coder->next.code(
762940b44dSPeter Avalos coder->next.coder, allocator,
772940b44dSPeter Avalos in, in_pos, in_size,
782940b44dSPeter Avalos out, out_pos, out_size, action);
792940b44dSPeter Avalos if (ret != LZMA_STREAM_END
802940b44dSPeter Avalos || (coder->flags & LZMA_CONCATENATED) == 0)
812940b44dSPeter Avalos return ret;
822940b44dSPeter Avalos
832940b44dSPeter Avalos coder->sequence = SEQ_FINISH;
842940b44dSPeter Avalos }
852940b44dSPeter Avalos
862940b44dSPeter Avalos // Fall through
872940b44dSPeter Avalos
882940b44dSPeter Avalos case SEQ_FINISH:
892940b44dSPeter Avalos // When LZMA_DECODE_CONCATENATED was used and we were decoding
902940b44dSPeter Avalos // LZMA_Alone file, we need to check check that there is no
912940b44dSPeter Avalos // trailing garbage and wait for LZMA_FINISH.
922940b44dSPeter Avalos if (*in_pos < in_size)
932940b44dSPeter Avalos return LZMA_DATA_ERROR;
942940b44dSPeter Avalos
952940b44dSPeter Avalos return action == LZMA_FINISH ? LZMA_STREAM_END : LZMA_OK;
962940b44dSPeter Avalos
972940b44dSPeter Avalos default:
982940b44dSPeter Avalos assert(0);
992940b44dSPeter Avalos return LZMA_PROG_ERROR;
1002940b44dSPeter Avalos }
1012940b44dSPeter Avalos }
1022940b44dSPeter Avalos
1032940b44dSPeter Avalos
1042940b44dSPeter Avalos static void
auto_decoder_end(void * coder_ptr,const lzma_allocator * allocator)105*46a2189dSzrj auto_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
1062940b44dSPeter Avalos {
107*46a2189dSzrj lzma_auto_coder *coder = coder_ptr;
1082940b44dSPeter Avalos lzma_next_end(&coder->next, allocator);
1092940b44dSPeter Avalos lzma_free(coder, allocator);
1102940b44dSPeter Avalos return;
1112940b44dSPeter Avalos }
1122940b44dSPeter Avalos
1132940b44dSPeter Avalos
1142940b44dSPeter Avalos static lzma_check
auto_decoder_get_check(const void * coder_ptr)115*46a2189dSzrj auto_decoder_get_check(const void *coder_ptr)
1162940b44dSPeter Avalos {
117*46a2189dSzrj const lzma_auto_coder *coder = coder_ptr;
118*46a2189dSzrj
1192940b44dSPeter Avalos // It is LZMA_Alone if get_check is NULL.
1202940b44dSPeter Avalos return coder->next.get_check == NULL ? LZMA_CHECK_NONE
1212940b44dSPeter Avalos : coder->next.get_check(coder->next.coder);
1222940b44dSPeter Avalos }
1232940b44dSPeter Avalos
1242940b44dSPeter Avalos
1252940b44dSPeter Avalos static lzma_ret
auto_decoder_memconfig(void * coder_ptr,uint64_t * memusage,uint64_t * old_memlimit,uint64_t new_memlimit)126*46a2189dSzrj auto_decoder_memconfig(void *coder_ptr, uint64_t *memusage,
1272940b44dSPeter Avalos uint64_t *old_memlimit, uint64_t new_memlimit)
1282940b44dSPeter Avalos {
129*46a2189dSzrj lzma_auto_coder *coder = coder_ptr;
130*46a2189dSzrj
1312940b44dSPeter Avalos lzma_ret ret;
1322940b44dSPeter Avalos
1332940b44dSPeter Avalos if (coder->next.memconfig != NULL) {
1342940b44dSPeter Avalos ret = coder->next.memconfig(coder->next.coder,
1352940b44dSPeter Avalos memusage, old_memlimit, new_memlimit);
1362940b44dSPeter Avalos assert(*old_memlimit == coder->memlimit);
1372940b44dSPeter Avalos } else {
1382940b44dSPeter Avalos // No coder is configured yet. Use the base value as
1392940b44dSPeter Avalos // the current memory usage.
1402940b44dSPeter Avalos *memusage = LZMA_MEMUSAGE_BASE;
1412940b44dSPeter Avalos *old_memlimit = coder->memlimit;
142*46a2189dSzrj
1432940b44dSPeter Avalos ret = LZMA_OK;
144*46a2189dSzrj if (new_memlimit != 0 && new_memlimit < *memusage)
145*46a2189dSzrj ret = LZMA_MEMLIMIT_ERROR;
1462940b44dSPeter Avalos }
1472940b44dSPeter Avalos
1482940b44dSPeter Avalos if (ret == LZMA_OK && new_memlimit != 0)
1492940b44dSPeter Avalos coder->memlimit = new_memlimit;
1502940b44dSPeter Avalos
1512940b44dSPeter Avalos return ret;
1522940b44dSPeter Avalos }
1532940b44dSPeter Avalos
1542940b44dSPeter Avalos
1552940b44dSPeter Avalos static lzma_ret
auto_decoder_init(lzma_next_coder * next,const lzma_allocator * allocator,uint64_t memlimit,uint32_t flags)15615ab8c86SJohn Marino auto_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
1572940b44dSPeter Avalos uint64_t memlimit, uint32_t flags)
1582940b44dSPeter Avalos {
1592940b44dSPeter Avalos lzma_next_coder_init(&auto_decoder_init, next, allocator);
1602940b44dSPeter Avalos
1612940b44dSPeter Avalos if (flags & ~LZMA_SUPPORTED_FLAGS)
1622940b44dSPeter Avalos return LZMA_OPTIONS_ERROR;
1632940b44dSPeter Avalos
164*46a2189dSzrj lzma_auto_coder *coder = next->coder;
165*46a2189dSzrj if (coder == NULL) {
166*46a2189dSzrj coder = lzma_alloc(sizeof(lzma_auto_coder), allocator);
167*46a2189dSzrj if (coder == NULL)
1682940b44dSPeter Avalos return LZMA_MEM_ERROR;
1692940b44dSPeter Avalos
170*46a2189dSzrj next->coder = coder;
1712940b44dSPeter Avalos next->code = &auto_decode;
1722940b44dSPeter Avalos next->end = &auto_decoder_end;
1732940b44dSPeter Avalos next->get_check = &auto_decoder_get_check;
1742940b44dSPeter Avalos next->memconfig = &auto_decoder_memconfig;
175*46a2189dSzrj coder->next = LZMA_NEXT_CODER_INIT;
1762940b44dSPeter Avalos }
1772940b44dSPeter Avalos
178*46a2189dSzrj coder->memlimit = my_max(1, memlimit);
179*46a2189dSzrj coder->flags = flags;
180*46a2189dSzrj coder->sequence = SEQ_INIT;
1812940b44dSPeter Avalos
1822940b44dSPeter Avalos return LZMA_OK;
1832940b44dSPeter Avalos }
1842940b44dSPeter Avalos
1852940b44dSPeter Avalos
1862940b44dSPeter Avalos extern LZMA_API(lzma_ret)
lzma_auto_decoder(lzma_stream * strm,uint64_t memlimit,uint32_t flags)1872940b44dSPeter Avalos lzma_auto_decoder(lzma_stream *strm, uint64_t memlimit, uint32_t flags)
1882940b44dSPeter Avalos {
1892940b44dSPeter Avalos lzma_next_strm_init(auto_decoder_init, strm, memlimit, flags);
1902940b44dSPeter Avalos
1912940b44dSPeter Avalos strm->internal->supported_actions[LZMA_RUN] = true;
1922940b44dSPeter Avalos strm->internal->supported_actions[LZMA_FINISH] = true;
1932940b44dSPeter Avalos
1942940b44dSPeter Avalos return LZMA_OK;
1952940b44dSPeter Avalos }
196