
//
//  Title:  InputByteStream Implementation
//
//  Copyright 1997-1999, Colosseum Builders, Inc.
//  All rights reserved.
//
//  Colosseum Builders, Inc. makes no warranty, expressed or implied
//  with regards to this software. It is provided as is.
//
//  Author:  John M. Miano (miano@colosseumbuilders.com)
//
//  Date:    March 15, 1999
//
//  Version: 1
//
//  Description:
//
//    InputByteStream is an abstract class for handing the input
//    from a stream of bytes.
//
//  Revision History:
//
//

#include <cstring>

#include "inputbytestream.h"
#include "checks.h"
using namespace std ;

namespace Colosseum
{
//
// Description:
//
//  Default Constructor
//
InputByteStream::InputByteStream ()
: bit_position (-1),
  current_byte (0),
  buffer_limit (0)
{
  return ;
}
//
//  Description:
//
//    The function returns the next byte in the input stream.
//
//  Return Value:
//
//   The next byte.
//
UBYTE1 InputByteStream::getByte ()
{
  ASSERT (bit_position < 0)
  while (current_byte >= buffer_limit)
    fillBuffer () ;

  BYTE1 result = *current_byte ;
  ++ current_byte ;
  return result ;
}
//
//  Description:
//
//    The function returns the next 2-byte integer in the input stream interpreted
//    as a big endian value.
//
//    This function may only be called when in byte input mode.
//
//  Return Value:
//
//   The next 2-byte integer converted from big-endian to system format.
//
UBYTE2 InputByteStream::getBigEndianWord ()
{
  ASSERT (bit_position < 0)
  UBYTE2 result ;
  read (reinterpret_cast<char*>(&result), sizeof (result)) ;
  result = BigEndianToSystem (result) ;
  return result ;
}
//
//  Description:
//
//    The function returns the next 2-byte integer in the input stream interpreted
//    as a little endian value.
//
//    This function may only be called when in byte input mode.
//
//  Return Value:
//
//   The next 2-byte integer converted from little-endian to system format.
//
UBYTE2 InputByteStream::getLittleEndianWord ()
{
  ASSERT (bit_position < 0)
  UBYTE2 result ;
  read (reinterpret_cast<char*>(&result), sizeof (result)) ;
  result = LittleEndianToSystem (result) ;
  return result ;
}

//
//  Description:
//
//    The function returns the next 4-byte integer in the input stream interpreted
//    as a big endian value.
//
//    This function may only be called when in byte input mode.
//
//  Return Value:
//
//   The next 4-byte integer converted from big-endian to system format..
//
UBYTE4 InputByteStream::getBigEndianLong () 
{
  ASSERT (bit_position < 0)
  UBYTE4 result ;
  read (reinterpret_cast<char*>(&result), sizeof (result)) ;
  result = BigEndianToSystem (result) ;
  return result ;
}
//
//  Description:
//
//    The function returns the next 4-byte integer in the input stream interpreted
//    as a little endian value.
//
//    This function may only be called when in byte input mode.
//
//  Return Value:
//
//   The next 4-byte integer converted from little-endian to system format..
//
UBYTE4 InputByteStream::getLittleEndianLong () 
{
  ASSERT (bit_position < 0)
  UBYTE4 result ;
  read (reinterpret_cast<char*>(&result), sizeof (result)) ;
  result = BigEndianToSystem (result) ;
  return result ;
}

//
//  Description:
//
//    The function reads a block from the input stream.
//
//  Parameters:
//
//    buffer: The input buffer
//    count:  The number of bytes to read
//
//  Return Value:
//
//   The number of bytes read.
//
int  InputByteStream::read (char *buffer, int count)
{
  ASSERT (bit_position < 0)
  int result ;
  size_t remaining = buffer_limit - current_byte ;
  if (count <= remaining)
  {
    // We can respond to this request using the data already in the buffer.
    memcpy (buffer, current_byte, count) ;
    current_byte += count ;
    result = count ;
  }
  else
  {
    // Consume all of the characters already in the buffer.
    result = remaining ;
    memcpy (buffer, current_byte, remaining) ;
    buffer += remaining ;
    count -= remaining ;
    // Refill the buffer and continue
    while (count > 0 && moreData ())
    {
      fillBuffer () ;
      remaining = buffer_limit - current_byte ;
      if (count <= remaining)
      {
        // We have read enough data to handle this request.
        memcpy (buffer, current_byte, count) ;
        current_byte += count ;
        result += count ;
        break ;
      }
      else
      {
        // The new buffer does not have enough data to
        // handle this request.
        result += remaining ;
        memcpy (buffer, current_byte, remaining) ;
        buffer += remaining ;
        count -= remaining ;
      }
    }
  }
  return result ;
}

} // End Namespace

