// Copyright (C) 2004 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. #ifndef DLIB_ENTROPY_ENCODER_KERNEL_2_CPp_ #define DLIB_ENTROPY_ENCODER_KERNEL_2_CPp_ #include "entropy_encoder_kernel_2.h" #include <iostream> #include <streambuf> namespace dlib { // ---------------------------------------------------------------------------------------- entropy_encoder_kernel_2:: entropy_encoder_kernel_2( ) : initial_low(0x00000001), initial_high(0xffffffff), out(0), low(initial_low), high(initial_high) { } // ---------------------------------------------------------------------------------------- entropy_encoder_kernel_2:: ~entropy_encoder_kernel_2 ( ) { try { if (out != 0) { flush(); } } catch (...) {} } // ---------------------------------------------------------------------------------------- void entropy_encoder_kernel_2:: clear( ) { if (out != 0) { flush(); } out = 0; } // ---------------------------------------------------------------------------------------- void entropy_encoder_kernel_2:: 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 low = initial_low; high = initial_high; } // ---------------------------------------------------------------------------------------- bool entropy_encoder_kernel_2:: stream_is_set ( ) const { if (out != 0) return true; else return false; } // ---------------------------------------------------------------------------------------- std::ostream& entropy_encoder_kernel_2:: get_stream ( ) const { return *out; } // ---------------------------------------------------------------------------------------- void entropy_encoder_kernel_2:: 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 high and low don't have the same 8 high order bits if ((high&0xFF000000) != (low&0xFF000000)) { // if the distance between high and low is small and there aren't // any bits we can roll off then force high and low to have common high // order bits. if ((high-low < 0x10000)) { if (high-low > 0x1000) { high>>=1; low>>=1; high = low = high+low; high += 0xFF; low -= 0xFF; } else /**/ { high>>=1; low>>=1; high = low = high+low; } } else { // there are no bits to roll off and high and low are not // too close so just quit the loop break; } } // else if there are 8 bits we can roll off else { // write the 8 high order bits from low into buf unsigned char buf = static_cast<unsigned char>(low>>24); // roll off the bits we just wrote to buf high <<= 8; low <<= 8; high |= 0xFF; // note that it is ok to add 0xFF 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; // write buf to the output stream if (streambuf->sputn(reinterpret_cast<char*>(&buf),1)==0) { throw std::ios_base::failure("error occured in the entropy_encoder object"); } } } // while (true) } // ---------------------------------------------------------------------------------------- void entropy_encoder_kernel_2:: flush ( ) { // flush low to the output stream unsigned char buf; 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"); 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 low = initial_low; high = initial_high; } // ---------------------------------------------------------------------------------------- } #endif // DLIB_ENTROPY_ENCODER_KERNEL_2_CPp_