// ===========================================================
//     _/_/_/   _/_/_/  _/_/_/_/    _/_/_/_/  _/_/_/   _/_/_/
//      _/    _/       _/             _/    _/    _/   _/   _/
//     _/    _/       _/_/_/_/       _/    _/    _/   _/_/_/
//    _/    _/       _/             _/    _/    _/   _/
// _/_/_/   _/_/_/  _/_/_/_/_/     _/     _/_/_/   _/_/
// ===========================================================
//
// dEndian.h: Cross-platform functions with independent endianness
//
// Copyright (C) 2007-2017    Xiuwen Zheng
//
// This file is part of CoreArray.
//
// CoreArray is free software: you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License Version 3 as
// published by the Free Software Foundation.
//
// CoreArray is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with CoreArray.
// If not, see <http://www.gnu.org/licenses/>.

/**
 *	\file     dEndian.h
 *	\author   Xiuwen Zheng [zhengxwen@gmail.com]
 *	\version  1.0
 *	\date     2007-2017
 *	\brief    Endianness-independent functions
 *	\details
**/

#ifndef _HEADER_COREARRAY_ENDIAN_
#define _HEADER_COREARRAY_ENDIAN_

#include "dPlatform.h"
#include "dTrait.h"


namespace CoreArray
{
	using namespace std;


	// =====================================================================
	// Bit stream object (little endianness)
	// =====================================================================

	/// Bit stream with reading with little endianness
	/** \tparam TYPE    it could be CdStream, CdBufStream or CdAllocator
	**/
	template<typename TYPE> struct COREARRAY_DLL_DEFAULT BIT_LE_R
	{
	public:
		TYPE *Stream;
		C_UInt8 Reminder, Offset;

		BIT_LE_R() { Stream = NULL; }
		BIT_LE_R(TYPE *s) { Stream = s; Reminder = Offset = 0; }
		BIT_LE_R(TYPE &s) { Stream = &s; Reminder = Offset = 0; }

		/// read an integer with 'nbit' bits
		C_UInt32 ReadBit(C_UInt8 nbit)
		{
			C_UInt8 shl = 0;
			C_UInt32 rv = 0;
			while (nbit > 0)
			{
				if (Offset == 0) Reminder = Stream->R8b();
				C_UInt8 I = 8 - Offset;
				if (I > nbit) I = nbit;
				C_UInt32 Mask = ~(0xFFFFFFFF << I);
				rv |= (C_UInt32(Reminder >> Offset) & Mask) << shl;
				shl += I; Offset += I;
				if (Offset > 7) Offset = 0;
				nbit -= I;
			}
			return rv;
		}

		void SkipBit(C_UInt8 nbit)
		{
			ReadBit(nbit);
		}
	};


	/// Bit stream with writing with little endianness
	/** \tparam TYPE    it could be CdStream, CdBufStream or CdAllocator
	**/
	template<typename TYPE> struct COREARRAY_DLL_DEFAULT BIT_LE_W
	{
	public:
		TYPE *Stream;
		C_UInt8 Reminder, Offset;

		BIT_LE_W() { Stream = NULL; }
		BIT_LE_W(TYPE *s) { Stream = s; Reminder = Offset = 0; }
		BIT_LE_W(TYPE &s) { Stream = &s; Reminder = Offset = 0; }

		/// finalize writing
		~BIT_LE_W()
		{
			if (Offset > 0)
			{
				Stream->W8b(Reminder);
				Reminder = Offset = 0;
			}
		}

		/// write an integer with 'nbits' bits to a stream
		void WriteBit(C_UInt32 Value, C_UInt8 nbit)
		{
			while (nbit > 0)
			{
				C_UInt8 I = 8 - Offset;
				if (I > nbit) I = nbit;
				C_UInt32 Mask = ~(0xFFFFFFFF << I);
				Reminder |= (Value & Mask) << Offset;
				Value >>= I; Offset += I;
				if (Offset > 7)
				{
					Offset = 0;
					Stream->W8b(Reminder);
					Reminder = 0;
				}
				nbit -= I;
			}
		}
	};



	// =====================================================================
	// Data stream object (native endianness)
	// =====================================================================

