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