(root)/
xz-5.4.5/
src/
liblzma/
delta/
delta_encoder.c
       1  ///////////////////////////////////////////////////////////////////////////////
       2  //
       3  /// \file       delta_encoder.c
       4  /// \brief      Delta filter encoder
       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 "delta_encoder.h"
      14  #include "delta_private.h"
      15  
      16  
      17  /// Copies and encodes the data at the same time. This is used when Delta
      18  /// is the first filter in the chain (and thus the last filter in the
      19  /// encoder's filter stack).
      20  static void
      21  copy_and_encode(lzma_delta_coder *coder,
      22  		const uint8_t *restrict in, uint8_t *restrict out, size_t size)
      23  {
      24  	const size_t distance = coder->distance;
      25  
      26  	for (size_t i = 0; i < size; ++i) {
      27  		const uint8_t tmp = coder->history[
      28  				(distance + coder->pos) & 0xFF];
      29  		coder->history[coder->pos-- & 0xFF] = in[i];
      30  		out[i] = in[i] - tmp;
      31  	}
      32  }
      33  
      34  
      35  /// Encodes the data in place. This is used when we are the last filter
      36  /// in the chain (and thus non-last filter in the encoder's filter stack).
      37  static void
      38  encode_in_place(lzma_delta_coder *coder, uint8_t *buffer, size_t size)
      39  {
      40  	const size_t distance = coder->distance;
      41  
      42  	for (size_t i = 0; i < size; ++i) {
      43  		const uint8_t tmp = coder->history[
      44  				(distance + coder->pos) & 0xFF];
      45  		coder->history[coder->pos-- & 0xFF] = buffer[i];
      46  		buffer[i] -= tmp;
      47  	}
      48  }
      49  
      50  
      51  static lzma_ret
      52  delta_encode(void *coder_ptr, const lzma_allocator *allocator,
      53  		const uint8_t *restrict in, size_t *restrict in_pos,
      54  		size_t in_size, uint8_t *restrict out,
      55  		size_t *restrict out_pos, size_t out_size, lzma_action action)
      56  {
      57  	lzma_delta_coder *coder = coder_ptr;
      58  
      59  	lzma_ret ret;
      60  
      61  	if (coder->next.code == NULL) {
      62  		const size_t in_avail = in_size - *in_pos;
      63  		const size_t out_avail = out_size - *out_pos;
      64  		const size_t size = my_min(in_avail, out_avail);
      65  
      66  		// in and out might be NULL. In such cases size == 0.
      67  		// Null pointer + 0 is undefined behavior so skip
      68  		// the call in that case as it would do nothing anyway.
      69  		if (size > 0)
      70  			copy_and_encode(coder, in + *in_pos, out + *out_pos,
      71  					size);
      72  
      73  		*in_pos += size;
      74  		*out_pos += size;
      75  
      76  		ret = action != LZMA_RUN && *in_pos == in_size
      77  				? LZMA_STREAM_END : LZMA_OK;
      78  
      79  	} else {
      80  		const size_t out_start = *out_pos;
      81  
      82  		ret = coder->next.code(coder->next.coder, allocator,
      83  				in, in_pos, in_size, out, out_pos, out_size,
      84  				action);
      85  
      86  		// Like above, avoid null pointer + 0.
      87  		const size_t size = *out_pos - out_start;
      88  		if (size > 0)
      89  			encode_in_place(coder, out + out_start, size);
      90  	}
      91  
      92  	return ret;
      93  }
      94  
      95  
      96  static lzma_ret
      97  delta_encoder_update(void *coder_ptr, const lzma_allocator *allocator,
      98  		const lzma_filter *filters_null lzma_attribute((__unused__)),
      99  		const lzma_filter *reversed_filters)
     100  {
     101  	lzma_delta_coder *coder = coder_ptr;
     102  
     103  	// Delta doesn't and will never support changing the options in
     104  	// the middle of encoding. If the app tries to change them, we
     105  	// simply ignore them.
     106  	return lzma_next_filter_update(
     107  			&coder->next, allocator, reversed_filters + 1);
     108  }
     109  
     110  
     111  extern lzma_ret
     112  lzma_delta_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
     113  		const lzma_filter_info *filters)
     114  {
     115  	next->code = &delta_encode;
     116  	next->update = &delta_encoder_update;
     117  	return lzma_delta_coder_init(next, allocator, filters);
     118  }
     119  
     120  
     121  extern lzma_ret
     122  lzma_delta_props_encode(const void *options, uint8_t *out)
     123  {
     124  	// The caller must have already validated the options, so it's
     125  	// LZMA_PROG_ERROR if they are invalid.
     126  	if (lzma_delta_coder_memusage(options) == UINT64_MAX)
     127  		return LZMA_PROG_ERROR;
     128  
     129  	const lzma_options_delta *opt = options;
     130  	out[0] = opt->dist - LZMA_DELTA_DIST_MIN;
     131  
     132  	return LZMA_OK;
     133  }