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 struct lzma_coder_s { 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 }; 41 42 43 static lzma_ret 44 index_encode(lzma_coder *coder, 45 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, lzma_action action lzma_attribute((unused))) 51 { 52 // Position where to start calculating CRC32. The idea is that we 53 // need to call lzma_crc32() only once per call to index_encode(). 54 const size_t out_start = *out_pos; 55 56 // Return value to use if we return at the end of this function. 57 // We use "goto out" to jump out of the while-switch construct 58 // instead of returning directly, because that way we don't need 59 // to copypaste the lzma_crc32() call to many places. 60 lzma_ret ret = LZMA_OK; 61 62 while (*out_pos < out_size) 63 switch (coder->sequence) { 64 case SEQ_INDICATOR: 65 out[*out_pos] = 0x00; 66 ++*out_pos; 67 coder->sequence = SEQ_COUNT; 68 break; 69 70 case SEQ_COUNT: { 71 const lzma_vli count = lzma_index_block_count(coder->index); 72 ret = lzma_vli_encode(count, &coder->pos, 73 out, out_pos, out_size); 74 if (ret != LZMA_STREAM_END) 75 goto out; 76 77 ret = LZMA_OK; 78 coder->pos = 0; 79 coder->sequence = SEQ_NEXT; 80 break; 81 } 82 83 case SEQ_NEXT: 84 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 151 out: 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 160 static void 161 index_encoder_end(lzma_coder *coder, lzma_allocator *allocator) 162 { 163 lzma_free(coder, allocator); 164 return; 165 } 166 167 168 static void 169 index_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 182 extern lzma_ret 183 lzma_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 206 extern LZMA_API(lzma_ret) 207 lzma_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 strm->internal->supported_actions[LZMA_FINISH] = true; 213 214 return LZMA_OK; 215 } 216 217 218 extern LZMA_API(lzma_ret) 219 lzma_index_buffer_encode(const lzma_index *i, 220 uint8_t *out, size_t *out_pos, size_t out_size) 221 { 222 // Validate the arguments. 223 if (i == NULL || out == NULL || out_pos == NULL || *out_pos > out_size) 224 return LZMA_PROG_ERROR; 225 226 // Don't try to encode if there's not enough output space. 227 if (out_size - *out_pos < lzma_index_size(i)) 228 return LZMA_BUF_ERROR; 229 230 // The Index encoder needs just one small data structure so we can 231 // allocate it on stack. 232 lzma_coder coder; 233 index_encoder_reset(&coder, i); 234 235 // Do the actual encoding. This should never fail, but store 236 // the original *out_pos just in case. 237 const size_t out_start = *out_pos; 238 lzma_ret ret = index_encode(&coder, NULL, NULL, NULL, 0, 239 out, out_pos, out_size, LZMA_RUN); 240 241 if (ret == LZMA_STREAM_END) { 242 ret = LZMA_OK; 243 } else { 244 // We should never get here, but just in case, restore the 245 // output position and set the error accordingly if something 246 // goes wrong and debugging isn't enabled. 247 assert(0); 248 *out_pos = out_start; 249 ret = LZMA_PROG_ERROR; 250 } 251 252 return ret; 253 } 254