| /* xdelta 3 - delta compression tools and library |
| * Copyright (C) 2002, 2003, 2006, 2007. Joshua P. MacDonald |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| |
| #ifndef _XDELTA3_SECOND_H_ |
| #define _XDELTA3_SECOND_H_ |
| |
| static inline void xd3_bit_state_encode_init (bit_state *bits) |
| { |
| bits->cur_byte = 0; |
| bits->cur_mask = 1; |
| } |
| |
| static inline int xd3_decode_bits (xd3_stream *stream, |
| bit_state *bits, |
| const uint8_t **input, |
| const uint8_t *input_max, |
| usize_t nbits, |
| usize_t *valuep) |
| { |
| usize_t value = 0; |
| usize_t vmask = 1 << nbits; |
| |
| if (bits->cur_mask == 0x100) { goto next_byte; } |
| |
| for (;;) |
| { |
| do |
| { |
| vmask >>= 1; |
| |
| if (bits->cur_byte & bits->cur_mask) |
| { |
| value |= vmask; |
| } |
| |
| bits->cur_mask <<= 1; |
| |
| if (vmask == 1) { goto done; } |
| } |
| while (bits->cur_mask != 0x100); |
| |
| next_byte: |
| |
| if (*input == input_max) |
| { |
| stream->msg = "secondary decoder end of input"; |
| return XD3_INTERNAL; |
| } |
| |
| bits->cur_byte = *(*input)++; |
| bits->cur_mask = 1; |
| } |
| |
| done: |
| |
| IF_DEBUG2 (DP(RINT "(d) %u ", value)); |
| |
| (*valuep) = value; |
| return 0; |
| } |
| |
| #if REGRESSION_TEST |
| /* There may be extra bits at the end of secondary decompression, this macro |
| * checks for non-zero bits. This is overly strict, but helps pass the |
| * single-bit-error regression test. */ |
| static int |
| xd3_test_clean_bits (xd3_stream *stream, bit_state *bits) |
| { |
| for (; bits->cur_mask != 0x100; bits->cur_mask <<= 1) |
| { |
| if (bits->cur_byte & bits->cur_mask) |
| { |
| stream->msg = "secondary decoder garbage"; |
| return XD3_INTERNAL; |
| } |
| } |
| |
| return 0; |
| } |
| #endif |
| |
| static int |
| xd3_get_secondary (xd3_stream *stream, xd3_sec_stream **sec_streamp, |
| int is_encode) |
| { |
| if (*sec_streamp == NULL) |
| { |
| int ret; |
| |
| if ((*sec_streamp = stream->sec_type->alloc (stream)) == NULL) |
| { |
| stream->msg = "error initializing secondary stream"; |
| return XD3_INVALID; |
| } |
| |
| if ((ret = stream->sec_type->init (stream, *sec_streamp, is_encode)) != 0) |
| { |
| return ret; |
| } |
| } |
| |
| return 0; |
| } |
| |
| static int |
| xd3_decode_secondary (xd3_stream *stream, |
| xd3_desect *sect, |
| xd3_sec_stream **sec_streamp) |
| { |
| uint32_t dec_size; |
| uint8_t *out_used; |
| int ret; |
| |
| if ((ret = xd3_get_secondary (stream, sec_streamp, 0)) != 0) |
| { |
| return ret; |
| } |
| |
| /* Decode the size, allocate the buffer. */ |
| if ((ret = xd3_read_size (stream, & sect->buf, |
| sect->buf_max, & dec_size)) || |
| (ret = xd3_decode_allocate (stream, dec_size, |
| & sect->copied2, & sect->alloc2))) |
| { |
| return ret; |
| } |
| |
| out_used = sect->copied2; |
| |
| if ((ret = stream->sec_type->decode (stream, *sec_streamp, |
| & sect->buf, sect->buf_max, |
| & out_used, out_used + dec_size))) |
| { |
| return ret; |
| } |
| |
| if (sect->buf != sect->buf_max) |
| { |
| stream->msg = "secondary decoder finished with unused input"; |
| return XD3_INTERNAL; |
| } |
| |
| if (out_used != sect->copied2 + dec_size) |
| { |
| stream->msg = "secondary decoder short output"; |
| return XD3_INTERNAL; |
| } |
| |
| sect->buf = sect->copied2; |
| sect->buf_max = sect->copied2 + dec_size; |
| sect->size = dec_size; |
| |
| return 0; |
| } |
| |
| #if XD3_ENCODER |
| static inline int xd3_encode_bit (xd3_stream *stream, |
| xd3_output **output, |
| bit_state *bits, |
| usize_t bit) |
| { |
| int ret; |
| |
| if (bit) |
| { |
| bits->cur_byte |= bits->cur_mask; |
| } |
| |
| /* OPT: Might help to buffer more than 8 bits at once. */ |
| if (bits->cur_mask == 0x80) |
| { |
| if ((ret = xd3_emit_byte (stream, output, bits->cur_byte)) != 0) |
| { |
| return ret; |
| } |
| |
| bits->cur_mask = 1; |
| bits->cur_byte = 0; |
| } |
| else |
| { |
| bits->cur_mask <<= 1; |
| } |
| |
| return 0; |
| } |
| |
| static inline int xd3_flush_bits (xd3_stream *stream, |
| xd3_output **output, |
| bit_state *bits) |
| { |
| return (bits->cur_mask == 1) ? 0 : |
| xd3_emit_byte (stream, output, bits->cur_byte); |
| } |
| |
| static inline int xd3_encode_bits (xd3_stream *stream, |
| xd3_output **output, |
| bit_state *bits, |
| usize_t nbits, |
| usize_t value) |
| { |
| int ret; |
| usize_t mask = 1 << nbits; |
| |
| XD3_ASSERT (nbits > 0); |
| XD3_ASSERT (nbits < sizeof (usize_t) * 8); |
| XD3_ASSERT (value < mask); |
| |
| do |
| { |
| mask >>= 1; |
| |
| if ((ret = xd3_encode_bit (stream, output, bits, value & mask))) |
| { |
| return ret; |
| } |
| } |
| while (mask != 1); |
| |
| IF_DEBUG2 (DP(RINT "(e) %u ", value)); |
| |
| return 0; |
| } |
| |
| static int |
| xd3_encode_secondary (xd3_stream *stream, |
| xd3_output **head, |
| xd3_output **tail, |
| xd3_sec_stream **sec_streamp, |
| xd3_sec_cfg *cfg, |
| int *did_it) |
| { |
| xd3_output *tmp_head; |
| xd3_output *tmp_tail; |
| |
| usize_t comp_size; |
| usize_t orig_size; |
| |
| int ret; |
| |
| orig_size = xd3_sizeof_output (*head); |
| |
| if (orig_size < SECONDARY_MIN_INPUT) { return 0; } |
| |
| if ((ret = xd3_get_secondary (stream, sec_streamp, 1)) != 0) |
| { |
| return ret; |
| } |
| |
| tmp_head = xd3_alloc_output (stream, NULL); |
| |
| /* Encode the size, encode the data. Encoding the size makes it |
| * simpler, but is a little gross. Should not need the entire |
| * section in contiguous memory, but it is much easier this way. */ |
| if ((ret = xd3_emit_size (stream, & tmp_head, orig_size)) || |
| (ret = stream->sec_type->encode (stream, *sec_streamp, *head, |
| tmp_head, cfg))) |
| { |
| goto getout; |
| } |
| |
| /* If the secondary compressor determines it's no good, it returns |
| * XD3_NOSECOND. */ |
| |
| /* Setup tmp_tail, comp_size */ |
| tmp_tail = tmp_head; |
| comp_size = tmp_head->next; |
| |
| while (tmp_tail->next_page != NULL) |
| { |
| tmp_tail = tmp_tail->next_page; |
| comp_size += tmp_tail->next; |
| } |
| |
| XD3_ASSERT (comp_size == xd3_sizeof_output (tmp_head)); |
| XD3_ASSERT (tmp_tail != NULL); |
| |
| if (comp_size < (orig_size - SECONDARY_MIN_SAVINGS)) |
| { |
| IF_DEBUG1(DP(RINT "secondary saved %u bytes: %u -> %u (%0.2f%%)\n", |
| orig_size - comp_size, orig_size, comp_size, |
| 100.0 * (double) comp_size / (double) orig_size)); |
| |
| xd3_free_output (stream, *head); |
| |
| *head = tmp_head; |
| *tail = tmp_tail; |
| *did_it = 1; |
| } |
| else |
| { |
| getout: |
| if (ret == XD3_NOSECOND) { ret = 0; } |
| xd3_free_output (stream, tmp_head); |
| } |
| |
| return ret; |
| } |
| #endif /* XD3_ENCODER */ |
| #endif /* _XDELTA3_SECOND_H_ */ |