	/// Data stream with native endianness
	/** \tparam TYPE    it could be CdStream, CdBufStream or CdAllocator
	**/
	template<typename TYPE> struct COREARRAY_DLL_DEFAULT BYTE_NT
	{
		TYPE *Stream;

		BYTE_NT() { Stream = NULL; }
		BYTE_NT(TYPE *s) { Stream = s; }
		BYTE_NT(TYPE &s) { Stream = &s; }

		/// Return the current position
		COREARRAY_FORCEINLINE SIZE64 Position()
		{
			return Stream->Position();
		}
		/// Reset the current position
		COREARRAY_FORCEINLINE void SetPosition(const SIZE64 Pos)
		{
			Stream->SetPosition(Pos);
		}

		/// Read block of data, or throw an exception if fail
		COREARRAY_FORCEINLINE void ReadData(void *Buffer, ssize_t Count)
		{
			Stream->ReadData(Buffer, Count);
		}
		/// Read a 8-bit integer
		COREARRAY_FORCEINLINE C_UInt8 R8b()
		{
			return Stream->R8b();
		}

		/// Write block of data, or throw an exception if fail
		COREARRAY_FORCEINLINE void WriteData(const void *Buffer, ssize_t Count)
		{
			Stream->WriteData(Buffer, Count);
		}
		/// Write a 8-bit integer with native endianness
		COREARRAY_FORCEINLINE void W8b(C_UInt8 val)
		{
			Stream->W8b(val);
		}


		// =================================================================
		// Operator - Read

		/// get a signed 8-bit integer
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& operator >>(C_Int8 &val)
		{
			val = Stream->R8b(); return *this;
		}
		/// get an unsigned 8-bit integer
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& operator >>(C_UInt8 &val)
		{
			val = Stream->R8b(); return *this;
		}
		/// get a vector of signed 8-bit integers
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& R(C_Int8 *pval, size_t n)
		{
			Stream->ReadData(pval, n); return *this;
		}
		/// get a vector of unsigned 8-bit integers
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& R(C_UInt8 *pval, size_t n)
		{
			Stream->ReadData(pval, n); return *this;
		}

		/// get a signed 16-bit integer
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& operator >>(C_Int16 &val)
		{
			val = Stream->R16b(); return *this;
		}
		/// get an unsigned 16-bit integer
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& operator >>(C_UInt16 &val)
		{
			val = Stream->R16b(); return *this;
		}
		/// get a vector of signed 16-bit integers
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& R(C_Int16 *pval, size_t n)
		{
			Stream->ReadData(pval, sizeof(*pval)*n); return *this;
		}
		/// get a vector of unsigned 16-bit integers
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& R(C_UInt16 *pval, size_t n)
		{
			Stream->ReadData(pval, sizeof(*pval)*n); return *this;
		}

		/// get a signed 32-bit integer
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& operator >>(C_Int32 &val)
		{
			val = Stream->R32b(); return *this;
		}
		/// get an unsigned 32-bit integer
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& operator >>(C_UInt32 &val)
		{
			val = Stream->R32b(); return *this;
		}
		/// get a vector of signed 32-bit integers
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& R(C_Int32 *pval, size_t n)
		{
			Stream->ReadData(pval, sizeof(*pval)*n); return *this;
		}
		/// get a vector of unsigned 32-bit integers
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& R(C_UInt32 *pval, size_t n)
		{
			Stream->ReadData(pval, sizeof(*pval)*n); return *this;
		}

		/// get a signed 64-bit integer
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& operator >>(C_Int64 &val)
		{
			val = Stream->R64b(); return *this;
		}
		/// get an unsigned 64-bit integer
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& operator >>(C_UInt64 &val)
		{
			val = Stream->R64b(); return *this;
		}
		/// get a vector of signed 64-bit integers
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& R(C_Int64 *pval, size_t n)
		{
			Stream->ReadData(pval, sizeof(*pval)*n); return *this;
		}
		/// get a vector of unsigned 64-bit integers
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& R(C_UInt64 *pval, size_t n)
		{
			Stream->ReadData(pval, sizeof(*pval)*n); return *this;
		}

		/// get a 32-bit floating number
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& operator >>(C_Float32 &val)
		{
			Stream->ReadData(&val, sizeof(val)); return *this;
		}
		/// get a 64-bit floating number
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& operator >>(C_Float64 &val)
		{
			Stream->ReadData(&val, sizeof(val)); return *this;
		}
		/// get a vector of 32-bit floating numbers
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& R(C_Float32 *pval, size_t n)
		{
			Stream->ReadData(pval, sizeof(*pval)*n); return *this;
		}
		/// get a vector of 64-bit floating numbers
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& R(C_Float64 *pval, size_t n)
		{
			Stream->ReadData(pval, sizeof(*pval)*n); return *this;
		}


		// =================================================================
		// Operator - Write

		// write a signed 8-bit integer
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& operator <<(C_Int8 val)
		{
			Stream->W8b(val); return *this;
		}
		// write an unsigned 8-bit integer
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& operator <<(C_UInt8 val)
		{
			Stream->W8b(val); return *this;
		}
		/// write a vector of signed 8-bit integers
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& W(const C_Int8 *pval, size_t n)
		{
			Stream->WriteData(pval, n); return *this;
		}
		/// write a vector of unsigned 8-bit integers
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& W(const C_UInt8 *pval, size_t n)
		{
			Stream->WriteData(pval, n); return *this;
		}

		// write a signed 16-bit integer
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& operator <<(C_Int16 val)
		{
			Stream->W16b(val); return *this;
		}
		// set an unsigned 16-bit integer
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& operator <<(C_UInt16 val)
		{
			Stream->W16b(val); return *this;
		}
		/// write a vector of signed 16-bit integers
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& W(const C_Int16 *pval, size_t n)
		{
			Stream->WriteData(pval, sizeof(*pval)*n); return *this;
		}
		/// write a vector of unsigned 16-bit integers
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& W(const C_UInt16 *pval, size_t n)
		{
			Stream->WriteData(pval, sizeof(*pval)*n); return *this;
		}

		/// write a signed 32-bit integer
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& operator <<(C_Int32 val)
		{
			Stream->W32b(val); return *this;
		}
		/// write an unsigned 32-bit integer
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& operator <<(C_UInt32 val)
		{
			Stream->W32b(val); return *this;
		}
		/// write a vector of signed 32-bit integers
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& W(const C_Int32 *pval, size_t n)
		{
			Stream->WriteData(pval, sizeof(*pval)*n); return *this;
		}
		/// write a vector of unsigned 32-bit integers
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& W(const C_UInt32 *pval, size_t n)
		{
			Stream->WriteData(pval, sizeof(*pval)*n); return *this;
		}

		/// write a signed 64-bit integer
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& operator <<(C_Int64 val)
		{
			Stream->W64b(val); return *this;
		}
		/// write an unsigned 64-bit integer
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& operator <<(C_UInt64 val)
		{
			Stream->W64b(val); return *this;
		}
		/// write a vector of signed 64-bit integers
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& W(const C_Int64 *pval, size_t n)
		{
			Stream->WriteData(pval, sizeof(*pval)*n); return *this;
		}
		/// write a vector of unsigned 64-bit integers
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& W(const C_UInt64 *pval, size_t n)
		{
			Stream->WriteData(pval, sizeof(*pval)*n); return *this;
		}

		/// write a 32-bit floating number
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& operator <<(const C_Float32 val)
		{
			Stream->WriteData(&val, sizeof(val)); return *this;
		}
		/// write a 64-bit floating number
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& operator <<(const C_Float64 val)
		{
			Stream->WriteData(&val, sizeof(val)); return *this;
		}
		/// write a vector of 32-bit floating number
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& W(const C_Float32 *pval, size_t n)
		{
			Stream->WriteData(pval, sizeof(*pval)*n); return *this;
		}
		/// write a vector of 64-bit floating number
		COREARRAY_FORCEINLINE BYTE_NT<TYPE>& W(const C_Float64 *pval, size_t n)
		{
			Stream->WriteData(pval, sizeof(*pval)*n); return *this;
		}
	};



