//- ****************************************************************************
//-
//- Copyright 2009 National Technology & Engineering Solutions of Sandia, LLC
//- (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S.
//- Government retains certain rights in this software.
//-
//- BSD Open Source License
//- All rights reserved.
//-
//- Redistribution and use in source and binary forms, with or without
//- modification, are permitted provided that the following conditions are met:
//-
//-   1. Redistributions of source code must retain the above copyright notice,
//-      this list of conditions and the following disclaimer.
//-
//-   2. Redistributions in binary form must reproduce the above copyright
//-      notice, this list of conditions and the following disclaimer in the
//-      documentation and/or other materials provided with the distribution.
//-
//-   3. Neither the name of the copyright holder nor the names of its
//-      contributors may be used to endorse or promote products derived from
//-      this software without specific prior written permission.
//-
//- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
//- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
//- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
//- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
//- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
//- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
//- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
//- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
//- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
//- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
//- POSSIBILITY OF SUCH DAMAGE.
//-
//- ****************************************************************************

#ifndef IFSTREAMBINARY_OBJECT_H
#define IFSTREAMBINARY_OBJECT_H

// **** _SYSTEM INCLUDES_ ******************************************************

#include <iostream>
#include <string>
#include <cstring>
#include <fstream>
#include <vector>
#include <sstream>

// use standard library objects
using namespace std;

// **** _LOCAL INCLUDES_ *******************************************************

#include "CPPUtils.h"
#include "GeoTessUtils.h"
#include "GeoTessException.h"

// **** _BEGIN GEOTESS NAMESPACE_ **********************************************

namespace geotess {

// **** _FORWARD REFERENCES_ ***************************************************

// **** _CLASS DEFINITION_ *****************************************************

/**
 * \brief Opens a file for binary read and write access.
 *
 * Opens a file for binary read and write access. The read portion is configured
 * to parse binary files using standard readType(...) functionality.
 *
 * Functionality is provided to read elemental, strings, booleans, bytes,
 * shorts, ints, longs, floats, or doubles, as-well-as array input forms of
 * each (except strings). The binary file can be read in intrinsic alignment form
 * (somewhat faster) where doubles and longs are assumed to be read (and written)
 * along 8 bytes boundaries, floats and ints are aligned on 4 byte boundaries,
 * and shorts are aligned on a 2 byte boundary. A little/big-endian byte
 * reversal flag can be set to reverse the byte structure if necessary.
 */
class GEOTESS_EXP_IMP IFStreamBinary
{
  protected:

        /**
         * A string object is used to contain the actual data.
         */
        string*						bData;

        /**
         * The current iterator position in the data container (dbData).
         */
        int							bDataPos;

        /**
         * The current size of the data container.
         */
        int							bSize;

        /**
         * A boolean, that if true, maintains 4 and 8 byte alignment in
         * support of double alignment compilation.
         */
        bool						bAlign;

        /**
         * A boolean, that if true, reverses the byte order of all 2, 4, and
         * 8 byte intrinsics (shorts, ints, long, floats, doubles, etc.). This
         * flag is set by client using this IFStreamBinary (default to false ...
         * no reversal). The flag is used to convert byte order between big- and
         * little- endian formats.
         */
        bool						bReverse;

        /**
         * A boolean, that if true, indicates the storage string for this
         * IFStreamBinary is owned and therefore deleted when the IFStreamBinary
         * is deleted.
         */
        bool						bOwnStr;

        string						bFileName;

        int							bMemIncr;

        /**
         * Ensure that the buffer position pointer (dbDataPos) is
         * aligned on a 4 byte boundary.
        */
        void						align2Byte()
        {
            int sm = bDataPos % CPPUtils::SSHT;
            if (sm && bAlign) bDataPos += CPPUtils::SSHT - sm;
        }

        /**
             * Ensure that the buffer position pointer (dbDataPos) is
             * aligned on a 4 byte boundary.
         */
        void						align4Byte()
        {
            int sm = bDataPos % CPPUtils::SINT;
            if (sm && bAlign) bDataPos += CPPUtils::SINT - sm;
        }

        /**
             * Ensure that the buffer position pointer (dbDataPos) is
             * aligned on a 8 byte boundary.
         */
        void						align8Byte()
        {
            int sm = bDataPos % CPPUtils::SDBL;
            if (sm && bAlign) bDataPos += CPPUtils::SDBL - sm;
        }

        /**
         * This function checks to make sure that the buffer is large enough to
         * contain sincr more bytes ... if not it is resized so that it can.
         */
        void						checkBufferSize(int sincr)
        {
            if (bDataPos + sincr > (int)bData->size())
            {
                if (sincr + bData->size() > bData->capacity())
                    bData->reserve(bData->capacity() + bMemIncr);
                bData->append(bDataPos + sincr - bData->size(), ' ');
            }
        }

        /*
         * Reverses each s-byte element of array a containing n elements
         * (s*n bytes). The element size s must be 2, 4, or 8.
         */
        static void					reverseBOArray(int n, char* a, int s);

        /*
         * Reverses the byte order of each element of a where a is an array of n
         * 2, 4, or 8 byte elements. Used to convert between big-and
         * little-endian formats.
         */
        static void					reverseBO2Array(int n, char* a);
        static void					reverseBO4Array(int n, char* a);
        static void					reverseBO8Array(int n, char* a);

        /*
         * Reverses the byte order of d, where d is a 2, 4, or 8 byte array. Used
         * to convert between big-and little-endian formats.
         */
        static void					reverseBO2(char* d);
        static void					reverseBO4(char* d);
        static void					reverseBO8(char* d);

    public:

        /**
         * Public Default Constructor.
         */
        IFStreamBinary();

        /**
         * Standard constructor that sets the padding (alignment) option to align.
         */
        IFStreamBinary(bool align);

        /**
         * Standard constructor creates a new IFStreamBinary and opens reads its
         * buffer from the input filename
         */
        IFStreamBinary(const string& filename);

        /**
         * Standard constructor creates a new IFStreamBinary and opens reads its
         * buffer from the input filename
         */
        IFStreamBinary(const string& filename, int num_bytes);

        /**
         * Standard constructor that uses a provided string ptr as the data
         * container.
         */
        IFStreamBinary(string* str);

        /**
         * Copy Constructor.
         */
        IFStreamBinary(const IFStreamBinary& db);

        /**
         * Public destructor
         */
        virtual						~IFStreamBinary();

        /**
         * Assignment operator
         */
        IFStreamBinary&	operator=(const IFStreamBinary& db);

