253 lines
7.1 KiB
C++
253 lines
7.1 KiB
C++
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
|
|
// License: Boost Software License See LICENSE.txt for the full license.
|
|
#ifndef DLIB_COMPRESS_STREAM_KERNEl_1_
|
|
#define DLIB_COMPRESS_STREAM_KERNEl_1_
|
|
|
|
#include "../algs.h"
|
|
#include <iostream>
|
|
#include <streambuf>
|
|
#include <cstdio>
|
|
#include "compress_stream_kernel_abstract.h"
|
|
|
|
namespace dlib
|
|
{
|
|
|
|
template <
|
|
typename fce,
|
|
typename fcd,
|
|
typename crc32
|
|
>
|
|
class compress_stream_kernel_1
|
|
{
|
|
/*!
|
|
REQUIREMENTS ON fce
|
|
is an implementation of entropy_encoder_model/entropy_encoder_model_kernel_abstract.h
|
|
the alphabet_size of fce must be 257.
|
|
fce and fcd share the same kernel number.
|
|
|
|
REQUIREMENTS ON fcd
|
|
is an implementation of entropy_decoder_model/entropy_decoder_model_kernel_abstract.h
|
|
the alphabet_size of fcd must be 257.
|
|
fce and fcd share the same kernel number.
|
|
|
|
REQUIREMENTS ON crc32
|
|
is an implementation of crc32/crc32_kernel_abstract.h
|
|
|
|
|
|
|
|
INITIAL VALUE
|
|
this object has no state
|
|
|
|
CONVENTION
|
|
this object has no state
|
|
!*/
|
|
|
|
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_1 (
|
|
)
|
|
{}
|
|
|
|
~compress_stream_kernel_1 (
|
|
)
|
|
{}
|
|
|
|
void compress (
|
|
std::istream& in,
|
|
std::ostream& out
|
|
) const;
|
|
|
|
void decompress (
|
|
std::istream& in,
|
|
std::ostream& out
|
|
) const;
|
|
|
|
private:
|
|
|
|
// restricted functions
|
|
compress_stream_kernel_1(compress_stream_kernel_1&); // copy constructor
|
|
compress_stream_kernel_1& operator=(compress_stream_kernel_1&); // assignment operator
|
|
|
|
};
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
// ----------------------------------------------------------------------------------------
|
|
// member function definitions
|
|
// ----------------------------------------------------------------------------------------
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename fce,
|
|
typename fcd,
|
|
typename crc32
|
|
>
|
|
void compress_stream_kernel_1<fce,fcd,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);
|
|
|
|
crc32 crc;
|
|
|
|
unsigned long count = 0;
|
|
|
|
while (true)
|
|
{
|
|
// write out a known value every 20000 symbols
|
|
if (count == 20000)
|
|
{
|
|
count = 0;
|
|
coder.encode(1500,1501,8000);
|
|
}
|
|
++count;
|
|
|
|
// get the next character
|
|
temp = in.sbumpc();
|
|
|
|
// if we have hit EOF then encode the marker symbol
|
|
if (temp != EOF)
|
|
{
|
|
// encode the symbol
|
|
model.encode(static_cast<unsigned long>(temp));
|
|
crc.add(static_cast<unsigned char>(temp));
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
model.encode(eof_symbol);
|
|
|
|
// now write the checksum
|
|
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 crc32
|
|
>
|
|
void compress_stream_kernel_1<fce,fcd,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);
|
|
|
|
unsigned long symbol;
|
|
unsigned long count = 0;
|
|
|
|
crc32 crc;
|
|
|
|
// decode until we hit the marker symbol
|
|
while (true)
|
|
{
|
|
// make sure this is the value we expect
|
|
if (count == 20000)
|
|
{
|
|
if (coder.get_target(8000) != 1500)
|
|
{
|
|
throw decompression_error("Error detected in compressed data stream.");
|
|
}
|
|
count = 0;
|
|
coder.decode(1500,1501);
|
|
}
|
|
++count;
|
|
|
|
// decode the next symbol
|
|
model.decode(symbol);
|
|
if (symbol != eof_symbol)
|
|
{
|
|
crc.add(static_cast<unsigned char>(symbol));
|
|
// write this symbol to out
|
|
if (out.sputc(static_cast<char>(symbol)) != static_cast<int>(symbol))
|
|
{
|
|
throw std::ios::failure("error occurred in compress_stream_kernel_1::decompress");
|
|
}
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
// we read eof from the encoded data. now we just have to check the checksum and we are done.
|
|
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;
|
|
}
|
|
} // while (true)
|
|
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
}
|
|
|
|
#endif // DLIB_COMPRESS_STREAM_KERNEl_1_
|
|
|