1 ///////////////////////////////////////////////////////////////////////////////
3 /// \file index_encoder.c
4 /// \brief Encodes the Index field
6 // Author: Lasse Collin
8 // This file has been put into the public domain.
9 // You can do whatever you want with this file.
11 ///////////////////////////////////////////////////////////////////////////////
13 #include "index_encoder.h"
29 /// Index being encoded
30 const lzma_index
*index
;
32 /// Iterator for the Index being encoded
35 /// Position in integers
38 /// CRC32 of the List of Records field
44 index_encode(void *coder_ptr
,
45 const lzma_allocator
*allocator
lzma_attribute((__unused__
)),
46 const uint8_t *restrict in
lzma_attribute((__unused__
)),
47 size_t *restrict in_pos
lzma_attribute((__unused__
)),
48 size_t in_size
lzma_attribute((__unused__
)),
49 uint8_t *restrict out
, size_t *restrict out_pos
,
51 lzma_action action
lzma_attribute((__unused__
)))
53 lzma_index_coder
*coder
= coder_ptr
;
55 // Position where to start calculating CRC32. The idea is that we
56 // need to call lzma_crc32() only once per call to index_encode().
57 const size_t out_start
= *out_pos
;
59 // Return value to use if we return at the end of this function.
60 // We use "goto out" to jump out of the while-switch construct
61 // instead of returning directly, because that way we don't need
62 // to copypaste the lzma_crc32() call to many places.
63 lzma_ret ret
= LZMA_OK
;
65 while (*out_pos
< out_size
)
66 switch (coder
->sequence
) {
68 out
[*out_pos
] = INDEX_INDICATOR
;
70 coder
->sequence
= SEQ_COUNT
;
74 const lzma_vli count
= lzma_index_block_count(coder
->index
);
75 ret
= lzma_vli_encode(count
, &coder
->pos
,
76 out
, out_pos
, out_size
);
77 if (ret
!= LZMA_STREAM_END
)
82 coder
->sequence
= SEQ_NEXT
;
87 if (lzma_index_iter_next(
88 &coder
->iter
, LZMA_INDEX_ITER_BLOCK
)) {
89 // Get the size of the Index Padding field.
90 coder
->pos
= lzma_index_padding_size(coder
->index
);
91 assert(coder
->pos
<= 3);
92 coder
->sequence
= SEQ_PADDING
;
96 coder
->sequence
= SEQ_UNPADDED
;
101 case SEQ_UNCOMPRESSED
: {
102 const lzma_vli size
= coder
->sequence
== SEQ_UNPADDED
103 ? coder
->iter
.block
.unpadded_size
104 : coder
->iter
.block
.uncompressed_size
;
106 ret
= lzma_vli_encode(size
, &coder
->pos
,
107 out
, out_pos
, out_size
);
108 if (ret
!= LZMA_STREAM_END
)
114 // Advance to SEQ_UNCOMPRESSED or SEQ_NEXT.
120 if (coder
->pos
> 0) {
122 out
[(*out_pos
)++] = 0x00;
126 // Finish the CRC32 calculation.
127 coder
->crc32
= lzma_crc32(out
+ out_start
,
128 *out_pos
- out_start
, coder
->crc32
);
130 coder
->sequence
= SEQ_CRC32
;
135 // We don't use the main loop, because we don't want
136 // coder->crc32 to be touched anymore.
138 if (*out_pos
== out_size
)
141 out
[*out_pos
] = (coder
->crc32
>> (coder
->pos
* 8))
145 } while (++coder
->pos
< 4);
147 return LZMA_STREAM_END
;
151 return LZMA_PROG_ERROR
;
157 // Avoid null pointer + 0 (undefined behavior) in "out + out_start".
158 // In such a case we had no input and thus out_used == 0.
160 const size_t out_used
= *out_pos
- out_start
;
162 coder
->crc32
= lzma_crc32(out
+ out_start
,
163 out_used
, coder
->crc32
);
171 index_encoder_end(void *coder
, const lzma_allocator
*allocator
)
173 lzma_free(coder
, allocator
);
179 index_encoder_reset(lzma_index_coder
*coder
, const lzma_index
*i
)
181 lzma_index_iter_init(&coder
->iter
, i
);
183 coder
->sequence
= SEQ_INDICATOR
;
193 lzma_index_encoder_init(lzma_next_coder
*next
, const lzma_allocator
*allocator
,
196 lzma_next_coder_init(&lzma_index_encoder_init
, next
, allocator
);
199 return LZMA_PROG_ERROR
;
201 if (next
->coder
== NULL
) {
202 next
->coder
= lzma_alloc(sizeof(lzma_index_coder
), allocator
);
203 if (next
->coder
== NULL
)
204 return LZMA_MEM_ERROR
;
206 next
->code
= &index_encode
;
207 next
->end
= &index_encoder_end
;
210 index_encoder_reset(next
->coder
, i
);
216 extern LZMA_API(lzma_ret
)
217 lzma_index_encoder(lzma_stream
*strm
, const lzma_index
*i
)
219 lzma_next_strm_init(lzma_index_encoder_init
, strm
, i
);
221 strm
->internal
->supported_actions
[LZMA_RUN
] = true;
222 strm
->internal
->supported_actions
[LZMA_FINISH
] = true;
228 extern LZMA_API(lzma_ret
)
229 lzma_index_buffer_encode(const lzma_index
*i
,
230 uint8_t *out
, size_t *out_pos
, size_t out_size
)
232 // Validate the arguments.
233 if (i
== NULL
|| out
== NULL
|| out_pos
== NULL
|| *out_pos
> out_size
)
234 return LZMA_PROG_ERROR
;
236 // Don't try to encode if there's not enough output space.
237 if (out_size
- *out_pos
< lzma_index_size(i
))
238 return LZMA_BUF_ERROR
;
240 // The Index encoder needs just one small data structure so we can
241 // allocate it on stack.
242 lzma_index_coder coder
;
243 index_encoder_reset(&coder
, i
);
245 // Do the actual encoding. This should never fail, but store
246 // the original *out_pos just in case.
247 const size_t out_start
= *out_pos
;
248 lzma_ret ret
= index_encode(&coder
, NULL
, NULL
, NULL
, 0,
249 out
, out_pos
, out_size
, LZMA_RUN
);
251 if (ret
== LZMA_STREAM_END
) {
254 // We should never get here, but just in case, restore the
255 // output position and set the error accordingly if something
256 // goes wrong and debugging isn't enabled.
258 *out_pos
= out_start
;
259 ret
= LZMA_PROG_ERROR
;