1207753Smm///////////////////////////////////////////////////////////////////////////////
2207753Smm//
3207753Smm/// \file       index_encoder.c
4207753Smm/// \brief      Encodes the Index field
5207753Smm//
6207753Smm//  Author:     Lasse Collin
7207753Smm//
8207753Smm//  This file has been put into the public domain.
9207753Smm//  You can do whatever you want with this file.
10207753Smm//
11207753Smm///////////////////////////////////////////////////////////////////////////////
12207753Smm
13207753Smm#include "index_encoder.h"
14207753Smm#include "index.h"
15207753Smm#include "check.h"
16207753Smm
17207753Smm
18207753Smmstruct lzma_coder_s {
19207753Smm	enum {
20207753Smm		SEQ_INDICATOR,
21207753Smm		SEQ_COUNT,
22207753Smm		SEQ_UNPADDED,
23207753Smm		SEQ_UNCOMPRESSED,
24207753Smm		SEQ_NEXT,
25207753Smm		SEQ_PADDING,
26207753Smm		SEQ_CRC32,
27207753Smm	} sequence;
28207753Smm
29207753Smm	/// Index being encoded
30207753Smm	const lzma_index *index;
31207753Smm
32207753Smm	/// Iterator for the Index being encoded
33207753Smm	lzma_index_iter iter;
34207753Smm
35207753Smm	/// Position in integers
36207753Smm	size_t pos;
37207753Smm
38207753Smm	/// CRC32 of the List of Records field
39207753Smm	uint32_t crc32;
40207753Smm};
41207753Smm
42207753Smm
43207753Smmstatic lzma_ret
44207753Smmindex_encode(lzma_coder *coder,
45223935Smm		lzma_allocator *allocator lzma_attribute((__unused__)),
46223935Smm		const uint8_t *restrict in lzma_attribute((__unused__)),
47223935Smm		size_t *restrict in_pos lzma_attribute((__unused__)),
48223935Smm		size_t in_size lzma_attribute((__unused__)),
49207753Smm		uint8_t *restrict out, size_t *restrict out_pos,
50223935Smm		size_t out_size,
51223935Smm		lzma_action action lzma_attribute((__unused__)))
52207753Smm{
53207753Smm	// Position where to start calculating CRC32. The idea is that we
54207753Smm	// need to call lzma_crc32() only once per call to index_encode().
55207753Smm	const size_t out_start = *out_pos;
56207753Smm
57207753Smm	// Return value to use if we return at the end of this function.
58207753Smm	// We use "goto out" to jump out of the while-switch construct
59207753Smm	// instead of returning directly, because that way we don't need
60207753Smm	// to copypaste the lzma_crc32() call to many places.
61207753Smm	lzma_ret ret = LZMA_OK;
62207753Smm
63207753Smm	while (*out_pos < out_size)
64207753Smm	switch (coder->sequence) {
65207753Smm	case SEQ_INDICATOR:
66207753Smm		out[*out_pos] = 0x00;
67207753Smm		++*out_pos;
68207753Smm		coder->sequence = SEQ_COUNT;
69207753Smm		break;
70207753Smm
71207753Smm	case SEQ_COUNT: {
72207753Smm		const lzma_vli count = lzma_index_block_count(coder->index);
73207753Smm		ret = lzma_vli_encode(count, &coder->pos,
74207753Smm				out, out_pos, out_size);
75207753Smm		if (ret != LZMA_STREAM_END)
76207753Smm			goto out;
77207753Smm
78207753Smm		ret = LZMA_OK;
79207753Smm		coder->pos = 0;
80207753Smm		coder->sequence = SEQ_NEXT;
81207753Smm		break;
82207753Smm	}
83207753Smm
84207753Smm	case SEQ_NEXT:
85207753Smm		if (lzma_index_iter_next(
86207753Smm				&coder->iter, LZMA_INDEX_ITER_BLOCK)) {
87207753Smm			// Get the size of the Index Padding field.
88207753Smm			coder->pos = lzma_index_padding_size(coder->index);
89207753Smm			assert(coder->pos <= 3);
90207753Smm			coder->sequence = SEQ_PADDING;
91207753Smm			break;
92207753Smm		}
93207753Smm
94207753Smm		coder->sequence = SEQ_UNPADDED;
95207753Smm
96207753Smm	// Fall through
97207753Smm
98207753Smm	case SEQ_UNPADDED:
99207753Smm	case SEQ_UNCOMPRESSED: {
100207753Smm		const lzma_vli size = coder->sequence == SEQ_UNPADDED
101207753Smm				? coder->iter.block.unpadded_size
102207753Smm				: coder->iter.block.uncompressed_size;
103207753Smm
104207753Smm		ret = lzma_vli_encode(size, &coder->pos,
105207753Smm				out, out_pos, out_size);
106207753Smm		if (ret != LZMA_STREAM_END)
107207753Smm			goto out;
108207753Smm
109207753Smm		ret = LZMA_OK;
110207753Smm		coder->pos = 0;
111207753Smm
112207753Smm		// Advance to SEQ_UNCOMPRESSED or SEQ_NEXT.
113207753Smm		++coder->sequence;
114207753Smm		break;
115207753Smm	}
116207753Smm
117207753Smm	case SEQ_PADDING:
118207753Smm		if (coder->pos > 0) {
119207753Smm			--coder->pos;
120207753Smm			out[(*out_pos)++] = 0x00;
121207753Smm			break;
122207753Smm		}
123207753Smm
124207753Smm		// Finish the CRC32 calculation.
125207753Smm		coder->crc32 = lzma_crc32(out + out_start,
126207753Smm				*out_pos - out_start, coder->crc32);
127207753Smm
128207753Smm		coder->sequence = SEQ_CRC32;
129207753Smm
130207753Smm	// Fall through
131207753Smm
132207753Smm	case SEQ_CRC32:
133207753Smm		// We don't use the main loop, because we don't want
134207753Smm		// coder->crc32 to be touched anymore.
135207753Smm		do {
136207753Smm			if (*out_pos == out_size)
137207753Smm				return LZMA_OK;
138207753Smm
139207753Smm			out[*out_pos] = (coder->crc32 >> (coder->pos * 8))
140207753Smm					& 0xFF;
141207753Smm			++*out_pos;
142207753Smm
143207753Smm		} while (++coder->pos < 4);
144207753Smm
145207753Smm		return LZMA_STREAM_END;
146207753Smm
147207753Smm	default:
148207753Smm		assert(0);
149207753Smm		return LZMA_PROG_ERROR;
150207753Smm	}
151207753Smm
152207753Smmout:
153207753Smm	// Update the CRC32.
154207753Smm	coder->crc32 = lzma_crc32(out + out_start,
155207753Smm			*out_pos - out_start, coder->crc32);
156207753Smm
157207753Smm	return ret;
158207753Smm}
159207753Smm
160207753Smm
161207753Smmstatic void
162207753Smmindex_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
163207753Smm{
164207753Smm	lzma_free(coder, allocator);
165207753Smm	return;
166207753Smm}
167207753Smm
168207753Smm
169207753Smmstatic void
170207753Smmindex_encoder_reset(lzma_coder *coder, const lzma_index *i)
171207753Smm{
172207753Smm	lzma_index_iter_init(&coder->iter, i);
173207753Smm
174207753Smm	coder->sequence = SEQ_INDICATOR;
175207753Smm	coder->index = i;
176207753Smm	coder->pos = 0;
177207753Smm	coder->crc32 = 0;
178207753Smm
179207753Smm	return;
180207753Smm}
181207753Smm
182207753Smm
183207753Smmextern lzma_ret
184207753Smmlzma_index_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
185207753Smm		const lzma_index *i)
186207753Smm{
187207753Smm	lzma_next_coder_init(&lzma_index_encoder_init, next, allocator);
188207753Smm
189207753Smm	if (i == NULL)
190207753Smm		return LZMA_PROG_ERROR;
191207753Smm
192207753Smm	if (next->coder == NULL) {
193207753Smm		next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
194207753Smm		if (next->coder == NULL)
195207753Smm			return LZMA_MEM_ERROR;
196207753Smm
197207753Smm		next->code = &index_encode;
198207753Smm		next->end = &index_encoder_end;
199207753Smm	}
200207753Smm
201207753Smm	index_encoder_reset(next->coder, i);
202207753Smm
203207753Smm	return LZMA_OK;
204207753Smm}
205207753Smm
206207753Smm
207207753Smmextern LZMA_API(lzma_ret)
208207753Smmlzma_index_encoder(lzma_stream *strm, const lzma_index *i)
209207753Smm{
210207753Smm	lzma_next_strm_init(lzma_index_encoder_init, strm, i);
211207753Smm
212207753Smm	strm->internal->supported_actions[LZMA_RUN] = true;
213215187Smm	strm->internal->supported_actions[LZMA_FINISH] = true;
214207753Smm
215207753Smm	return LZMA_OK;
216207753Smm}
217207753Smm
218207753Smm
219207753Smmextern LZMA_API(lzma_ret)
220207753Smmlzma_index_buffer_encode(const lzma_index *i,
221207753Smm		uint8_t *out, size_t *out_pos, size_t out_size)
222207753Smm{
223207753Smm	// Validate the arguments.
224207753Smm	if (i == NULL || out == NULL || out_pos == NULL || *out_pos > out_size)
225207753Smm		return LZMA_PROG_ERROR;
226207753Smm
227207753Smm	// Don't try to encode if there's not enough output space.
228207753Smm	if (out_size - *out_pos < lzma_index_size(i))
229207753Smm		return LZMA_BUF_ERROR;
230207753Smm
231207753Smm	// The Index encoder needs just one small data structure so we can
232207753Smm	// allocate it on stack.
233207753Smm	lzma_coder coder;
234207753Smm	index_encoder_reset(&coder, i);
235207753Smm
236207753Smm	// Do the actual encoding. This should never fail, but store
237207753Smm	// the original *out_pos just in case.
238207753Smm	const size_t out_start = *out_pos;
239207753Smm	lzma_ret ret = index_encode(&coder, NULL, NULL, NULL, 0,
240207753Smm			out, out_pos, out_size, LZMA_RUN);
241207753Smm
242207753Smm	if (ret == LZMA_STREAM_END) {
243207753Smm		ret = LZMA_OK;
244207753Smm	} else {
245207753Smm		// We should never get here, but just in case, restore the
246207753Smm		// output position and set the error accordingly if something
247207753Smm		// goes wrong and debugging isn't enabled.
248207753Smm		assert(0);
249207753Smm		*out_pos = out_start;
250207753Smm		ret = LZMA_PROG_ERROR;
251207753Smm	}
252207753Smm
253207753Smm	return ret;
254207753Smm}
255