// Copyright (C) 2003 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. #ifndef DLIB_ENTROPY_ENCODER_KERNEL_1_CPp_ #define DLIB_ENTROPY_ENCODER_KERNEL_1_CPp_ #include "entropy_encoder_kernel_1.h" #include <iostream> #include <streambuf> namespace dlib { // ---------------------------------------------------------------------------------------- entropy_encoder_kernel_1:: entropy_encoder_kernel_1( ) : initial_low(0x00000001), initial_high(0xffffffff), out(0), low(initial_low), high(initial_high), buf(0), buf_used(0) { } // ---------------------------------------------------------------------------------------- entropy_encoder_kernel_1:: ~entropy_encoder_kernel_1 ( ) { try { if (out != 0) { flush(); } } catch (...) {} } // ---------------------------------------------------------------------------------------- void entropy_encoder_kernel_1:: clear( ) { if (out != 0) { flush(); } out = 0; } // ---------------------------------------------------------------------------------------- void entropy_encoder_kernel_1:: set_stream ( std::ostream& out_ ) { if (out != 0) { // if a stream is currently set then flush the buffers to it before // we switch to the new stream flush(); } out = &out_; streambuf = out_.rdbuf(); // reset the encoder state buf_used = 0; buf = 0; low = initial_low; high = initial_high; } // ---------------------------------------------------------------------------------------- bool entropy_encoder_kernel_1:: stream_is_set ( ) const { if (out != 0) return true; else return false; } // ---------------------------------------------------------------------------------------- std::ostream& entropy_encoder_kernel_1:: get_stream ( ) const { return *out; } // ---------------------------------------------------------------------------------------- void entropy_encoder_kernel_1:: encode ( uint32 low_count, uint32 high_count, uint32 total ) { // note that we must add one because of the convention that // high == the real upper range minus 1 uint32 r = (high-low+1)/total; // note that we must subtract 1 to preserve the convention that // high == the real upper range - 1 high = low + r*high_count-1; low = low + r*low_count; while (true) { // if the highest order bit in high and low is the same if ( low >= 0x80000000 || high < 0x80000000) { // if buf is full then write it out if (buf_used == 8) { if (streambuf->sputn(reinterpret_cast<char*>(&buf),1)==0) { throw std::ios_base::failure("error occured in the entropy_encoder object"); } buf = 0; buf_used = 0; } // write the high order bit from low into buf buf <<= 1; ++buf_used; if (low&0x80000000) buf |= 0x1; // roll off the bit we just wrote to buf low <<= 1; high <<= 1; high |= 1; // note that it is ok to add one to high here because // of the convention that high == real upper range - 1. // so that means that if we want to shift the upper range // left by one then we must shift a one into high also // since real upper range == high + 0.999999999... // make sure low is never zero if (low == 0) low = 1; } // if the distance between high and low is small and there aren't // any bits we can roll off then round low up or high down. else if (high-low < 0x10000) { if (high == 0x80000000) high = 0x7fffffff; else low = 0x80000000; } else { break; } } // while (true) } // ---------------------------------------------------------------------------------------- void entropy_encoder_kernel_1:: flush ( ) { // flush the next 4 or 5 bytes that are buffered // thats whatever is contained in buf and then all of low plus any extra // bits needed to pad that to be an even 4 or 5 bytes if (buf_used != 8) { buf <<= (8-buf_used); buf |= static_cast<unsigned char>(low>>(24+buf_used)); low <<= (8-buf_used); } if (streambuf->sputn(reinterpret_cast<char*>(&buf),1) == 0) throw std::ios_base::failure("error occured in the entropy_encoder object"); buf = static_cast<unsigned char>((low >> 24)&0xFF); if (streambuf->sputn(reinterpret_cast<char*>(&buf),1) == 0) throw std::ios_base::failure("error occured in the entropy_encoder object"); buf = static_cast<unsigned char>((low >> 16)&0xFF); if (streambuf->sputn(reinterpret_cast<char*>(&buf),1)==0) throw std::ios_base::failure("error occured in the entropy_encoder object"); buf = static_cast<unsigned char>((low >> 8)&0xFF); if (streambuf->sputn(reinterpret_cast<char*>(&buf),1)==0) throw std::ios_base::failure("error occured in the entropy_encoder object"); if (buf_used != 0) { buf = static_cast<unsigned char>((low)&0xFF); if (streambuf->sputn(reinterpret_cast<char*>(&buf),1)==0) throw std::ios_base::failure("error occured in the entropy_encoder object"); } // make sure the stream buffer flushes to its I/O channel streambuf->pubsync(); // reset the encoder state buf_used = 0; buf = 0; low = initial_low; high = initial_high; } // ---------------------------------------------------------------------------------------- } #endif // DLIB_ENTROPY_ENCODER_KERNEL_1_CPp_