	// =====================================================================
	// Endian Macro and Function
	// =====================================================================

	#ifdef COREARRAY_ENDIAN_LITTLE

		/// native format to little endian, single value
		#define COREARRAY_ENDIAN_NT_TO_LE(x)               (x)
		/// native format to little endian, array
		#define COREARRAY_ENDIAN_NT_TO_LE_ARRAY(p, n)
		/// native format to little endian, array
		#define COREARRAY_ENDIAN_NT_TO_LE_ARRAY2(d, s, n)

		/// little endian to native format, single value
		#define COREARRAY_ENDIAN_LE_TO_NT(x)               (x)
		/// little endian to native format, array
		#define COREARRAY_ENDIAN_LE_TO_NT_ARRAY(p, n)
		/// little endian to native format, array
		#define COREARRAY_ENDIAN_LE_TO_NT_ARRAY2(d, s, n)

	#else

		/// native format to little endian, single value
		#define COREARRAY_ENDIAN_NT_TO_LE(x)               CoreArray::NT_TO_LE(x)
		/// native format to little endian, array
		#define COREARRAY_ENDIAN_NT_TO_LE_ARRAY(p, n)      CoreArray::NT_TO_LE_ARRAY(p, n)
		/// native format to little endian, array
		#define COREARRAY_ENDIAN_NT_TO_LE_ARRAY2(d, s, n)  CoreArray::NT_TO_LE_ARRAY2(d, s, n)

		/// little endian to native format, single value
		#define COREARRAY_ENDIAN_LE_TO_NT(x)               CoreArray::LE_TO_NT(x)
		/// little endian to native format, array
		#define COREARRAY_ENDIAN_LE_TO_NT_ARRAY(p, n)      CoreArray::LE_TO_NT_ARRAY(p, n)
		/// little endian to native format, array
		#define COREARRAY_ENDIAN_LE_TO_NT_ARRAY2(d, s, n)  CoreArray::LE_TO_NT_ARRAY2(d, s, n)


		/// define a buffer for endianness conversion, 8K
		#define COREARRAY_ENDIAN_BUF_SIZE                  8192u

		///
		#define COREARRAY_ENDIAN_BYTE_LE_W(TYPE)	\
			const size_t N = COREARRAY_ENDIAN_BUF_SIZE / sizeof(*pval); \
			TYPE Buffer[N]; \
			while (n > 0) \
			{ \
				size_t L = (n <= N) ? n : N; \
				COREARRAY_ENDIAN_NT_TO_LE_ARRAY2(Buffer, pval, L); \
				pval += L; \
				Stream->WriteData(Buffer, sizeof(*pval)*L); \
				n -= L; \
			}


		// Worry about neither big or little endian? NOT support.

		// Function -- native format to little endian, single value

		static COREARRAY_FORCEINLINE C_Int8 NT_TO_LE(C_Int8 val)
			{ return val; }
		static COREARRAY_FORCEINLINE C_UInt8 NT_TO_LE(C_UInt8 val)
			{ return val; }
		static COREARRAY_FORCEINLINE C_Int16 NT_TO_LE(C_Int16 val)
			{ return ((C_UInt16)val << 8) | ((C_UInt16)val >> 8); }
		static COREARRAY_FORCEINLINE C_UInt16 NT_TO_LE(C_UInt16 val)
			{ return (val << 8) | (val >> 8); }
		static COREARRAY_FORCEINLINE C_Int32 NT_TO_LE(C_Int32 val)
			{
				return ((C_UInt32)val << 24) | (((C_UInt32)val & 0xFF00) << 8)
					| (((C_UInt32)val >> 8) & 0xFF00) | ((C_UInt32)val >> 24);
			}
		static COREARRAY_FORCEINLINE C_UInt32 NT_TO_LE(C_UInt32 val)
			{
				return (val << 24) | ((val & 0xFF00) << 8) |
					((val >> 8) & 0xFF00) | (val >> 24);
			}
		static COREARRAY_FORCEINLINE C_Int64 NT_TO_LE(C_Int64 val)
			{
				C_UInt32 L = NT_TO_LE((C_UInt32)val);
				C_UInt32 H = NT_TO_LE((C_UInt32)(val >> 32));
				return ((C_UInt64)L << 32) | (C_UInt64)H;
			}
		static COREARRAY_FORCEINLINE C_UInt64 NT_TO_LE(C_UInt64 val)
			{
				C_UInt32 L = NT_TO_LE((C_UInt32)val);
				C_UInt32 H = NT_TO_LE((C_UInt32)(val >> 32));
				return ((C_UInt64)L << 32) | (C_UInt64)H;
			}


		// Function -- native format to little endian, array

		static COREARRAY_FORCEINLINE
			void NT_TO_LE_ARRAY(C_Int8 *p, size_t n) { }
		static COREARRAY_FORCEINLINE
			void NT_TO_LE_ARRAY(C_UInt8 *p, size_t n) { }
		void NT_TO_LE_ARRAY(C_Int16 *p, size_t n);
		void NT_TO_LE_ARRAY(C_UInt16 *p, size_t n);
		void NT_TO_LE_ARRAY(C_Int32 *p, size_t n);
		void NT_TO_LE_ARRAY(C_UInt32 *p, size_t n);
		void NT_TO_LE_ARRAY(C_Int64 *p, size_t n);
		void NT_TO_LE_ARRAY(C_UInt64 *p, size_t n);
		void NT_TO_LE_ARRAY(C_Float32 *p, size_t n);
		void NT_TO_LE_ARRAY(C_Float64 *p, size_t n);

