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