1 // SPDX-License-Identifier: 0BSD
3 ///////////////////////////////////////////////////////////////////////////////
5 /// \file index_encoder.c
6 /// \brief Encodes the Index field
8 // Author: Lasse Collin
10 ///////////////////////////////////////////////////////////////////////////////
12 #include "index_encoder.h"
28 /// Index being encoded
29 const lzma_index
*index
;
31 /// Iterator for the Index being encoded
34 /// Position in integers
37 /// CRC32 of the List of Records field
43 index_encode(void *coder_ptr
,
44 const lzma_allocator
*allocator
lzma_attribute((__unused__
)),
45 const uint8_t *restrict in
lzma_attribute((__unused__
)),
46 size_t *restrict in_pos
lzma_attribute((__unused__
)),
47 size_t in_size
lzma_attribute((__unused__
)),
48 uint8_t *restrict out
, size_t *restrict out_pos
,
50 lzma_action action
lzma_attribute((__unused__
)))
52 lzma_index_coder
*coder
= coder_ptr
;
54 // Position where to start calculating CRC32. The idea is that we
55 // need to call lzma_crc32() only once per call to index_encode().
56 const size_t out_start
= *out_pos
;
58 // Return value to use if we return at the end of this function.
59 // We use "goto out" to jump out of the while-switch construct
60 // instead of returning directly, because that way we don't need
61 // to copypaste the lzma_crc32() call to many places.
62 lzma_ret ret
= LZMA_OK
;
64 while (*out_pos
< out_size
)
65 switch (coder
->sequence
) {
67 out
[*out_pos
] = INDEX_INDICATOR
;
69 coder
->sequence
= SEQ_COUNT
;
73 const lzma_vli count
= lzma_index_block_count(coder
->index
);
74 ret
= lzma_vli_encode(count
, &coder
->pos
,
75 out
, out_pos
, out_size
);
76 if (ret
!= LZMA_STREAM_END
)
81 coder
->sequence
= SEQ_NEXT
;
86 if (lzma_index_iter_next(
87 &coder
->iter
, LZMA_INDEX_ITER_BLOCK
)) {
88 // Get the size of the Index Padding field.
89 coder
->pos
= lzma_index_padding_size(coder
->index
);
90 assert(coder
->pos
<= 3);
91 coder
->sequence
= SEQ_PADDING
;
95 coder
->sequence
= SEQ_UNPADDED
;
100 case SEQ_UNCOMPRESSED
: {
101 const lzma_vli size
= coder
->sequence
== SEQ_UNPADDED
102 ? coder
->iter
.block
.unpadded_size
103 : coder
->iter
.block
.uncompressed_size
;
105 ret
= lzma_vli_encode(size
, &coder
->pos
,
106 out
, out_pos
, out_size
);
107 if (ret
!= LZMA_STREAM_END
)
113 // Advance to SEQ_UNCOMPRESSED or SEQ_NEXT.
119 if (coder
->pos
> 0) {
121 out
[(*out_pos
)++] = 0x00;
125 // Finish the CRC32 calculation.
126 coder
->crc32
= lzma_crc32(out
+ out_start
,
127 *out_pos
- out_start
, coder
->crc32
);
129 coder
->sequence
= SEQ_CRC32
;
134 // We don't use the main loop, because we don't want
135 // coder->crc32 to be touched anymore.
137 if (*out_pos
== out_size
)
140 out
[*out_pos
] = (coder
->crc32
>> (coder
->pos
* 8))
144 } while (++coder
->pos
< 4);
146 return LZMA_STREAM_END
;
150 return LZMA_PROG_ERROR
;
156 // Avoid null pointer + 0 (undefined behavior) in "out + out_start".
157 // In such a case we had no input and thus out_used == 0.
159 const size_t out_used
= *out_pos
- out_start
;
161 coder
->crc32
= lzma_crc32(out
+ out_start
,
162 out_used
, coder
->crc32
);
170 index_encoder_end(void *coder
, const lzma_allocator
*allocator
)
172 lzma_free(coder
, allocator
);
178 index_encoder_reset(lzma_index_coder
*coder
, const lzma_index
*i
)
180 lzma_index_iter_init(&coder
->iter
, i
);
182 coder
->sequence
= SEQ_INDICATOR
;
192 lzma_index_encoder_init(lzma_next_coder
*next
, const lzma_allocator
*allocator
,
195 lzma_next_coder_init(&lzma_index_encoder_init
, next
, allocator
);
198 return LZMA_PROG_ERROR
;
200 if (next
->coder
== NULL
) {
201 next
->coder
= lzma_alloc(sizeof(lzma_index_coder
), allocator
);
202 if (next
->coder
== NULL
)
203 return LZMA_MEM_ERROR
;
205 next
->code
= &index_encode
;
206 next
->end
= &index_encoder_end
;
209 index_encoder_reset(next
->coder
, i
);
215 extern LZMA_API(lzma_ret
)
216 lzma_index_encoder(lzma_stream
*strm
, const lzma_index
*i
)
218 lzma_next_strm_init(lzma_index_encoder_init
, strm
, i
);
220 strm
->internal
->supported_actions
[LZMA_RUN
] = true;
221 strm
->internal
->supported_actions
[LZMA_FINISH
] = true;
227 extern LZMA_API(lzma_ret
)
228 lzma_index_buffer_encode(const lzma_index
*i
,
229 uint8_t *out
, size_t *out_pos
, size_t out_size
)
231 // Validate the arguments.
232 if (i
== NULL
|| out
== NULL
|| out_pos
== NULL
|| *out_pos
> out_size
)
233 return LZMA_PROG_ERROR
;
235 // Don't try to encode if there's not enough output space.
236 if (out_size
- *out_pos
< lzma_index_size(i
))
237 return LZMA_BUF_ERROR
;
239 // The Index encoder needs just one small data structure so we can
240 // allocate it on stack.
241 lzma_index_coder coder
;
242 index_encoder_reset(&coder
, i
);
244 // Do the actual encoding. This should never fail, but store
245 // the original *out_pos just in case.
246 const size_t out_start
= *out_pos
;
247 lzma_ret ret
= index_encode(&coder
, NULL
, NULL
, NULL
, 0,
248 out
, out_pos
, out_size
, LZMA_RUN
);
250 if (ret
== LZMA_STREAM_END
) {
253 // We should never get here, but just in case, restore the
254 // output position and set the error accordingly if something
255 // goes wrong and debugging isn't enabled.
257 *out_pos
= out_start
;
258 ret
= LZMA_PROG_ERROR
;