        /**
         * Debug dump of the data.
         */
        void						dumpBuffer();

        /**
         * Static function that returns true if the input filename exists.
         */
        static bool 				exists(const string& filename);

        /**
         * Write the buffer to the output file name.
         */
        void						writeToFile(const string& filename);

        /**
         * Write the buffer to the output stream.
         */
        void						writeToFile(ofstream& ofs);

        /**
     * Read and fills the buffer from the input file name.
         */
        void						readFromFile(const string& filename);

        /**
         * Read num_bytes from input file (Partial read).
         */
        void						readFromFile(const string& filename, int num_bytes);

        /**
         * Reads num_bytes data from the input ifstream into this buffer.
         * the read begins at position file_pos in the input stream.
         */
         //		void						readFromFile(ifstream& ifs, streampos file_pos,
         //																	int num_bytes);

         /**
          * Reads num_bytes data from the input ifstream into this buffer.
          */
        void						readFromFile(ifstream& ifs, int num_bytes);

        /**
         * Return the file name with which this binary reader was opened
         */
        const string&				getFileName() const { return bFileName; }

        /**
         * Clears the buffer.
         */
        void						clear()
        {
            (*bData) = "";
            bDataPos = 0;
            bSize = 0;
        }

        /**
         * Set the amount of memory increase (bytes) for bData everytime it's
         * current capacity is exceeded (defaults to 1MB = 1000000).
         */
        void						setMemoryCapacityIncrement(int mci)
        {
            if (mci > 0) bMemIncr = mci;
        }

        /**
         * Read string data. readString() assumes the string length immediately
         * precedes the string data. readString(string& s) is the same as the
         * first but assigns the string to the input reference. The next two
         * functions read in num_chars and assign them into the input string
         * reference s, or presized character array, respectively. The functions
         * readType* are for templatized access.
         */
        string						readString();
        void						readString(string& s);
        void						readCharArray(string& s, int num_chars);
        void						readCharArray(char* array, int num_chars);
        void						readType(string& s);
        void						readTypeArray(string& array, int num_chars);

        /**
         * Read bool data. readBool() reads one bool from the IFStreamBinary and
         * updates buffer iterator. The second form specifies where to read but
         * does not update the iterator. The last form reads num_bool into the
         * input array. readType is for templatization and behaves like readBool().
         * Similarly, readTypeArray behaves as readBoolArray.
         */
        bool						readBool();
        bool						readBool(int pos);
        void						readBoolArray(bool* array, int num_bools);
        void						readType(bool& b);
        void						readTypeArray(bool* array, int num_bools);

        /**
         * Read byte data. readByte() reads one byte from the IFStreamBinary and
         * updates buffer iterator. The second form specifies where to read but
         * does not update the iterator. The last form reads num_bytes into the
         * input array. readType is for templatization and behaves like readByte().
         * Similarly, readTypeArray behaves as readByteArray.
         */
        byte						readByte();
        byte						readByte(int pos);
        void						readByteArray(byte* array, int num_bs);
        void						readType(byte& b);
        void						readTypeArray(byte* array, int num_bs);

        /**
         * Read short data. readShort() reads one short from the IFStreamBinary
         * and updates buffer iterator. The second form is like the first except
         * that byte alignment is assumed to be ok (not checked). The third
         * form specifies where to read but does not update the iterator or
         * check alignment. The last form reads num_shorts into the input array.
         * readType is for templatization and behaves like readShort(). Similarly,
         * readTypeArray behaves as readShortArray.
         */
        short						readShort();
        short						readShortNC();
        short						readShort(int pos);
        void						readShortArray(short* array, int num_shorts);
        void						readType(short& s);
        void						readTypeArray(short* array, int num_shorts);

        /**
         * Read int data. readInt() reads one int from the IFStreamBinary and
         * updates buffer iterator. The second form is like the first except
         * that byte alignment is assumed to be ok (not checked). The third
         * form specifies where to read but does not update the iterator or
         * check alignment. The last form reads num_ints into the input array.
         * readType is for templatization and behaves like readInt(). Similarly,
         * readTypeArray behaves as readIntArray.
         */
        int							readInt();
        int							readIntNC();
        int							readInt(int pos);
        void						readIntArray(int* array, int num_ints);
        void						readType(int& i);
        void						readTypeArray(int* array, int num_ints);

        /**
         * Read long data. readLong() reads one long from the IFStreamBinary and
         * updates buffer iterator. The second form is like the first except
         * that byte alignment is assumed to be ok (not checked). The third
         * form specifies where to read but does not update the iterator or
         * check alignment. The last form reads num_longs into the input array.
         * readType is for templatization and behaves like readLong(). Similarly,
         * readTypeArray behaves as readLongArray.
         */
        LONG_INT					readLong();
        LONG_INT					readLongNC();
        LONG_INT					readLong(int pos);
        void						readLongArray(LONG_INT* array, int num_longs);
        void						readType(LONG_INT& l);
        void						readTypeArray(LONG_INT* array, int num_longs);

        /**
         * Read float data. readFloat() reads one float from the IFStreamBinary
         * and updates buffer iterator. The second form is like the first except
         * that byte alignment is assumed to be ok (not checked). The third
         * form specifies where to read but does not update the iterator or
         * check alignment. The last form reads num_floats into the input array.
         * readType is for templatization and behaves like readFloat(). Similarly,
         * readTypeArray behaves as readFloatArray.
         */
        float						readFloat();
        float						readFloatNC();
        float						readFloat(int pos);
        void						readFloatArray(float* array, int num_floats);
        void						readType(float& f);
        void						readTypeArray(float* array, int num_floats);

        /**
         * Read double data. readDouble() reads one double from the IFStreamBinary
         * and updates buffer iterator. The second form is like the first except
         * that byte alignment is assumed to be ok (not checked). The third
         * form specifies where to read but does not update the iterator or
         * check alignment. The last form reads num_doubles into the input array.
         * readType is for templatization and behaves like readDouble(). Similarly,
         * readTypeArray behaves as readDoubleArray.
         */
        double						readDouble();
        double						readDoubleNC();
        double						readDouble(int pos);
        void						readDoubleArray(double* array, int num_doubles);
        void						readType(double& d);
        void						readTypeArray(double* array, int num_doubles);

        /**
         * Write string data to 'this' IFStreamBinary. The two writeString functions
         * first writes the the input string length immediately followed by the
         * string data. The next function writes num_chars from the input character
         * array into 'this' IFStreamBinary. readType is for templatization and
         * behaves like readString(). Similarly, readTypeArray behaves like
         * readCharArray.
         */
        void						writeString(const string& str);
        void						writeString(const char* char_string);
        void						writeCharArray(const char* array, int num_chars);
        void						writeType(const string& str);
        void						writeType(const char* char_string);

