(root)/
xz-5.4.5/
src/
liblzma/
common/
stream_encoder.c
       1  ///////////////////////////////////////////////////////////////////////////////
       2  //
       3  /// \file       stream_encoder.c
       4  /// \brief      Encodes .xz Streams
       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 "block_encoder.h"
      14  #include "index_encoder.h"
      15  
      16  
      17  typedef struct {
      18  	enum {
      19  		SEQ_STREAM_HEADER,
      20  		SEQ_BLOCK_INIT,
      21  		SEQ_BLOCK_HEADER,
      22  		SEQ_BLOCK_ENCODE,
      23  		SEQ_INDEX_ENCODE,
      24  		SEQ_STREAM_FOOTER,
      25  	} sequence;
      26  
      27  	/// True if Block encoder has been initialized by
      28  	/// stream_encoder_init() or stream_encoder_update()
      29  	/// and thus doesn't need to be initialized in stream_encode().
      30  	bool block_encoder_is_initialized;
      31  
      32  	/// Block
      33  	lzma_next_coder block_encoder;
      34  
      35  	/// Options for the Block encoder
      36  	lzma_block block_options;
      37  
      38  	/// The filter chain currently in use
      39  	lzma_filter filters[LZMA_FILTERS_MAX + 1];
      40  
      41  	/// Index encoder. This is separate from Block encoder, because this
      42  	/// doesn't take much memory, and when encoding multiple Streams
      43  	/// with the same encoding options we avoid reallocating memory.
      44  	lzma_next_coder index_encoder;
      45  
      46  	/// Index to hold sizes of the Blocks
      47  	lzma_index *index;
      48  
      49  	/// Read position in buffer[]
      50  	size_t buffer_pos;
      51  
      52  	/// Total number of bytes in buffer[]
      53  	size_t buffer_size;
      54  
      55  	/// Buffer to hold Stream Header, Block Header, and Stream Footer.
      56  	/// Block Header has biggest maximum size.
      57  	uint8_t buffer[LZMA_BLOCK_HEADER_SIZE_MAX];
      58  } lzma_stream_coder;
      59  
      60  
      61  static lzma_ret
      62  block_encoder_init(lzma_stream_coder *coder, const lzma_allocator *allocator)
      63  {
      64  	// Prepare the Block options. Even though Block encoder doesn't need
      65  	// compressed_size, uncompressed_size, and header_size to be
      66  	// initialized, it is a good idea to do it here, because this way
      67  	// we catch if someone gave us Filter ID that cannot be used in
      68  	// Blocks/Streams.
      69  	coder->block_options.compressed_size = LZMA_VLI_UNKNOWN;
      70  	coder->block_options.uncompressed_size = LZMA_VLI_UNKNOWN;
      71  
      72  	return_if_error(lzma_block_header_size(&coder->block_options));
      73  
      74  	// Initialize the actual Block encoder.
      75  	return lzma_block_encoder_init(&coder->block_encoder, allocator,
      76  			&coder->block_options);
      77  }
      78  
      79  
      80  static lzma_ret
      81  stream_encode(void *coder_ptr, const lzma_allocator *allocator,
      82  		const uint8_t *restrict in, size_t *restrict in_pos,
      83  		size_t in_size, uint8_t *restrict out,
      84  		size_t *restrict out_pos, size_t out_size, lzma_action action)
      85  {
      86  	lzma_stream_coder *coder = coder_ptr;
      87  
      88  	// Main loop
      89  	while (*out_pos < out_size)
      90  	switch (coder->sequence) {
      91  	case SEQ_STREAM_HEADER:
      92  	case SEQ_BLOCK_HEADER:
      93  	case SEQ_STREAM_FOOTER:
      94  		lzma_bufcpy(coder->buffer, &coder->buffer_pos,
      95  				coder->buffer_size, out, out_pos, out_size);
      96  		if (coder->buffer_pos < coder->buffer_size)
      97  			return LZMA_OK;
      98  
      99  		if (coder->sequence == SEQ_STREAM_FOOTER)
     100  			return LZMA_STREAM_END;
     101  
     102  		coder->buffer_pos = 0;
     103  		++coder->sequence;
     104  		break;
     105  
     106  	case SEQ_BLOCK_INIT: {
     107  		if (*in_pos == in_size) {
     108  			// If we are requested to flush or finish the current
     109  			// Block, return LZMA_STREAM_END immediately since
     110  			// there's nothing to do.
     111  			if (action != LZMA_FINISH)
     112  				return action == LZMA_RUN
     113  						? LZMA_OK : LZMA_STREAM_END;
     114  
     115  			// The application had used LZMA_FULL_FLUSH to finish
     116  			// the previous Block, but now wants to finish without
     117  			// encoding new data, or it is simply creating an
     118  			// empty Stream with no Blocks.
     119  			//
     120  			// Initialize the Index encoder, and continue to
     121  			// actually encoding the Index.
     122  			return_if_error(lzma_index_encoder_init(
     123  					&coder->index_encoder, allocator,
     124  					coder->index));
     125  			coder->sequence = SEQ_INDEX_ENCODE;
     126  			break;
     127  		}
     128  
     129  		// Initialize the Block encoder unless it was already
     130  		// initialized by stream_encoder_init() or
     131  		// stream_encoder_update().
     132  		if (!coder->block_encoder_is_initialized)
     133  			return_if_error(block_encoder_init(coder, allocator));
     134  
     135  		// Make it false so that we don't skip the initialization
     136  		// with the next Block.
     137  		coder->block_encoder_is_initialized = false;
     138  
     139  		// Encode the Block Header. This shouldn't fail since we have
     140  		// already initialized the Block encoder.
     141  		if (lzma_block_header_encode(&coder->block_options,
     142  				coder->buffer) != LZMA_OK)
     143  			return LZMA_PROG_ERROR;
     144  
     145  		coder->buffer_size = coder->block_options.header_size;
     146  		coder->sequence = SEQ_BLOCK_HEADER;
     147  		break;
     148  	}
     149  
     150  	case SEQ_BLOCK_ENCODE: {
     151  		static const lzma_action convert[LZMA_ACTION_MAX + 1] = {
     152  			LZMA_RUN,
     153  			LZMA_SYNC_FLUSH,
     154  			LZMA_FINISH,
     155  			LZMA_FINISH,
     156  			LZMA_FINISH,
     157  		};
     158  
     159  		const lzma_ret ret = coder->block_encoder.code(
     160  				coder->block_encoder.coder, allocator,
     161  				in, in_pos, in_size,
     162  				out, out_pos, out_size, convert[action]);
     163  		if (ret != LZMA_STREAM_END || action == LZMA_SYNC_FLUSH)
     164  			return ret;
     165  
     166  		// Add a new Index Record.
     167  		const lzma_vli unpadded_size = lzma_block_unpadded_size(
     168  				&coder->block_options);
     169  		assert(unpadded_size != 0);
     170  		return_if_error(lzma_index_append(coder->index, allocator,
     171  				unpadded_size,
     172  				coder->block_options.uncompressed_size));
     173  
     174  		coder->sequence = SEQ_BLOCK_INIT;
     175  		break;
     176  	}
     177  
     178  	case SEQ_INDEX_ENCODE: {
     179  		// Call the Index encoder. It doesn't take any input, so
     180  		// those pointers can be NULL.
     181  		const lzma_ret ret = coder->index_encoder.code(
     182  				coder->index_encoder.coder, allocator,
     183  				NULL, NULL, 0,
     184  				out, out_pos, out_size, LZMA_RUN);
     185  		if (ret != LZMA_STREAM_END)
     186  			return ret;
     187  
     188  		// Encode the Stream Footer into coder->buffer.
     189  		const lzma_stream_flags stream_flags = {
     190  			.version = 0,
     191  			.backward_size = lzma_index_size(coder->index),
     192  			.check = coder->block_options.check,
     193  		};
     194  
     195  		if (lzma_stream_footer_encode(&stream_flags, coder->buffer)
     196  				!= LZMA_OK)
     197  			return LZMA_PROG_ERROR;
     198  
     199  		coder->buffer_size = LZMA_STREAM_HEADER_SIZE;
     200  		coder->sequence = SEQ_STREAM_FOOTER;
     201  		break;
     202  	}
     203  
     204  	default:
     205  		assert(0);
     206  		return LZMA_PROG_ERROR;
     207  	}
     208  
     209  	return LZMA_OK;
     210  }
     211  
     212  
     213  static void
     214  stream_encoder_end(void *coder_ptr, const lzma_allocator *allocator)
     215  {
     216  	lzma_stream_coder *coder = coder_ptr;
     217  
     218  	lzma_next_end(&coder->block_encoder, allocator);
     219  	lzma_next_end(&coder->index_encoder, allocator);
     220  	lzma_index_end(coder->index, allocator);
     221  
     222  	lzma_filters_free(coder->filters, allocator);
     223  
     224  	lzma_free(coder, allocator);
     225  	return;
     226  }
     227  
     228  
     229  static lzma_ret
     230  stream_encoder_update(void *coder_ptr, const lzma_allocator *allocator,
     231  		const lzma_filter *filters,
     232  		const lzma_filter *reversed_filters)
     233  {
     234  	lzma_stream_coder *coder = coder_ptr;
     235  	lzma_ret ret;
     236  
     237  	// Make a copy to a temporary buffer first. This way it is easier
     238  	// to keep the encoder state unchanged if an error occurs with
     239  	// lzma_filters_copy().
     240  	lzma_filter temp[LZMA_FILTERS_MAX + 1];
     241  	return_if_error(lzma_filters_copy(filters, temp, allocator));
     242  
     243  	if (coder->sequence <= SEQ_BLOCK_INIT) {
     244  		// There is no incomplete Block waiting to be finished,
     245  		// thus we can change the whole filter chain. Start by
     246  		// trying to initialize the Block encoder with the new
     247  		// chain. This way we detect if the chain is valid.
     248  		coder->block_encoder_is_initialized = false;
     249  		coder->block_options.filters = temp;
     250  		ret = block_encoder_init(coder, allocator);
     251  		coder->block_options.filters = coder->filters;
     252  		if (ret != LZMA_OK)
     253  			goto error;
     254  
     255  		coder->block_encoder_is_initialized = true;
     256  
     257  	} else if (coder->sequence <= SEQ_BLOCK_ENCODE) {
     258  		// We are in the middle of a Block. Try to update only
     259  		// the filter-specific options.
     260  		ret = coder->block_encoder.update(
     261  				coder->block_encoder.coder, allocator,
     262  				filters, reversed_filters);
     263  		if (ret != LZMA_OK)
     264  			goto error;
     265  	} else {
     266  		// Trying to update the filter chain when we are already
     267  		// encoding Index or Stream Footer.
     268  		ret = LZMA_PROG_ERROR;
     269  		goto error;
     270  	}
     271  
     272  	// Free the options of the old chain.
     273  	lzma_filters_free(coder->filters, allocator);
     274  
     275  	// Copy the new filter chain in place.
     276  	memcpy(coder->filters, temp, sizeof(temp));
     277  
     278  	return LZMA_OK;
     279  
     280  error:
     281  	lzma_filters_free(temp, allocator);
     282  	return ret;
     283  }
     284  
     285  
     286  static lzma_ret
     287  stream_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
     288  		const lzma_filter *filters, lzma_check check)
     289  {
     290  	lzma_next_coder_init(&stream_encoder_init, next, allocator);
     291  
     292  	if (filters == NULL)
     293  		return LZMA_PROG_ERROR;
     294  
     295  	lzma_stream_coder *coder = next->coder;
     296  
     297  	if (coder == NULL) {
     298  		coder = lzma_alloc(sizeof(lzma_stream_coder), allocator);
     299  		if (coder == NULL)
     300  			return LZMA_MEM_ERROR;
     301  
     302  		next->coder = coder;
     303  		next->code = &stream_encode;
     304  		next->end = &stream_encoder_end;
     305  		next->update = &stream_encoder_update;
     306  
     307  		coder->filters[0].id = LZMA_VLI_UNKNOWN;
     308  		coder->block_encoder = LZMA_NEXT_CODER_INIT;
     309  		coder->index_encoder = LZMA_NEXT_CODER_INIT;
     310  		coder->index = NULL;
     311  	}
     312  
     313  	// Basic initializations
     314  	coder->sequence = SEQ_STREAM_HEADER;
     315  	coder->block_options.version = 0;
     316  	coder->block_options.check = check;
     317  
     318  	// Initialize the Index
     319  	lzma_index_end(coder->index, allocator);
     320  	coder->index = lzma_index_init(allocator);
     321  	if (coder->index == NULL)
     322  		return LZMA_MEM_ERROR;
     323  
     324  	// Encode the Stream Header
     325  	lzma_stream_flags stream_flags = {
     326  		.version = 0,
     327  		.check = check,
     328  	};
     329  	return_if_error(lzma_stream_header_encode(
     330  			&stream_flags, coder->buffer));
     331  
     332  	coder->buffer_pos = 0;
     333  	coder->buffer_size = LZMA_STREAM_HEADER_SIZE;
     334  
     335  	// Initialize the Block encoder. This way we detect unsupported
     336  	// filter chains when initializing the Stream encoder instead of
     337  	// giving an error after Stream Header has already been written out.
     338  	return stream_encoder_update(coder, allocator, filters, NULL);
     339  }
     340  
     341  
     342  extern LZMA_API(lzma_ret)
     343  lzma_stream_encoder(lzma_stream *strm,
     344  		const lzma_filter *filters, lzma_check check)
     345  {
     346  	lzma_next_strm_init(stream_encoder_init, strm, filters, check);
     347  
     348  	strm->internal->supported_actions[LZMA_RUN] = true;
     349  	strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;
     350  	strm->internal->supported_actions[LZMA_FULL_FLUSH] = true;
     351  	strm->internal->supported_actions[LZMA_FULL_BARRIER] = true;
     352  	strm->internal->supported_actions[LZMA_FINISH] = true;
     353  
     354  	return LZMA_OK;
     355  }