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