#ifndef __XENTAX_DATA_H
#define __XENTAX_DATA_H

/*
** DATA TYPES
*/

typedef __int8  sint08;
typedef __int16 sint16;
typedef __int32 sint32;
typedef __int64 sint64;
typedef unsigned __int8  uint08;
typedef unsigned __int16 uint16;
typedef unsigned __int32 uint32;
typedef unsigned __int64 uint64;

typedef float float32;
typedef double float64;

/*
** DATA CONVERSION
*/

float32 float_16_to_32(unsigned short value);
inline uint32 interpret_as_uint32(float32 x) { return *(reinterpret_cast<uint32*>(&x)); }
inline uint64 interpret_as_uint64(float64 x) { return *(reinterpret_cast<uint64*>(&x)); }
inline float32 interpret_as_float32(uint32 x) { return *(reinterpret_cast<float32*>(&x)); }
inline float64 interpret_as_float64(uint64 x) { return *(reinterpret_cast<float64*>(&x)); }

/*
** BYTE ORDER FUNCTIONS
** (1) FOR SINGLE ITEMS
** (2) FOR ARRAYS
*/

template<class T>
inline void reverse_byte_order(T* data)
{
 unsigned char* ptr = reinterpret_cast<unsigned char*>(data);
 std::reverse(ptr, ptr + sizeof(T)); 
}

template<class T>
inline void reverse_byte_order(T* data, size_t elem)
{
 for(size_t i = 0; i < elem; i++) {
     unsigned char* ptr = reinterpret_cast<unsigned char*>(&data[i]);
     std::reverse(ptr, ptr + sizeof(T));
    }
}

/*
** READING FUNCTIONS (INTEGERS)
** (LE) LITTLE ENDIAN
** (BE) BIG ENDIAN
*/

sint08 LE_read_sint08(std::istream& ifile);
uint08 LE_read_uint08(std::istream& ifile);
sint16 LE_read_sint16(std::istream& ifile);
uint16 LE_read_uint16(std::istream& ifile);
sint32 LE_read_sint32(std::istream& ifile);
uint32 LE_read_uint32(std::istream& ifile);
sint64 LE_read_sint64(std::istream& ifile);
uint64 LE_read_uint64(std::istream& ifile);
sint08 LE_read_sint08(std::istream& ifile, unsigned int offset);
uint08 LE_read_uint08(std::istream& ifile, unsigned int offset);
sint16 LE_read_sint16(std::istream& ifile, unsigned int offset);
uint16 LE_read_uint16(std::istream& ifile, unsigned int offset);
sint32 LE_read_sint32(std::istream& ifile, unsigned int offset);
uint32 LE_read_uint32(std::istream& ifile, unsigned int offset);
sint64 LE_read_sint64(std::istream& ifile, unsigned int offset);
uint64 LE_read_uint64(std::istream& ifile, unsigned int offset);

sint08 BE_read_sint08(std::istream& ifile);
uint08 BE_read_uint08(std::istream& ifile);
sint16 BE_read_sint16(std::istream& ifile);
uint16 BE_read_uint16(std::istream& ifile);
sint32 BE_read_sint32(std::istream& ifile);
uint32 BE_read_uint32(std::istream& ifile);
sint64 BE_read_sint64(std::istream& ifile);
uint64 BE_read_uint64(std::istream& ifile);
sint08 BE_read_sint08(std::istream& ifile, unsigned int offset);
uint08 BE_read_uint08(std::istream& ifile, unsigned int offset);
sint16 BE_read_sint16(std::istream& ifile, unsigned int offset);
uint16 BE_read_uint16(std::istream& ifile, unsigned int offset);
sint32 BE_read_sint32(std::istream& ifile, unsigned int offset);
uint32 BE_read_uint32(std::istream& ifile, unsigned int offset);
sint64 BE_read_sint64(std::istream& ifile, unsigned int offset);
uint64 BE_read_uint64(std::istream& ifile, unsigned int offset);

/*
** READING FUNCTIONS (FLOATING-POINT)
** (LE) LITTLE ENDIAN
** (BE) BIG ENDIAN
*/

float32 LE_read_float16(std::istream& ifile);
float32 LE_read_float32(std::istream& ifile);
float64 LE_read_float64(std::istream& ifile);
float32 LE_read_float16(std::istream& ifile, unsigned int offset);
float32 LE_read_float32(std::istream& ifile, unsigned int offset);
float64 LE_read_float64(std::istream& ifile, unsigned int offset);

float32 BE_read_float16(std::istream& ifile);
float32 BE_read_float32(std::istream& ifile);
float64 BE_read_float64(std::istream& ifile);
float32 BE_read_float16(std::istream& ifile, unsigned int offset);
float32 BE_read_float32(std::istream& ifile, unsigned int offset);
float64 BE_read_float64(std::istream& ifile, unsigned int offset);

/*
** READING FUNCTIONS (ARRAYS)
** (LE) LITTLE ENDIAN
** (BE) BIG ENDIAN
*/

template<class T>
inline bool LE_read_array(std::istream& ifile, T* data, size_t n)
{
 ifile.read((char*)&data[0], n*sizeof(T));
 if(ifile.fail()) return false;
 return true;
}

template<class T>
inline bool BE_read_array(std::istream& ifile, T* data, size_t n)
{
 ifile.read((char*)&data[0], n*sizeof(T));
 if(ifile.fail()) return false;
 reverse_byte_order(data, n);
 return true;
}

template<class T>
inline bool LE_read_array(std::istream& ifile, unsigned int offset, T* data, unsigned int n)
{
 ifile.seekg(offset);
 if(ifile.fail()) return false;
 return LE_read_array(ifile, data, n);
}

template<class T>
inline bool BE_read_array(std::istream& ifile, unsigned int offset, T* data, unsigned int n)
{
 ifile.seekg(offset);
 if(ifile.fail()) return false;
 return BE_read_array(ifile, data, n);
}

/*
** READING FUNCTIONS (STRINGS)
*/
bool read_string(std::istream& ifile, char* data, size_t size);
bool read_string(std::istream& ifile, char* data, size_t size, char delimiter);

#endif
