index_encoder.c revision 207842
1139825Simp/////////////////////////////////////////////////////////////////////////////// 286231Stmm// 386231Stmm/// \file index_encoder.c 486231Stmm/// \brief Encodes the Index field 586231Stmm// 686231Stmm// Author: Lasse Collin 786231Stmm// 886231Stmm// This file has been put into the public domain. 986231Stmm// You can do whatever you want with this file. 1086231Stmm// 1186231Stmm/////////////////////////////////////////////////////////////////////////////// 1286231Stmm 1386231Stmm#include "index_encoder.h" 1486231Stmm#include "index.h" 1586231Stmm#include "check.h" 1686231Stmm 1786231Stmm 1886231Stmmstruct lzma_coder_s { 1986231Stmm enum { 2086231Stmm SEQ_INDICATOR, 2186231Stmm SEQ_COUNT, 2286231Stmm SEQ_UNPADDED, 2386231Stmm SEQ_UNCOMPRESSED, 2486231Stmm SEQ_NEXT, 2586231Stmm SEQ_PADDING, 26219567Smarius SEQ_CRC32, 2786231Stmm } sequence; 2886231Stmm 2986231Stmm /// Index being encoded 3086231Stmm const lzma_index *index; 3186231Stmm 3286231Stmm /// Iterator for the Index being encoded 3386231Stmm lzma_index_iter iter; 3486231Stmm 35128625Stmm /// Position in integers 36128625Stmm size_t pos; 3786231Stmm 3886231Stmm /// CRC32 of the List of Records field 39220147Smarius uint32_t crc32; 40220039Smarius}; 4186231Stmm 4286231Stmm 43170851Smariusstatic lzma_ret 44170851Smariusindex_encode(lzma_coder *coder, 4586231Stmm lzma_allocator *allocator lzma_attribute((unused)), 46174117Smarius const uint8_t *restrict in lzma_attribute((unused)), 4786231Stmm size_t *restrict in_pos lzma_attribute((unused)), 4890617Stmm size_t in_size lzma_attribute((unused)), 4990617Stmm uint8_t *restrict out, size_t *restrict out_pos, 50152696Smarius size_t out_size, lzma_action action lzma_attribute((unused))) 51174117Smarius{ 52190109Smarius // Position where to start calculating CRC32. The idea is that we 53190109Smarius // need to call lzma_crc32() only once per call to index_encode(). 5486231Stmm const size_t out_start = *out_pos; 55115417Stmm 56174117Smarius // Return value to use if we return at the end of this function. 57115417Stmm // We use "goto out" to jump out of the while-switch construct 5886231Stmm // instead of returning directly, because that way we don't need 5986231Stmm // to copypaste the lzma_crc32() call to many places. 6088823Stmm lzma_ret ret = LZMA_OK; 61152696Smarius 62152696Smarius while (*out_pos < out_size) 6386231Stmm switch (coder->sequence) { 64152696Smarius case SEQ_INDICATOR: 65117119Stmm out[*out_pos] = 0x00; 66152696Smarius ++*out_pos; 67152696Smarius coder->sequence = SEQ_COUNT; 68152696Smarius break; 69152696Smarius 7086231Stmm case SEQ_COUNT: { 71152696Smarius const lzma_vli count = lzma_index_block_count(coder->index); 7286231Stmm ret = lzma_vli_encode(count, &coder->pos, 73152696Smarius out, out_pos, out_size); 74152696Smarius if (ret != LZMA_STREAM_END) 75105274Stmm goto out; 76178279Smarius 77201395Smarius ret = LZMA_OK; 78178279Smarius coder->pos = 0; 79174117Smarius coder->sequence = SEQ_NEXT; 80174117Smarius break; 81105274Stmm } 8286231Stmm 8386231Stmm case SEQ_NEXT: 84152696Smarius if (lzma_index_iter_next( 85 &coder->iter, LZMA_INDEX_ITER_BLOCK)) { 86 // Get the size of the Index Padding field. 87 coder->pos = lzma_index_padding_size(coder->index); 88 assert(coder->pos <= 3); 89 coder->sequence = SEQ_PADDING; 90 break; 91 } 92 93 coder->sequence = SEQ_UNPADDED; 94 95 // Fall through 96 97 case SEQ_UNPADDED: 98 case SEQ_UNCOMPRESSED: { 99 const lzma_vli size = coder->sequence == SEQ_UNPADDED 100 ? coder->iter.block.unpadded_size 101 : coder->iter.block.uncompressed_size; 102 103 ret = lzma_vli_encode(size, &coder->pos, 104 out, out_pos, out_size); 105 if (ret != LZMA_STREAM_END) 106 goto out; 107 108 ret = LZMA_OK; 109 coder->pos = 0; 110 111 // Advance to SEQ_UNCOMPRESSED or SEQ_NEXT. 112 ++coder->sequence; 113 break; 114 } 115 116 case SEQ_PADDING: 117 if (coder->pos > 0) { 118 --coder->pos; 119 out[(*out_pos)++] = 0x00; 120 break; 121 } 122 123 // Finish the CRC32 calculation. 124 coder->crc32 = lzma_crc32(out + out_start, 125 *out_pos - out_start, coder->crc32); 126 127 coder->sequence = SEQ_CRC32; 128 129 // Fall through 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 151out: 152 // Update the CRC32. 153 coder->crc32 = lzma_crc32(out + out_start, 154 *out_pos - out_start, coder->crc32); 155 156 return ret; 157} 158 159 160static void 161index_encoder_end(lzma_coder *coder, lzma_allocator *allocator) 162{ 163 lzma_free(coder, allocator); 164 return; 165} 166 167 168static void 169index_encoder_reset(lzma_coder *coder, const lzma_index *i) 170{ 171 lzma_index_iter_init(&coder->iter, i); 172 173 coder->sequence = SEQ_INDICATOR; 174 coder->index = i; 175 coder->pos = 0; 176 coder->crc32 = 0; 177 178 return; 179} 180 181 182extern lzma_ret 183lzma_index_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, 184 const lzma_index *i) 185{ 186 lzma_next_coder_init(&lzma_index_encoder_init, next, allocator); 187 188 if (i == NULL) 189 return LZMA_PROG_ERROR; 190 191 if (next->coder == NULL) { 192 next->coder = lzma_alloc(sizeof(lzma_coder), allocator); 193 if (next->coder == NULL) 194 return LZMA_MEM_ERROR; 195 196 next->code = &index_encode; 197 next->end = &index_encoder_end; 198 } 199 200 index_encoder_reset(next->coder, i); 201 202 return LZMA_OK; 203} 204 205 206extern LZMA_API(lzma_ret) 207lzma_index_encoder(lzma_stream *strm, const lzma_index *i) 208{ 209 lzma_next_strm_init(lzma_index_encoder_init, strm, i); 210 211 strm->internal->supported_actions[LZMA_RUN] = true; 212 213 return LZMA_OK; 214} 215 216 217extern LZMA_API(lzma_ret) 218lzma_index_buffer_encode(const lzma_index *i, 219 uint8_t *out, size_t *out_pos, size_t out_size) 220{ 221 // Validate the arguments. 222 if (i == NULL || out == NULL || out_pos == NULL || *out_pos > out_size) 223 return LZMA_PROG_ERROR; 224 225 // Don't try to encode if there's not enough output space. 226 if (out_size - *out_pos < lzma_index_size(i)) 227 return LZMA_BUF_ERROR; 228 229 // The Index encoder needs just one small data structure so we can 230 // allocate it on stack. 231 lzma_coder coder; 232 index_encoder_reset(&coder, i); 233 234 // Do the actual encoding. This should never fail, but store 235 // the original *out_pos just in case. 236 const size_t out_start = *out_pos; 237 lzma_ret ret = index_encode(&coder, NULL, NULL, NULL, 0, 238 out, out_pos, out_size, LZMA_RUN); 239 240 if (ret == LZMA_STREAM_END) { 241 ret = LZMA_OK; 242 } else { 243 // We should never get here, but just in case, restore the 244 // output position and set the error accordingly if something 245 // goes wrong and debugging isn't enabled. 246 assert(0); 247 *out_pos = out_start; 248 ret = LZMA_PROG_ERROR; 249 } 250 251 return ret; 252} 253