1207753Smm/////////////////////////////////////////////////////////////////////////////// 2207753Smm// 3207753Smm/// \file stream_encoder.c 4207753Smm/// \brief Encodes .xz Streams 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 "stream_encoder.h" 14207753Smm#include "block_encoder.h" 15207753Smm#include "index_encoder.h" 16207753Smm 17207753Smm 18207753Smmstruct lzma_coder_s { 19207753Smm enum { 20207753Smm SEQ_STREAM_HEADER, 21207753Smm SEQ_BLOCK_INIT, 22207753Smm SEQ_BLOCK_HEADER, 23207753Smm SEQ_BLOCK_ENCODE, 24207753Smm SEQ_INDEX_ENCODE, 25207753Smm SEQ_STREAM_FOOTER, 26207753Smm } sequence; 27207753Smm 28207753Smm /// True if Block encoder has been initialized by 29207753Smm /// lzma_stream_encoder_init() or stream_encoder_update() 30207753Smm /// and thus doesn't need to be initialized in stream_encode(). 31207753Smm bool block_encoder_is_initialized; 32207753Smm 33207753Smm /// Block 34207753Smm lzma_next_coder block_encoder; 35207753Smm 36207753Smm /// Options for the Block encoder 37207753Smm lzma_block block_options; 38207753Smm 39207753Smm /// The filter chain currently in use 40207753Smm lzma_filter filters[LZMA_FILTERS_MAX + 1]; 41207753Smm 42207753Smm /// Index encoder. This is separate from Block encoder, because this 43207753Smm /// doesn't take much memory, and when encoding multiple Streams 44207753Smm /// with the same encoding options we avoid reallocating memory. 45207753Smm lzma_next_coder index_encoder; 46207753Smm 47207753Smm /// Index to hold sizes of the Blocks 48207753Smm lzma_index *index; 49207753Smm 50207753Smm /// Read position in buffer[] 51207753Smm size_t buffer_pos; 52207753Smm 53207753Smm /// Total number of bytes in buffer[] 54207753Smm size_t buffer_size; 55207753Smm 56207753Smm /// Buffer to hold Stream Header, Block Header, and Stream Footer. 57207753Smm /// Block Header has biggest maximum size. 58207753Smm uint8_t buffer[LZMA_BLOCK_HEADER_SIZE_MAX]; 59207753Smm}; 60207753Smm 61207753Smm 62207753Smmstatic lzma_ret 63207753Smmblock_encoder_init(lzma_coder *coder, lzma_allocator *allocator) 64207753Smm{ 65207753Smm // Prepare the Block options. Even though Block encoder doesn't need 66207753Smm // compressed_size, uncompressed_size, and header_size to be 67207753Smm // initialized, it is a good idea to do it here, because this way 68207753Smm // we catch if someone gave us Filter ID that cannot be used in 69207753Smm // Blocks/Streams. 70207753Smm coder->block_options.compressed_size = LZMA_VLI_UNKNOWN; 71207753Smm coder->block_options.uncompressed_size = LZMA_VLI_UNKNOWN; 72207753Smm 73207753Smm return_if_error(lzma_block_header_size(&coder->block_options)); 74207753Smm 75207753Smm // Initialize the actual Block encoder. 76207753Smm return lzma_block_encoder_init(&coder->block_encoder, allocator, 77207753Smm &coder->block_options); 78207753Smm} 79207753Smm 80207753Smm 81207753Smmstatic lzma_ret 82207753Smmstream_encode(lzma_coder *coder, lzma_allocator *allocator, 83207753Smm const uint8_t *restrict in, size_t *restrict in_pos, 84207753Smm size_t in_size, uint8_t *restrict out, 85207753Smm size_t *restrict out_pos, size_t out_size, lzma_action action) 86207753Smm{ 87207753Smm // Main loop 88207753Smm while (*out_pos < out_size) 89207753Smm switch (coder->sequence) { 90207753Smm case SEQ_STREAM_HEADER: 91207753Smm case SEQ_BLOCK_HEADER: 92207753Smm case SEQ_STREAM_FOOTER: 93207753Smm lzma_bufcpy(coder->buffer, &coder->buffer_pos, 94207753Smm coder->buffer_size, out, out_pos, out_size); 95207753Smm if (coder->buffer_pos < coder->buffer_size) 96207753Smm return LZMA_OK; 97207753Smm 98207753Smm if (coder->sequence == SEQ_STREAM_FOOTER) 99207753Smm return LZMA_STREAM_END; 100207753Smm 101207753Smm coder->buffer_pos = 0; 102207753Smm ++coder->sequence; 103207753Smm break; 104207753Smm 105207753Smm case SEQ_BLOCK_INIT: { 106207753Smm if (*in_pos == in_size) { 107207753Smm // If we are requested to flush or finish the current 108207753Smm // Block, return LZMA_STREAM_END immediately since 109207753Smm // there's nothing to do. 110207753Smm if (action != LZMA_FINISH) 111207753Smm return action == LZMA_RUN 112207753Smm ? LZMA_OK : LZMA_STREAM_END; 113207753Smm 114207753Smm // The application had used LZMA_FULL_FLUSH to finish 115207753Smm // the previous Block, but now wants to finish without 116207753Smm // encoding new data, or it is simply creating an 117207753Smm // empty Stream with no Blocks. 118207753Smm // 119207753Smm // Initialize the Index encoder, and continue to 120207753Smm // actually encoding the Index. 121207753Smm return_if_error(lzma_index_encoder_init( 122207753Smm &coder->index_encoder, allocator, 123207753Smm coder->index)); 124207753Smm coder->sequence = SEQ_INDEX_ENCODE; 125207753Smm break; 126207753Smm } 127207753Smm 128207753Smm // Initialize the Block encoder unless it was already 129207753Smm // initialized by lzma_stream_encoder_init() or 130207753Smm // stream_encoder_update(). 131207753Smm if (!coder->block_encoder_is_initialized) 132207753Smm return_if_error(block_encoder_init(coder, allocator)); 133207753Smm 134207753Smm // Make it false so that we don't skip the initialization 135207753Smm // with the next Block. 136207753Smm coder->block_encoder_is_initialized = false; 137207753Smm 138207753Smm // Encode the Block Header. This shouldn't fail since we have 139207753Smm // already initialized the Block encoder. 140207753Smm if (lzma_block_header_encode(&coder->block_options, 141207753Smm coder->buffer) != LZMA_OK) 142207753Smm return LZMA_PROG_ERROR; 143207753Smm 144207753Smm coder->buffer_size = coder->block_options.header_size; 145207753Smm coder->sequence = SEQ_BLOCK_HEADER; 146207753Smm break; 147207753Smm } 148207753Smm 149207753Smm case SEQ_BLOCK_ENCODE: { 150207753Smm static const lzma_action convert[4] = { 151207753Smm LZMA_RUN, 152207753Smm LZMA_SYNC_FLUSH, 153207753Smm LZMA_FINISH, 154207753Smm LZMA_FINISH, 155207753Smm }; 156207753Smm 157207753Smm const lzma_ret ret = coder->block_encoder.code( 158207753Smm coder->block_encoder.coder, allocator, 159207753Smm in, in_pos, in_size, 160207753Smm out, out_pos, out_size, convert[action]); 161207753Smm if (ret != LZMA_STREAM_END || action == LZMA_SYNC_FLUSH) 162207753Smm return ret; 163207753Smm 164207753Smm // Add a new Index Record. 165207753Smm const lzma_vli unpadded_size = lzma_block_unpadded_size( 166207753Smm &coder->block_options); 167207753Smm assert(unpadded_size != 0); 168207753Smm return_if_error(lzma_index_append(coder->index, allocator, 169207753Smm unpadded_size, 170207753Smm coder->block_options.uncompressed_size)); 171207753Smm 172207753Smm coder->sequence = SEQ_BLOCK_INIT; 173207753Smm break; 174207753Smm } 175207753Smm 176207753Smm case SEQ_INDEX_ENCODE: { 177207753Smm // Call the Index encoder. It doesn't take any input, so 178207753Smm // those pointers can be NULL. 179207753Smm const lzma_ret ret = coder->index_encoder.code( 180207753Smm coder->index_encoder.coder, allocator, 181207753Smm NULL, NULL, 0, 182207753Smm out, out_pos, out_size, LZMA_RUN); 183207753Smm if (ret != LZMA_STREAM_END) 184207753Smm return ret; 185207753Smm 186207753Smm // Encode the Stream Footer into coder->buffer. 187207753Smm const lzma_stream_flags stream_flags = { 188207753Smm .version = 0, 189207753Smm .backward_size = lzma_index_size(coder->index), 190207753Smm .check = coder->block_options.check, 191207753Smm }; 192207753Smm 193207753Smm if (lzma_stream_footer_encode(&stream_flags, coder->buffer) 194207753Smm != LZMA_OK) 195207753Smm return LZMA_PROG_ERROR; 196207753Smm 197207753Smm coder->buffer_size = LZMA_STREAM_HEADER_SIZE; 198207753Smm coder->sequence = SEQ_STREAM_FOOTER; 199207753Smm break; 200207753Smm } 201207753Smm 202207753Smm default: 203207753Smm assert(0); 204207753Smm return LZMA_PROG_ERROR; 205207753Smm } 206207753Smm 207207753Smm return LZMA_OK; 208207753Smm} 209207753Smm 210207753Smm 211207753Smmstatic void 212207753Smmstream_encoder_end(lzma_coder *coder, lzma_allocator *allocator) 213207753Smm{ 214207753Smm lzma_next_end(&coder->block_encoder, allocator); 215207753Smm lzma_next_end(&coder->index_encoder, allocator); 216207753Smm lzma_index_end(coder->index, allocator); 217207753Smm 218207753Smm for (size_t i = 0; coder->filters[i].id != LZMA_VLI_UNKNOWN; ++i) 219207753Smm lzma_free(coder->filters[i].options, allocator); 220207753Smm 221207753Smm lzma_free(coder, allocator); 222207753Smm return; 223207753Smm} 224207753Smm 225207753Smm 226207753Smmstatic lzma_ret 227207753Smmstream_encoder_update(lzma_coder *coder, lzma_allocator *allocator, 228207753Smm const lzma_filter *filters, 229207753Smm const lzma_filter *reversed_filters) 230207753Smm{ 231207753Smm if (coder->sequence <= SEQ_BLOCK_INIT) { 232207753Smm // There is no incomplete Block waiting to be finished, 233207753Smm // thus we can change the whole filter chain. Start by 234207753Smm // trying to initialize the Block encoder with the new 235207753Smm // chain. This way we detect if the chain is valid. 236207753Smm coder->block_encoder_is_initialized = false; 237207753Smm coder->block_options.filters = (lzma_filter *)(filters); 238207753Smm const lzma_ret ret = block_encoder_init(coder, allocator); 239207753Smm coder->block_options.filters = coder->filters; 240207753Smm if (ret != LZMA_OK) 241207753Smm return ret; 242207753Smm 243207753Smm coder->block_encoder_is_initialized = true; 244207753Smm 245207753Smm } else if (coder->sequence <= SEQ_BLOCK_ENCODE) { 246207753Smm // We are in the middle of a Block. Try to update only 247207753Smm // the filter-specific options. 248207753Smm return_if_error(coder->block_encoder.update( 249207753Smm coder->block_encoder.coder, allocator, 250207753Smm filters, reversed_filters)); 251207753Smm } else { 252207753Smm // Trying to update the filter chain when we are already 253207753Smm // encoding Index or Stream Footer. 254207753Smm return LZMA_PROG_ERROR; 255207753Smm } 256207753Smm 257207753Smm // Free the copy of the old chain and make a copy of the new chain. 258207753Smm for (size_t i = 0; coder->filters[i].id != LZMA_VLI_UNKNOWN; ++i) 259207753Smm lzma_free(coder->filters[i].options, allocator); 260207753Smm 261207753Smm return lzma_filters_copy(filters, coder->filters, allocator); 262207753Smm} 263207753Smm 264207753Smm 265207753Smmextern lzma_ret 266207753Smmlzma_stream_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, 267207753Smm const lzma_filter *filters, lzma_check check) 268207753Smm{ 269207753Smm lzma_next_coder_init(&lzma_stream_encoder_init, next, allocator); 270207753Smm 271207753Smm if (filters == NULL) 272207753Smm return LZMA_PROG_ERROR; 273207753Smm 274207753Smm if (next->coder == NULL) { 275207753Smm next->coder = lzma_alloc(sizeof(lzma_coder), allocator); 276207753Smm if (next->coder == NULL) 277207753Smm return LZMA_MEM_ERROR; 278207753Smm 279207753Smm next->code = &stream_encode; 280207753Smm next->end = &stream_encoder_end; 281207753Smm next->update = &stream_encoder_update; 282207753Smm 283223935Smm next->coder->filters[0].id = LZMA_VLI_UNKNOWN; 284207753Smm next->coder->block_encoder = LZMA_NEXT_CODER_INIT; 285207753Smm next->coder->index_encoder = LZMA_NEXT_CODER_INIT; 286207753Smm next->coder->index = NULL; 287207753Smm } 288207753Smm 289207753Smm // Basic initializations 290207753Smm next->coder->sequence = SEQ_STREAM_HEADER; 291207753Smm next->coder->block_options.version = 0; 292207753Smm next->coder->block_options.check = check; 293207753Smm 294207753Smm // Initialize the Index 295207753Smm lzma_index_end(next->coder->index, allocator); 296207753Smm next->coder->index = lzma_index_init(allocator); 297207753Smm if (next->coder->index == NULL) 298207753Smm return LZMA_MEM_ERROR; 299207753Smm 300207753Smm // Encode the Stream Header 301207753Smm lzma_stream_flags stream_flags = { 302207753Smm .version = 0, 303207753Smm .check = check, 304207753Smm }; 305207753Smm return_if_error(lzma_stream_header_encode( 306207753Smm &stream_flags, next->coder->buffer)); 307207753Smm 308207753Smm next->coder->buffer_pos = 0; 309207753Smm next->coder->buffer_size = LZMA_STREAM_HEADER_SIZE; 310207753Smm 311207753Smm // Initialize the Block encoder. This way we detect unsupported 312207753Smm // filter chains when initializing the Stream encoder instead of 313207753Smm // giving an error after Stream Header has already written out. 314207753Smm return stream_encoder_update( 315207753Smm next->coder, allocator, filters, NULL); 316207753Smm} 317207753Smm 318207753Smm 319207753Smmextern LZMA_API(lzma_ret) 320207753Smmlzma_stream_encoder(lzma_stream *strm, 321207753Smm const lzma_filter *filters, lzma_check check) 322207753Smm{ 323207753Smm lzma_next_strm_init(lzma_stream_encoder_init, strm, filters, check); 324207753Smm 325207753Smm strm->internal->supported_actions[LZMA_RUN] = true; 326207753Smm strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true; 327207753Smm strm->internal->supported_actions[LZMA_FULL_FLUSH] = true; 328207753Smm strm->internal->supported_actions[LZMA_FINISH] = true; 329207753Smm 330207753Smm return LZMA_OK; 331207753Smm} 332