Home | History | Annotate | Line # | Download | only in common
      1 // SPDX-License-Identifier: 0BSD
      2 
      3 ///////////////////////////////////////////////////////////////////////////////
      4 //
      5 /// \file       index_encoder.c
      6 /// \brief      Encodes the Index field
      7 //
      8 //  Author:     Lasse Collin
      9 //
     10 ///////////////////////////////////////////////////////////////////////////////
     11 
     12 #include "index_encoder.h"
     13 #include "index.h"
     14 #include "check.h"
     15 
     16 
     17 typedef struct {
     18 	enum {
     19 		SEQ_INDICATOR,
     20 		SEQ_COUNT,
     21 		SEQ_UNPADDED,
     22 		SEQ_UNCOMPRESSED,
     23 		SEQ_NEXT,
     24 		SEQ_PADDING,
     25 		SEQ_CRC32,
     26 	} sequence;
     27 
     28 	/// Index being encoded
     29 	const lzma_index *index;
     30 
     31 	/// Iterator for the Index being encoded
     32 	lzma_index_iter iter;
     33 
     34 	/// Position in integers
     35 	size_t pos;
     36 
     37 	/// CRC32 of the List of Records field
     38 	uint32_t crc32;
     39 } lzma_index_coder;
     40 
     41 
     42 static lzma_ret
     43 index_encode(void *coder_ptr,
     44 		const lzma_allocator *allocator lzma_attribute((__unused__)),
     45 		const uint8_t *restrict in lzma_attribute((__unused__)),
     46 		size_t *restrict in_pos lzma_attribute((__unused__)),
     47 		size_t in_size lzma_attribute((__unused__)),
     48 		uint8_t *restrict out, size_t *restrict out_pos,
     49 		size_t out_size,
     50 		lzma_action action lzma_attribute((__unused__)))
     51 {
     52 	lzma_index_coder *coder = coder_ptr;
     53 
     54 	// Position where to start calculating CRC32. The idea is that we
     55 	// need to call lzma_crc32() only once per call to index_encode().
     56 	const size_t out_start = *out_pos;
     57 
     58 	// Return value to use if we return at the end of this function.
     59 	// We use "goto out" to jump out of the while-switch construct
     60 	// instead of returning directly, because that way we don't need
     61 	// to copypaste the lzma_crc32() call to many places.
     62 	lzma_ret ret = LZMA_OK;
     63 
     64 	while (*out_pos < out_size)
     65 	switch (coder->sequence) {
     66 	case SEQ_INDICATOR:
     67 		out[*out_pos] = INDEX_INDICATOR;
     68 		++*out_pos;
     69 		coder->sequence = SEQ_COUNT;
     70 		break;
     71 
     72 	case SEQ_COUNT: {
     73 		const lzma_vli count = lzma_index_block_count(coder->index);
     74 		ret = lzma_vli_encode(count, &coder->pos,
     75 				out, out_pos, out_size);
     76 		if (ret != LZMA_STREAM_END)
     77 			goto out;
     78 
     79 		ret = LZMA_OK;
     80 		coder->pos = 0;
     81 		coder->sequence = SEQ_NEXT;
     82 		break;
     83 	}
     84 
     85 	case SEQ_NEXT:
     86 		if (lzma_index_iter_next(
     87 				&coder->iter, LZMA_INDEX_ITER_BLOCK)) {
     88 			// Get the size of the Index Padding field.
     89 			coder->pos = lzma_index_padding_size(coder->index);
     90 			assert(coder->pos <= 3);
     91 			coder->sequence = SEQ_PADDING;
     92 			break;
     93 		}
     94 
     95 		coder->sequence = SEQ_UNPADDED;
     96 		FALLTHROUGH;
     97 
     98 	case SEQ_UNPADDED:
     99 	case SEQ_UNCOMPRESSED: {
    100 		const lzma_vli size = coder->sequence == SEQ_UNPADDED
    101 				? coder->iter.block.unpadded_size
    102 				: coder->iter.block.uncompressed_size;
    103 
    104 		ret = lzma_vli_encode(size, &coder->pos,
    105 				out, out_pos, out_size);
    106 		if (ret != LZMA_STREAM_END)
    107 			goto out;
    108 
    109 		ret = LZMA_OK;
    110 		coder->pos = 0;
    111 
    112 		// Advance to SEQ_UNCOMPRESSED or SEQ_NEXT.
    113 		++coder->sequence;
    114 		break;
    115 	}
    116 
    117 	case SEQ_PADDING:
    118 		if (coder->pos > 0) {
    119 			--coder->pos;
    120 			out[(*out_pos)++] = 0x00;
    121 			break;
    122 		}
    123 
    124 		// Finish the CRC32 calculation.
    125 		coder->crc32 = lzma_crc32(out + out_start,
    126 				*out_pos - out_start, coder->crc32);
    127 
    128 		coder->sequence = SEQ_CRC32;
    129 		FALLTHROUGH;
    130 
    131 	case SEQ_CRC32:
    132 		// We don't use the main loop, because we don't want
    133 		// coder->crc32 to be touched anymore.
    134 		do {
    135 			if (*out_pos == out_size)
    136 				return LZMA_OK;
    137 
    138 			out[*out_pos] = (coder->crc32 >> (coder->pos * 8))
    139 					& 0xFF;
    140 			++*out_pos;
    141 
    142 		} while (++coder->pos < 4);
    143 
    144 		return LZMA_STREAM_END;
    145 
    146 	default:
    147 		assert(0);
    148 		return LZMA_PROG_ERROR;
    149 	}
    150 
    151 out:
    152 	// Update the CRC32.
    153 	//
    154 	// Avoid null pointer + 0 (undefined behavior) in "out + out_start".
    155 	// In such a case we had no input and thus out_used == 0.
    156 	{
    157 		const size_t out_used = *out_pos - out_start;
    158 		if (out_used > 0)
    159 			coder->crc32 = lzma_crc32(out + out_start,
    160 					out_used, coder->crc32);
    161 	}
    162 
    163 	return ret;
    164 }
    165 
    166 
    167 static void
    168 index_encoder_end(void *coder, const lzma_allocator *allocator)
    169 {
    170 	lzma_free(coder, allocator);
    171 	return;
    172 }
    173 
    174 
    175 static void
    176 index_encoder_reset(lzma_index_coder *coder, const lzma_index *i)
    177 {
    178 	lzma_index_iter_init(&coder->iter, i);
    179 
    180 	coder->sequence = SEQ_INDICATOR;
    181 	coder->index = i;
    182 	coder->pos = 0;
    183 	coder->crc32 = 0;
    184 
    185 	return;
    186 }
    187 
    188 
    189 extern lzma_ret
    190 lzma_index_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
    191 		const lzma_index *i)
    192 {
    193 	lzma_next_coder_init(&lzma_index_encoder_init, next, allocator);
    194 
    195 	if (i == NULL)
    196 		return LZMA_PROG_ERROR;
    197 
    198 	if (next->coder == NULL) {
    199 		next->coder = lzma_alloc(sizeof(lzma_index_coder), allocator);
    200 		if (next->coder == NULL)
    201 			return LZMA_MEM_ERROR;
    202 
    203 		next->code = &index_encode;
    204 		next->end = &index_encoder_end;
    205 	}
    206 
    207 	index_encoder_reset(next->coder, i);
    208 
    209 	return LZMA_OK;
    210 }
    211 
    212 
    213 extern LZMA_API(lzma_ret)
    214 lzma_index_encoder(lzma_stream *strm, const lzma_index *i)
    215 {
    216 	lzma_next_strm_init(lzma_index_encoder_init, strm, i);
    217 
    218 	strm->internal->supported_actions[LZMA_RUN] = true;
    219 	strm->internal->supported_actions[LZMA_FINISH] = true;
    220 
    221 	return LZMA_OK;
    222 }
    223 
    224 
    225 extern LZMA_API(lzma_ret)
    226 lzma_index_buffer_encode(const lzma_index *i,
    227 		uint8_t *out, size_t *out_pos, size_t out_size)
    228 {
    229 	// Validate the arguments.
    230 	if (i == NULL || out == NULL || out_pos == NULL || *out_pos > out_size)
    231 		return LZMA_PROG_ERROR;
    232 
    233 	// Don't try to encode if there's not enough output space.
    234 	if (out_size - *out_pos < lzma_index_size(i))
    235 		return LZMA_BUF_ERROR;
    236 
    237 	// The Index encoder needs just one small data structure so we can
    238 	// allocate it on stack.
    239 	lzma_index_coder coder;
    240 	index_encoder_reset(&coder, i);
    241 
    242 	// Do the actual encoding. This should never fail, but store
    243 	// the original *out_pos just in case.
    244 	const size_t out_start = *out_pos;
    245 	lzma_ret ret = index_encode(&coder, NULL, NULL, NULL, 0,
    246 			out, out_pos, out_size, LZMA_RUN);
    247 
    248 	if (ret == LZMA_STREAM_END) {
    249 		ret = LZMA_OK;
    250 	} else {
    251 		// We should never get here, but just in case, restore the
    252 		// output position and set the error accordingly if something
    253 		// goes wrong and debugging isn't enabled.
    254 		assert(0);
    255 		*out_pos = out_start;
    256 		ret = LZMA_PROG_ERROR;
    257 	}
    258 
    259 	return ret;
    260 }
    261