alone_encoder.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. // SPDX-License-Identifier: 0BSD
  2. ///////////////////////////////////////////////////////////////////////////////
  3. //
  4. /// \file alone_encoder.c
  5. /// \brief Encoder for LZMA_Alone files
  6. //
  7. // Author: Lasse Collin
  8. //
  9. ///////////////////////////////////////////////////////////////////////////////
  10. #include "common.h"
  11. #include "lzma_encoder.h"
  12. #define ALONE_HEADER_SIZE (1 + 4 + 8)
  13. typedef struct {
  14. lzma_next_coder next;
  15. enum {
  16. SEQ_HEADER,
  17. SEQ_CODE,
  18. } sequence;
  19. size_t header_pos;
  20. uint8_t header[ALONE_HEADER_SIZE];
  21. } lzma_alone_coder;
  22. static lzma_ret
  23. alone_encode(void *coder_ptr, const lzma_allocator *allocator,
  24. const uint8_t *restrict in, size_t *restrict in_pos,
  25. size_t in_size, uint8_t *restrict out,
  26. size_t *restrict out_pos, size_t out_size,
  27. lzma_action action)
  28. {
  29. lzma_alone_coder *coder = coder_ptr;
  30. while (*out_pos < out_size)
  31. switch (coder->sequence) {
  32. case SEQ_HEADER:
  33. lzma_bufcpy(coder->header, &coder->header_pos,
  34. ALONE_HEADER_SIZE,
  35. out, out_pos, out_size);
  36. if (coder->header_pos < ALONE_HEADER_SIZE)
  37. return LZMA_OK;
  38. coder->sequence = SEQ_CODE;
  39. break;
  40. case SEQ_CODE:
  41. return coder->next.code(coder->next.coder,
  42. allocator, in, in_pos, in_size,
  43. out, out_pos, out_size, action);
  44. default:
  45. assert(0);
  46. return LZMA_PROG_ERROR;
  47. }
  48. return LZMA_OK;
  49. }
  50. static void
  51. alone_encoder_end(void *coder_ptr, const lzma_allocator *allocator)
  52. {
  53. lzma_alone_coder *coder = coder_ptr;
  54. lzma_next_end(&coder->next, allocator);
  55. lzma_free(coder, allocator);
  56. return;
  57. }
  58. static lzma_ret
  59. alone_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
  60. const lzma_options_lzma *options)
  61. {
  62. lzma_next_coder_init(&alone_encoder_init, next, allocator);
  63. lzma_alone_coder *coder = next->coder;
  64. if (coder == NULL) {
  65. coder = lzma_alloc(sizeof(lzma_alone_coder), allocator);
  66. if (coder == NULL)
  67. return LZMA_MEM_ERROR;
  68. next->coder = coder;
  69. next->code = &alone_encode;
  70. next->end = &alone_encoder_end;
  71. coder->next = LZMA_NEXT_CODER_INIT;
  72. }
  73. // Basic initializations
  74. coder->sequence = SEQ_HEADER;
  75. coder->header_pos = 0;
  76. // Encode the header:
  77. // - Properties (1 byte)
  78. if (lzma_lzma_lclppb_encode(options, coder->header))
  79. return LZMA_OPTIONS_ERROR;
  80. // - Dictionary size (4 bytes)
  81. if (options->dict_size < LZMA_DICT_SIZE_MIN)
  82. return LZMA_OPTIONS_ERROR;
  83. // Round up to the next 2^n or 2^n + 2^(n - 1) depending on which
  84. // one is the next unless it is UINT32_MAX. While the header would
  85. // allow any 32-bit integer, we do this to keep the decoder of liblzma
  86. // accepting the resulting files.
  87. uint32_t d = options->dict_size - 1;
  88. d |= d >> 2;
  89. d |= d >> 3;
  90. d |= d >> 4;
  91. d |= d >> 8;
  92. d |= d >> 16;
  93. if (d != UINT32_MAX)
  94. ++d;
  95. write32le(coder->header + 1, d);
  96. // - Uncompressed size (always unknown and using EOPM)
  97. memset(coder->header + 1 + 4, 0xFF, 8);
  98. // Initialize the LZMA encoder.
  99. const lzma_filter_info filters[2] = {
  100. {
  101. .id = LZMA_FILTER_LZMA1,
  102. .init = &lzma_lzma_encoder_init,
  103. .options = (void *)(options),
  104. }, {
  105. .init = NULL,
  106. }
  107. };
  108. return lzma_next_filter_init(&coder->next, allocator, filters);
  109. }
  110. extern LZMA_API(lzma_ret)
  111. lzma_alone_encoder(lzma_stream *strm, const lzma_options_lzma *options)
  112. {
  113. lzma_next_strm_init(alone_encoder_init, strm, options);
  114. strm->internal->supported_actions[LZMA_RUN] = true;
  115. strm->internal->supported_actions[LZMA_FINISH] = true;
  116. return LZMA_OK;
  117. }