stream_encoder.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. // SPDX-License-Identifier: 0BSD
  2. ///////////////////////////////////////////////////////////////////////////////
  3. //
  4. /// \file stream_encoder.c
  5. /// \brief Encodes .xz Streams
  6. //
  7. // Author: Lasse Collin
  8. //
  9. ///////////////////////////////////////////////////////////////////////////////
  10. #include "block_encoder.h"
  11. #include "index_encoder.h"
  12. typedef struct {
  13. enum {
  14. SEQ_STREAM_HEADER,
  15. SEQ_BLOCK_INIT,
  16. SEQ_BLOCK_HEADER,
  17. SEQ_BLOCK_ENCODE,
  18. SEQ_INDEX_ENCODE,
  19. SEQ_STREAM_FOOTER,
  20. } sequence;
  21. /// True if Block encoder has been initialized by
  22. /// stream_encoder_init() or stream_encoder_update()
  23. /// and thus doesn't need to be initialized in stream_encode().
  24. bool block_encoder_is_initialized;
  25. /// Block
  26. lzma_next_coder block_encoder;
  27. /// Options for the Block encoder
  28. lzma_block block_options;
  29. /// The filter chain currently in use
  30. lzma_filter filters[LZMA_FILTERS_MAX + 1];
  31. /// Index encoder. This is separate from Block encoder, because this
  32. /// doesn't take much memory, and when encoding multiple Streams
  33. /// with the same encoding options we avoid reallocating memory.
  34. lzma_next_coder index_encoder;
  35. /// Index to hold sizes of the Blocks
  36. lzma_index *index;
  37. /// Read position in buffer[]
  38. size_t buffer_pos;
  39. /// Total number of bytes in buffer[]
  40. size_t buffer_size;
  41. /// Buffer to hold Stream Header, Block Header, and Stream Footer.
  42. /// Block Header has biggest maximum size.
  43. uint8_t buffer[LZMA_BLOCK_HEADER_SIZE_MAX];
  44. } lzma_stream_coder;
  45. static lzma_ret
  46. block_encoder_init(lzma_stream_coder *coder, const lzma_allocator *allocator)
  47. {
  48. // Prepare the Block options. Even though Block encoder doesn't need
  49. // compressed_size, uncompressed_size, and header_size to be
  50. // initialized, it is a good idea to do it here, because this way
  51. // we catch if someone gave us Filter ID that cannot be used in
  52. // Blocks/Streams.
  53. coder->block_options.compressed_size = LZMA_VLI_UNKNOWN;
  54. coder->block_options.uncompressed_size = LZMA_VLI_UNKNOWN;
  55. return_if_error(lzma_block_header_size(&coder->block_options));
  56. // Initialize the actual Block encoder.
  57. return lzma_block_encoder_init(&coder->block_encoder, allocator,
  58. &coder->block_options);
  59. }
  60. static lzma_ret
  61. stream_encode(void *coder_ptr, const lzma_allocator *allocator,
  62. const uint8_t *restrict in, size_t *restrict in_pos,
  63. size_t in_size, uint8_t *restrict out,
  64. size_t *restrict out_pos, size_t out_size, lzma_action action)
  65. {
  66. lzma_stream_coder *coder = coder_ptr;
  67. // Main loop
  68. while (*out_pos < out_size)
  69. switch (coder->sequence) {
  70. case SEQ_STREAM_HEADER:
  71. case SEQ_BLOCK_HEADER:
  72. case SEQ_STREAM_FOOTER:
  73. lzma_bufcpy(coder->buffer, &coder->buffer_pos,
  74. coder->buffer_size, out, out_pos, out_size);
  75. if (coder->buffer_pos < coder->buffer_size)
  76. return LZMA_OK;
  77. if (coder->sequence == SEQ_STREAM_FOOTER)
  78. return LZMA_STREAM_END;
  79. coder->buffer_pos = 0;
  80. ++coder->sequence;
  81. break;
  82. case SEQ_BLOCK_INIT: {
  83. if (*in_pos == in_size) {
  84. // If we are requested to flush or finish the current
  85. // Block, return LZMA_STREAM_END immediately since
  86. // there's nothing to do.
  87. if (action != LZMA_FINISH)
  88. return action == LZMA_RUN
  89. ? LZMA_OK : LZMA_STREAM_END;
  90. // The application had used LZMA_FULL_FLUSH to finish
  91. // the previous Block, but now wants to finish without
  92. // encoding new data, or it is simply creating an
  93. // empty Stream with no Blocks.
  94. //
  95. // Initialize the Index encoder, and continue to
  96. // actually encoding the Index.
  97. return_if_error(lzma_index_encoder_init(
  98. &coder->index_encoder, allocator,
  99. coder->index));
  100. coder->sequence = SEQ_INDEX_ENCODE;
  101. break;
  102. }
  103. // Initialize the Block encoder unless it was already
  104. // initialized by stream_encoder_init() or
  105. // stream_encoder_update().
  106. if (!coder->block_encoder_is_initialized)
  107. return_if_error(block_encoder_init(coder, allocator));
  108. // Make it false so that we don't skip the initialization
  109. // with the next Block.
  110. coder->block_encoder_is_initialized = false;
  111. // Encode the Block Header. This shouldn't fail since we have
  112. // already initialized the Block encoder.
  113. if (lzma_block_header_encode(&coder->block_options,
  114. coder->buffer) != LZMA_OK)
  115. return LZMA_PROG_ERROR;
  116. coder->buffer_size = coder->block_options.header_size;
  117. coder->sequence = SEQ_BLOCK_HEADER;
  118. break;
  119. }
  120. case SEQ_BLOCK_ENCODE: {
  121. static const lzma_action convert[LZMA_ACTION_MAX + 1] = {
  122. LZMA_RUN,
  123. LZMA_SYNC_FLUSH,
  124. LZMA_FINISH,
  125. LZMA_FINISH,
  126. LZMA_FINISH,
  127. };
  128. const lzma_ret ret = coder->block_encoder.code(
  129. coder->block_encoder.coder, allocator,
  130. in, in_pos, in_size,
  131. out, out_pos, out_size, convert[action]);
  132. if (ret != LZMA_STREAM_END || action == LZMA_SYNC_FLUSH)
  133. return ret;
  134. // Add a new Index Record.
  135. const lzma_vli unpadded_size = lzma_block_unpadded_size(
  136. &coder->block_options);
  137. assert(unpadded_size != 0);
  138. return_if_error(lzma_index_append(coder->index, allocator,
  139. unpadded_size,
  140. coder->block_options.uncompressed_size));
  141. coder->sequence = SEQ_BLOCK_INIT;
  142. break;
  143. }
  144. case SEQ_INDEX_ENCODE: {
  145. // Call the Index encoder. It doesn't take any input, so
  146. // those pointers can be NULL.
  147. const lzma_ret ret = coder->index_encoder.code(
  148. coder->index_encoder.coder, allocator,
  149. NULL, NULL, 0,
  150. out, out_pos, out_size, LZMA_RUN);
  151. if (ret != LZMA_STREAM_END)
  152. return ret;
  153. // Encode the Stream Footer into coder->buffer.
  154. const lzma_stream_flags stream_flags = {
  155. .version = 0,
  156. .backward_size = lzma_index_size(coder->index),
  157. .check = coder->block_options.check,
  158. };
  159. if (lzma_stream_footer_encode(&stream_flags, coder->buffer)
  160. != LZMA_OK)
  161. return LZMA_PROG_ERROR;
  162. coder->buffer_size = LZMA_STREAM_HEADER_SIZE;
  163. coder->sequence = SEQ_STREAM_FOOTER;
  164. break;
  165. }
  166. default:
  167. assert(0);
  168. return LZMA_PROG_ERROR;
  169. }
  170. return LZMA_OK;
  171. }
  172. static void
  173. stream_encoder_end(void *coder_ptr, const lzma_allocator *allocator)
  174. {
  175. lzma_stream_coder *coder = coder_ptr;
  176. lzma_next_end(&coder->block_encoder, allocator);
  177. lzma_next_end(&coder->index_encoder, allocator);
  178. lzma_index_end(coder->index, allocator);
  179. lzma_filters_free(coder->filters, allocator);
  180. lzma_free(coder, allocator);
  181. return;
  182. }
  183. static lzma_ret
  184. stream_encoder_update(void *coder_ptr, const lzma_allocator *allocator,
  185. const lzma_filter *filters,
  186. const lzma_filter *reversed_filters)
  187. {
  188. lzma_stream_coder *coder = coder_ptr;
  189. lzma_ret ret;
  190. // Make a copy to a temporary buffer first. This way it is easier
  191. // to keep the encoder state unchanged if an error occurs with
  192. // lzma_filters_copy().
  193. lzma_filter temp[LZMA_FILTERS_MAX + 1];
  194. return_if_error(lzma_filters_copy(filters, temp, allocator));
  195. if (coder->sequence <= SEQ_BLOCK_INIT) {
  196. // There is no incomplete Block waiting to be finished,
  197. // thus we can change the whole filter chain. Start by
  198. // trying to initialize the Block encoder with the new
  199. // chain. This way we detect if the chain is valid.
  200. coder->block_encoder_is_initialized = false;
  201. coder->block_options.filters = temp;
  202. ret = block_encoder_init(coder, allocator);
  203. coder->block_options.filters = coder->filters;
  204. if (ret != LZMA_OK)
  205. goto error;
  206. coder->block_encoder_is_initialized = true;
  207. } else if (coder->sequence <= SEQ_BLOCK_ENCODE) {
  208. // We are in the middle of a Block. Try to update only
  209. // the filter-specific options.
  210. ret = coder->block_encoder.update(
  211. coder->block_encoder.coder, allocator,
  212. filters, reversed_filters);
  213. if (ret != LZMA_OK)
  214. goto error;
  215. } else {
  216. // Trying to update the filter chain when we are already
  217. // encoding Index or Stream Footer.
  218. ret = LZMA_PROG_ERROR;
  219. goto error;
  220. }
  221. // Free the options of the old chain.
  222. lzma_filters_free(coder->filters, allocator);
  223. // Copy the new filter chain in place.
  224. memcpy(coder->filters, temp, sizeof(temp));
  225. return LZMA_OK;
  226. error:
  227. lzma_filters_free(temp, allocator);
  228. return ret;
  229. }
  230. static lzma_ret
  231. stream_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
  232. const lzma_filter *filters, lzma_check check)
  233. {
  234. lzma_next_coder_init(&stream_encoder_init, next, allocator);
  235. if (filters == NULL)
  236. return LZMA_PROG_ERROR;
  237. lzma_stream_coder *coder = next->coder;
  238. if (coder == NULL) {
  239. coder = lzma_alloc(sizeof(lzma_stream_coder), allocator);
  240. if (coder == NULL)
  241. return LZMA_MEM_ERROR;
  242. next->coder = coder;
  243. next->code = &stream_encode;
  244. next->end = &stream_encoder_end;
  245. next->update = &stream_encoder_update;
  246. coder->filters[0].id = LZMA_VLI_UNKNOWN;
  247. coder->block_encoder = LZMA_NEXT_CODER_INIT;
  248. coder->index_encoder = LZMA_NEXT_CODER_INIT;
  249. coder->index = NULL;
  250. }
  251. // Basic initializations
  252. coder->sequence = SEQ_STREAM_HEADER;
  253. coder->block_options.version = 0;
  254. coder->block_options.check = check;
  255. // Initialize the Index
  256. lzma_index_end(coder->index, allocator);
  257. coder->index = lzma_index_init(allocator);
  258. if (coder->index == NULL)
  259. return LZMA_MEM_ERROR;
  260. // Encode the Stream Header
  261. lzma_stream_flags stream_flags = {
  262. .version = 0,
  263. .check = check,
  264. };
  265. return_if_error(lzma_stream_header_encode(
  266. &stream_flags, coder->buffer));
  267. coder->buffer_pos = 0;
  268. coder->buffer_size = LZMA_STREAM_HEADER_SIZE;
  269. // Initialize the Block encoder. This way we detect unsupported
  270. // filter chains when initializing the Stream encoder instead of
  271. // giving an error after Stream Header has already been written out.
  272. return stream_encoder_update(coder, allocator, filters, NULL);
  273. }
  274. extern LZMA_API(lzma_ret)
  275. lzma_stream_encoder(lzma_stream *strm,
  276. const lzma_filter *filters, lzma_check check)
  277. {
  278. lzma_next_strm_init(stream_encoder_init, strm, filters, check);
  279. strm->internal->supported_actions[LZMA_RUN] = true;
  280. strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;
  281. strm->internal->supported_actions[LZMA_FULL_FLUSH] = true;
  282. strm->internal->supported_actions[LZMA_FULL_BARRIER] = true;
  283. strm->internal->supported_actions[LZMA_FINISH] = true;
  284. return LZMA_OK;
  285. }