/* Clzip - LZMA lossless data compressor
Copyright (C) 2010-2017 Antonio Diaz Diaz.
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, see . */
#define _FILE_OFFSET_BITS 64
#include
#include
#include
#include
#include
#include "lzip.h"
#include "encoder_base.h"
Dis_slots dis_slots;
Prob_prices prob_prices;
bool
Mb_read_block(Matchfinder_base *mb)
{
if (!mb->at_stream_end && mb->stream_pos < mb->buffer_size) {
int size = mb->buffer_size - mb->stream_pos;
int rd = readblock(mb->infd, mb->buffer + mb->stream_pos, size);
mb->stream_pos += rd;
if (rd != size && errno) {
show_error( "Read error", errno, false );
cleanup_and_fail(1);
}
if (rd < size) {
mb->at_stream_end = true;
mb->pos_limit = mb->buffer_size;
}
}
return mb->pos < mb->stream_pos;
}
void
Mb_normalize_pos(Matchfinder_base *mb)
{
if (mb->pos > mb->stream_pos)
internal_error( "pos > stream_pos in Mb_normalize_pos." );
if (!mb->at_stream_end) {
int i, offset = mb->pos - mb->before_size - mb->dict_size;
int size = mb->stream_pos - offset;
memmove(mb->buffer, mb->buffer + offset, size);
mb->partial_data_pos += offset;
mb->pos -= offset; /* pos = before_size + dict_size */
mb->stream_pos -= offset;
for (i = 0; i < mb->num_prev_positions; ++i)
if (mb->prev_positions[i] < offset)
mb->prev_positions[i] = 0;
else
mb->prev_positions[i] -= offset;
for (i = 0; i < mb->pos_array_size; ++i)
if (mb->pos_array[i] < offset)
mb->pos_array[i] = 0;
else
mb->pos_array[i] -= offset;
Mb_read_block(mb);
}
}
bool
Mb_init(Matchfinder_base *mb, int before, int dict_size, int after_size, int dict_factor, int num_prev_positions23, int pos_array_factor, int ifd)
{
int buffer_size_limit = (dict_factor * dict_size) + before + after_size;
unsigned size;
int i;
mb->partial_data_pos = 0;
mb->before_size = before;
mb->pos = 0;
mb->cyclic_pos = 0;
mb->stream_pos = 0;
mb->infd = ifd;
mb->at_stream_end = false;
mb->buffer_size = max(65536, dict_size);
mb->buffer = (uint8_t *)malloc(mb->buffer_size);
if (!mb->buffer)
return false;
if (Mb_read_block(mb) && !mb->at_stream_end &&
mb->buffer_size < buffer_size_limit) {
uint8_t * tmp;
mb->buffer_size = buffer_size_limit;
tmp = (uint8_t *)realloc(mb->buffer, mb->buffer_size);
if (!tmp) {
free(mb->buffer);
return false;
}
mb->buffer = tmp;
Mb_read_block(mb);
}
if (mb->at_stream_end && mb->stream_pos < dict_size)
mb->dict_size = max(min_dict_size, mb->stream_pos);
else
mb->dict_size = dict_size;
mb->pos_limit = mb->buffer_size;
if (!mb->at_stream_end)
mb->pos_limit -= after_size;
size = real_bits(mb->dict_size - 1) - 2;
if (size < 16)
size = 16;
size = 1 << size;
// if (mb->dict_size > (1 << 26)) /* 64 MiB */
// size >>= 1;
mb->key4_mask = size - 1;
size += num_prev_positions23;
mb->num_prev_positions = size;
mb->pos_array_size = pos_array_factor * (mb->dict_size + 1);
size += mb->pos_array_size;
if (size * sizeof mb->prev_positions[0] <= size)
mb->prev_positions = 0;
else
mb->prev_positions =
(int32_t *)malloc(size * sizeof mb->prev_positions[0]);
if (!mb->prev_positions) {
free(mb->buffer);
return false;
}
mb->pos_array = mb->prev_positions + mb->num_prev_positions;
for (i = 0; i < mb->num_prev_positions; ++i)
mb->prev_positions[i] = 0;
return true;
}
void
Mb_reset(Matchfinder_base *mb)
{
int i;
if (mb->stream_pos > mb->pos)
memmove(mb->buffer, mb->buffer + mb->pos, mb->stream_pos - mb->pos);
mb->partial_data_pos = 0;
mb->stream_pos -= mb->pos;
mb->pos = 0;
mb->cyclic_pos = 0;
for (i = 0; i < mb->num_prev_positions; ++i)
mb->prev_positions[i] = 0;
Mb_read_block(mb);
}
void
Re_flush_data(Range_encoder *renc)
{
if (renc->pos > 0) {
if (renc->outfd >= 0 &&
writeblock(renc->outfd, renc->buffer, renc->pos) != renc->pos) {
show_error( "Write error", errno, false );
cleanup_and_fail(1);
}
renc->partial_member_pos += renc->pos;
renc->pos = 0;
show_progress(0, 0, 0, 0);
}
}
/* End Of Stream mark => (dis == 0xFFFFFFFFU, len == min_match_len) */
void
LZeb_full_flush(LZ_encoder_base *eb, State state)
{
int i;
int pos_state = Mb_data_position(&eb->mb) & pos_state_mask;
File_trailer trailer;
Re_encode_bit(&eb->renc, &eb->bm_match[state][pos_state], 1);
Re_encode_bit(&eb->renc, &eb->bm_rep[state], 0);
LZeb_encode_pair(eb, 0xFFFFFFFFU, min_match_len, pos_state);
Re_flush(&eb->renc);
Ft_set_data_crc(trailer, LZeb_crc(eb));
Ft_set_data_size(trailer, Mb_data_position(&eb->mb));
Ft_set_member_size(trailer, Re_member_position(&eb->renc) + Ft_size);
for (i = 0; i < Ft_size; ++i)
Re_put_byte(&eb->renc, trailer[i]);
Re_flush_data(&eb->renc);
}
void
LZeb_reset(LZ_encoder_base *eb)
{
Mb_reset(&eb->mb);
eb->crc = 0xFFFFFFFFU;
Bm_array_init(eb->bm_literal[0], (1 << literal_context_bits) * 0x300);
Bm_array_init(eb->bm_match[0], states * pos_states);
Bm_array_init(eb->bm_rep, states);
Bm_array_init(eb->bm_rep0, states);
Bm_array_init(eb->bm_rep1, states);
Bm_array_init(eb->bm_rep2, states);
Bm_array_init(eb->bm_len[0], states * pos_states);
Bm_array_init(eb->bm_dis_slot[0], len_states * (1 << dis_slot_bits));
Bm_array_init(eb->bm_dis, modeled_distances - end_dis_model + 1);
Bm_array_init(eb->bm_align, dis_align_size);
Lm_init(&eb->match_len_model);
Lm_init(&eb->rep_len_model);
Re_reset(&eb->renc);
}