        /**
         * Write bool data. writeBool writes one byte to the IFStreamBinary
         * and updates buffer iterator. The second form is like the first except
         * that sufficient buffer size is not checked. The third form simply
         * writes the data at the input position (pos) but does not check for
         * buffer size, nor does it update the internal buffer iterator. The
         * last method writes num_bools from the input array into 'this'
         * IFStreamBinary. writeType is for templatization and behaves like
         * writeBool. Similarly, writeTypeArray behaves like writeBoolArray.
         */
        void						writeBool(bool b);
        void						writeBoolNC(bool b);
        void						writeBool(bool b, int pos);
        void						writeBoolArray(const bool* array, int num_bools);
        void						writeType(bool b);
        void						writeTypeArray(const bool* array, int num_bools);

        /**
         * Write byte data. writeByte writes one byte to the IFStreamBinary
         * and updates buffer iterator. The second form is like the first except
         * that sufficient buffer size is not checked. The third form simply
         * writes the data at the input position (pos) but does not check for
         * buffer size, nor does it update the internal buffer iterator. The
         * last method writes num_bytes from the input array into 'this'
         * IFStreamBinary. writeType is for templatization and behaves like
         * writeByte. Similarly, writeTypeArray behaves like writeByteArray.
         */
        void						writeByte(byte b);
        void						writeByteNC(byte b);
        void						writeByte(byte b, int pos);
        void						writeByteArray(const byte* array, int num_bytes);
        void						writeType(byte b);
        void						writeTypeArray(const byte* array, int num_bytes);

        /**
         * Write short data. writeShort writes one short to the IFStreamBinary
         * and updates buffer iterator. The second form is like the first except
         * that byte alignment and sufficient buffer size are not checked. The
         * third form simply writes the data at the input position (pos) but does
         * not check for alignment, buffer size, nor does it update the internal
         * buffer iterator. The last method writes num_shorts from the input
         * array into 'this' IFStreamBinary. writeType is for templatization and
         * behaves like writeShort. Similarly, writeTypeArray behaves like
         * writeShortArray.
         */
        void						writeShort(short i);
        void						writeShortNC(short i);
        void						writeShort(short i, int pos);
        void						writeShortArray(const short* array, int num_ints);
        void						writeType(short i);
        void						writeTypeArray(const short* array, int num_ints);

        /**
         * Write int data. writeInt writes one int to the IFStreamBinary
         * and updates buffer iterator. The second form is like the first except
         * that byte alignment and sufficient buffer size are not checked. The
         * third form simply writes the data at the input position (pos) but does
         * not check for alignment, buffer size, nor does it update the internal
         * buffer iterator. The last method writes num_ints from the input
         * array into 'this' IFStreamBinary. writeType is for templatization and
         * behaves like writeInt. Similarly, writeTypeArray behaves like
         * writeIntArray.
         */
        void						writeInt(int i);
        void						writeIntNC(int i);
        void						writeInt(int i, int pos);
        void						writeIntArray(const int* array, int num_ints);
        void						writeType(int i);
        void						writeTypeArray(const int* array, int num_ints);

        /**
         * Write long data. writeLong writes one long to the IFStreamBinary
         * and updates buffer iterator. The second form is like the first except
         * that byte alignment and sufficient buffer size are not checked. The
         * third form simply writes the data at the input position (pos) but does
         * not check for alignment, buffer size, nor does it update the internal
         * buffer iterator. The last method writes num_longs from the input
         * array into 'this' IFStreamBinary. writeType is for templatization and
         * behaves like writeLong. Similarly, writeTypeArray behaves like
         * writeLongArray.
         */
        void						writeLong(LONG_INT l);
        void						writeLongNC(LONG_INT l);
        void						writeLong(LONG_INT l, int pos);
        void						writeLongArray(const LONG_INT* array, int num_longs);
        void						writeType(LONG_INT l);
        void						writeTypeArray(const LONG_INT* array, int num_longs);

        /**
         * Write float data. writeFloat writes one float to the IFStreamBinary
         * and updates buffer iterator. The second form is like the first except
         * that byte alignment and sufficient buffer size are not checked. The
         * third form simply writes the data at the input position (pos) but does
         * not check for alignment, buffer size, nor does it update the internal
         * buffer iterator. The last method writes num_floats from the input
         * array into 'this' IFStreamBinary. writeType is for templatization and
         * behaves like writeFloat. Similarly, writeTypeArray behaves like
         * writeFloatArray.
         */
        void						writeFloat(float f);
        void						writeFloatNC(float f);
        void						writeFloat(float f, int pos);
        void						writeFloatArray(const float* array, int num_floats);
        void						writeType(float f);
        void						writeTypeArray(const float* array, int num_floats);

        /**
         * Write double data. writeDouble writes one double to the IFStreamBinary
         * and updates buffer iterator. The second form is like the first except
         * that byte alignment and sufficient buffer size are not checked. The
         * third form simply writes the data at the input position (pos) but does
         * not check for alignment, buffer size, nor does it update the internal
         * buffer iterator. The last method writes num_doubles from the input
         * array into 'this' IFStreamBinary. writeType is for templatization and
         * behaves like writeDouble. Similarly, writeTypeArray behaves like
         * writeDoubleArray.
         */
        void						writeDouble(double d);
        void						writeDoubleNC(double d);
        void						writeDouble(double d, int pos);
        void						writeDoubleArray(const double* array, int num_doubles);
        void						writeType(double d);
        void						writeTypeArray(const double* array, int num_doubles);

        /*
         * Return class name.
         */
        static string				className()
        {
            return "IFStreamBinary";
        }

        /*
         * Return class size.
         */
        static int					classSize()
        {
            return (int) sizeof(IFStreamBinary);
        }

        /**
         * This function allocates spc bytes in the buffer. Used to
         * minimize reallocation.
         */
        void						reSize(int spc)
        {
            bData->resize(spc);
        }

        /**
         * Sets the storage capacity. Attained on next required resize.
         */
        void						reserve(int sze)
        {
            bData->reserve(sze);
        }

        /**
         * Returns the IFStreamBinary size.
         */
        int							size()
        {
            if (bDataPos > bSize) bSize = bDataPos;
            return bSize;
        }

