text: // Copyright (C) 2003  Davis E. King (davis@dlib.net)
  // License: Boost Software License   See LICENSE.txt for the full license.
  #ifndef DLIB_ENTROPY_DECODER_KERNEL_1_CPp_
  #define DLIB_ENTROPY_DECODER_KERNEL_1_CPp_
  #include "entropy_decoder_kernel_1.h"
  #include <iostream>
  #include <streambuf>
  #include <sstream>
  
  #include "../assert.h"
  
  namespace dlib
  {
  
  // ----------------------------------------------------------------------------------------
  
      entropy_decoder_kernel_1::
      entropy_decoder_kernel_1(
      ) :
          initial_low(0x00000001),
          initial_high(0xffffffff),
          in(0),
          low(initial_low),
          high(initial_high),
          buf(0),
          buf_used(0),
          target(0x00000000),
          r(0)
      {
      }
  
  // ----------------------------------------------------------------------------------------
  
      entropy_decoder_kernel_1::
      ~entropy_decoder_kernel_1 (
      )
      {
      }
  
  // ----------------------------------------------------------------------------------------
  
      void entropy_decoder_kernel_1::
      clear(
      )
      {
          in       = 0;
          buf_used = 0;
          buf      = 0;
          r        = 0;
          low      = initial_low;
          high     = initial_high;
          target   = 0x00000000;
      }
  
  // ----------------------------------------------------------------------------------------
  
      void entropy_decoder_kernel_1::
      set_stream (
          std::istream& in_
      )
      {
          buf_used = 0;
          buf      = 0;
          r        = 0;
          low      = initial_low;
          high     = initial_high;
          target   = 0x00000000;
  
          in = &in_;
          streambuf = in_.rdbuf();
  
  
  
          unsigned char ch;
  
          
          streambuf->sgetn((char*)&ch,1);
          target = ch;
          
          target <<= 8;
          if (streambuf->sgetn((char*)&ch,1))
              target += ch;
  
  
          target <<= 8;
          if (streambuf->sgetn((char*)&ch,1))
              target += ch;
  
  
          target <<= 8;
          if (streambuf->sgetn((char*)&ch,1))
              target += ch;
  
      }
  
  // ----------------------------------------------------------------------------------------
  
      bool entropy_decoder_kernel_1::
      stream_is_set (
      ) const
      {
          if (in != 0)
              return true;
          else
              return false;
      }
  
  // ----------------------------------------------------------------------------------------
  
      std::istream& entropy_decoder_kernel_1::
      get_stream (
      ) const
      {
          return *in;
      }
  
  // ----------------------------------------------------------------------------------------
  
      void entropy_decoder_kernel_1::
      decode (
          uint32 low_count,
          uint32 high_count
      )
      {
          // 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;
          r = 0;
  
  
  
          while (true)
          {
  
              // if the highest order bit in high and low is the same
              if ( low >= 0x80000000 || high < 0x80000000)
              {
                  // make sure buf isn't empty
                  if (buf_used == 0)
                  {
                      buf_used = 8;
                      if (streambuf->sgetn(reinterpret_cast<char*>(&buf),1)==0)
                      {
                          // if there isn't anything else in the streambuffer then just
                          // make buf zero.  
                          buf = 0;      
                      }
                  }
  
                  // we will be taking one bit from buf to replace the one we threw away
                  --buf_used;
  
                  // roll off the bit in target
                  target <<= 1;  
  
                  // roll off the bit
                  high <<= 1;
                  low <<= 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;
  
                    // take a bit from buf to fill in the one we threw away                
                  target += (buf>>buf_used)&0x01;   
              }
              // 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)
  
      }
  
  // ----------------------------------------------------------------------------------------
  
      bool entropy_decoder_kernel_1::
      get_target_called (        
      ) const
      {           
          return (r != 0);
      }
  
  // ----------------------------------------------------------------------------------------
  
      uint32 entropy_decoder_kernel_1::
      get_target (
          uint32 total
      ) 
      {   
          // note that we must add one because of the convention that
          // high == the real upper range minus 1
          r = (high-low+1)/total;                   
          uint32 temp = (target-low)/r;
          if (temp < total)
              return temp;
          else
              return total-1;
      }
  
  // ----------------------------------------------------------------------------------------
  
  }
  #endif // DLIB_ENTROPY_DECODER_KERNEL_1_CPp_
  
  