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, 45223935Smm lzma_allocator *allocator lzma_attribute((__unused__)), 46223935Smm const uint8_t *restrict in lzma_attribute((__unused__)), 47223935Smm size_t *restrict in_pos lzma_attribute((__unused__)), 48223935Smm size_t in_size lzma_attribute((__unused__)), 49207753Smm uint8_t *restrict out, size_t *restrict out_pos, 50223935Smm size_t out_size, 51223935Smm lzma_action action lzma_attribute((__unused__))) 52207753Smm{ 53207753Smm // Position where to start calculating CRC32. The idea is that we 54207753Smm // need to call lzma_crc32() only once per call to index_encode(). 55207753Smm const size_t out_start = *out_pos; 56207753Smm 57207753Smm // Return value to use if we return at the end of this function. 58207753Smm // We use "goto out" to jump out of the while-switch construct 59207753Smm // instead of returning directly, because that way we don't need 60207753Smm // to copypaste the lzma_crc32() call to many places. 61207753Smm lzma_ret ret = LZMA_OK; 62207753Smm 63207753Smm while (*out_pos < out_size) 64207753Smm switch (coder->sequence) { 65207753Smm case SEQ_INDICATOR: 66207753Smm out[*out_pos] = 0x00; 67207753Smm ++*out_pos; 68207753Smm coder->sequence = SEQ_COUNT; 69207753Smm break; 70207753Smm 71207753Smm case SEQ_COUNT: { 72207753Smm const lzma_vli count = lzma_index_block_count(coder->index); 73207753Smm ret = lzma_vli_encode(count, &coder->pos, 74207753Smm out, out_pos, out_size); 75207753Smm if (ret != LZMA_STREAM_END) 76207753Smm goto out; 77207753Smm 78207753Smm ret = LZMA_OK; 79207753Smm coder->pos = 0; 80207753Smm coder->sequence = SEQ_NEXT; 81207753Smm break; 82207753Smm } 83207753Smm 84207753Smm case SEQ_NEXT: 85207753Smm if (lzma_index_iter_next( 86207753Smm &coder->iter, LZMA_INDEX_ITER_BLOCK)) { 87207753Smm // Get the size of the Index Padding field. 88207753Smm coder->pos = lzma_index_padding_size(coder->index); 89207753Smm assert(coder->pos <= 3); 90207753Smm coder->sequence = SEQ_PADDING; 91207753Smm break; 92207753Smm } 93207753Smm 94207753Smm coder->sequence = SEQ_UNPADDED; 95207753Smm 96207753Smm // Fall through 97207753Smm 98207753Smm case SEQ_UNPADDED: 99207753Smm case SEQ_UNCOMPRESSED: { 100207753Smm const lzma_vli size = coder->sequence == SEQ_UNPADDED 101207753Smm ? coder->iter.block.unpadded_size 102207753Smm : coder->iter.block.uncompressed_size; 103207753Smm 104207753Smm ret = lzma_vli_encode(size, &coder->pos, 105207753Smm out, out_pos, out_size); 106207753Smm if (ret != LZMA_STREAM_END) 107207753Smm goto out; 108207753Smm 109207753Smm ret = LZMA_OK; 110207753Smm coder->pos = 0; 111207753Smm 112207753Smm // Advance to SEQ_UNCOMPRESSED or SEQ_NEXT. 113207753Smm ++coder->sequence; 114207753Smm break; 115207753Smm } 116207753Smm 117207753Smm case SEQ_PADDING: 118207753Smm if (coder->pos > 0) { 119207753Smm --coder->pos; 120207753Smm out[(*out_pos)++] = 0x00; 121207753Smm break; 122207753Smm } 123207753Smm 124207753Smm // Finish the CRC32 calculation. 125207753Smm coder->crc32 = lzma_crc32(out + out_start, 126207753Smm *out_pos - out_start, coder->crc32); 127207753Smm 128207753Smm coder->sequence = SEQ_CRC32; 129207753Smm 130207753Smm // Fall through 131207753Smm 132207753Smm case SEQ_CRC32: 133207753Smm // We don't use the main loop, because we don't want 134207753Smm // coder->crc32 to be touched anymore. 135207753Smm do { 136207753Smm if (*out_pos == out_size) 137207753Smm return LZMA_OK; 138207753Smm 139207753Smm out[*out_pos] = (coder->crc32 >> (coder->pos * 8)) 140207753Smm & 0xFF; 141207753Smm ++*out_pos; 142207753Smm 143207753Smm } while (++coder->pos < 4); 144207753Smm 145207753Smm return LZMA_STREAM_END; 146207753Smm 147207753Smm default: 148207753Smm assert(0); 149207753Smm return LZMA_PROG_ERROR; 150207753Smm } 151207753Smm 152207753Smmout: 153207753Smm // Update the CRC32. 154207753Smm coder->crc32 = lzma_crc32(out + out_start, 155207753Smm *out_pos - out_start, coder->crc32); 156207753Smm 157207753Smm return ret; 158207753Smm} 159207753Smm 160207753Smm 161207753Smmstatic void 162207753Smmindex_encoder_end(lzma_coder *coder, lzma_allocator *allocator) 163207753Smm{ 164207753Smm lzma_free(coder, allocator); 165207753Smm return; 166207753Smm} 167207753Smm 168207753Smm 169207753Smmstatic void 170207753Smmindex_encoder_reset(lzma_coder *coder, const lzma_index *i) 171207753Smm{ 172207753Smm lzma_index_iter_init(&coder->iter, i); 173207753Smm 174207753Smm coder->sequence = SEQ_INDICATOR; 175207753Smm coder->index = i; 176207753Smm coder->pos = 0; 177207753Smm coder->crc32 = 0; 178207753Smm 179207753Smm return; 180207753Smm} 181207753Smm 182207753Smm 183207753Smmextern lzma_ret 184207753Smmlzma_index_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, 185207753Smm const lzma_index *i) 186207753Smm{ 187207753Smm lzma_next_coder_init(&lzma_index_encoder_init, next, allocator); 188207753Smm 189207753Smm if (i == NULL) 190207753Smm return LZMA_PROG_ERROR; 191207753Smm 192207753Smm if (next->coder == NULL) { 193207753Smm next->coder = lzma_alloc(sizeof(lzma_coder), allocator); 194207753Smm if (next->coder == NULL) 195207753Smm return LZMA_MEM_ERROR; 196207753Smm 197207753Smm next->code = &index_encode; 198207753Smm next->end = &index_encoder_end; 199207753Smm } 200207753Smm 201207753Smm index_encoder_reset(next->coder, i); 202207753Smm 203207753Smm return LZMA_OK; 204207753Smm} 205207753Smm 206207753Smm 207207753Smmextern LZMA_API(lzma_ret) 208207753Smmlzma_index_encoder(lzma_stream *strm, const lzma_index *i) 209207753Smm{ 210207753Smm lzma_next_strm_init(lzma_index_encoder_init, strm, i); 211207753Smm 212207753Smm strm->internal->supported_actions[LZMA_RUN] = true; 213215187Smm strm->internal->supported_actions[LZMA_FINISH] = true; 214207753Smm 215207753Smm return LZMA_OK; 216207753Smm} 217207753Smm 218207753Smm 219207753Smmextern LZMA_API(lzma_ret) 220207753Smmlzma_index_buffer_encode(const lzma_index *i, 221207753Smm uint8_t *out, size_t *out_pos, size_t out_size) 222207753Smm{ 223207753Smm // Validate the arguments. 224207753Smm if (i == NULL || out == NULL || out_pos == NULL || *out_pos > out_size) 225207753Smm return LZMA_PROG_ERROR; 226207753Smm 227207753Smm // Don't try to encode if there's not enough output space. 228207753Smm if (out_size - *out_pos < lzma_index_size(i)) 229207753Smm return LZMA_BUF_ERROR; 230207753Smm 231207753Smm // The Index encoder needs just one small data structure so we can 232207753Smm // allocate it on stack. 233207753Smm lzma_coder coder; 234207753Smm index_encoder_reset(&coder, i); 235207753Smm 236207753Smm // Do the actual encoding. This should never fail, but store 237207753Smm // the original *out_pos just in case. 238207753Smm const size_t out_start = *out_pos; 239207753Smm lzma_ret ret = index_encode(&coder, NULL, NULL, NULL, 0, 240207753Smm out, out_pos, out_size, LZMA_RUN); 241207753Smm 242207753Smm if (ret == LZMA_STREAM_END) { 243207753Smm ret = LZMA_OK; 244207753Smm } else { 245207753Smm // We should never get here, but just in case, restore the 246207753Smm // output position and set the error accordingly if something 247207753Smm // goes wrong and debugging isn't enabled. 248207753Smm assert(0); 249207753Smm *out_pos = out_start; 250207753Smm ret = LZMA_PROG_ERROR; 251207753Smm } 252207753Smm 253207753Smm return ret; 254207753Smm} 255