(root)/
xz-5.4.5/
src/
liblzma/
common/
auto_decoder.c
       1  ///////////////////////////////////////////////////////////////////////////////
       2  //
       3  /// \file       auto_decoder.c
       4  /// \brief      Autodetect between .xz, .lzma (LZMA_Alone), and .lz (lzip)
       5  //
       6  //  Author:     Lasse Collin
       7  //
       8  //  This file has been put into the public domain.
       9  //  You can do whatever you want with this file.
      10  //
      11  ///////////////////////////////////////////////////////////////////////////////
      12  
      13  #include "stream_decoder.h"
      14  #include "alone_decoder.h"
      15  #ifdef HAVE_LZIP_DECODER
      16  #	include "lzip_decoder.h"
      17  #endif
      18  
      19  
      20  typedef struct {
      21  	/// .xz Stream decoder, LZMA_Alone decoder, or lzip decoder
      22  	lzma_next_coder next;
      23  
      24  	uint64_t memlimit;
      25  	uint32_t flags;
      26  
      27  	enum {
      28  		SEQ_INIT,
      29  		SEQ_CODE,
      30  		SEQ_FINISH,
      31  	} sequence;
      32  } lzma_auto_coder;
      33  
      34  
      35  static lzma_ret
      36  auto_decode(void *coder_ptr, const lzma_allocator *allocator,
      37  		const uint8_t *restrict in, size_t *restrict in_pos,
      38  		size_t in_size, uint8_t *restrict out,
      39  		size_t *restrict out_pos, size_t out_size, lzma_action action)
      40  {
      41  	lzma_auto_coder *coder = coder_ptr;
      42  
      43  	switch (coder->sequence) {
      44  	case SEQ_INIT:
      45  		if (*in_pos >= in_size)
      46  			return LZMA_OK;
      47  
      48  		// Update the sequence now, because we want to continue from
      49  		// SEQ_CODE even if we return some LZMA_*_CHECK.
      50  		coder->sequence = SEQ_CODE;
      51  
      52  		// Detect the file format. .xz files start with 0xFD which
      53  		// cannot be the first byte of .lzma (LZMA_Alone) format.
      54  		// The .lz format starts with 0x4C which could be the
      55  		// first byte of a .lzma file but luckily it would mean
      56  		// lc/lp/pb being 4/3/1 which liblzma doesn't support because
      57  		// lc + lp > 4. So using just 0x4C to detect .lz is OK here.
      58  		if (in[*in_pos] == 0xFD) {
      59  			return_if_error(lzma_stream_decoder_init(
      60  					&coder->next, allocator,
      61  					coder->memlimit, coder->flags));
      62  #ifdef HAVE_LZIP_DECODER
      63  		} else if (in[*in_pos] == 0x4C) {
      64  			return_if_error(lzma_lzip_decoder_init(
      65  					&coder->next, allocator,
      66  					coder->memlimit, coder->flags));
      67  #endif
      68  		} else {
      69  			return_if_error(lzma_alone_decoder_init(&coder->next,
      70  					allocator, coder->memlimit, true));
      71  
      72  			// If the application wants to know about missing
      73  			// integrity check or about the check in general, we
      74  			// need to handle it here, because LZMA_Alone decoder
      75  			// doesn't accept any flags.
      76  			if (coder->flags & LZMA_TELL_NO_CHECK)
      77  				return LZMA_NO_CHECK;
      78  
      79  			if (coder->flags & LZMA_TELL_ANY_CHECK)
      80  				return LZMA_GET_CHECK;
      81  		}
      82  
      83  	// Fall through
      84  
      85  	case SEQ_CODE: {
      86  		const lzma_ret ret = coder->next.code(
      87  				coder->next.coder, allocator,
      88  				in, in_pos, in_size,
      89  				out, out_pos, out_size, action);
      90  		if (ret != LZMA_STREAM_END
      91  				|| (coder->flags & LZMA_CONCATENATED) == 0)
      92  			return ret;
      93  
      94  		coder->sequence = SEQ_FINISH;
      95  	}
      96  
      97  	// Fall through
      98  
      99  	case SEQ_FINISH:
     100  		// When LZMA_CONCATENATED was used and we were decoding
     101  		// a LZMA_Alone file, we need to check that there is no
     102  		// trailing garbage and wait for LZMA_FINISH.
     103  		if (*in_pos < in_size)
     104  			return LZMA_DATA_ERROR;
     105  
     106  		return action == LZMA_FINISH ? LZMA_STREAM_END : LZMA_OK;
     107  
     108  	default:
     109  		assert(0);
     110  		return LZMA_PROG_ERROR;
     111  	}
     112  }
     113  
     114  
     115  static void
     116  auto_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
     117  {
     118  	lzma_auto_coder *coder = coder_ptr;
     119  	lzma_next_end(&coder->next, allocator);
     120  	lzma_free(coder, allocator);
     121  	return;
     122  }
     123  
     124  
     125  static lzma_check
     126  auto_decoder_get_check(const void *coder_ptr)
     127  {
     128  	const lzma_auto_coder *coder = coder_ptr;
     129  
     130  	// It is LZMA_Alone if get_check is NULL.
     131  	return coder->next.get_check == NULL ? LZMA_CHECK_NONE
     132  			: coder->next.get_check(coder->next.coder);
     133  }
     134  
     135  
     136  static lzma_ret
     137  auto_decoder_memconfig(void *coder_ptr, uint64_t *memusage,
     138  		uint64_t *old_memlimit, uint64_t new_memlimit)
     139  {
     140  	lzma_auto_coder *coder = coder_ptr;
     141  
     142  	lzma_ret ret;
     143  
     144  	if (coder->next.memconfig != NULL) {
     145  		ret = coder->next.memconfig(coder->next.coder,
     146  				memusage, old_memlimit, new_memlimit);
     147  		assert(*old_memlimit == coder->memlimit);
     148  	} else {
     149  		// No coder is configured yet. Use the base value as
     150  		// the current memory usage.
     151  		*memusage = LZMA_MEMUSAGE_BASE;
     152  		*old_memlimit = coder->memlimit;
     153  
     154  		ret = LZMA_OK;
     155  		if (new_memlimit != 0 && new_memlimit < *memusage)
     156  			ret = LZMA_MEMLIMIT_ERROR;
     157  	}
     158  
     159  	if (ret == LZMA_OK && new_memlimit != 0)
     160  		coder->memlimit = new_memlimit;
     161  
     162  	return ret;
     163  }
     164  
     165  
     166  static lzma_ret
     167  auto_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
     168  		uint64_t memlimit, uint32_t flags)
     169  {
     170  	lzma_next_coder_init(&auto_decoder_init, next, allocator);
     171  
     172  	if (flags & ~LZMA_SUPPORTED_FLAGS)
     173  		return LZMA_OPTIONS_ERROR;
     174  
     175  	lzma_auto_coder *coder = next->coder;
     176  	if (coder == NULL) {
     177  		coder = lzma_alloc(sizeof(lzma_auto_coder), allocator);
     178  		if (coder == NULL)
     179  			return LZMA_MEM_ERROR;
     180  
     181  		next->coder = coder;
     182  		next->code = &auto_decode;
     183  		next->end = &auto_decoder_end;
     184  		next->get_check = &auto_decoder_get_check;
     185  		next->memconfig = &auto_decoder_memconfig;
     186  		coder->next = LZMA_NEXT_CODER_INIT;
     187  	}
     188  
     189  	coder->memlimit = my_max(1, memlimit);
     190  	coder->flags = flags;
     191  	coder->sequence = SEQ_INIT;
     192  
     193  	return LZMA_OK;
     194  }
     195  
     196  
     197  extern LZMA_API(lzma_ret)
     198  lzma_auto_decoder(lzma_stream *strm, uint64_t memlimit, uint32_t flags)
     199  {
     200  	lzma_next_strm_init(auto_decoder_init, strm, memlimit, flags);
     201  
     202  	strm->internal->supported_actions[LZMA_RUN] = true;
     203  	strm->internal->supported_actions[LZMA_FINISH] = true;
     204  
     205  	return LZMA_OK;
     206  }