microlzma_decoder.c 6.2 KB

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