		static COREARRAY_FORCEINLINE
			void NT_TO_LE_ARRAY2(C_Int8 *d, const C_Int8 *s, size_t n) { }
		static COREARRAY_FORCEINLINE
			void NT_TO_LE_ARRAY2(C_UInt8 *d, const C_UInt8 *s, size_t n) { }
		void NT_TO_LE_ARRAY2(C_Int16 *d, const C_Int16 *s, size_t n);
		void NT_TO_LE_ARRAY2(C_UInt16 *d, const C_UInt16 *s, size_t n);
		void NT_TO_LE_ARRAY2(C_Int32 *d, const C_Int32 *s, size_t n);
		void NT_TO_LE_ARRAY2(C_UInt32 *d, const C_UInt32 *s, size_t n);
		void NT_TO_LE_ARRAY2(C_Int64 *d, const C_Int64 *s, size_t n);
		void NT_TO_LE_ARRAY2(C_UInt64 *d, const C_UInt64 *s, size_t n);
		void NT_TO_LE_ARRAY2(C_Float32 *d, const C_Float32 *s, size_t n);
		void NT_TO_LE_ARRAY2(C_Float64 *d, const C_Float64 *s, size_t n);


		// Function -- little endian to native format, single value

		static COREARRAY_FORCEINLINE C_Int8 LE_TO_NT(C_Int8 val)
			{ return val; }
		static COREARRAY_FORCEINLINE C_UInt8 LE_TO_NT(C_UInt8 val)
			{ return val; }
		static COREARRAY_FORCEINLINE C_Int16 LE_TO_NT(C_Int16 val)
			{ return ((C_UInt16)val << 8) | ((C_UInt16)val >> 8); }
		static COREARRAY_FORCEINLINE C_UInt16 LE_TO_NT(C_UInt16 val)
			{ return (val << 8) | (val >> 8); }
		static COREARRAY_FORCEINLINE C_Int32 LE_TO_NT(C_Int32 val)
			{
				return ((C_UInt32)val << 24) | (((C_UInt32)val & 0xFF00) << 8)
					| (((C_UInt32)val >> 8) & 0xFF00) | ((C_UInt32)val >> 24);
			}
		static COREARRAY_FORCEINLINE C_UInt32 LE_TO_NT(C_UInt32 val)
			{
				return (val << 24) | ((val & 0xFF00) << 8) |
					((val >> 8) & 0xFF00) | (val >> 24);
			}
		static COREARRAY_FORCEINLINE C_Int64 LE_TO_NT(C_Int64 val)
			{
				C_UInt32 L = NT_TO_LE((C_UInt32)val);
				C_UInt32 H = NT_TO_LE((C_UInt32)(val >> 32));
				return ((C_UInt64)L << 32) | (C_UInt64)H;
			}
		static COREARRAY_FORCEINLINE C_UInt64 LE_TO_NT(C_UInt64 val)
			{
				C_UInt32 L = NT_TO_LE((C_UInt32)val);
				C_UInt32 H = NT_TO_LE((C_UInt32)(val >> 32));
				return ((C_UInt64)L << 32) | (C_UInt64)H;
			}

		// Function -- little endian to native format, array

		static COREARRAY_FORCEINLINE
			void LE_TO_NT_ARRAY(C_Int8 *p, size_t n) { }
		static COREARRAY_FORCEINLINE
			void LE_TO_NT_ARRAY(C_UInt8 *p, size_t n) { }
		void LE_TO_NT_ARRAY(C_Int16 *p, size_t n);
		void LE_TO_NT_ARRAY(C_UInt16 *p, size_t n);
		void LE_TO_NT_ARRAY(C_Int32 *p, size_t n);
		void LE_TO_NT_ARRAY(C_UInt32 *p, size_t n);
		void LE_TO_NT_ARRAY(C_Int64 *p, size_t n);
		void LE_TO_NT_ARRAY(C_UInt64 *p, size_t n);
		void LE_TO_NT_ARRAY(C_Float32 *p, size_t n);
		void LE_TO_NT_ARRAY(C_Float64 *p, size_t n);

		static COREARRAY_FORCEINLINE
			void LE_TO_NT_ARRAY2(C_Int8 *d, const C_Int8 *s, size_t n) { }
		static COREARRAY_FORCEINLINE
			void LE_TO_NT_ARRAY2(C_UInt8 *d, const C_UInt8 *s, size_t n) { }
		void LE_TO_NT_ARRAY2(C_Int16 *d, const C_Int16 *s, size_t n);
		void LE_TO_NT_ARRAY2(C_UInt16 *d, const C_UInt16 *s, size_t n);
		void LE_TO_NT_ARRAY2(C_Int32 *d, const C_Int32 *s, size_t n);
		void LE_TO_NT_ARRAY2(C_UInt32 *d, const C_UInt32 *s, size_t n);
		void LE_TO_NT_ARRAY2(C_Int64 *d, const C_Int64 *s, size_t n);
		void LE_TO_NT_ARRAY2(C_UInt64 *d, const C_UInt64 *s, size_t n);
		void LE_TO_NT_ARRAY2(C_Float32 *d, const C_Float32 *s, size_t n);
		void LE_TO_NT_ARRAY2(C_Float64 *d, const C_Float64 *s, size_t n);


	#endif



	// =====================================================================
	// Data stream object (little endianness)
	// =====================================================================

