#ifndef _BFSTREAM_H
#define _BFSTREAM_H

#include <fstream>
#include <string>
#include <cstring>

using namespace std;

class bfstream : public fstream {
public:
   bfstream(const char * file_name, _Ios_Openmode op);
   bfstream(const bfstream & bf);
   bfstream() { }
   ~bfstream();

   bfstream & operator=(const bfstream & out);

   bfstream & operator<<(const string & str);
   bfstream & operator<<(const char * str);
   bfstream & operator<<(const char ch);
   bfstream & operator<<(const short s);
   bfstream & operator<<(const int i);
   bfstream & operator<<(const long long & l);
   bfstream & operator<<(const float f);
   bfstream & operator<<(const double & d);
   bfstream & operator<<(const unsigned short s);
   bfstream & operator<<(const unsigned char ch);
   bfstream & operator<<(const unsigned int i);
   bfstream & operator<<(const unsigned long long & l);
   bfstream & operator<<(const bool & b);

   bfstream & operator>>(string & str);
   bfstream & operator>>(char * str);  
   bfstream & operator>>(char & ch);
   bfstream & operator>>(short & s);
   bfstream & operator>>(int & i);  
   bfstream & operator>>(long long & l);
   bfstream & operator>>(float & f);
   bfstream & operator>>(double & d);
   bfstream & operator>>(unsigned short & s);
   bfstream & operator>>(unsigned char & ch);  
   bfstream & operator>>(unsigned int & i);  
   bfstream & operator>>(unsigned long long & l);
   bfstream & operator>>(bool & b);

   void seek_current(off_t offset);
};

inline
bfstream &
bfstream::operator>>(unsigned char & ch)
{
   read((char*)&ch, sizeof(unsigned char));
   return *this;
}

inline
bfstream &
bfstream::operator<<(unsigned char ch)
{
   write((char*)&ch, sizeof(unsigned char));
   return *this;
}

inline
bfstream &
bfstream::operator>>(bool & b)
{
   read((char*)&b, sizeof(bool));
   return *this;
}

inline
bfstream &
bfstream::operator<<(const bool & b)
{
   write((char*)&b, sizeof(bool));
   return *this;
}

inline
void
bfstream::seek_current(off_t offset)
{
   off_t off = tellg();
   if(off < offset) {
      off_t temp = offset - off;
      seekg(temp, ios::cur);
   }
   else if(off == offset) {

   }
   else {
      off_t temp = off - offset;
      seekg(-temp, ios::cur);
   }
}

inline
bfstream::bfstream(const char * file_name, _Ios_Openmode opt)
:fstream(file_name, opt | ios::binary) 
{
}

inline
bfstream::bfstream(const bfstream & bf)
{
}

inline
bfstream::~bfstream()
{
   fstream::close();
}

inline
bfstream & bfstream::operator<<(const string & str)
{
   size_t size = str.size() + 1;
   fstream::write(reinterpret_cast< const char * >(&size), sizeof(size_t));
   fstream::write(str.c_str(), size);
   return *this;
}

inline
bfstream & bfstream::operator<<(const char * str)
{
   size_t size = strlen(str) + 1;
   fstream::write(reinterpret_cast< const char * >(&size), sizeof(size_t));
   fstream::write(str, size);
   return *this;
}

inline
bfstream & bfstream::operator<<(const char ch)
{
   fstream::write(&ch, sizeof(const char));
   return *this;
}

inline
bfstream & bfstream::operator<<(const short s)
{
   fstream::write(reinterpret_cast< const char * >(&s), sizeof(const short));
   return *this;
}

inline
bfstream & bfstream::operator<<(const int i)
{
   fstream::write((const char *)(&i), sizeof(const int));
   return *this;
}

inline
bfstream & bfstream::operator<<(const long long & l)
{
   fstream::write(reinterpret_cast< const char * >(&l), sizeof(const long long));
   return *this;
}

inline
bfstream & bfstream::operator<<(const float f)
{
   fstream::write(reinterpret_cast< const char * >(&f), sizeof(const float));
   return *this;
}

inline
bfstream & bfstream::operator<<(const double & d)
{
   fstream::write(reinterpret_cast< const char * >(&d), sizeof(const double));
   return *this;
}

inline
bfstream & bfstream::operator<<(const unsigned short s)
{
   fstream::write(reinterpret_cast< const char * >(&s), sizeof(const unsigned short));
   return *this;
}

inline
bfstream & bfstream::operator<<(const unsigned int i)
{
   fstream::write(reinterpret_cast< const char * >(&i), sizeof(const unsigned int));
   return *this;
}

inline
bfstream & bfstream::operator<<(const unsigned long long & l)
{
   fstream::write(reinterpret_cast< const char * >(&l), sizeof(const unsigned long long));
   return *this;
}

inline
bfstream & bfstream::operator>>(string & str)
{
   size_t sz;

   fstream::read(reinterpret_cast< char * >(&sz), sizeof(size_t));

   char * buffer = new char [ sz ];

   memset(buffer, 0, sz);

   fstream::read(buffer, sz);

   str = string(buffer);

   delete [] buffer;

   return *this;
}

inline
bfstream & bfstream::operator>>(char * str)
{
   size_t sz;

   fstream::read(reinterpret_cast< char * >(&sz), sizeof(size_t));

   fstream::read(str, sz);

   return *this;
}

inline
bfstream & bfstream::operator>>(char & ch)
{
   fstream::read(&ch, sizeof(char));
   return *this;
}

inline
bfstream & bfstream::operator>>(short & s)
{
   fstream::read((char*)&s, sizeof(short));
   return *this;
}

inline
bfstream & bfstream::operator>>(int & i)
{
   fstream::read((char*)&i, sizeof(int));
   return *this;
}

inline
bfstream & bfstream::operator>>(long long & l)
{
   fstream::read(reinterpret_cast< char * >(&l), sizeof(long long));

   return *this;
}

inline
bfstream & bfstream::operator>>(float & f)
{
   fstream::read(reinterpret_cast< char * >(&f), sizeof(float));

   return *this;
}

inline
bfstream & bfstream::operator>>(double & d)
{
   fstream::read(reinterpret_cast< char * >(&d), sizeof(double));

   return *this;
}

inline
bfstream & bfstream::operator>>(unsigned short & s)
{
   fstream::read(reinterpret_cast< char * >(&s), sizeof(unsigned short));

   return *this;
}

inline
bfstream & bfstream::operator>>(unsigned int & i)
{
   fstream::read(reinterpret_cast< char * >(&i), sizeof(unsigned int));

   return *this;
}

bfstream & bfstream::operator>>(unsigned long long & l)
{
   fstream::read(reinterpret_cast< char * >(&l), sizeof(unsigned long long));

   return *this;
}

#endif /* _BFSTREAM_H */
