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
) {
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
;
156 coder
->crc32
= lzma_crc32(out
+ out_start
,
157 *out_pos
- out_start
, coder
->crc32
);
164 index_encoder_end(void *coder
, const lzma_allocator
*allocator
)
166 lzma_free(coder
, allocator
);
172 index_encoder_reset(lzma_index_coder
*coder
, const lzma_index
*i
)
174 lzma_index_iter_init(&coder
->iter
, i
);
176 coder
->sequence
= SEQ_INDICATOR
;
186 lzma_index_encoder_init(lzma_next_coder
*next
, const lzma_allocator
*allocator
,
189 lzma_next_coder_init(&lzma_index_encoder_init
, next
, allocator
);
192 return LZMA_PROG_ERROR
;
194 if (next
->coder
== NULL
) {
195 next
->coder
= lzma_alloc(sizeof(lzma_index_coder
), allocator
);
196 if (next
->coder
== NULL
)
197 return LZMA_MEM_ERROR
;
199 next
->code
= &index_encode
;
200 next
->end
= &index_encoder_end
;
203 index_encoder_reset(next
->coder
, i
);
209 extern LZMA_API(lzma_ret
)
210 lzma_index_encoder(lzma_stream
*strm
, const lzma_index
*i
)
212 lzma_next_strm_init(lzma_index_encoder_init
, strm
, i
);
214 strm
->internal
->supported_actions
[LZMA_RUN
] = true;
215 strm
->internal
->supported_actions
[LZMA_FINISH
] = true;
221 extern LZMA_API(lzma_ret
)
222 lzma_index_buffer_encode(const lzma_index
*i
,
223 uint8_t *out
, size_t *out_pos
, size_t out_size
)
225 // Validate the arguments.
226 if (i
== NULL
|| out
== NULL
|| out_pos
== NULL
|| *out_pos
> out_size
)
227 return LZMA_PROG_ERROR
;
229 // Don't try to encode if there's not enough output space.
230 if (out_size
- *out_pos
< lzma_index_size(i
))
231 return LZMA_BUF_ERROR
;
233 // The Index encoder needs just one small data structure so we can
234 // allocate it on stack.
235 lzma_index_coder coder
;
236 index_encoder_reset(&coder
, i
);
238 // Do the actual encoding. This should never fail, but store
239 // the original *out_pos just in case.
240 const size_t out_start
= *out_pos
;
241 lzma_ret ret
= index_encode(&coder
, NULL
, NULL
, NULL
, 0,
242 out
, out_pos
, out_size
, LZMA_RUN
);
244 if (ret
== LZMA_STREAM_END
) {
247 // We should never get here, but just in case, restore the
248 // output position and set the error accordingly if something
249 // goes wrong and debugging isn't enabled.
251 *out_pos
= out_start
;
252 ret
= LZMA_PROG_ERROR
;