	/// Data stream with little endianness
	/** \tparam TYPE    it could be CdStream, CdBufStream or CdAllocator
	**/
	template<typename TYPE> struct COREARRAY_DLL_DEFAULT BYTE_LE
	{
		TYPE *Stream;

		BYTE_LE() { Stream = NULL; }
		BYTE_LE(TYPE *s) { Stream = s; }
		BYTE_LE(TYPE &s) { Stream = &s; }

		/// Return the current position
		COREARRAY_FORCEINLINE SIZE64 Position()
		{
			return Stream->Position();
		}
		/// Reset the current position
		COREARRAY_FORCEINLINE void SetPosition(const SIZE64 Pos)
		{
			Stream->SetPosition(Pos);
		}

		/// Read block of data, or throw an exception if fail
		COREARRAY_FORCEINLINE void ReadData(void *Buffer, ssize_t Count)
		{
			Stream->ReadData(Buffer, Count);
		}
		/// Read a 8-bit integer
		COREARRAY_FORCEINLINE C_UInt8 R8b()
		{
			return Stream->R8b();
		}

		/// Write block of data, or throw an exception if fail
		COREARRAY_FORCEINLINE void WriteData(const void *Buffer, ssize_t Count)
		{
			Stream->WriteData(Buffer, Count);
		}
		/// Write a 8-bit integer with native endianness
		COREARRAY_FORCEINLINE void W8b(C_UInt8 val)
		{
			Stream->W8b(val);
		}


		// =================================================================
		// Operator - Read

		/// get a signed 8-bit integer
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& operator >>(C_Int8 &val)
		{
			val = Stream->R8b(); return *this;
		}
		/// get an unsigned 8-bit integer
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& operator >>(C_UInt8 &val)
		{
			val = Stream->R8b(); return *this;
		}
		/// get a vector of signed 8-bit integers
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& R(C_Int8 *pval, size_t n)
		{
			Stream->ReadData(pval, n); return *this;
		}
		/// get a vector of unsigned 8-bit integers
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& R(C_UInt8 *pval, size_t n)
		{
			Stream->ReadData(pval, n); return *this;
		}

		/// get a signed 16-bit integer
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& operator >>(C_Int16 &val)
		{
			val = COREARRAY_ENDIAN_LE_TO_NT(Stream->R16b()); return *this;
		}
		/// get an unsigned 16-bit integer
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& operator >>(C_UInt16 &val)
		{
			val = COREARRAY_ENDIAN_LE_TO_NT(Stream->R16b()); return *this;
		}
		/// get a vector of signed 16-bit integers
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& R(C_Int16 *pval, size_t n)
		{
			Stream->ReadData(pval, sizeof(*pval)*n);
			COREARRAY_ENDIAN_LE_TO_NT_ARRAY(pval, n);
			return *this;
		}
		/// get a vector of unsigned 16-bit integers
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& R(C_UInt16 *pval, size_t n)
		{
			Stream->ReadData(pval, sizeof(*pval)*n);
			COREARRAY_ENDIAN_LE_TO_NT_ARRAY(pval, n);
			return *this;
		}

		/// get a signed 32-bit integer
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& operator >>(C_Int32 &val)
		{
			val = COREARRAY_ENDIAN_LE_TO_NT(Stream->R32b()); return *this;
		}
		/// get an unsigned 32-bit integer
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& operator >>(C_UInt32 &val)
		{
			val = COREARRAY_ENDIAN_LE_TO_NT(Stream->R32b()); return *this;
		}
		/// get a vector of signed 32-bit integers
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& R(C_Int32 *pval, size_t n)
		{
			Stream->ReadData(pval, sizeof(*pval)*n);
			COREARRAY_ENDIAN_LE_TO_NT_ARRAY(pval, n);
			return *this;
		}
		/// get a vector of unsigned 32-bit integers
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& R(C_UInt32 *pval, size_t n)
		{
			Stream->ReadData(pval, sizeof(*pval)*n);
			COREARRAY_ENDIAN_LE_TO_NT_ARRAY(pval, n);
			return *this;
		}

		/// get a signed 64-bit integer
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& operator >>(C_Int64 &val)
		{
			val = COREARRAY_ENDIAN_LE_TO_NT(Stream->R64b()); return *this;
		}
		/// get an unsigned 64-bit integer
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& operator >>(C_UInt64 &val)
		{
			val = COREARRAY_ENDIAN_LE_TO_NT(Stream->R64b()); return *this;
		}
		/// get a vector of signed 64-bit integers
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& R(C_Int64 *pval, size_t n)
		{
			Stream->ReadData(pval, sizeof(*pval)*n);
			COREARRAY_ENDIAN_LE_TO_NT_ARRAY(pval, n);
			return *this;
		}
		/// get a vector of unsigned 64-bit integers
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& R(C_UInt64 *pval, size_t n)
		{
			Stream->ReadData(pval, sizeof(*pval)*n);
			COREARRAY_ENDIAN_LE_TO_NT_ARRAY(pval, n);
			return *this;
		}

		/// get a 32-bit floating number
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& operator >>(C_Float32 &val)
		{
			Stream->ReadData(&val, sizeof(val));
			COREARRAY_ENDIAN_LE_TO_NT_ARRAY(&val, 1);
			return *this;
		}
		/// get a 64-bit floating number
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& operator >>(C_Float64 &val)
		{
			Stream->ReadData(&val, sizeof(val));
			COREARRAY_ENDIAN_LE_TO_NT_ARRAY(&val, 1);
			return *this;
		}
		/// get a vector of 32-bit floating numbers
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& R(C_Float32 *pval, size_t n)
		{
			Stream->ReadData(pval, sizeof(*pval)*n);
			COREARRAY_ENDIAN_LE_TO_NT_ARRAY(pval, n);
			return *this;
		}
		/// get a vector of 64-bit floating numbers
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& R(C_Float64 *pval, size_t n)
		{
			Stream->ReadData(pval, sizeof(*pval)*n);
			COREARRAY_ENDIAN_LE_TO_NT_ARRAY(pval, n);
			return *this;
		}


		// =================================================================
		// Operator - Write

		// write a signed 8-bit integer
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& operator <<(C_Int8 val)
		{
			Stream->W8b(val); return *this;
		}
		// write an unsigned 8-bit integer
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& operator <<(C_UInt8 val)
		{
			Stream->W8b(val); return *this;
		}
		/// write a vector of signed 8-bit integers
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& W(const C_Int8 *pval, size_t n)
		{
			Stream->WriteData(pval, n); return *this;
		}
		/// write a vector of unsigned 8-bit integers
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& W(const C_UInt8 *pval, size_t n)
		{
			Stream->WriteData(pval, n); return *this;
		}

		// write a signed 16-bit integer
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& operator <<(C_Int16 val)
		{
			Stream->W16b(COREARRAY_ENDIAN_NT_TO_LE(val)); return *this;
		}
		// set an unsigned 16-bit integer
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& operator <<(C_UInt16 val)
		{
			Stream->W16b(COREARRAY_ENDIAN_NT_TO_LE(val)); return *this;
		}
		/// write a vector of signed 16-bit integers
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& W(const C_Int16 *pval, size_t n)
		{
		#ifdef COREARRAY_ENDIAN_LITTLE
			Stream->WriteData(pval, sizeof(*pval)*n); return *this;
		#else
			COREARRAY_ENDIAN_BYTE_LE_W(C_Int16); return *this;
		#endif
		}
		/// write a vector of unsigned 16-bit integers
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& W(const C_UInt16 *pval, size_t n)
		{
		#ifdef COREARRAY_ENDIAN_LITTLE
			Stream->WriteData(pval, sizeof(*pval)*n); return *this;
		#else
			COREARRAY_ENDIAN_BYTE_LE_W(C_UInt16); return *this;
		#endif
		}

		/// write a signed 32-bit integer
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& operator <<(C_Int32 val)
		{
			Stream->W32b(COREARRAY_ENDIAN_NT_TO_LE(val)); return *this;
		}
		/// write an unsigned 32-bit integer
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& operator <<(C_UInt32 val)
		{
			Stream->W32b(COREARRAY_ENDIAN_NT_TO_LE(val)); return *this;
		}
		/// write a vector of signed 32-bit integers
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& W(const C_Int32 *pval, size_t n)
		{
		#ifdef COREARRAY_ENDIAN_LITTLE
			Stream->WriteData(pval, sizeof(*pval)*n); return *this;
		#else
			COREARRAY_ENDIAN_BYTE_LE_W(C_Int32); return *this;
		#endif
		}
		/// write a vector of unsigned 32-bit integers
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& W(const C_UInt32 *pval, size_t n)
		{
		#ifdef COREARRAY_ENDIAN_LITTLE
			Stream->WriteData(pval, sizeof(*pval)*n); return *this;
		#else
			COREARRAY_ENDIAN_BYTE_LE_W(C_UInt32); return *this;
		#endif
		}

		/// write a signed 64-bit integer
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& operator <<(C_Int64 val)
		{
			Stream->W64b(COREARRAY_ENDIAN_NT_TO_LE(val)); return *this;
		}
		/// write an unsigned 64-bit integer
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& operator <<(C_UInt64 val)
		{
			Stream->W64b(COREARRAY_ENDIAN_NT_TO_LE(val)); return *this;
		}
		/// write a vector of signed 64-bit integers
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& W(const C_Int64 *pval, size_t n)
		{
		#ifdef COREARRAY_ENDIAN_LITTLE
			Stream->WriteData(pval, sizeof(*pval)*n); return *this;
		#else
			COREARRAY_ENDIAN_BYTE_LE_W(C_Int64); return *this;
		#endif
		}
		/// write a vector of unsigned 64-bit integers
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& W(const C_UInt64 *pval, size_t n)
		{
		#ifdef COREARRAY_ENDIAN_LITTLE
			Stream->WriteData(pval, sizeof(*pval)*n); return *this;
		#else
			COREARRAY_ENDIAN_BYTE_LE_W(C_UInt64); return *this;
		#endif
		}

		/// write a 32-bit floating number
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& operator <<(C_Float32 val)
		{
			COREARRAY_ENDIAN_NT_TO_LE_ARRAY(&val, 1);
			Stream->WriteData(&val, sizeof(val));
			return *this;
		}
		/// write a 64-bit floating number
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& operator <<(C_Float64 val)
		{
			COREARRAY_ENDIAN_NT_TO_LE_ARRAY(&val, 1);
			Stream->WriteData(&val, sizeof(val));
			return *this;
		}
		/// write a vector of 32-bit floating number
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& W(const C_Float32 *pval, size_t n)
		{
		#ifdef COREARRAY_ENDIAN_LITTLE
			Stream->WriteData(pval, sizeof(*pval)*n); return *this;
		#else
			COREARRAY_ENDIAN_BYTE_LE_W(C_Float32); return *this;
		#endif
		}
		/// write a vector of 64-bit floating number
		COREARRAY_FORCEINLINE BYTE_LE<TYPE>& W(const C_Float64 *pval, size_t n)
		{
		#ifdef COREARRAY_ENDIAN_LITTLE
			Stream->WriteData(pval, sizeof(*pval)*n); return *this;
		#else
			COREARRAY_ENDIAN_BYTE_LE_W(C_Float64); return *this;
		#endif
		}


		// =================================================================
		// Read/Write packed integer

		/// get an unsigned 16-bit integer from packed stream
		C_UInt16 Rp16b()
		{
			C_UInt16 B, rv;
			B = Stream->R8b(); rv = B & 0x7F;			// 1
			if ((B & 0x80) == 0) return rv;
			B = Stream->R8b(); rv |= (B & 0x7F) << 7;	// 2
			if ((B & 0x80) == 0) return rv;
			B = Stream->R8b(); rv |= (B & 0x7F) << 14;	// 3
			return rv;
		}
		/// get an unsigned 32-bit integer from packed stream
		C_UInt32 Rp32b()
		{
			C_UInt32 B, rv;
			B = Stream->R8b(); rv = B & 0x7F;			// 1
			if ((B & 0x80) == 0) return rv;
			B = Stream->R8b(); rv |= (B & 0x7F) << 7;	// 2
			if ((B & 0x80) == 0) return rv;
			B = Stream->R8b(); rv |= (B & 0x7F) << 14;	// 3
			if ((B & 0x80) == 0) return rv;
			B = Stream->R8b(); rv |= (B & 0x7F) << 21;	// 4
			if ((B & 0x80) == 0) return rv;
			B = Stream->R8b(); rv |= (B & 0x7F) << 28;	// 5
			return rv;
		}
		/// get an unsigned 64-bit integer from packed stream
		C_UInt64 Rp64b()
		{
			C_UInt64 rv; C_UInt8 B;
			B = Stream->R8b(); rv = B & 0x7F;					// 1
			if ((B & 0x80) == 0) return rv;
			B = Stream->R8b(); rv |= C_UInt64(B & 0x7F) << 7;	// 2
			if ((B & 0x80) == 0) return rv;
			B = Stream->R8b(); rv |= C_UInt64(B & 0x7F) << 14;	// 3
			if ((B & 0x80) == 0) return rv;
			B = Stream->R8b(); rv |= C_UInt64(B & 0x7F) << 21;	// 4
			if ((B & 0x80) == 0) return rv;
			B = Stream->R8b(); rv |= C_UInt64(B & 0x7F) << 28;	// 5
			if ((B & 0x80) == 0) return rv;
			B = Stream->R8b(); rv |= C_UInt64(B & 0x7F) << 35;	// 6
			if ((B & 0x80) == 0) return rv;
			B = Stream->R8b(); rv |= C_UInt64(B & 0x7F) << 42;	// 7
			if ((B & 0x80) == 0) return rv;
			B = Stream->R8b(); rv |= C_UInt64(B & 0x7F) << 49;	// 8
			if ((B & 0x80) == 0) return rv;
			B = Stream->R8b(); rv |= C_UInt64(B) << 56;			// 9
			return rv;
		}

		// write an unsigned 16-bit integer to packed stream
		void Wp16b(C_UInt16 val)
		{
			C_UInt8 B;
			B = val & 0x7F; val >>= 7;		// 1
			if (val > 0) { Stream->W8b(B | 0x80); } else { Stream->W8b(B); return; }
			B = val & 0x7F; val >>= 7;		// 2
			if (val > 0) { Stream->W8b(B | 0x80); } else { Stream->W8b(B); return; }
			Stream->W8b(val);				// 3
		}
		// write an unsigned 32-bit integer to packed stream
		void Wp32b(C_UInt32 val)
		{
			C_UInt8 B;
			B = val & 0x7F; val >>= 7;		// 1
			if (val > 0) { Stream->W8b(B | 0x80); } else { Stream->W8b(B); return; }
			B = val & 0x7F; val >>= 7;		// 2
			if (val > 0) { Stream->W8b(B | 0x80); } else { Stream->W8b(B); return; }
			B = val & 0x7F; val >>= 7;		// 3
			if (val > 0) { Stream->W8b(B | 0x80); } else { Stream->W8b(B); return; }
			B = val & 0x7F; val >>= 7;		// 4
			if (val > 0) { Stream->W8b(B | 0x80); } else { Stream->W8b(B); return; }
			Stream->W8b(val);				// 5
		}
		// write an unsigned 64-bit integer to packed stream
		void Wp64b(C_UInt64 val)
		{
			C_UInt8 B;
			B = val & 0x7F; val >>= 7;		// 1
			if (val > 0) { Stream->W8b(B | 0x80); } else { Stream->W8b(B); return; }
			B = val & 0x7F; val >>= 7;		// 2
			if (val > 0) { Stream->W8b(B | 0x80); } else { Stream->W8b(B); return; }
			B = val & 0x7F; val >>= 7;		// 3
			if (val > 0) { Stream->W8b(B | 0x80); } else { Stream->W8b(B); return; }
			B = val & 0x7F; val >>= 7;		// 4
			if (val > 0) { Stream->W8b(B | 0x80); } else { Stream->W8b(B); return; }
			B = val & 0x7F; val >>= 7;		// 5
			if (val > 0) { Stream->W8b(B | 0x80); } else { Stream->W8b(B); return; }
			B = val & 0x7F; val >>= 7;		// 6
			if (val > 0) { Stream->W8b(B | 0x80); } else { Stream->W8b(B); return; }
			B = val & 0x7F; val >>= 7;		// 7
			if (val > 0) { Stream->W8b(B | 0x80); } else { Stream->W8b(B); return; }
			B = val & 0x7F; val >>= 7;		// 8
			if (val > 0) { Stream->W8b(B | 0x80); } else { Stream->W8b(B); return; }
			Stream->W8b(val);				// 9
		}


		// =================================================================
		// Read/Write string from packed stream

		/// Read a UTF-8 string
		UTF8String RpUTF8()
		{
			size_t L = Rp32b();
			UTF8String rv(L, 0);
			Stream->ReadData(&rv[0], L);
			return rv;
		}
		/// Read a UTF-16 string
		UTF16String RpUTF16()
		{
			size_t L = Rp32b();
			BIT_LE_R<TYPE> RBit(Stream);
			UTF16String rv(L, 0);
			for (size_t i=0; i < L; i++)
			{
				C_UTF16 w = RBit.ReadBit(8);
				if (w > 0x7F)
					w = (w & 0x7F) | (RBit.ReadBit(9) << 7);
				rv[i] = w;
			}
			return rv;
		}
		/// Read a UTF-32 string
		UTF32String RpUTF32()
		{
			size_t L = Rp32b();
			UTF32String rv(L, 0);
			for (size_t i=0; i < L; i++) rv[i] = Rp32b();
			return rv;
		}

		/// Write a UTF-8 string
		void WpUTF8(const UTF8String &val)
		{
			Wp32b(val.size());
			Stream->WriteData(&(val[0]), val.size());
		}
		/// Write a UTF-16 string
		void WpUTF16(const UTF16String &val)
		{
			size_t L = val.size();
			Wp32b(L);
			BIT_LE_W<TYPE> WBit(Stream);
			for (size_t i=0; i < L; i++)
			{
				C_UTF16 w = val[i];
				if (w <= 0x7F)
				{
					WBit.WriteBit(w, 8);
				} else {
					WBit.WriteBit(w | 0x80, 8);
					w >>= 7;
					WBit.WriteBit(w, 9);
				}
			}
		}
		/// Write a UTF-32 string
		void WpUTF32(const UTF32String &val)
		{
			size_t L = val.size();
			Wp32b(L);
			for (size_t i=0; i < L; i++) Wp32b(val[i]);
		}


		// =================================================================
		// Read/Write TdGDSPos

		/// an operator, to read TdGDSPos
		BYTE_LE<TYPE>& operator >>(TdGDSPos& out)
		{
			C_UInt64 v = 0;
		#ifdef COREARRAY_ENDIAN_LITTLE
			Stream->ReadData(&v, GDS_POS_SIZE);
		#else
			v |= Stream->R8b();
			v |= (C_UInt64)Stream->R8b() << 8;
			v |= (C_UInt64)Stream->R8b() << 16;
			v |= (C_UInt64)Stream->R8b() << 24;
			v |= (C_UInt64)Stream->R8b() << 32;
			v |= (C_UInt64)Stream->R8b() << 40;
		#endif
			out = (C_Int64)v;
			return *this;
		}
		/// an operator, to write TdGDSPos
		BYTE_LE<TYPE>& operator <<(const TdGDSPos &in)
		{
			C_UInt64 v = (C_UInt64)in;
		#ifdef COREARRAY_ENDIAN_LITTLE
			Stream->WriteData(&v, GDS_POS_SIZE);
		#else
			Stream->W8b(v); v >>= 8;
			Stream->W8b(v); v >>= 8;
			Stream->W8b(v); v >>= 8;
			Stream->W8b(v); v >>= 8;
			Stream->W8b(v); v >>= 8;
			Stream->W8b(v);
		#endif
			return *this;
		}


		// =================================================================
		// Read/Write TdGDSBlockID

		/// an operator, to read TdGDSBlockID
		BYTE_LE<TYPE>& operator >>(TdGDSBlockID& out)
		{
			(*this) >> out.Get();
			return *this;
		}
		/// an operator, to write TdGDSBlockID
		BYTE_LE<TYPE>& operator <<(const TdGDSBlockID &in)
		{
			(*this) << in.Get();
			return *this;
		}
	};



