microlzma_decoder.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. // SPDX-License-Identifier: 0BSD
  2. ///////////////////////////////////////////////////////////////////////////////
  3. //
  4. /// \file microlzma_decoder.c
  5. /// \brief Decode MicroLZMA format
  6. //
  7. // Author: Lasse Collin
  8. //
  9. ///////////////////////////////////////////////////////////////////////////////
  10. #include "lzma_decoder.h"
  11. #include "lz_decoder.h"
  12. typedef struct {
  13. /// LZMA1 decoder
  14. lzma_next_coder lzma;
  15. /// Compressed size of the stream as given by the application.
  16. /// This must be exactly correct.
  17. ///
  18. /// This will be decremented when input is read.
  19. uint64_t comp_size;
  20. /// Uncompressed size of the stream as given by the application.
  21. /// This may be less than the actual uncompressed size if
  22. /// uncomp_size_is_exact is false.
  23. ///
  24. /// This will be decremented when output is produced.
  25. lzma_vli uncomp_size;
  26. /// LZMA dictionary size as given by the application
  27. uint32_t dict_size;
  28. /// If true, the exact uncompressed size is known. If false,
  29. /// uncomp_size may be smaller than the real uncompressed size;
  30. /// uncomp_size may never be bigger than the real uncompressed size.
  31. bool uncomp_size_is_exact;
  32. /// True once the first byte of the MicroLZMA stream
  33. /// has been processed.
  34. bool props_decoded;
  35. } lzma_microlzma_coder;
  36. static lzma_ret
  37. microlzma_decode(void *coder_ptr, const lzma_allocator *allocator,
  38. const uint8_t *restrict in, size_t *restrict in_pos,
  39. size_t in_size, uint8_t *restrict out,
  40. size_t *restrict out_pos, size_t out_size, lzma_action action)
  41. {
  42. lzma_microlzma_coder *coder = coder_ptr;
  43. // Remember the in start position so that we can update comp_size.
  44. const size_t in_start = *in_pos;
  45. // Remember the out start position so that we can update uncomp_size.
  46. const size_t out_start = *out_pos;
  47. // Limit the amount of input so that the decoder won't read more than
  48. // comp_size. This is required when uncomp_size isn't exact because
  49. // in that case the LZMA decoder will try to decode more input even
  50. // when it has no output space (it can be looking for EOPM).
  51. if (in_size - *in_pos > coder->comp_size)
  52. in_size = *in_pos + (size_t)(coder->comp_size);
  53. // When the exact uncompressed size isn't known, we must limit
  54. // the available output space to prevent the LZMA decoder from
  55. // trying to decode too much.
  56. if (!coder->uncomp_size_is_exact
  57. && out_size - *out_pos > coder->uncomp_size)
  58. out_size = *out_pos + (size_t)(coder->uncomp_size);
  59. if (!coder->props_decoded) {
  60. // There must be at least one byte of input to decode
  61. // the properties byte.
  62. if (*in_pos >= in_size)
  63. return LZMA_OK;
  64. lzma_options_lzma options = {
  65. .dict_size = coder->dict_size,
  66. .preset_dict = NULL,
  67. .preset_dict_size = 0,
  68. .ext_flags = 0, // EOPM not allowed when size is known
  69. .ext_size_low = UINT32_MAX, // Unknown size by default
  70. .ext_size_high = UINT32_MAX,
  71. };
  72. if (coder->uncomp_size_is_exact)
  73. lzma_set_ext_size(options, coder->uncomp_size);
  74. // The properties are stored as bitwise-negation
  75. // of the typical encoding.
  76. if (lzma_lzma_lclppb_decode(&options, ~in[*in_pos]))
  77. return LZMA_OPTIONS_ERROR;
  78. ++*in_pos;
  79. // Initialize the decoder.
  80. lzma_filter_info filters[2] = {
  81. {
  82. .id = LZMA_FILTER_LZMA1EXT,
  83. .init = &lzma_lzma_decoder_init,
  84. .options = &options,
  85. }, {
  86. .init = NULL,
  87. }
  88. };
  89. return_if_error(lzma_next_filter_init(&coder->lzma,
  90. allocator, filters));
  91. // Pass one dummy 0x00 byte to the LZMA decoder since that
  92. // is what it expects the first byte to be.
  93. const uint8_t dummy_in = 0;
  94. size_t dummy_in_pos = 0;
  95. if (coder->lzma.code(coder->lzma.coder, allocator,
  96. &dummy_in, &dummy_in_pos, 1,
  97. out, out_pos, out_size, LZMA_RUN) != LZMA_OK)
  98. return LZMA_PROG_ERROR;
  99. assert(dummy_in_pos == 1);
  100. coder->props_decoded = true;
  101. }
  102. // The rest is normal LZMA decoding.
  103. lzma_ret ret = coder->lzma.code(coder->lzma.coder, allocator,
  104. in, in_pos, in_size,
  105. out, out_pos, out_size, action);
  106. // Update the remaining compressed size.
  107. assert(coder->comp_size >= *in_pos - in_start);
  108. coder->comp_size -= *in_pos - in_start;
  109. if (coder->uncomp_size_is_exact) {
  110. // After successful decompression of the complete stream
  111. // the compressed size must match.
  112. if (ret == LZMA_STREAM_END && coder->comp_size != 0)
  113. ret = LZMA_DATA_ERROR;
  114. } else {
  115. // Update the amount of output remaining.
  116. assert(coder->uncomp_size >= *out_pos - out_start);
  117. coder->uncomp_size -= *out_pos - out_start;
  118. // - We must not get LZMA_STREAM_END because the stream
  119. // shouldn't have EOPM.
  120. // - We must use uncomp_size to determine when to
  121. // return LZMA_STREAM_END.
  122. if (ret == LZMA_STREAM_END)
  123. ret = LZMA_DATA_ERROR;
  124. else if (coder->uncomp_size == 0)
  125. ret = LZMA_STREAM_END;
  126. }
  127. return ret;
  128. }
  129. static void
  130. microlzma_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
  131. {
  132. lzma_microlzma_coder *coder = coder_ptr;
  133. lzma_next_end(&coder->lzma, allocator);
  134. lzma_free(coder, allocator);
  135. return;
  136. }
  137. static lzma_ret
  138. microlzma_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
  139. uint64_t comp_size,
  140. uint64_t uncomp_size, bool uncomp_size_is_exact,
  141. uint32_t dict_size)
  142. {
  143. lzma_next_coder_init(&microlzma_decoder_init, next, allocator);
  144. lzma_microlzma_coder *coder = next->coder;
  145. if (coder == NULL) {
  146. coder = lzma_alloc(sizeof(lzma_microlzma_coder), allocator);
  147. if (coder == NULL)
  148. return LZMA_MEM_ERROR;
  149. next->coder = coder;
  150. next->code = &microlzma_decode;
  151. next->end = &microlzma_decoder_end;
  152. coder->lzma = LZMA_NEXT_CODER_INIT;
  153. }
  154. // The public API is uint64_t but the internal LZ decoder API uses
  155. // lzma_vli.
  156. if (uncomp_size > LZMA_VLI_MAX)
  157. return LZMA_OPTIONS_ERROR;
  158. coder->comp_size = comp_size;
  159. coder->uncomp_size = uncomp_size;
  160. coder->uncomp_size_is_exact = uncomp_size_is_exact;
  161. coder->dict_size = dict_size;
  162. coder->props_decoded = false;
  163. return LZMA_OK;
  164. }
  165. extern LZMA_API(lzma_ret)
  166. lzma_microlzma_decoder(lzma_stream *strm, uint64_t comp_size,
  167. uint64_t uncomp_size, lzma_bool uncomp_size_is_exact,
  168. uint32_t dict_size)
  169. {
  170. lzma_next_strm_init(microlzma_decoder_init, strm, comp_size,
  171. uncomp_size, uncomp_size_is_exact, dict_size);
  172. strm->internal->supported_actions[LZMA_RUN] = true;
  173. strm->internal->supported_actions[LZMA_FINISH] = true;
  174. return LZMA_OK;
  175. }