|
|
|
|
|
#ifndef DLIB_COMPRESS_STREAM_KERNEl_3_ |
|
#define DLIB_COMPRESS_STREAM_KERNEl_3_ |
|
|
|
#include "../algs.h" |
|
#include "compress_stream_kernel_abstract.h" |
|
#include "../assert.h" |
|
|
|
namespace dlib |
|
{ |
|
|
|
template < |
|
typename lzp_buf, |
|
typename crc32, |
|
unsigned long buffer_size |
|
> |
|
class compress_stream_kernel_3 |
|
{ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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_3 ( |
|
) |
|
{ |
|
COMPILE_TIME_ASSERT(10 < buffer_size && buffer_size < 32); |
|
} |
|
|
|
~compress_stream_kernel_3 ( |
|
) |
|
{} |
|
|
|
void compress ( |
|
std::istream& in, |
|
std::ostream& out |
|
) const; |
|
|
|
void decompress ( |
|
std::istream& in, |
|
std::ostream& out |
|
) const; |
|
|
|
|
|
|
|
private: |
|
|
|
inline void write ( |
|
unsigned char symbol |
|
) const |
|
{ |
|
if (out->sputn(reinterpret_cast<char*>(&symbol),1)==0) |
|
throw std::ios_base::failure("error writing to output stream in compress_stream_kernel_3"); |
|
} |
|
|
|
inline void decode ( |
|
unsigned char& symbol, |
|
unsigned char& flag |
|
) const |
|
{ |
|
if (count == 0) |
|
{ |
|
if (((size_t)in->sgetn(reinterpret_cast<char*>(buffer),sizeof(buffer)))!=sizeof(buffer)) |
|
throw decompression_error("Error detected in compressed data stream."); |
|
count = 8; |
|
} |
|
--count; |
|
symbol = buffer[8-count]; |
|
flag = buffer[0] >> 7; |
|
buffer[0] <<= 1; |
|
} |
|
|
|
inline void encode ( |
|
unsigned char symbol, |
|
unsigned char flag |
|
) const |
|
|
|
|
|
|
|
|
|
|
|
|
|
{ |
|
|
|
++count; |
|
buffer[0] <<= 1; |
|
buffer[count] = symbol; |
|
buffer[0] |= flag; |
|
|
|
if (count == 8) |
|
{ |
|
if (((size_t)out->sputn(reinterpret_cast<char*>(buffer),sizeof(buffer)))!=sizeof(buffer)) |
|
throw std::ios_base::failure("error writing to output stream in compress_stream_kernel_3"); |
|
count = 0; |
|
buffer[0] = 0; |
|
} |
|
} |
|
|
|
void clear ( |
|
) const |
|
|
|
|
|
|
|
|
|
{ |
|
count = 0; |
|
} |
|
|
|
void flush ( |
|
) const |
|
|
|
|
|
|
|
|
|
{ |
|
if (count != 0) |
|
{ |
|
buffer[0] <<= (8-count); |
|
if (((size_t)out->sputn(reinterpret_cast<char*>(buffer),sizeof(buffer)))!=sizeof(buffer)) |
|
throw std::ios_base::failure("error writing to output stream in compress_stream_kernel_3"); |
|
} |
|
} |
|
|
|
mutable unsigned int count; |
|
|
|
|
|
mutable unsigned char buffer[9]; |
|
|
|
|
|
|
|
mutable std::streambuf* in; |
|
mutable std::streambuf* out; |
|
|
|
|
|
compress_stream_kernel_3(compress_stream_kernel_3<lzp_buf,crc32,buffer_size>&); |
|
compress_stream_kernel_3<lzp_buf,crc32,buffer_size>& operator=(compress_stream_kernel_3<lzp_buf,crc32,buffer_size>&); |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template < |
|
typename lzp_buf, |
|
typename crc32, |
|
unsigned long buffer_size |
|
> |
|
void compress_stream_kernel_3<lzp_buf,crc32,buffer_size>:: |
|
compress ( |
|
std::istream& in_, |
|
std::ostream& out_ |
|
) const |
|
{ |
|
in = in_.rdbuf(); |
|
out = out_.rdbuf(); |
|
clear(); |
|
|
|
crc32 crc; |
|
|
|
lzp_buf buffer(buffer_size); |
|
|
|
std::streambuf::int_type temp = in->sbumpc(); |
|
unsigned long index; |
|
unsigned char symbol; |
|
unsigned char length; |
|
|
|
while (temp != EOF) |
|
{ |
|
symbol = static_cast<unsigned char>(temp); |
|
if (buffer.predict_match(index)) |
|
{ |
|
if (buffer[index] == symbol) |
|
{ |
|
|
|
length = 1; |
|
|
|
buffer.add(symbol); |
|
crc.add(symbol); |
|
|
|
temp = in->sbumpc(); |
|
while (length < 255) |
|
{ |
|
if (temp == EOF) |
|
{ |
|
break; |
|
} |
|
else if (static_cast<unsigned long>(length) >= index) |
|
{ |
|
break; |
|
} |
|
else if (static_cast<unsigned char>(temp) == buffer[index]) |
|
{ |
|
++length; |
|
buffer.add(static_cast<unsigned char>(temp)); |
|
crc.add(static_cast<unsigned char>(temp)); |
|
temp = in->sbumpc(); |
|
} |
|
else |
|
{ |
|
break; |
|
} |
|
} |
|
|
|
encode(length,1); |
|
} |
|
else |
|
{ |
|
|
|
encode(symbol,0); |
|
buffer.add(symbol); |
|
crc.add(symbol); |
|
|
|
|
|
temp = in->sbumpc(); |
|
} |
|
} |
|
else |
|
{ |
|
|
|
encode(symbol,0); |
|
buffer.add(symbol); |
|
crc.add(symbol); |
|
|
|
|
|
temp = in->sbumpc(); |
|
} |
|
} |
|
|
|
|
|
encode(0,1); |
|
|
|
|
|
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); |
|
|
|
encode(byte1,0); |
|
encode(byte2,0); |
|
encode(byte3,0); |
|
encode(byte4,0); |
|
|
|
flush(); |
|
} |
|
|
|
|
|
|
|
template < |
|
typename lzp_buf, |
|
typename crc32, |
|
unsigned long buffer_size |
|
> |
|
void compress_stream_kernel_3<lzp_buf,crc32,buffer_size>:: |
|
decompress ( |
|
std::istream& in_, |
|
std::ostream& out_ |
|
) const |
|
{ |
|
in = in_.rdbuf(); |
|
out = out_.rdbuf(); |
|
clear(); |
|
|
|
crc32 crc; |
|
|
|
lzp_buf buffer(buffer_size); |
|
|
|
|
|
unsigned long index = 0; |
|
unsigned char symbol; |
|
unsigned char length; |
|
unsigned char flag; |
|
|
|
decode(symbol,flag); |
|
while (flag == 0 || symbol != 0) |
|
{ |
|
buffer.predict_match(index); |
|
|
|
if (flag == 1) |
|
{ |
|
length = symbol; |
|
do |
|
{ |
|
--length; |
|
symbol = buffer[index]; |
|
write(symbol); |
|
buffer.add(symbol); |
|
crc.add(symbol); |
|
} while (length != 0); |
|
} |
|
else |
|
{ |
|
|
|
write(symbol); |
|
buffer.add(symbol); |
|
crc.add(symbol); |
|
} |
|
decode(symbol,flag); |
|
} |
|
|
|
|
|
|
|
unsigned char byte1; |
|
unsigned char byte2; |
|
unsigned char byte3; |
|
unsigned char byte4; |
|
|
|
decode(byte1,flag); |
|
if (flag != 0) |
|
throw decompression_error("Error detected in compressed data stream."); |
|
decode(byte2,flag); |
|
if (flag != 0) |
|
throw decompression_error("Error detected in compressed data stream."); |
|
decode(byte3,flag); |
|
if (flag != 0) |
|
throw decompression_error("Error detected in compressed data stream."); |
|
decode(byte4,flag); |
|
if (flag != 0) |
|
throw decompression_error("Error detected in compressed data stream."); |
|
|
|
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."); |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
#endif |
|
|
|
|