// 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 #include #include #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:: 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(temp)); crc.add(static_cast(temp)); continue; } else { model.encode(eof_symbol); // now write the checksum unsigned long checksum = crc.get_checksum(); unsigned char byte1 = static_cast((checksum>>24)&0xFF); unsigned char byte2 = static_cast((checksum>>16)&0xFF); unsigned char byte3 = static_cast((checksum>>8)&0xFF); unsigned char byte4 = static_cast((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:: 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(symbol)); // write this symbol to out if (out.sputc(static_cast(symbol)) != static_cast(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(symbol); model.decode(symbol); byte2 = static_cast(symbol); model.decode(symbol); byte3 = static_cast(symbol); model.decode(symbol); byte4 = static_cast(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_