stream_encoder.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  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 "stream_encoder.h"
  13. #include "block_encoder.h"
  14. #include "index_encoder.h"
  15. struct lzma_coder_s {
  16. enum {
  17. SEQ_STREAM_HEADER,
  18. SEQ_BLOCK_INIT,
  19. SEQ_BLOCK_HEADER,
  20. SEQ_BLOCK_ENCODE,
  21. SEQ_INDEX_ENCODE,
  22. SEQ_STREAM_FOOTER,
  23. } sequence;
  24. /// True if Block encoder has been initialized by
  25. /// lzma_stream_encoder_init() or stream_encoder_update()
  26. /// and thus doesn't need to be initialized in stream_encode().
  27. bool block_encoder_is_initialized;
  28. /// Block
  29. lzma_next_coder block_encoder;
  30. /// Options for the Block encoder
  31. lzma_block block_options;
  32. /// The filter chain currently in use
  33. lzma_filter filters[LZMA_FILTERS_MAX + 1];
  34. /// Index encoder. This is separate from Block encoder, because this
  35. /// doesn't take much memory, and when encoding multiple Streams
  36. /// with the same encoding options we avoid reallocating memory.
  37. lzma_next_coder index_encoder;
  38. /// Index to hold sizes of the Blocks
  39. lzma_index *index;
  40. /// Read position in buffer[]
  41. size_t buffer_pos;
  42. /// Total number of bytes in buffer[]
  43. size_t buffer_size;
  44. /// Buffer to hold Stream Header, Block Header, and Stream Footer.
  45. /// Block Header has biggest maximum size.
  46. uint8_t buffer[LZMA_BLOCK_HEADER_SIZE_MAX];
  47. };
  48. static lzma_ret
  49. block_encoder_init(lzma_coder *coder, lzma_allocator *allocator)
  50. {
  51. // Prepare the Block options. Even though Block encoder doesn't need
  52. // compressed_size, uncompressed_size, and header_size to be
  53. // initialized, it is a good idea to do it here, because this way
  54. // we catch if someone gave us Filter ID that cannot be used in
  55. // Blocks/Streams.
  56. coder->block_options.compressed_size = LZMA_VLI_UNKNOWN;
  57. coder->block_options.uncompressed_size = LZMA_VLI_UNKNOWN;
  58. return_if_error(lzma_block_header_size(&coder->block_options));
  59. // Initialize the actual Block encoder.
  60. return lzma_block_encoder_init(&coder->block_encoder, allocator,
  61. &coder->block_options);
  62. }
  63. static lzma_ret
  64. stream_encode(lzma_coder *coder, lzma_allocator *allocator,
  65. const uint8_t *LZMA_RESTRICT in, size_t *LZMA_RESTRICT in_pos,
  66. size_t in_size, uint8_t *LZMA_RESTRICT out,
  67. size_t *LZMA_RESTRICT out_pos, size_t out_size, lzma_action action)
  68. {
  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 lzma_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. lzma_vli unpadded_size;
  124. static const lzma_action convert[4] = {
  125. LZMA_RUN,
  126. LZMA_SYNC_FLUSH,
  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. 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. const lzma_stream_flags stream_flags = {
  148. 0,
  149. lzma_index_size(coder->index),
  150. coder->block_options.check,
  151. };
  152. // Call the Index encoder. It doesn't take any input, so
  153. // those pointers can be NULL.
  154. const lzma_ret ret = coder->index_encoder.code(
  155. coder->index_encoder.coder, allocator,
  156. NULL, NULL, 0,
  157. out, out_pos, out_size, LZMA_RUN);
  158. if (ret != LZMA_STREAM_END)
  159. return ret;
  160. // Encode the Stream Footer into coder->buffer.
  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(lzma_coder *coder, lzma_allocator *allocator)
  176. {
  177. size_t i;
  178. lzma_next_end(&coder->block_encoder, allocator);
  179. lzma_next_end(&coder->index_encoder, allocator);
  180. lzma_index_end(coder->index, allocator);
  181. for (i = 0; coder->filters[i].id != LZMA_VLI_UNKNOWN; ++i)
  182. lzma_free(coder->filters[i].options, allocator);
  183. lzma_free(coder, allocator);
  184. return;
  185. }
  186. static lzma_ret
  187. stream_encoder_update(lzma_coder *coder, lzma_allocator *allocator,
  188. const lzma_filter *filters,
  189. const lzma_filter *reversed_filters)
  190. {
  191. size_t i;
  192. if (coder->sequence <= SEQ_BLOCK_INIT) {
  193. lzma_ret ret;
  194. // There is no incomplete Block waiting to be finished,
  195. // thus we can change the whole filter chain. Start by
  196. // trying to initialize the Block encoder with the new
  197. // chain. This way we detect if the chain is valid.
  198. coder->block_encoder_is_initialized = false;
  199. coder->block_options.filters = (lzma_filter *)(filters);
  200. ret = block_encoder_init(coder, allocator);
  201. coder->block_options.filters = coder->filters;
  202. if (ret != LZMA_OK)
  203. return ret;
  204. coder->block_encoder_is_initialized = true;
  205. } else if (coder->sequence <= SEQ_BLOCK_ENCODE) {
  206. // We are in the middle of a Block. Try to update only
  207. // the filter-specific options.
  208. return_if_error(coder->block_encoder.update(
  209. coder->block_encoder.coder, allocator,
  210. filters, reversed_filters));
  211. } else {
  212. // Trying to update the filter chain when we are already
  213. // encoding Index or Stream Footer.
  214. return LZMA_PROG_ERROR;
  215. }
  216. // Free the copy of the old chain and make a copy of the new chain.
  217. for (i = 0; coder->filters[i].id != LZMA_VLI_UNKNOWN; ++i)
  218. lzma_free(coder->filters[i].options, allocator);
  219. return lzma_filters_copy(filters, coder->filters, allocator);
  220. }
  221. extern lzma_ret
  222. lzma_stream_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
  223. const lzma_filter *filters, lzma_check check)
  224. {
  225. lzma_stream_flags stream_flags = { 0, 0, check };
  226. lzma_next_coder_init(&lzma_stream_encoder_init, next, allocator);
  227. if (filters == NULL)
  228. return LZMA_PROG_ERROR;
  229. if (next->coder == NULL) {
  230. next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
  231. if (next->coder == NULL)
  232. return LZMA_MEM_ERROR;
  233. next->code = &stream_encode;
  234. next->end = &stream_encoder_end;
  235. next->update = &stream_encoder_update;
  236. next->coder->filters[0].id = LZMA_VLI_UNKNOWN;
  237. next->coder->block_encoder = LZMA_NEXT_CODER_INIT;
  238. next->coder->index_encoder = LZMA_NEXT_CODER_INIT;
  239. next->coder->index = NULL;
  240. }
  241. // Basic initializations
  242. next->coder->sequence = SEQ_STREAM_HEADER;
  243. next->coder->block_options.version = 0;
  244. next->coder->block_options.check = check;
  245. // Initialize the Index
  246. lzma_index_end(next->coder->index, allocator);
  247. next->coder->index = lzma_index_init(allocator);
  248. if (next->coder->index == NULL)
  249. return LZMA_MEM_ERROR;
  250. // Encode the Stream Header
  251. return_if_error(lzma_stream_header_encode(
  252. &stream_flags, next->coder->buffer));
  253. next->coder->buffer_pos = 0;
  254. next->coder->buffer_size = LZMA_STREAM_HEADER_SIZE;
  255. // Initialize the Block encoder. This way we detect unsupported
  256. // filter chains when initializing the Stream encoder instead of
  257. // giving an error after Stream Header has already written out.
  258. return stream_encoder_update(
  259. next->coder, allocator, filters, NULL);
  260. }
  261. extern LZMA_API(lzma_ret)
  262. lzma_stream_encoder(lzma_stream *strm,
  263. const lzma_filter *filters, lzma_check check)
  264. {
  265. lzma_next_strm_init2(lzma_stream_encoder_init, strm, filters, check);
  266. strm->internal->supported_actions[LZMA_RUN] = true;
  267. strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;
  268. strm->internal->supported_actions[LZMA_FULL_FLUSH] = true;
  269. strm->internal->supported_actions[LZMA_FINISH] = true;
  270. return LZMA_OK;
  271. }