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