Path: blob/master/Utilities/cmliblzma/liblzma/common/auto_decoder.c
3153 views
// SPDX-License-Identifier: 0BSD12///////////////////////////////////////////////////////////////////////////////3//4/// \file auto_decoder.c5/// \brief Autodetect between .xz, .lzma (LZMA_Alone), and .lz (lzip)6//7// Author: Lasse Collin8//9///////////////////////////////////////////////////////////////////////////////1011#include "stream_decoder.h"12#include "alone_decoder.h"13#ifdef HAVE_LZIP_DECODER14# include "lzip_decoder.h"15#endif161718typedef struct {19/// .xz Stream decoder, LZMA_Alone decoder, or lzip decoder20lzma_next_coder next;2122uint64_t memlimit;23uint32_t flags;2425enum {26SEQ_INIT,27SEQ_CODE,28SEQ_FINISH,29} sequence;30} lzma_auto_coder;313233static lzma_ret34auto_decode(void *coder_ptr, const lzma_allocator *allocator,35const uint8_t *restrict in, size_t *restrict in_pos,36size_t in_size, uint8_t *restrict out,37size_t *restrict out_pos, size_t out_size, lzma_action action)38{39lzma_auto_coder *coder = coder_ptr;4041switch (coder->sequence) {42case SEQ_INIT:43if (*in_pos >= in_size)44return LZMA_OK;4546// Update the sequence now, because we want to continue from47// SEQ_CODE even if we return some LZMA_*_CHECK.48coder->sequence = SEQ_CODE;4950// Detect the file format. .xz files start with 0xFD which51// cannot be the first byte of .lzma (LZMA_Alone) format.52// The .lz format starts with 0x4C which could be the53// first byte of a .lzma file but luckily it would mean54// lc/lp/pb being 4/3/1 which liblzma doesn't support because55// lc + lp > 4. So using just 0x4C to detect .lz is OK here.56if (in[*in_pos] == 0xFD) {57return_if_error(lzma_stream_decoder_init(58&coder->next, allocator,59coder->memlimit, coder->flags));60#ifdef HAVE_LZIP_DECODER61} else if (in[*in_pos] == 0x4C) {62return_if_error(lzma_lzip_decoder_init(63&coder->next, allocator,64coder->memlimit, coder->flags));65#endif66} else {67return_if_error(lzma_alone_decoder_init(&coder->next,68allocator, coder->memlimit, true));6970// If the application wants to know about missing71// integrity check or about the check in general, we72// need to handle it here, because LZMA_Alone decoder73// doesn't accept any flags.74if (coder->flags & LZMA_TELL_NO_CHECK)75return LZMA_NO_CHECK;7677if (coder->flags & LZMA_TELL_ANY_CHECK)78return LZMA_GET_CHECK;79}8081// Fall through8283case SEQ_CODE: {84const lzma_ret ret = coder->next.code(85coder->next.coder, allocator,86in, in_pos, in_size,87out, out_pos, out_size, action);88if (ret != LZMA_STREAM_END89|| (coder->flags & LZMA_CONCATENATED) == 0)90return ret;9192coder->sequence = SEQ_FINISH;93}9495// Fall through9697case SEQ_FINISH:98// When LZMA_CONCATENATED was used and we were decoding99// a LZMA_Alone file, we need to check that there is no100// trailing garbage and wait for LZMA_FINISH.101if (*in_pos < in_size)102return LZMA_DATA_ERROR;103104return action == LZMA_FINISH ? LZMA_STREAM_END : LZMA_OK;105106default:107assert(0);108return LZMA_PROG_ERROR;109}110}111112113static void114auto_decoder_end(void *coder_ptr, const lzma_allocator *allocator)115{116lzma_auto_coder *coder = coder_ptr;117lzma_next_end(&coder->next, allocator);118lzma_free(coder, allocator);119return;120}121122123static lzma_check124auto_decoder_get_check(const void *coder_ptr)125{126const lzma_auto_coder *coder = coder_ptr;127128// It is LZMA_Alone if get_check is NULL.129return coder->next.get_check == NULL ? LZMA_CHECK_NONE130: coder->next.get_check(coder->next.coder);131}132133134static lzma_ret135auto_decoder_memconfig(void *coder_ptr, uint64_t *memusage,136uint64_t *old_memlimit, uint64_t new_memlimit)137{138lzma_auto_coder *coder = coder_ptr;139140lzma_ret ret;141142if (coder->next.memconfig != NULL) {143ret = coder->next.memconfig(coder->next.coder,144memusage, old_memlimit, new_memlimit);145assert(*old_memlimit == coder->memlimit);146} else {147// No coder is configured yet. Use the base value as148// the current memory usage.149*memusage = LZMA_MEMUSAGE_BASE;150*old_memlimit = coder->memlimit;151152ret = LZMA_OK;153if (new_memlimit != 0 && new_memlimit < *memusage)154ret = LZMA_MEMLIMIT_ERROR;155}156157if (ret == LZMA_OK && new_memlimit != 0)158coder->memlimit = new_memlimit;159160return ret;161}162163164static lzma_ret165auto_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,166uint64_t memlimit, uint32_t flags)167{168lzma_next_coder_init(&auto_decoder_init, next, allocator);169170if (flags & ~LZMA_SUPPORTED_FLAGS)171return LZMA_OPTIONS_ERROR;172173lzma_auto_coder *coder = next->coder;174if (coder == NULL) {175coder = lzma_alloc(sizeof(lzma_auto_coder), allocator);176if (coder == NULL)177return LZMA_MEM_ERROR;178179next->coder = coder;180next->code = &auto_decode;181next->end = &auto_decoder_end;182next->get_check = &auto_decoder_get_check;183next->memconfig = &auto_decoder_memconfig;184coder->next = LZMA_NEXT_CODER_INIT;185}186187coder->memlimit = my_max(1, memlimit);188coder->flags = flags;189coder->sequence = SEQ_INIT;190191return LZMA_OK;192}193194195extern LZMA_API(lzma_ret)196lzma_auto_decoder(lzma_stream *strm, uint64_t memlimit, uint32_t flags)197{198lzma_next_strm_init(auto_decoder_init, strm, memlimit, flags);199200strm->internal->supported_actions[LZMA_RUN] = true;201strm->internal->supported_actions[LZMA_FINISH] = true;202203return LZMA_OK;204}205206207