        /**
         * Reset the current iterator position to the beginning of the buffer.
         */
        void						resetPos()
        {
            if (bDataPos > bSize) bSize = bDataPos;
            bDataPos = 0;
        }

        /**
         * Set the current iterator position to the end of the buffer.
         */
        void						setPosToEnd()
        {
            if (bDataPos > bSize) bSize = bDataPos;
            bDataPos = bSize;
        }

        /**
         * Get the current iterator position.
         */
        int							getPos() const
        {
            return bDataPos;
        }

        /**
         * Increment the iterator position.
         */
        void						incrementPos(int increment = 1)
        {
            bDataPos += increment;
        }

        /**
         * Decrement the iterator position.
         */
        void						decrementPos(int decrement = 1)
        {
            bDataPos -= decrement;
        }

        /**
         * Return a const reference to 'this' IFStreamBinarys data.
         */
        const string&				getData() const
        {
            return *bData;
        }

        /**
         * Return the allocated capacity of this IFStreamBinary.
         */
        int							getCapacity() const
        {
            return (int)bData->capacity();
        }

        /**
         * Return a pointer at the current iterator location in the IFStreamBinary
         * data.
         */
        char*						getPosPointer()
        {
            return getPosPointer(bDataPos);
        }

        /**
         * Return a pointer to position pos in 'this' IFStreamBinarys data.
         */
        char*						getPosPointer(int pos)
        {
            char* p = &(*bData)[pos];
            return p;
        }

        /**
         * Sets the byte order reverse flag to bor.
         */
        void						setByteOrderReverse(bool bor)
        {
            bReverse = bor;
        }

        /**
         * Turns on byte order reversal.
         */
        void						byteOrderReverseOn()
        {
            bReverse = true;
        }

        /**
         * Turns off byte order reversal.
         */
        void						byteOrderReverseOff()
        {
            bReverse = false;
        }

        /**
         * Returns true if the byte order in reads and writes is reversed for all
         * 2, 4, or 8 byte intrinsincs (short, int, long, float, double, etc.).
         */
        bool						isByteOrderReversalOn() const
        {
            return bReverse;
        }

        /**
         * Sets the intrinsic boundary alignment flag to align.
         */
        void						setBoundaryAlignment(bool align)
        {
            bAlign = align;
        }

        /**
         * Turns on intrinsic boundary alignment.
         */
        void						boundaryAlignmentOn()
        {
            bAlign = true;
        }

        /**
         * Turns off intrinsic boundary alignment.
         */
        void						boundaryAlignmentOff()
        {
            bAlign = false;
        }

