Path: blob/master/Utilities/cmliblzma/liblzma/delta/delta_encoder.c
3156 views
// SPDX-License-Identifier: 0BSD12///////////////////////////////////////////////////////////////////////////////3//4/// \file delta_encoder.c5/// \brief Delta filter encoder6//7// Author: Lasse Collin8//9///////////////////////////////////////////////////////////////////////////////1011#include "delta_encoder.h"12#include "delta_private.h"131415/// Copies and encodes the data at the same time. This is used when Delta16/// is the first filter in the chain (and thus the last filter in the17/// encoder's filter stack).18static void19copy_and_encode(lzma_delta_coder *coder,20const uint8_t *restrict in, uint8_t *restrict out, size_t size)21{22const size_t distance = coder->distance;2324for (size_t i = 0; i < size; ++i) {25const uint8_t tmp = coder->history[26(distance + coder->pos) & 0xFF];27coder->history[coder->pos-- & 0xFF] = in[i];28out[i] = in[i] - tmp;29}30}313233/// Encodes the data in place. This is used when we are the last filter34/// in the chain (and thus non-last filter in the encoder's filter stack).35static void36encode_in_place(lzma_delta_coder *coder, uint8_t *buffer, size_t size)37{38const size_t distance = coder->distance;3940for (size_t i = 0; i < size; ++i) {41const uint8_t tmp = coder->history[42(distance + coder->pos) & 0xFF];43coder->history[coder->pos-- & 0xFF] = buffer[i];44buffer[i] -= tmp;45}46}474849static lzma_ret50delta_encode(void *coder_ptr, const lzma_allocator *allocator,51const uint8_t *restrict in, size_t *restrict in_pos,52size_t in_size, uint8_t *restrict out,53size_t *restrict out_pos, size_t out_size, lzma_action action)54{55lzma_delta_coder *coder = coder_ptr;5657lzma_ret ret;5859if (coder->next.code == NULL) {60const size_t in_avail = in_size - *in_pos;61const size_t out_avail = out_size - *out_pos;62const size_t size = my_min(in_avail, out_avail);6364// in and out might be NULL. In such cases size == 0.65// Null pointer + 0 is undefined behavior so skip66// the call in that case as it would do nothing anyway.67if (size > 0)68copy_and_encode(coder, in + *in_pos, out + *out_pos,69size);7071*in_pos += size;72*out_pos += size;7374ret = action != LZMA_RUN && *in_pos == in_size75? LZMA_STREAM_END : LZMA_OK;7677} else {78const size_t out_start = *out_pos;7980ret = coder->next.code(coder->next.coder, allocator,81in, in_pos, in_size, out, out_pos, out_size,82action);8384// Like above, avoid null pointer + 0.85const size_t size = *out_pos - out_start;86if (size > 0)87encode_in_place(coder, out + out_start, size);88}8990return ret;91}929394static lzma_ret95delta_encoder_update(void *coder_ptr, const lzma_allocator *allocator,96const lzma_filter *filters_null lzma_attribute((__unused__)),97const lzma_filter *reversed_filters)98{99lzma_delta_coder *coder = coder_ptr;100101// Delta doesn't and will never support changing the options in102// the middle of encoding. If the app tries to change them, we103// simply ignore them.104return lzma_next_filter_update(105&coder->next, allocator, reversed_filters + 1);106}107108109extern lzma_ret110lzma_delta_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,111const lzma_filter_info *filters)112{113next->code = &delta_encode;114next->update = &delta_encoder_update;115return lzma_delta_coder_init(next, allocator, filters);116}117118119extern lzma_ret120lzma_delta_props_encode(const void *options, uint8_t *out)121{122// The caller must have already validated the options, so it's123// LZMA_PROG_ERROR if they are invalid.124if (lzma_delta_coder_memusage(options) == UINT64_MAX)125return LZMA_PROG_ERROR;126127const lzma_options_delta *opt = options;128out[0] = opt->dist - LZMA_DELTA_DIST_MIN;129130return LZMA_OK;131}132133134