1207753Smm/////////////////////////////////////////////////////////////////////////////// 2207753Smm// 3207753Smm/// \file delta_encoder.c 4207753Smm/// \brief Delta filter encoder 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 "delta_encoder.h" 14207753Smm#include "delta_private.h" 15207753Smm 16207753Smm 17207753Smm/// Copies and encodes the data at the same time. This is used when Delta 18207753Smm/// is the first filter in the chain (and thus the last filter in the 19207753Smm/// encoder's filter stack). 20207753Smmstatic void 21207753Smmcopy_and_encode(lzma_coder *coder, 22207753Smm const uint8_t *restrict in, uint8_t *restrict out, size_t size) 23207753Smm{ 24207753Smm const size_t distance = coder->distance; 25207753Smm 26207753Smm for (size_t i = 0; i < size; ++i) { 27207753Smm const uint8_t tmp = coder->history[ 28207753Smm (distance + coder->pos) & 0xFF]; 29207753Smm coder->history[coder->pos-- & 0xFF] = in[i]; 30207753Smm out[i] = in[i] - tmp; 31207753Smm } 32207753Smm} 33207753Smm 34207753Smm 35207753Smm/// Encodes the data in place. This is used when we are the last filter 36207753Smm/// in the chain (and thus non-last filter in the encoder's filter stack). 37207753Smmstatic void 38207753Smmencode_in_place(lzma_coder *coder, uint8_t *buffer, size_t size) 39207753Smm{ 40207753Smm const size_t distance = coder->distance; 41207753Smm 42207753Smm for (size_t i = 0; i < size; ++i) { 43207753Smm const uint8_t tmp = coder->history[ 44207753Smm (distance + coder->pos) & 0xFF]; 45207753Smm coder->history[coder->pos-- & 0xFF] = buffer[i]; 46207753Smm buffer[i] -= tmp; 47207753Smm } 48207753Smm} 49207753Smm 50207753Smm 51207753Smmstatic lzma_ret 52292588Sdelphijdelta_encode(lzma_coder *coder, const lzma_allocator *allocator, 53207753Smm const uint8_t *restrict in, size_t *restrict in_pos, 54207753Smm size_t in_size, uint8_t *restrict out, 55207753Smm size_t *restrict out_pos, size_t out_size, lzma_action action) 56207753Smm{ 57207753Smm lzma_ret ret; 58207753Smm 59207753Smm if (coder->next.code == NULL) { 60207753Smm const size_t in_avail = in_size - *in_pos; 61207753Smm const size_t out_avail = out_size - *out_pos; 62213700Smm const size_t size = my_min(in_avail, out_avail); 63207753Smm 64207753Smm copy_and_encode(coder, in + *in_pos, out + *out_pos, size); 65207753Smm 66207753Smm *in_pos += size; 67207753Smm *out_pos += size; 68207753Smm 69207753Smm ret = action != LZMA_RUN && *in_pos == in_size 70207753Smm ? LZMA_STREAM_END : LZMA_OK; 71207753Smm 72207753Smm } else { 73207753Smm const size_t out_start = *out_pos; 74207753Smm 75207753Smm ret = coder->next.code(coder->next.coder, allocator, 76207753Smm in, in_pos, in_size, out, out_pos, out_size, 77207753Smm action); 78207753Smm 79207753Smm encode_in_place(coder, out + out_start, *out_pos - out_start); 80207753Smm } 81207753Smm 82207753Smm return ret; 83207753Smm} 84207753Smm 85207753Smm 86207753Smmstatic lzma_ret 87292588Sdelphijdelta_encoder_update(lzma_coder *coder, const lzma_allocator *allocator, 88223935Smm const lzma_filter *filters_null lzma_attribute((__unused__)), 89207753Smm const lzma_filter *reversed_filters) 90207753Smm{ 91207753Smm // Delta doesn't and will never support changing the options in 92207753Smm // the middle of encoding. If the app tries to change them, we 93207753Smm // simply ignore them. 94207753Smm return lzma_next_filter_update( 95207753Smm &coder->next, allocator, reversed_filters + 1); 96207753Smm} 97207753Smm 98207753Smm 99207753Smmextern lzma_ret 100292588Sdelphijlzma_delta_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator, 101207753Smm const lzma_filter_info *filters) 102207753Smm{ 103207753Smm next->code = &delta_encode; 104207753Smm next->update = &delta_encoder_update; 105207753Smm return lzma_delta_coder_init(next, allocator, filters); 106207753Smm} 107207753Smm 108207753Smm 109207753Smmextern lzma_ret 110207753Smmlzma_delta_props_encode(const void *options, uint8_t *out) 111207753Smm{ 112207753Smm // The caller must have already validated the options, so it's 113207753Smm // LZMA_PROG_ERROR if they are invalid. 114207753Smm if (lzma_delta_coder_memusage(options) == UINT64_MAX) 115207753Smm return LZMA_PROG_ERROR; 116207753Smm 117207753Smm const lzma_options_delta *opt = options; 118207753Smm out[0] = opt->dist - LZMA_DELTA_DIST_MIN; 119207753Smm 120207753Smm return LZMA_OK; 121207753Smm} 122