Home | History | Annotate | Line # | Download | only in delta
      1 // SPDX-License-Identifier: 0BSD
      2 
      3 ///////////////////////////////////////////////////////////////////////////////
      4 //
      5 /// \file       delta_decoder.c
      6 /// \brief      Delta filter decoder
      7 //
      8 //  Author:     Lasse Collin
      9 //
     10 ///////////////////////////////////////////////////////////////////////////////
     11 
     12 #include "delta_decoder.h"
     13 #include "delta_private.h"
     14 
     15 
     16 static void
     17 decode_buffer(lzma_delta_coder *coder, uint8_t *buffer, size_t size)
     18 {
     19 	const size_t distance = coder->distance;
     20 
     21 	for (size_t i = 0; i < size; ++i) {
     22 		buffer[i] += coder->history[(distance + coder->pos) & 0xFF];
     23 		coder->history[coder->pos-- & 0xFF] = buffer[i];
     24 	}
     25 }
     26 
     27 
     28 // For an unknown reason NVIDIA HPC Compiler needs this pragma
     29 // to produce working code.
     30 #ifdef __NVCOMPILER
     31 #	pragma routine novector
     32 #endif
     33 static lzma_ret
     34 delta_decode(void *coder_ptr, const lzma_allocator *allocator,
     35 		const uint8_t *restrict in, size_t *restrict in_pos,
     36 		size_t in_size, uint8_t *restrict out,
     37 		size_t *restrict out_pos, size_t out_size, lzma_action action)
     38 {
     39 	lzma_delta_coder *coder = coder_ptr;
     40 
     41 	assert(coder->next.code != NULL);
     42 
     43 	const size_t out_start = *out_pos;
     44 
     45 	const lzma_ret ret = coder->next.code(coder->next.coder, allocator,
     46 			in, in_pos, in_size, out, out_pos, out_size,
     47 			action);
     48 
     49 	// out might be NULL. In that case size == 0. Null pointer + 0 is
     50 	// undefined behavior so skip the call in that case as it would
     51 	// do nothing anyway.
     52 	const size_t size = *out_pos - out_start;
     53 	if (size > 0)
     54 		decode_buffer(coder, out + out_start, size);
     55 
     56 	return ret;
     57 }
     58 
     59 
     60 extern lzma_ret
     61 lzma_delta_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
     62 		const lzma_filter_info *filters)
     63 {
     64 	next->code = &delta_decode;
     65 	return lzma_delta_coder_init(next, allocator, filters);
     66 }
     67 
     68 
     69 extern lzma_ret
     70 lzma_delta_props_decode(void **options, const lzma_allocator *allocator,
     71 		const uint8_t *props, size_t props_size)
     72 {
     73 	if (props_size != 1)
     74 		return LZMA_OPTIONS_ERROR;
     75 
     76 	lzma_options_delta *opt
     77 			= lzma_alloc(sizeof(lzma_options_delta), allocator);
     78 	if (opt == NULL)
     79 		return LZMA_MEM_ERROR;
     80 
     81 	opt->type = LZMA_DELTA_TYPE_BYTE;
     82 	opt->dist = props[0] + 1U;
     83 
     84 	*options = opt;
     85 
     86 	return LZMA_OK;
     87 }
     88