        /**
         * Returns true if the byte order in reads and writes is reversed for all
         * 2, 4, or 8 byte intrinsincs (short, int, long, float, double, etc.).
         */
        bool						isBoundaryAlignmentOn() const
        {
            return bAlign;
        }

}; // end class IFStreamBinary

//************* Read Strings **************************************************

/**
 * Read in a single string and return it.
 */
inline string IFStreamBinary::readString()
{
  string s;
  readString(s);
  return s;
}

/**
 * Read in a string and assign it to s.
 */
inline void IFStreamBinary::readString(string& s)
{
  int len;
  // check for zero added by sballar 2013-01-04
  len = readInt();
  if (len == 0)
      s="";
  else
  {
      // read the data
      s = bData->substr(bDataPos, len);
      bDataPos += len;
  }
}

/**
 * Read in num_chars to the string s
 */
inline void IFStreamBinary::readCharArray(string& s, int num_chars)
{
    s.resize(num_chars);
    readCharArray(&s[0], num_chars);
}

/**
 * Read in num_chars to the presized character array
 */
inline void IFStreamBinary::readCharArray(char* array, int num_chars)
{
  // read the data

  memcpy(array, &(*bData)[bDataPos], num_chars);
  bDataPos += num_chars;
}

/**
 * Read in a string and assign it to s.
 */
inline void IFStreamBinary::readType(string& s)
{
    readString(s);
}

/**
 * Read in num_chars to the string s
 */
inline void IFStreamBinary::readTypeArray(string& s, int num_chars)
{
    readCharArray(s, num_chars);
}

//************* Read Bools ****************************************************

/**
 * Read in a single bool and return it.
 */
inline bool IFStreamBinary::readBool()
{
  // read the data

    int pos = bDataPos;
    bDataPos += CPPUtils::SBOL;
    return readBool(pos);
}

/**
 * Read in a single bool starting at the input position and return it.
 * Don't check for alignment.
 */
inline bool IFStreamBinary::readBool(int pos)
{
  return *((bool*) &(*bData)[pos]);
}

/**
 * Read in num_bools into the input array.
 */
inline void IFStreamBinary::readBoolArray(bool* array, int num_bools)
{
    // get bytes and perform alignment

  int num_bytes = num_bools * CPPUtils::SBOL;

    // copy from buffer into array ...
    // update buffer position and exit

  memcpy(array, &(*bData)[bDataPos], num_bytes);
  bDataPos += num_bytes;
}

/**
 * Read in a single bool and assign to s.
 */
inline void IFStreamBinary::readType(bool& b)
{
    b = readBool();
}

/**
 * Read in num_bools into the input array.
 */
inline void IFStreamBinary::readTypeArray(bool* array, int num_bools)
{
    readBoolArray(array, num_bools);
}

//************* Read Bytes ****************************************************

/**
 * Read in a single byte and return it.
 */
inline byte IFStreamBinary::readByte()
{
  // read the data

    int pos = bDataPos;
    bDataPos += CPPUtils::SBYT;
    return readByte(pos);
}

/**
 * Read in a single byte starting at the input position and return it.
 * Don't check for alignment.
 */
inline byte IFStreamBinary::readByte(int pos)
{
  return *((byte*) &(*bData)[pos]);
}

/**
 * Read in num_bytes into the input array.
 */
inline void IFStreamBinary::readByteArray(byte* array, int num_bytes)
{
    // get bytes and perform alignment

  num_bytes *= CPPUtils::SBYT;

    // copy from buffer into array ...
    // update buffer position and exit

  memcpy(array, &(*bData)[bDataPos], num_bytes);
  bDataPos += num_bytes;
}

/**
 * Read in a single byte and assign to s.
 */
inline void IFStreamBinary::readType(byte& b)
{
    b = readByte();
}

/**
 * Read in num_bytes into the input array.
 */
inline void IFStreamBinary::readTypeArray(byte* array, int num_bytes)
{
    readByteArray(array, num_bytes);
}

//************* Read Shorts ***************************************************

/**
 * Read in a single short and return it.
 */
inline short IFStreamBinary::readShort()
{
  align2Byte();
  return readShortNC();
}

/**
 * Read in a single short and return it. Don't check for alignment.
 */
inline short IFStreamBinary::readShortNC()
{
  // read the data

    int pos = bDataPos;
    bDataPos += CPPUtils::SSHT;
    return readShort(pos);
}

/**
 * Read in a single short starting at the input position and return it.
 * Don't check for alignment.
 */
inline short IFStreamBinary::readShort(int pos)
{
  // read the data ... use memcpy if alignment is off

    short s;
    if (bAlign)
    s = *((short*) &(*bData)[pos]);
    else
      memcpy(&s, &(*bData)[pos], 2);

  if (bReverse) reverseBO2((char*) &s);
    return s;
}

/**
 * Read in num_shorts into the input array.
 */
inline void IFStreamBinary::readShortArray(short* array, int num_shorts)
{
    // get bytes and perform alignment

  int num_bytes = num_shorts * CPPUtils::SSHT;
  align2Byte();

    // copy from buffer into array ... reverse data if necessary ...
    // update buffer position and exit

  memcpy(array, &(*bData)[bDataPos], num_bytes);
  if (bReverse) reverseBO2Array(num_shorts, (char*) array);
  bDataPos += num_bytes;
}

/**
 * Read in a single short and assign to s.
 */
inline void IFStreamBinary::readType(short& s)
{
    s = readShort();
}

/**
 * Read in num_shorts into the input array.
 */
inline void IFStreamBinary::readTypeArray(short* array, int num_shorts)
{
    readShortArray(array, num_shorts);
}

//************* Read Ints *****************************************************

/**
 * Read in a single int and return it.
 */
inline int IFStreamBinary::readInt()
{
  align4Byte();
  return readIntNC();
}

/**
 * Read in a single int and return it. Don't check for alignment.
 */
inline int IFStreamBinary::readIntNC()
{
  // read the data

    int pos = bDataPos;
    bDataPos += CPPUtils::SINT;
    return readInt(pos);
}

/**
 * Read in a single int starting at the input position and return it.
 * Don't check for alignment.
 */
inline int IFStreamBinary::readInt(int pos)
{
  // read the data ... use memcpy if alignment is off

    int i;
    if (bAlign)
        i = *((int*) &(*bData)[pos]);
    else
        memcpy(&i, &(*bData)[pos], 4);

  if (bReverse) reverseBO4((char*) &i);
    return i;
}

/**
 * Read in num_ints into the input array.
 */
inline void IFStreamBinary::readIntArray(int* array, int num_ints)
{
    // get bytes and perform alignment

  int num_bytes = num_ints * CPPUtils::SINT;
  align4Byte();

    // copy from buffer into array ... reverse data if necessary ...
    // update buffer position and exit

  memcpy(array, &(*bData)[bDataPos], num_bytes);
  if (bReverse) reverseBO4Array(num_ints, (char*) array);
  bDataPos += num_bytes;
}

/**
 * Read in a single int and assign to i.
 */
inline void IFStreamBinary::readType(int& i)
{
    i = readInt();
}

/**
 * Read in num_ints into the input array.
 */
inline void IFStreamBinary::readTypeArray(int* array, int num_ints)
{
    readIntArray(array, num_ints);
}

//************* Read Longs ****************************************************

/**
 * Read in a single long and return it.
 */
inline LONG_INT IFStreamBinary::readLong()
{
  align8Byte();
  return readLongNC();
}

/**
 * Read in a single long and return it. Don't check for alignment.
 */
inline LONG_INT IFStreamBinary::readLongNC()
{
  // read the data

    int pos = bDataPos;
    bDataPos += CPPUtils::SLNG;
    return readLong(pos);
}

/**
 * Read in a single long starting at the input position and return it.
 * Don't check for alignment.
 */
inline LONG_INT IFStreamBinary::readLong(int pos)
{
  // read the data ... use memcpy if alignment is off

    LONG_INT l;
    if (bAlign)
        l = *((LONG_INT*) &(*bData)[pos]);
    else
      memcpy(&l, &(*bData)[pos], 8);

  if (bReverse) reverseBO8((char*) &l);
    return l;
}

/**
 * Read in num_longs into the input array.
 */
inline void IFStreamBinary::readLongArray(LONG_INT* array, int num_longs)
{
    // get bytes and perform alignment

  int num_bytes = num_longs * CPPUtils::SLNG;
  align8Byte();

    // copy from buffer into array ... reverse data if necessary ...
    // update buffer position and exit

  memcpy(array, &(*bData)[bDataPos], num_bytes);
  if (bReverse) reverseBO8Array(num_longs, (char*) array);
  bDataPos += num_bytes;
}

/**
 * Read in a single long and assign to l.
 */
inline void IFStreamBinary::readType(LONG_INT& l)
{
    l = readLong();
}

/**
 * Read in num_longs into the input array.
 */
inline void IFStreamBinary::readTypeArray(LONG_INT* array, int num_longs)
{
    readLongArray(array, num_longs);
}

//************* Read Floats ***************************************************

/**
 * Read in a single float and return it.
 */
inline float IFStreamBinary::readFloat()
{
  align4Byte();
  return readFloatNC();
}

/**
 * Read in a single float and return it. Don't check for alignment.
 */
inline float IFStreamBinary::readFloatNC()
{
  // read the data

    int pos = bDataPos;
    bDataPos += CPPUtils::SFLT;
    return readFloat(pos);
}

/**
 * Read in a single float starting at the input position and return it.
 * Don't check for alignment.
 */
inline float IFStreamBinary::readFloat(int pos)
{
  // read the data ... use memcpy if alignment is off

    float f;
    if (bAlign)
        f = *((float*) &(*bData)[pos]);
    else
      memcpy(&f, &(*bData)[pos], 4);

  if (bReverse) reverseBO4((char*) &f);
    return f;
}

/**
 * Read in num_floats into the input array.
 */
inline void IFStreamBinary::readFloatArray(float* array, int num_floats)
{
    // get bytes and perform alignment

  int num_bytes = num_floats * CPPUtils::SFLT;
  align4Byte();

    // copy from buffer into array ... reverse data if necessary ...
    // update buffer position and exit

  memcpy(array, &(*bData)[bDataPos], num_bytes);
  if (bReverse) reverseBO4Array(num_floats, (char*) array);
  bDataPos += num_bytes;
}

/**
 * Read in a single float and assign to f.
 */
inline void IFStreamBinary::readType(float& f)
{
    f = readFloat();
}

/**
 * Read in num_floats into the input array.
 */
inline void IFStreamBinary::readTypeArray(float* array, int num_floats)
{
    readFloatArray(array, num_floats);
}

//************* Read Doubles **************************************************

/**
 * Read in a single double and return it.
 */
inline double IFStreamBinary::readDouble()
{
  align8Byte();
  return readDoubleNC();
}

/**
 * Read in a single double and return it. Don't check for alignment.
 */
inline double IFStreamBinary::readDoubleNC()
{
  // read the data

    int pos = bDataPos;
    bDataPos += CPPUtils::SDBL;
    return readDouble(pos);
}

/**
 * Read in a single double starting at the input position and return it.
 * Don't check for alignment.
 */
inline double IFStreamBinary::readDouble(int pos)
{
  // read the data ... use memcpy if alignment is off

    double d;
    if (bAlign)
        d = *((double*) &(*bData)[pos]);
    else
      memcpy(&d, &(*bData)[pos], 8);

  if (bReverse) reverseBO8((char*) &d);
    return d;
}

/**
 * Read in num_doubles into the input array.
 */
inline void IFStreamBinary::readDoubleArray(double* array, int num_doubles)
{
    // get bytes and perform alignment

  int num_bytes = num_doubles * CPPUtils::SDBL;
  align8Byte();

    // copy from buffer into array ... reverse data if necessary ...
    // update buffer position and exit

  memcpy(array, &(*bData)[bDataPos], num_bytes);
  if (bReverse) reverseBO8Array(num_doubles, (char*) array);
  bDataPos += num_bytes;
}

/**
 * Read in a single double and assign to d.
 */
inline void IFStreamBinary::readType(double& d)
{
    d = readDouble();
}

/**
 * Read in num_doubles into the input array.
 */
inline void IFStreamBinary::readTypeArray(double* array, int num_doubles)
{
    readDoubleArray(array, num_doubles);
}

//************* Write Strings *************************************************

/**
 * Write the input string at the current buffer position.
 * Ensure alignment and sufficient buffer size. Increment the
 * internal buffer position on exit. Both the string size (int) and
 * the strings data are written.
 */
inline void IFStreamBinary::writeString(const string& str)
{
  // get total size, align, and check capacity

    int sz = (int) str.size() + CPPUtils::SINT;
  align4Byte();
  checkBufferSize(sz);

  // write the data

    writeIntNC((int) str.size());
  memcpy(&(*bData)[bDataPos], &str[0], str.size());
  bDataPos += (int) str.size();
}

/**
 * Write the null terminated character string at the current buffer position.
 * Ensure alignment and sufficient buffer size. Increment the internal buffer
 * position on exit. Both the string size (int) and its data are written.
 */
inline void IFStreamBinary::writeString(const char* char_string)
{
  string tmp_string = char_string;
  writeString(tmp_string);
}

/**
 * Write num_chars from the input character array to the output buffer.
 */
inline void IFStreamBinary::writeCharArray(const char* array, int num_chars)
{
  checkBufferSize(num_chars);

  // write data

  memcpy(&(*bData)[bDataPos], array, num_chars);
  bDataPos += num_chars;
}

/**
 * Write the input string at the current buffer position.
 * Ensure alignment and sufficient buffer size. Increment the
 * internal buffer position on exit. Both the string size (int) and
 * the strings data are written.
 */
inline void IFStreamBinary::writeType(const string& str)
{
    writeString(str);
}

/**
 * Write the null terminated character string at the current buffer position.
 * Ensure alignment and sufficient buffer size. Increment the internal buffer
 * position on exit. Both the string size (int) and its data are written.
 */
inline void IFStreamBinary::writeType(const char* char_string)
{
    writeString(char_string);
}

//************* Write Bools ***************************************************

/**
 * Write the input bool at the current buffer position.
 * Ensure alignment and sufficient buffer size. Increment the
 * internal buffer position on exit.
 */
inline void IFStreamBinary::writeBool(bool b)
{
    checkBufferSize(CPPUtils::SBOL);

  writeBoolNC(b);
}

/**
 * Write the input bool at the current buffer position.
 * Don't check for alignment or sufficient buffer size. Increment
 * the internal buffer position on exit.
 */
inline void IFStreamBinary::writeBoolNC(bool b)
{
    writeBool(b, bDataPos);
  bDataPos += CPPUtils::SBOL;
}

/**
 * Write the input bool at the input buffer position. Don't
 * check for alignment or sufficient buffer size. Don't update
 * the internal buffer position.
 */
inline void IFStreamBinary::writeBool(bool b, int pos)
{
  *((bool*) &(*bData)[pos]) = b;
}

/**
 * Write num_bools from the input bool array to the output buffer.
 */
inline void IFStreamBinary::writeBoolArray(const bool* array, int num_bools)
{
    // get number of bytes to be written and check for alignment and buffer
    // size

  num_bools *= CPPUtils::SBOL;
  checkBufferSize(num_bools);

    // copy array into data buffer. Reverse data buffer entries if necessary
    // and increment the buffer output pointer.

  memcpy(&(*bData)[bDataPos], array, num_bools);
  bDataPos += num_bools;
}

/**
 * Write the input bool at the current buffer position.
 * Ensure alignment and sufficient buffer size. Increment the
 * internal buffer position on exit.
 */
inline void IFStreamBinary::writeType(bool b)
{
    writeBool(b);
}

/**
 * Write num_bools from the input bool array to the output buffer.
 */
inline void IFStreamBinary::writeTypeArray(const bool* array, int num_bools)
{
    writeBoolArray(array, num_bools);
}

//************* Write Bytes ***************************************************

/**
 * Write the input byte at the current buffer position.
 * Ensure alignment and sufficient buffer size. Increment the
 * internal buffer position on exit.
 */
inline void IFStreamBinary::writeByte(byte b)
{
  checkBufferSize(CPPUtils::SBYT);

  writeByteNC(b);
}

/**
 * Write the input byte at the current buffer position.
 * Don't check for alignment or sufficient buffer size. Increment
 * the internal buffer position on exit.
 */
inline void IFStreamBinary::writeByteNC(byte b)
{
    writeByte(b, bDataPos);
  bDataPos += CPPUtils::SBYT;
}

/**
 * Write the input byte at the input buffer position. Don't
 * check for alignment or sufficient buffer size. Don't update
 * the internal buffer position.
 */
inline void IFStreamBinary::writeByte(byte b, int pos)
{
  *((byte*) &(*bData)[pos]) = b;
}

/**
 * Write num_bytes from the input byte array to the output buffer.
 */
inline void IFStreamBinary::writeByteArray(const byte* array, int num_bytes)
{
    // get number of bytes to be written and check for alignment and buffer
    // size

  num_bytes *= CPPUtils::SBYT;
  checkBufferSize(num_bytes);

    // copy array into data buffer. Reverse data buffer entries if necessary
    // and increment the buffer output pointer.

  memcpy(&(*bData)[bDataPos], array, num_bytes);
  bDataPos += num_bytes;
}

/**
 * Write the input byte at the current buffer position.
 * Ensure alignment and sufficient buffer size. Increment the
 * internal buffer position on exit.
 */
inline void IFStreamBinary::writeType(byte b)
{
    writeByte(b);
}

/**
 * Write num_bytes from the input byte array to the output buffer.
 */
inline void IFStreamBinary::writeTypeArray(const byte* array, int num_bytes)
{
    writeByteArray(array, num_bytes);
}

//************* Write Shorts **************************************************

/**
 * Write the input short at the current buffer position.
 * Ensure alignment and sufficient buffer size. Increment the
 * internal buffer position on exit.
 */
inline void IFStreamBinary::writeShort(short s)
{
  align2Byte();
  checkBufferSize(CPPUtils::SSHT);

  writeShortNC(s);
}

/**
 * Write the input short at the current buffer position.
 * Don't check for alignment or sufficient buffer size. Increment
 * the internal buffer position on exit.
 */
inline void IFStreamBinary::writeShortNC(short s)
{
    writeShort(s, bDataPos);
  bDataPos += CPPUtils::SSHT;
}

/**
 * Write the input short at the input buffer position. Don't
 * check for alignment or sufficient buffer size. Don't update
 * the internal buffer position.
 */
inline void IFStreamBinary::writeShort(short s, int pos)
{
  if (bReverse) reverseBO2((char*) &s);

  if (bAlign)
    *((short*) &(*bData)[pos]) = s;
  else
    memcpy(&(*bData)[pos], &s, CPPUtils::SSHT);
}

/**
 * Write num_shorts from the input short array to the output buffer.
 */
inline void IFStreamBinary::writeShortArray(const short* array, int num_shorts)
{
    // get number of bytes to be written and check for alignment and buffer
    // size

  int num_bytes = num_shorts * CPPUtils::SSHT;
  align2Byte();
  checkBufferSize(num_bytes);

    // copy array into data buffer. Reverse data buffer entries if necessary
    // and increment the buffer output pointer.

  memcpy(&(*bData)[bDataPos], array, num_bytes);
  if (bReverse) reverseBO2Array(num_shorts, &(*bData)[bDataPos]);
  bDataPos += num_bytes;
}

/**
 * Write the input short at the current buffer position.
 * Ensure alignment and sufficient buffer size. Increment the
 * internal buffer position on exit.
 */
inline void IFStreamBinary::writeType(short s)
{
    writeShort(s);
}

/**
 * Write num_shorts from the input short array to the output buffer.
 */
inline void IFStreamBinary::writeTypeArray(const short* array, int num_shorts)
{
    writeShortArray(array, num_shorts);
}

//************* Write Ints ****************************************************

/**
 * Write the input int at the current buffer position.
 * Ensure alignment and sufficient buffer size. Increment the
 * internal buffer position on exit.
 */
inline void IFStreamBinary::writeInt(int i)
{
  align4Byte();
  checkBufferSize(CPPUtils::SINT);

  writeIntNC(i);
}

/**
 * Write the input int at the current buffer position.
 * Don't check for alignment or sufficient buffer size. Increment
 * the internal buffer position on exit.
 */
inline void IFStreamBinary::writeIntNC(int i)
{
    writeInt(i, bDataPos);
  bDataPos += CPPUtils::SINT;
}

/**
 * Write the input int at the input buffer position. Don't
 * check for alignment or sufficient buffer size. Don't update
 * the internal buffer position.
 */
inline void IFStreamBinary::writeInt(int i, int pos)
{
  if (bReverse) reverseBO4((char*) &i);

  if (bAlign)
    *((int*) &(*bData)[pos]) = i;
  else
    memcpy(&(*bData)[pos], &i, CPPUtils::SINT);
}

/**
 * Write num_ints from the input int array to the output buffer.
 */
inline void IFStreamBinary::writeIntArray(const int* array, int num_ints)
{
    // get number of bytes to be written and check for alignment and buffer
    // size

  int num_bytes = num_ints * CPPUtils::SINT;
  align4Byte();
  checkBufferSize(num_bytes);

    // copy array into data buffer. Reverse data buffer entries if necessary
    // and increment the buffer output pointer.

  memcpy(&(*bData)[bDataPos], array, num_bytes);
  if (bReverse) reverseBO4Array(num_ints, &(*bData)[bDataPos]);
  bDataPos += num_bytes;
}

/**
 * Write the input int at the current buffer position.
 * Ensure alignment and sufficient buffer size. Increment the
 * internal buffer position on exit.
 */
inline void IFStreamBinary::writeType(int i)
{
    writeInt(i);
}

/**
 * Write num_ints from the input int array to the output buffer.
 */
inline void IFStreamBinary::writeTypeArray(const int* array, int num_ints)
{
    writeIntArray(array, num_ints);
}

//************* Write Longs ***************************************************

/**
 * Write the input long at the current buffer position.
 * Ensure alignment and sufficient buffer size. Increment the
 * internal buffer position on exit.
 */
inline void IFStreamBinary::writeLong(LONG_INT l)
{
  align8Byte();
  checkBufferSize(CPPUtils::SLNG);

  writeLongNC(l);
}

/**
 * Write the input long at the current buffer position.
 * Don't check for alignment or sufficient buffer size. Increment
 * the internal buffer position on exit.
 */
inline void IFStreamBinary::writeLongNC(LONG_INT l)
{
    writeLong(l, bDataPos);
  bDataPos += CPPUtils::SLNG;
}

/**
 * Write the input long at the input buffer position. Don't
 * check for alignment or sufficient buffer size. Don't update
 * the internal buffer position.
 */
inline void IFStreamBinary::writeLong(LONG_INT l, int pos)
{
  if (bReverse) reverseBO8((char*) &l);

  if (bAlign)
    *((LONG_INT*) &(*bData)[pos]) = l;
  else
    memcpy(&(*bData)[pos], &l, CPPUtils::SLNG);
}

/**
 * Write num_longs from the input long array to the output buffer.
 */
inline void IFStreamBinary::writeLongArray(const LONG_INT* array, int num_longs)
{
    // get number of bytes to be written and check for alignment and buffer
    // size

  int num_bytes = num_longs * CPPUtils::SLNG;
  align8Byte();
  checkBufferSize(num_bytes);

    // copy array into data buffer. Reverse data buffer entries if necessary
    // and increment the buffer output pointer.

  memcpy(&(*bData)[bDataPos], array, num_bytes);
  if (bReverse) reverseBO8Array(num_longs, &(*bData)[bDataPos]);
  bDataPos += num_bytes;
}

/**
 * Write the input long at the current buffer position.
 * Ensure alignment and sufficient buffer size. Increment the
 * internal buffer position on exit.
 */
inline void IFStreamBinary::writeType(LONG_INT l)
{
    writeLong(l);
}

/**
 * Write num_longs from the input long array to the output buffer.
 */
inline void IFStreamBinary::writeTypeArray(const LONG_INT* array, int num_longs)
{
    writeLongArray(array, num_longs);
}

//************* Write Floats **************************************************

/**
 * Write the input float at the current buffer position.
 * Ensure alignment and sufficient buffer size. Increment the
 * internal buffer position on exit.
 */
inline void IFStreamBinary::writeFloat(float f)
{
  align4Byte();
  checkBufferSize(CPPUtils::SFLT);

  writeFloatNC(f);
}

/**
 * Write the input float at the current buffer position.
 * Don't check for alignment or sufficient buffer size. Increment
 * the internal buffer position on exit.
 */
inline void IFStreamBinary::writeFloatNC(float f)
{
    writeFloat(f, bDataPos);
  bDataPos += CPPUtils::SFLT;
}

/**
 * Write the input float at the input buffer position. Don't
 * check for alignment or sufficient buffer size. Don't update
 * the internal buffer position.
 */
inline void IFStreamBinary::writeFloat(float f, int pos)
{
  if (bReverse) reverseBO4((char*) &f);

  if (bAlign)
    *((float*) &(*bData)[pos]) = f;
  else
    memcpy(&(*bData)[pos], &f, CPPUtils::SFLT);
}

/**
 * Write num_floats from the input float array to the output buffer.
 */
inline void IFStreamBinary::writeFloatArray(const float* array, int num_floats)
{
    // get number of bytes to be written and check for alignment and buffer
    // size

  int num_bytes = num_floats * CPPUtils::SFLT;
  align4Byte();
  checkBufferSize(num_bytes);

    // copy array into data buffer. Reverse data buffer entries if necessary
    // and increment the buffer output pointer.

  memcpy(&(*bData)[bDataPos], array, num_bytes);
  if (bReverse) reverseBO4Array(num_floats, &(*bData)[bDataPos]);
  bDataPos += num_bytes;
}

/**
 * Write the input float at the current buffer position.
 * Ensure alignment and sufficient buffer size. Increment the
 * internal buffer position on exit.
 */
inline void IFStreamBinary::writeType(float f)
{
    writeFloat(f);
}

/**
 * Write num_floats from the input float array to the output buffer.
 */
inline void IFStreamBinary::writeTypeArray(const float* array, int num_floats)
{
    writeFloatArray(array, num_floats);
}

//************* Write Doubles *************************************************

/**
 * Write the input double at the current buffer position.
 * Ensure alignment and sufficient buffer size. Increment the
 * internal buffer position on exit.
 */
inline void IFStreamBinary::writeDouble(double d)
{
  align8Byte();
    checkBufferSize(CPPUtils::SDBL);

  writeDoubleNC(d);
}

/**
 * Write the input double at the current buffer position.
 * Don't check for alignment or sufficient buffer size. Increment
 * the internal buffer position on exit.
 */
inline void IFStreamBinary::writeDoubleNC(double d)
{
    writeDouble(d, bDataPos);
  bDataPos += CPPUtils::SDBL;
}

/**
 * Write the input double at the input buffer position. Don't
 * check for alignment or sufficient buffer size. Don't update
 * the internal buffer position.
 */
inline void IFStreamBinary::writeDouble(double d, int pos)
{
  if (bReverse) reverseBO8((char*) &d);

  if (bAlign)
    *((double*) &(*bData)[pos]) = d;
  else
    memcpy(&(*bData)[pos], &d, CPPUtils::SDBL);
}

/**
 * Write num_doubles from the input double array to the output buffer.
 */
inline void IFStreamBinary::writeDoubleArray(const double* array, int num_doubles)
{
    // get number of bytes to be written and check for alignment and buffer
    // size

  int num_bytes = num_doubles * CPPUtils::SDBL;
  align8Byte();
  checkBufferSize(num_bytes);

    // copy array into data buffer. Reverse data buffer entries if necessary
    // and increment the buffer output pointer.

  memcpy(&(*bData)[bDataPos], array, num_bytes);
  if (bReverse) reverseBO8Array(num_doubles, &(*bData)[bDataPos]);
  bDataPos += num_bytes;
}

/**
 * Write the input double at the current buffer position.
 * Ensure alignment and sufficient buffer size. Increment the
 * internal buffer position on exit.
 */
inline void IFStreamBinary::writeType(double d)
{
    writeDouble(d);
}

/**
 * Write num_doubles from the input double array to the output buffer.
 */
inline void IFStreamBinary::writeTypeArray(const double* array, int num_doubles)
{
    writeDoubleArray(array, num_doubles);
}

//************* Byte reversal functions ***************************************

/**
 * Reverses byte order of d. d is assumed to point to an 2 byte element.
 */
inline void IFStreamBinary::reverseBO2(char* d)
{
  char tmp = d[0];
  d[0] = d[1];
  d[1] = tmp;
}

/**
 * Reverses byte order of d. d is assumed to point to an 4 byte element.
 */
inline void IFStreamBinary::reverseBO4(char* d)
{
  char tmp = d[0];
  d[0] = d[3];
  d[3] = tmp;

  tmp = d[1];
  d[1] = d[2];
  d[2] = tmp;
}

/**
 * Reverses byte order of d. d is assumed to point to an 8 byte element.
 */
inline void IFStreamBinary::reverseBO8(char* d)
{
  char tmp = d[0];
  d[0] = d[7];
  d[7] = tmp;

  tmp = d[1];
  d[1] = d[6];
  d[6] = tmp;

  tmp = d[2];
  d[2] = d[5];
  d[5] = tmp;

  tmp = d[3];
  d[3] = d[4];
  d[4] = tmp;
}

} // end namespace geotess

#endif  // IFSTREAMBINARY_OBJECT_H