	// =====================================================================
	// Get value
	// =====================================================================

	/// Unaligned C_Int16 -- get
	static COREARRAY_FORCEINLINE C_Int16 GET_VAL_UNALIGNED_LE_PTR(const C_Int16 *p)
	{
		if (size_t(p) & 0x01)
		{
			const C_UInt8 *s = (const C_UInt8*)p;
			return C_Int16(s[0]) | (C_Int16(s[1]) << 8);
		} else
			return COREARRAY_ENDIAN_LE_TO_NT(*p);
	}

	/// Unaligned C_UInt16 -- get
	static COREARRAY_FORCEINLINE C_UInt16 GET_VAL_UNALIGNED_LE_PTR(const C_UInt16 *p)
	{
		if (size_t(p) & 0x01)
		{
			const C_UInt8 *s = (const C_UInt8*)p;
			return C_UInt16(s[0]) | (C_UInt16(s[1]) << 8);
		} else
			return COREARRAY_ENDIAN_LE_TO_NT(*p);
	}

	/// Unaligned C_Int32 -- get
	static COREARRAY_FORCEINLINE C_Int32 GET_VAL_UNALIGNED_LE_PTR(const C_Int32 *p)
	{
		if (size_t(p) & 0x03)
		{
			const C_UInt8 *s = (const C_UInt8*)p;
			return C_Int32(s[0]) | (C_Int32(s[1]) << 8) |
				(C_Int32(s[2]) << 16) | (C_Int32(s[3]) << 24);
		} else
			return COREARRAY_ENDIAN_LE_TO_NT(*p);
	}

