|
|
|
|
|
#ifndef DLIB_COMPRESS_STREAM_KERNEl_2_ |
|
#define DLIB_COMPRESS_STREAM_KERNEl_2_ |
|
|
|
#include "../algs.h" |
|
#include <iostream> |
|
#include <streambuf> |
|
#include "compress_stream_kernel_abstract.h" |
|
|
|
namespace dlib |
|
{ |
|
|
|
template < |
|
typename fce, |
|
typename fcd, |
|
typename lz77_buffer, |
|
typename sliding_buffer, |
|
typename fce_length, |
|
typename fcd_length, |
|
typename fce_index, |
|
typename fcd_index, |
|
typename crc32 |
|
> |
|
class compress_stream_kernel_2 |
|
{ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const static unsigned long eof_symbol = 256; |
|
|
|
public: |
|
|
|
class decompression_error : public dlib::error |
|
{ |
|
public: |
|
decompression_error( |
|
const char* i |
|
) : |
|
dlib::error(std::string(i)) |
|
{} |
|
|
|
decompression_error( |
|
const std::string& i |
|
) : |
|
dlib::error(i) |
|
{} |
|
}; |
|
|
|
|
|
compress_stream_kernel_2 ( |
|
) |
|
{} |
|
|
|
~compress_stream_kernel_2 ( |
|
) |
|
{} |
|
|
|
void compress ( |
|
std::istream& in, |
|
std::ostream& out |
|
) const; |
|
|
|
void decompress ( |
|
std::istream& in, |
|
std::ostream& out |
|
) const; |
|
|
|
private: |
|
|
|
|
|
compress_stream_kernel_2(compress_stream_kernel_2&); |
|
compress_stream_kernel_2& operator=(compress_stream_kernel_2&); |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template < |
|
typename fce, |
|
typename fcd, |
|
typename lz77_buffer, |
|
typename sliding_buffer, |
|
typename fce_length, |
|
typename fcd_length, |
|
typename fce_index, |
|
typename fcd_index, |
|
typename crc32 |
|
> |
|
void compress_stream_kernel_2<fce,fcd,lz77_buffer,sliding_buffer,fce_length,fcd_length,fce_index,fcd_index,crc32>:: |
|
compress ( |
|
std::istream& in_, |
|
std::ostream& out_ |
|
) const |
|
{ |
|
std::streambuf::int_type temp; |
|
|
|
std::streambuf& in = *in_.rdbuf(); |
|
|
|
typename fce::entropy_encoder_type coder; |
|
coder.set_stream(out_); |
|
|
|
fce model(coder); |
|
fce_length model_length(coder); |
|
fce_index model_index(coder); |
|
|
|
const unsigned long LOOKAHEAD_LIMIT = 512; |
|
lz77_buffer buffer(15,LOOKAHEAD_LIMIT); |
|
|
|
crc32 crc; |
|
|
|
|
|
unsigned long count = 0; |
|
|
|
unsigned long lz77_count = 1; |
|
unsigned long ppm_count = 1; |
|
|
|
|
|
while (true) |
|
{ |
|
|
|
if (count == 20000) |
|
{ |
|
count = 0; |
|
coder.encode(150,151,400); |
|
} |
|
++count; |
|
|
|
|
|
if (buffer.get_lookahead_buffer_size() < buffer.get_lookahead_buffer_limit()) |
|
{ |
|
temp = in.sbumpc(); |
|
while (temp != EOF) |
|
{ |
|
crc.add(static_cast<unsigned char>(temp)); |
|
buffer.add(static_cast<unsigned char>(temp)); |
|
if (buffer.get_lookahead_buffer_size() == buffer.get_lookahead_buffer_limit()) |
|
break; |
|
temp = in.sbumpc(); |
|
} |
|
} |
|
|
|
|
|
|
|
unsigned long sum = ppm_count + lz77_count; |
|
if (sum >= 65536) |
|
{ |
|
ppm_count >>= 1; |
|
lz77_count >>= 1; |
|
ppm_count |= 1; |
|
lz77_count |= 1; |
|
sum = ppm_count+lz77_count; |
|
} |
|
|
|
|
|
if (buffer.get_lookahead_buffer_size() > 0) |
|
{ |
|
unsigned long match_index, match_length; |
|
buffer.find_match(match_index,match_length,6); |
|
if (match_length != 0) |
|
{ |
|
|
|
|
|
coder.encode(0,lz77_count,sum); |
|
++lz77_count; |
|
|
|
|
|
model_index.encode(match_index); |
|
model_length.encode(match_length); |
|
|
|
} |
|
else |
|
{ |
|
|
|
|
|
coder.encode(lz77_count,sum,sum); |
|
++ppm_count; |
|
|
|
|
|
model.encode(buffer.lookahead_buffer(0)); |
|
buffer.shift_buffers(1); |
|
} |
|
} |
|
else |
|
{ |
|
|
|
coder.encode(lz77_count,sum,sum); |
|
|
|
|
|
model.encode(eof_symbol); |
|
|
|
unsigned long checksum = crc.get_checksum(); |
|
unsigned char byte1 = static_cast<unsigned char>((checksum>>24)&0xFF); |
|
unsigned char byte2 = static_cast<unsigned char>((checksum>>16)&0xFF); |
|
unsigned char byte3 = static_cast<unsigned char>((checksum>>8)&0xFF); |
|
unsigned char byte4 = static_cast<unsigned char>((checksum)&0xFF); |
|
|
|
model.encode(byte1); |
|
model.encode(byte2); |
|
model.encode(byte3); |
|
model.encode(byte4); |
|
|
|
break; |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
template < |
|
typename fce, |
|
typename fcd, |
|
typename lz77_buffer, |
|
typename sliding_buffer, |
|
typename fce_length, |
|
typename fcd_length, |
|
typename fce_index, |
|
typename fcd_index, |
|
typename crc32 |
|
> |
|
void compress_stream_kernel_2<fce,fcd,lz77_buffer,sliding_buffer,fce_length,fcd_length,fce_index,fcd_index,crc32>:: |
|
decompress ( |
|
std::istream& in_, |
|
std::ostream& out_ |
|
) const |
|
{ |
|
|
|
std::streambuf& out = *out_.rdbuf(); |
|
|
|
typename fcd::entropy_decoder_type coder; |
|
coder.set_stream(in_); |
|
|
|
fcd model(coder); |
|
fcd_length model_length(coder); |
|
fcd_index model_index(coder); |
|
|
|
unsigned long symbol; |
|
unsigned long count = 0; |
|
|
|
sliding_buffer buffer; |
|
buffer.set_size(15); |
|
|
|
|
|
|
|
|
|
for (unsigned long i = 0; i < buffer.size(); ++i) |
|
buffer[i] = 0; |
|
|
|
crc32 crc; |
|
|
|
unsigned long lz77_count = 1; |
|
unsigned long ppm_count = 1; |
|
bool next_block_lz77; |
|
|
|
|
|
|
|
while (true) |
|
{ |
|
|
|
if (count == 20000) |
|
{ |
|
if (coder.get_target(400) != 150) |
|
{ |
|
throw decompression_error("Error detected in compressed data stream."); |
|
} |
|
count = 0; |
|
coder.decode(150,151); |
|
} |
|
++count; |
|
|
|
|
|
|
|
|
|
unsigned long sum = ppm_count + lz77_count; |
|
if (sum >= 65536) |
|
{ |
|
ppm_count >>= 1; |
|
lz77_count >>= 1; |
|
ppm_count |= 1; |
|
lz77_count |= 1; |
|
sum = ppm_count+lz77_count; |
|
} |
|
|
|
|
|
if (coder.get_target(sum) < lz77_count) |
|
{ |
|
coder.decode(0,lz77_count); |
|
next_block_lz77 = true; |
|
++lz77_count; |
|
} |
|
else |
|
{ |
|
coder.decode(lz77_count,sum); |
|
next_block_lz77 = false; |
|
++ppm_count; |
|
} |
|
|
|
|
|
if (next_block_lz77) |
|
{ |
|
|
|
unsigned long match_length, match_index; |
|
|
|
model_index.decode(match_index); |
|
|
|
|
|
model_length.decode(match_length); |
|
|
|
|
|
match_index += match_length; |
|
buffer.rotate_left(match_length); |
|
for (unsigned long i = 0; i < match_length; ++i) |
|
{ |
|
unsigned char ch = buffer[match_index-i]; |
|
buffer[match_length-i-1] = ch; |
|
|
|
crc.add(ch); |
|
|
|
if (out.sputc(static_cast<char>(ch)) != static_cast<int>(ch)) |
|
{ |
|
throw std::ios::failure("error occurred in compress_stream_kernel_2::decompress"); |
|
} |
|
} |
|
|
|
} |
|
else |
|
{ |
|
|
|
|
|
model.decode(symbol); |
|
if (symbol != eof_symbol) |
|
{ |
|
buffer.rotate_left(1); |
|
buffer[0] = static_cast<unsigned char>(symbol); |
|
|
|
|
|
crc.add(static_cast<unsigned char>(symbol)); |
|
|
|
if (out.sputc(static_cast<char>(symbol)) != static_cast<int>(symbol)) |
|
{ |
|
throw std::ios::failure("error occurred in compress_stream_kernel_2::decompress"); |
|
} |
|
} |
|
else |
|
{ |
|
|
|
|
|
|
|
unsigned char byte1; |
|
unsigned char byte2; |
|
unsigned char byte3; |
|
unsigned char byte4; |
|
|
|
model.decode(symbol); byte1 = static_cast<unsigned char>(symbol); |
|
model.decode(symbol); byte2 = static_cast<unsigned char>(symbol); |
|
model.decode(symbol); byte3 = static_cast<unsigned char>(symbol); |
|
model.decode(symbol); byte4 = static_cast<unsigned char>(symbol); |
|
|
|
unsigned long checksum = byte1; |
|
checksum <<= 8; |
|
checksum |= byte2; |
|
checksum <<= 8; |
|
checksum |= byte3; |
|
checksum <<= 8; |
|
checksum |= byte4; |
|
|
|
if (checksum != crc.get_checksum()) |
|
throw decompression_error("Error detected in compressed data stream."); |
|
|
|
break; |
|
} |
|
} |
|
|
|
} |
|
} |
|
|
|
|
|
|
|
} |
|
|
|
#endif |
|
|
|
|