12940b44dSPeter Avalos ///////////////////////////////////////////////////////////////////////////////
22940b44dSPeter Avalos //
32940b44dSPeter Avalos /// \file delta_encoder.c
42940b44dSPeter Avalos /// \brief Delta filter encoder
52940b44dSPeter Avalos //
62940b44dSPeter Avalos // Author: Lasse Collin
72940b44dSPeter Avalos //
82940b44dSPeter Avalos // This file has been put into the public domain.
92940b44dSPeter Avalos // You can do whatever you want with this file.
102940b44dSPeter Avalos //
112940b44dSPeter Avalos ///////////////////////////////////////////////////////////////////////////////
122940b44dSPeter Avalos
132940b44dSPeter Avalos #include "delta_encoder.h"
142940b44dSPeter Avalos #include "delta_private.h"
152940b44dSPeter Avalos
162940b44dSPeter Avalos
172940b44dSPeter Avalos /// Copies and encodes the data at the same time. This is used when Delta
182940b44dSPeter Avalos /// is the first filter in the chain (and thus the last filter in the
192940b44dSPeter Avalos /// encoder's filter stack).
202940b44dSPeter Avalos static void
copy_and_encode(lzma_delta_coder * coder,const uint8_t * restrict in,uint8_t * restrict out,size_t size)21*46a2189dSzrj copy_and_encode(lzma_delta_coder *coder,
222940b44dSPeter Avalos const uint8_t *restrict in, uint8_t *restrict out, size_t size)
232940b44dSPeter Avalos {
242940b44dSPeter Avalos const size_t distance = coder->distance;
252940b44dSPeter Avalos
262940b44dSPeter Avalos for (size_t i = 0; i < size; ++i) {
272940b44dSPeter Avalos const uint8_t tmp = coder->history[
282940b44dSPeter Avalos (distance + coder->pos) & 0xFF];
292940b44dSPeter Avalos coder->history[coder->pos-- & 0xFF] = in[i];
302940b44dSPeter Avalos out[i] = in[i] - tmp;
312940b44dSPeter Avalos }
322940b44dSPeter Avalos }
332940b44dSPeter Avalos
342940b44dSPeter Avalos
352940b44dSPeter Avalos /// Encodes the data in place. This is used when we are the last filter
362940b44dSPeter Avalos /// in the chain (and thus non-last filter in the encoder's filter stack).
372940b44dSPeter Avalos static void
encode_in_place(lzma_delta_coder * coder,uint8_t * buffer,size_t size)38*46a2189dSzrj encode_in_place(lzma_delta_coder *coder, uint8_t *buffer, size_t size)
392940b44dSPeter Avalos {
402940b44dSPeter Avalos const size_t distance = coder->distance;
412940b44dSPeter Avalos
422940b44dSPeter Avalos for (size_t i = 0; i < size; ++i) {
432940b44dSPeter Avalos const uint8_t tmp = coder->history[
442940b44dSPeter Avalos (distance + coder->pos) & 0xFF];
452940b44dSPeter Avalos coder->history[coder->pos-- & 0xFF] = buffer[i];
462940b44dSPeter Avalos buffer[i] -= tmp;
472940b44dSPeter Avalos }
482940b44dSPeter Avalos }
492940b44dSPeter Avalos
502940b44dSPeter Avalos
512940b44dSPeter Avalos static lzma_ret
delta_encode(void * coder_ptr,const lzma_allocator * allocator,const uint8_t * restrict in,size_t * restrict in_pos,size_t in_size,uint8_t * restrict out,size_t * restrict out_pos,size_t out_size,lzma_action action)52*46a2189dSzrj delta_encode(void *coder_ptr, const lzma_allocator *allocator,
532940b44dSPeter Avalos const uint8_t *restrict in, size_t *restrict in_pos,
542940b44dSPeter Avalos size_t in_size, uint8_t *restrict out,
552940b44dSPeter Avalos size_t *restrict out_pos, size_t out_size, lzma_action action)
562940b44dSPeter Avalos {
57*46a2189dSzrj lzma_delta_coder *coder = coder_ptr;
58*46a2189dSzrj
592940b44dSPeter Avalos lzma_ret ret;
602940b44dSPeter Avalos
612940b44dSPeter Avalos if (coder->next.code == NULL) {
622940b44dSPeter Avalos const size_t in_avail = in_size - *in_pos;
632940b44dSPeter Avalos const size_t out_avail = out_size - *out_pos;
642940b44dSPeter Avalos const size_t size = my_min(in_avail, out_avail);
652940b44dSPeter Avalos
662940b44dSPeter Avalos copy_and_encode(coder, in + *in_pos, out + *out_pos, size);
672940b44dSPeter Avalos
682940b44dSPeter Avalos *in_pos += size;
692940b44dSPeter Avalos *out_pos += size;
702940b44dSPeter Avalos
712940b44dSPeter Avalos ret = action != LZMA_RUN && *in_pos == in_size
722940b44dSPeter Avalos ? LZMA_STREAM_END : LZMA_OK;
732940b44dSPeter Avalos
742940b44dSPeter Avalos } else {
752940b44dSPeter Avalos const size_t out_start = *out_pos;
762940b44dSPeter Avalos
772940b44dSPeter Avalos ret = coder->next.code(coder->next.coder, allocator,
782940b44dSPeter Avalos in, in_pos, in_size, out, out_pos, out_size,
792940b44dSPeter Avalos action);
802940b44dSPeter Avalos
812940b44dSPeter Avalos encode_in_place(coder, out + out_start, *out_pos - out_start);
822940b44dSPeter Avalos }
832940b44dSPeter Avalos
842940b44dSPeter Avalos return ret;
852940b44dSPeter Avalos }
862940b44dSPeter Avalos
872940b44dSPeter Avalos
882940b44dSPeter Avalos static lzma_ret
delta_encoder_update(void * coder_ptr,const lzma_allocator * allocator,const lzma_filter * filters_null lzma_attribute ((__unused__)),const lzma_filter * reversed_filters)89*46a2189dSzrj delta_encoder_update(void *coder_ptr, const lzma_allocator *allocator,
90114db65bSPeter Avalos const lzma_filter *filters_null lzma_attribute((__unused__)),
912940b44dSPeter Avalos const lzma_filter *reversed_filters)
922940b44dSPeter Avalos {
93*46a2189dSzrj lzma_delta_coder *coder = coder_ptr;
94*46a2189dSzrj
952940b44dSPeter Avalos // Delta doesn't and will never support changing the options in
962940b44dSPeter Avalos // the middle of encoding. If the app tries to change them, we
972940b44dSPeter Avalos // simply ignore them.
982940b44dSPeter Avalos return lzma_next_filter_update(
992940b44dSPeter Avalos &coder->next, allocator, reversed_filters + 1);
1002940b44dSPeter Avalos }
1012940b44dSPeter Avalos
1022940b44dSPeter Avalos
1032940b44dSPeter Avalos extern lzma_ret
lzma_delta_encoder_init(lzma_next_coder * next,const lzma_allocator * allocator,const lzma_filter_info * filters)10415ab8c86SJohn Marino lzma_delta_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
1052940b44dSPeter Avalos const lzma_filter_info *filters)
1062940b44dSPeter Avalos {
1072940b44dSPeter Avalos next->code = &delta_encode;
1082940b44dSPeter Avalos next->update = &delta_encoder_update;
1092940b44dSPeter Avalos return lzma_delta_coder_init(next, allocator, filters);
1102940b44dSPeter Avalos }
1112940b44dSPeter Avalos
1122940b44dSPeter Avalos
1132940b44dSPeter Avalos extern lzma_ret
lzma_delta_props_encode(const void * options,uint8_t * out)1142940b44dSPeter Avalos lzma_delta_props_encode(const void *options, uint8_t *out)
1152940b44dSPeter Avalos {
1162940b44dSPeter Avalos // The caller must have already validated the options, so it's
1172940b44dSPeter Avalos // LZMA_PROG_ERROR if they are invalid.
1182940b44dSPeter Avalos if (lzma_delta_coder_memusage(options) == UINT64_MAX)
1192940b44dSPeter Avalos return LZMA_PROG_ERROR;
1202940b44dSPeter Avalos
1212940b44dSPeter Avalos const lzma_options_delta *opt = options;
1222940b44dSPeter Avalos out[0] = opt->dist - LZMA_DELTA_DIST_MIN;
1232940b44dSPeter Avalos
1242940b44dSPeter Avalos return LZMA_OK;
1252940b44dSPeter Avalos }
126