xref: /freebsd/contrib/xz/src/liblzma/common/index_encoder.c (revision 6829dae12bb055451fa467da4589c43bd03b1e64)
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 /// \file       index_encoder.c
4 /// \brief      Encodes the Index field
5 //
6 //  Author:     Lasse Collin
7 //
8 //  This file has been put into the public domain.
9 //  You can do whatever you want with this file.
10 //
11 ///////////////////////////////////////////////////////////////////////////////
12 
13 #include "index_encoder.h"
14 #include "index.h"
15 #include "check.h"
16 
17 
18 typedef struct {
19 	enum {
20 		SEQ_INDICATOR,
21 		SEQ_COUNT,
22 		SEQ_UNPADDED,
23 		SEQ_UNCOMPRESSED,
24 		SEQ_NEXT,
25 		SEQ_PADDING,
26 		SEQ_CRC32,
27 	} sequence;
28 
29 	/// Index being encoded
30 	const lzma_index *index;
31 
32 	/// Iterator for the Index being encoded
33 	lzma_index_iter iter;
34 
35 	/// Position in integers
36 	size_t pos;
37 
38 	/// CRC32 of the List of Records field
39 	uint32_t crc32;
40 } lzma_index_coder;
41 
42 
43 static lzma_ret
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,
50 		size_t out_size,
51 		lzma_action action lzma_attribute((__unused__)))
52 {
53 	lzma_index_coder *coder = coder_ptr;
54 
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;
58 
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;
64 
65 	while (*out_pos < out_size)
66 	switch (coder->sequence) {
67 	case SEQ_INDICATOR:
68 		out[*out_pos] = 0x00;
69 		++*out_pos;
70 		coder->sequence = SEQ_COUNT;
71 		break;
72 
73 	case 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)
78 			goto out;
79 
80 		ret = LZMA_OK;
81 		coder->pos = 0;
82 		coder->sequence = SEQ_NEXT;
83 		break;
84 	}
85 
86 	case 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;
93 			break;
94 		}
95 
96 		coder->sequence = SEQ_UNPADDED;
97 
98 	// Fall through
99 
100 	case 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;
105 
106 		ret = lzma_vli_encode(size, &coder->pos,
107 				out, out_pos, out_size);
108 		if (ret != LZMA_STREAM_END)
109 			goto out;
110 
111 		ret = LZMA_OK;
112 		coder->pos = 0;
113 
114 		// Advance to SEQ_UNCOMPRESSED or SEQ_NEXT.
115 		++coder->sequence;
116 		break;
117 	}
118 
119 	case SEQ_PADDING:
120 		if (coder->pos > 0) {
121 			--coder->pos;
122 			out[(*out_pos)++] = 0x00;
123 			break;
124 		}
125 
126 		// Finish the CRC32 calculation.
127 		coder->crc32 = lzma_crc32(out + out_start,
128 				*out_pos - out_start, coder->crc32);
129 
130 		coder->sequence = SEQ_CRC32;
131 
132 	// Fall through
133 
134 	case SEQ_CRC32:
135 		// We don't use the main loop, because we don't want
136 		// coder->crc32 to be touched anymore.
137 		do {
138 			if (*out_pos == out_size)
139 				return LZMA_OK;
140 
141 			out[*out_pos] = (coder->crc32 >> (coder->pos * 8))
142 					& 0xFF;
143 			++*out_pos;
144 
145 		} while (++coder->pos < 4);
146 
147 		return LZMA_STREAM_END;
148 
149 	default:
150 		assert(0);
151 		return LZMA_PROG_ERROR;
152 	}
153 
154 out:
155 	// Update the CRC32.
156 	coder->crc32 = lzma_crc32(out + out_start,
157 			*out_pos - out_start, coder->crc32);
158 
159 	return ret;
160 }
161 
162 
163 static void
164 index_encoder_end(void *coder, const lzma_allocator *allocator)
165 {
166 	lzma_free(coder, allocator);
167 	return;
168 }
169 
170 
171 static void
172 index_encoder_reset(lzma_index_coder *coder, const lzma_index *i)
173 {
174 	lzma_index_iter_init(&coder->iter, i);
175 
176 	coder->sequence = SEQ_INDICATOR;
177 	coder->index = i;
178 	coder->pos = 0;
179 	coder->crc32 = 0;
180 
181 	return;
182 }
183 
184 
185 extern lzma_ret
186 lzma_index_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
187 		const lzma_index *i)
188 {
189 	lzma_next_coder_init(&lzma_index_encoder_init, next, allocator);
190 
191 	if (i == NULL)
192 		return LZMA_PROG_ERROR;
193 
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;
198 
199 		next->code = &index_encode;
200 		next->end = &index_encoder_end;
201 	}
202 
203 	index_encoder_reset(next->coder, i);
204 
205 	return LZMA_OK;
206 }
207 
208 
209 extern LZMA_API(lzma_ret)
210 lzma_index_encoder(lzma_stream *strm, const lzma_index *i)
211 {
212 	lzma_next_strm_init(lzma_index_encoder_init, strm, i);
213 
214 	strm->internal->supported_actions[LZMA_RUN] = true;
215 	strm->internal->supported_actions[LZMA_FINISH] = true;
216 
217 	return LZMA_OK;
218 }
219 
220 
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)
224 {
225 	// Validate the arguments.
226 	if (i == NULL || out == NULL || out_pos == NULL || *out_pos > out_size)
227 		return LZMA_PROG_ERROR;
228 
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;
232 
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);
237 
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);
243 
244 	if (ret == LZMA_STREAM_END) {
245 		ret = LZMA_OK;
246 	} else {
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.
250 		assert(0);
251 		*out_pos = out_start;
252 		ret = LZMA_PROG_ERROR;
253 	}
254 
255 	return ret;
256 }
257