#include "pnginputmapstream.h"
using namespace std ;

namespace Colosseum
{



PngInputMapStream::PngInputMapStream ()
: is_open (false),
  file_mapping (0),
  file_handle (0),
  file_pointer (0),
  file_limit (0)
{
  return;
}


PngInputMapStream::~PngInputMapStream ()
{
  close () ;
  return ;
}


//
//  Description:
//
//    This function returns the bool value of the file stream.
//
//  Return Value:
//
//    The bool value of the file stream.
//
PngInputMapStream::operator bool () 
{
  return is_open ;
}

void PngInputMapStream::open (const std::string &filename) 
{
  OFSTRUCT ofstruct = { sizeof (OFSTRUCT) } ;

  try
  {
    file_handle = OpenFile (filename.c_str (), &ofstruct, OF_READ) ;
    if (file_handle == HFILE_ERROR)
      throw StreamError ("Can't open input file") ;

    file_mapping = CreateFileMapping (reinterpret_cast<HANDLE>(file_handle),
                                            0, // Security
                                            PAGE_READONLY, // Attributes
                                            0,  // Mapping High
                                            0,  // Mapping Low
                                            0) ; // Name
    if (file_mapping == 0)
      throw StreamError ("Can't create file mapping") ;

    map_location = MapViewOfFile(
                    file_mapping, 
                    FILE_MAP_READ, // Access
                    0, // Offset High
                    0, // Offset Low
                    0) ; // Byte Count
    if (map_location == 0)
      throw StreamError ("Can't map input file") ;
  }
  catch (...)
  {
    close () ;
    throw ;
  }
  file_pointer = reinterpret_cast<UBYTE1*>(map_location) ;

  long filesize = GetFileSize (reinterpret_cast<HANDLE>(file_handle), 0) ;
  file_limit = &file_pointer [filesize] ;

  file_pointer = reinterpret_cast<UBYTE1*>(map_location) ;
  is_open = true ;
  return ;
}

void PngInputMapStream::close () 
{
  is_open = false ;
  UnmapViewOfFile (map_location) ;
  CloseHandle (file_mapping) ;
  CloseHandle (reinterpret_cast<HANDLE>(file_handle)) ;
  file_pointer = 0 ;
  file_limit = 0 ;
  map_location = 0 ;
  return ;
}


UBYTE4 PngInputMapStream::readChunkLength ()
{
  UBYTE4 result ;
  if (file_pointer + 4 >= file_limit) 
    throw StreamError ("Premature End of File") ;

  UBYTE4 *resultpointer = reinterpret_cast<UBYTE4*>(file_pointer) ;
  file_pointer += 4 ;

  result = BigEndianToSystem (*resultpointer) ;
  return result ;
}

void PngInputMapStream::readChunkData (UBYTE4 length, UBYTE1 *&buffer)
{
  if (&file_pointer [length] >= file_limit)
    throw StreamError ("Premature End of File") ;

  buffer = file_pointer ;
  file_pointer += length ;

  return ;
}

UBYTE4 PngInputMapStream::readCrc ()
{
  UBYTE4 result ;
  if (file_pointer + 4 >= file_limit) 
    throw StreamError ("Premature End of File") ;

  UBYTE4 *resultpointer = reinterpret_cast<UBYTE4*>(file_pointer) ;
  file_pointer += 4 ;

  result = BigEndianToSystem (*resultpointer) ;
  return result ;
}

bool PngInputMapStream::endReached ()
{
  bool result = file_pointer >= file_limit ;
  return result ;
}


void PngInputMapStream::readRaw (UBYTE1 *&buffer, unsigned int count)
{
  if (&file_pointer [count] >= file_limit)
    throw StreamError ("Premature End of File") ;
  buffer = file_pointer ;
  file_pointer += count ;
  return ;
}



}  // End Namespace Colosseum
