stream_encoder.c 9.8 KB

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