	/// Unaligned C_UInt32 -- get
	static COREARRAY_FORCEINLINE C_UInt32 GET_VAL_UNALIGNED_LE_PTR(const C_UInt32 *p)
	{
		if (size_t(p) & 0x03)
		{
			const C_UInt8 *s = (const C_UInt8*)p;
			return C_UInt32(s[0]) | (C_UInt32(s[1]) << 8) |
				(C_UInt32(s[2]) << 16) | (C_UInt32(s[3]) << 24);
		} else
			return COREARRAY_ENDIAN_LE_TO_NT(*p);
	}

	/// Unaligned C_Int16 -- set
	static COREARRAY_FORCEINLINE void SET_VAL_UNALIGNED_LE_PTR(C_Int16 *p, C_Int16 val)
	{
		if (size_t(p) & 0x01)
		{
			const C_UInt8 *s1 = (const C_UInt8*)&val;
			C_UInt8 *s2 = (C_UInt8*)p;
			s2[0] = s1[0]; s2[1] = s1[1];
		} else
			*p = COREARRAY_ENDIAN_NT_TO_LE(val);
	}

	/// Unaligned C_UInt16 -- set
	static COREARRAY_FORCEINLINE void SET_VAL_UNALIGNED_LE_PTR(C_UInt16 *p, C_UInt16 val)
	{
		if (size_t(p) & 0x01)
		{
			const C_UInt8 *s1 = (const C_UInt8*)&val;
			C_UInt8 *s2 = (C_UInt8*)p;
			s2[0] = s1[0]; s2[1] = s1[1];
		} else
			*p = COREARRAY_ENDIAN_NT_TO_LE(val);
	}

	/// Unaligned C_Int32 -- set
	static COREARRAY_FORCEINLINE void SET_VAL_UNALIGNED_LE_PTR(C_Int32 *p, C_Int32 val)
	{
		if (size_t(p) & 0x03)
		{
			const C_UInt8 *s1 = (const C_UInt8*)&val;
			C_UInt8 *s2 = (C_UInt8*)p;
			s2[0] = s1[0]; s2[1] = s1[1]; s2[2] = s1[2]; s2[3] = s1[3];
		} else
			*p = COREARRAY_ENDIAN_NT_TO_LE(val);
	}

	/// Unaligned C_UInt32 -- set
	static COREARRAY_FORCEINLINE void SET_VAL_UNALIGNED_LE_PTR(C_UInt32 *p, C_UInt32 val)
	{
		if (size_t(p) & 0x03)
		{
			const C_UInt8 *s1 = (const C_UInt8*)&val;
			C_UInt8 *s2 = (C_UInt8*)p;
			s2[0] = s1[0]; s2[1] = s1[1]; s2[2] = s1[2]; s2[3] = s1[3];
		} else
			*p = COREARRAY_ENDIAN_NT_TO_LE(val);
	}
}

#endif /* _HEADER_COREARRAY_ENDIAN_ */