index_encoder.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. // SPDX-License-Identifier: 0BSD
  2. ///////////////////////////////////////////////////////////////////////////////
  3. //
  4. /// \file index_encoder.c
  5. /// \brief Encodes the Index field
  6. //
  7. // Author: Lasse Collin
  8. //
  9. ///////////////////////////////////////////////////////////////////////////////
  10. #include "index_encoder.h"
  11. #include "index.h"
  12. #include "check.h"
  13. typedef struct {
  14. enum {
  15. SEQ_INDICATOR,
  16. SEQ_COUNT,
  17. SEQ_UNPADDED,
  18. SEQ_UNCOMPRESSED,
  19. SEQ_NEXT,
  20. SEQ_PADDING,
  21. SEQ_CRC32,
  22. } sequence;
  23. /// Index being encoded
  24. const lzma_index *index;
  25. /// Iterator for the Index being encoded
  26. lzma_index_iter iter;
  27. /// Position in integers
  28. size_t pos;
  29. /// CRC32 of the List of Records field
  30. uint32_t crc32;
  31. } lzma_index_coder;
  32. static lzma_ret
  33. index_encode(void *coder_ptr,
  34. const lzma_allocator *allocator lzma_attribute((__unused__)),
  35. const uint8_t *restrict in lzma_attribute((__unused__)),
  36. size_t *restrict in_pos lzma_attribute((__unused__)),
  37. size_t in_size lzma_attribute((__unused__)),
  38. uint8_t *restrict out, size_t *restrict out_pos,
  39. size_t out_size,
  40. lzma_action action lzma_attribute((__unused__)))
  41. {
  42. lzma_index_coder *coder = coder_ptr;
  43. // Position where to start calculating CRC32. The idea is that we
  44. // need to call lzma_crc32() only once per call to index_encode().
  45. const size_t out_start = *out_pos;
  46. // Return value to use if we return at the end of this function.
  47. // We use "goto out" to jump out of the while-switch construct
  48. // instead of returning directly, because that way we don't need
  49. // to copypaste the lzma_crc32() call to many places.
  50. lzma_ret ret = LZMA_OK;
  51. while (*out_pos < out_size)
  52. switch (coder->sequence) {
  53. case SEQ_INDICATOR:
  54. out[*out_pos] = INDEX_INDICATOR;
  55. ++*out_pos;
  56. coder->sequence = SEQ_COUNT;
  57. break;
  58. case SEQ_COUNT: {
  59. const lzma_vli count = lzma_index_block_count(coder->index);
  60. ret = lzma_vli_encode(count, &coder->pos,
  61. out, out_pos, out_size);
  62. if (ret != LZMA_STREAM_END)
  63. goto out;
  64. ret = LZMA_OK;
  65. coder->pos = 0;
  66. coder->sequence = SEQ_NEXT;
  67. break;
  68. }
  69. case SEQ_NEXT:
  70. if (lzma_index_iter_next(
  71. &coder->iter, LZMA_INDEX_ITER_BLOCK)) {
  72. // Get the size of the Index Padding field.
  73. coder->pos = lzma_index_padding_size(coder->index);
  74. assert(coder->pos <= 3);
  75. coder->sequence = SEQ_PADDING;
  76. break;
  77. }
  78. coder->sequence = SEQ_UNPADDED;
  79. // Fall through
  80. case SEQ_UNPADDED:
  81. case SEQ_UNCOMPRESSED: {
  82. const lzma_vli size = coder->sequence == SEQ_UNPADDED
  83. ? coder->iter.block.unpadded_size
  84. : coder->iter.block.uncompressed_size;
  85. ret = lzma_vli_encode(size, &coder->pos,
  86. out, out_pos, out_size);
  87. if (ret != LZMA_STREAM_END)
  88. goto out;
  89. ret = LZMA_OK;
  90. coder->pos = 0;
  91. // Advance to SEQ_UNCOMPRESSED or SEQ_NEXT.
  92. ++coder->sequence;
  93. break;
  94. }
  95. case SEQ_PADDING:
  96. if (coder->pos > 0) {
  97. --coder->pos;
  98. out[(*out_pos)++] = 0x00;
  99. break;
  100. }
  101. // Finish the CRC32 calculation.
  102. coder->crc32 = lzma_crc32(out + out_start,
  103. *out_pos - out_start, coder->crc32);
  104. coder->sequence = SEQ_CRC32;
  105. // Fall through
  106. case SEQ_CRC32:
  107. // We don't use the main loop, because we don't want
  108. // coder->crc32 to be touched anymore.
  109. do {
  110. if (*out_pos == out_size)
  111. return LZMA_OK;
  112. out[*out_pos] = (coder->crc32 >> (coder->pos * 8))
  113. & 0xFF;
  114. ++*out_pos;
  115. } while (++coder->pos < 4);
  116. return LZMA_STREAM_END;
  117. default:
  118. assert(0);
  119. return LZMA_PROG_ERROR;
  120. }
  121. out:
  122. // Update the CRC32.
  123. //
  124. // Avoid null pointer + 0 (undefined behavior) in "out + out_start".
  125. // In such a case we had no input and thus out_used == 0.
  126. {
  127. const size_t out_used = *out_pos - out_start;
  128. if (out_used > 0)
  129. coder->crc32 = lzma_crc32(out + out_start,
  130. out_used, coder->crc32);
  131. }
  132. return ret;
  133. }
  134. static void
  135. index_encoder_end(void *coder, const lzma_allocator *allocator)
  136. {
  137. lzma_free(coder, allocator);
  138. return;
  139. }
  140. static void
  141. index_encoder_reset(lzma_index_coder *coder, const lzma_index *i)
  142. {
  143. lzma_index_iter_init(&coder->iter, i);
  144. coder->sequence = SEQ_INDICATOR;
  145. coder->index = i;
  146. coder->pos = 0;
  147. coder->crc32 = 0;
  148. return;
  149. }
  150. extern lzma_ret
  151. lzma_index_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
  152. const lzma_index *i)
  153. {
  154. lzma_next_coder_init(&lzma_index_encoder_init, next, allocator);
  155. if (i == NULL)
  156. return LZMA_PROG_ERROR;
  157. if (next->coder == NULL) {
  158. next->coder = lzma_alloc(sizeof(lzma_index_coder), allocator);
  159. if (next->coder == NULL)
  160. return LZMA_MEM_ERROR;
  161. next->code = &index_encode;
  162. next->end = &index_encoder_end;
  163. }
  164. index_encoder_reset(next->coder, i);
  165. return LZMA_OK;
  166. }
  167. extern LZMA_API(lzma_ret)
  168. lzma_index_encoder(lzma_stream *strm, const lzma_index *i)
  169. {
  170. lzma_next_strm_init(lzma_index_encoder_init, strm, i);
  171. strm->internal->supported_actions[LZMA_RUN] = true;
  172. strm->internal->supported_actions[LZMA_FINISH] = true;
  173. return LZMA_OK;
  174. }
  175. extern LZMA_API(lzma_ret)
  176. lzma_index_buffer_encode(const lzma_index *i,
  177. uint8_t *out, size_t *out_pos, size_t out_size)
  178. {
  179. // Validate the arguments.
  180. if (i == NULL || out == NULL || out_pos == NULL || *out_pos > out_size)
  181. return LZMA_PROG_ERROR;
  182. // Don't try to encode if there's not enough output space.
  183. if (out_size - *out_pos < lzma_index_size(i))
  184. return LZMA_BUF_ERROR;
  185. // The Index encoder needs just one small data structure so we can
  186. // allocate it on stack.
  187. lzma_index_coder coder;
  188. index_encoder_reset(&coder, i);
  189. // Do the actual encoding. This should never fail, but store
  190. // the original *out_pos just in case.
  191. const size_t out_start = *out_pos;
  192. lzma_ret ret = index_encode(&coder, NULL, NULL, NULL, 0,
  193. out, out_pos, out_size, LZMA_RUN);
  194. if (ret == LZMA_STREAM_END) {
  195. ret = LZMA_OK;
  196. } else {
  197. // We should never get here, but just in case, restore the
  198. // output position and set the error accordingly if something
  199. // goes wrong and debugging isn't enabled.
  200. assert(0);
  201. *out_pos = out_start;
  202. ret = LZMA_PROG_ERROR;
  203. }
  204. return ret;
  205. }