You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
295 lines
7.2 KiB
C++
295 lines
7.2 KiB
C++
/*
|
|
* Copyright (c) Contributors to the Open 3D Engine Project
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
*
|
|
*/
|
|
|
|
|
|
#ifndef CRYINCLUDE_CRYCOMMON_CRYENDIAN_H
|
|
#define CRYINCLUDE_CRYCOMMON_CRYENDIAN_H
|
|
#pragma once
|
|
|
|
#include <BaseTypes.h>
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Endian support
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
// NEED_ENDIAN_SWAP is an older define still used in several places to toggle endian swapping.
|
|
// It is only used when reading files which are assumed to be little-endian.
|
|
// For legacy support, define it to swap on big endian platforms.
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
typedef bool EEndian;
|
|
|
|
#if defined(SYSTEM_IS_LITTLE_ENDIAN)
|
|
# undef SYSTEM_IS_LITTLE_ENDIAN
|
|
#endif
|
|
#if defined(SYSTEM_IS_BIG_ENDIAN)
|
|
# undef SYSTEM_IS_BIG_ENDIAN
|
|
#endif
|
|
|
|
#if 0 // no big-endian platforms right now, but keep the code
|
|
// Big-endian platform
|
|
# define SYSTEM_IS_LITTLE_ENDIAN 0
|
|
# define SYSTEM_IS_BIG_ENDIAN 1
|
|
#else
|
|
// Little-endian platform
|
|
# define SYSTEM_IS_LITTLE_ENDIAN 1
|
|
# define SYSTEM_IS_BIG_ENDIAN 0
|
|
#endif
|
|
|
|
#if SYSTEM_IS_BIG_ENDIAN
|
|
// Big-endian platform. Swap to/from little.
|
|
#define eBigEndian false
|
|
#define eLittleEndian true
|
|
#define NEED_ENDIAN_SWAP
|
|
#else
|
|
// Little-endian platform. Swap to/from big.
|
|
#define eLittleEndian false
|
|
#define eBigEndian true
|
|
#undef NEED_ENDIAN_SWAP
|
|
#endif
|
|
|
|
|
|
enum EEndianness
|
|
{
|
|
eEndianness_Little,
|
|
eEndianness_Big,
|
|
#if SYSTEM_IS_BIG_ENDIAN
|
|
eEndianness_Native = eEndianness_Big,
|
|
eEndianness_NonNative = eEndianness_Little,
|
|
#else
|
|
eEndianness_Native = eEndianness_Little,
|
|
eEndianness_NonNative = eEndianness_Big,
|
|
#endif
|
|
};
|
|
|
|
|
|
// Legacy macros
|
|
#define GetPlatformEndian() false
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
inline bool IsSystemLittleEndian()
|
|
{
|
|
const int a = 1;
|
|
return 1 == *(const char*)&a;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// SwapEndian function, using TypeInfo.
|
|
struct CTypeInfo;
|
|
void SwapEndian(const CTypeInfo& Info, size_t nSizeCheck, void* pData, size_t nCount = 1, bool bWriting = false);
|
|
|
|
// Default template utilizes TypeInfo.
|
|
template<class T>
|
|
inline void SwapEndianBase(T* t, size_t nCount = 1, bool bWriting = false)
|
|
{
|
|
SwapEndian(TypeInfo(t), sizeof(T), t, nCount, bWriting);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
// SwapEndianBase functions.
|
|
// Always swap the data (the functions named SwapEndian swap based on an optional bSwapEndian parameter).
|
|
// The bWriting parameter must be specified in general when the output is for writing,
|
|
// but it matters only for types with bitfields.
|
|
|
|
// Overrides for base types.
|
|
|
|
template<>
|
|
inline void SwapEndianBase(char* p, size_t nCount, bool bWriting)
|
|
{
|
|
(void)p;
|
|
(void)nCount;
|
|
(void)bWriting;
|
|
}
|
|
|
|
template<>
|
|
inline void SwapEndianBase(uint8* p, size_t nCount, bool bWriting)
|
|
{
|
|
(void)p;
|
|
(void)nCount;
|
|
(void)bWriting;
|
|
}
|
|
|
|
template<>
|
|
inline void SwapEndianBase(int8* p, size_t nCount, bool bWriting)
|
|
{
|
|
(void)p;
|
|
(void)nCount;
|
|
(void)bWriting;
|
|
}
|
|
|
|
template<>
|
|
inline void SwapEndianBase(uint16* p, size_t nCount, bool bWriting)
|
|
{
|
|
(void)bWriting;
|
|
for (; nCount-- > 0; p++)
|
|
{
|
|
*p = (uint16) (((*p >> 8) + (*p << 8)) & 0xFFFF);
|
|
}
|
|
}
|
|
|
|
template<>
|
|
inline void SwapEndianBase(int16* p, size_t nCount, bool bWriting)
|
|
{
|
|
(void)bWriting;
|
|
SwapEndianBase((uint16*)p, nCount);
|
|
}
|
|
|
|
template<>
|
|
inline void SwapEndianBase(uint32* p, size_t nCount, bool bWriting)
|
|
{
|
|
(void)bWriting;
|
|
for (; nCount-- > 0; p++)
|
|
{
|
|
*p = (*p >> 24) + ((*p >> 8) & 0xFF00) + ((*p & 0xFF00) << 8) + (*p << 24);
|
|
}
|
|
}
|
|
|
|
template<>
|
|
inline void SwapEndianBase(int32* p, size_t nCount, bool bWriting)
|
|
{
|
|
(void)bWriting;
|
|
SwapEndianBase((uint32*)p, nCount);
|
|
}
|
|
|
|
template<>
|
|
inline void SwapEndianBase(float* p, size_t nCount, bool bWriting)
|
|
{
|
|
(void)bWriting;
|
|
SwapEndianBase((uint32*)p, nCount);
|
|
}
|
|
|
|
template<>
|
|
inline void SwapEndianBase(uint64* p, size_t nCount, bool bWriting)
|
|
{
|
|
(void)bWriting;
|
|
for (; nCount-- > 0; p++)
|
|
{
|
|
*p = (*p >> 56) + ((*p >> 40) & 0xFF00) + ((*p >> 24) & 0xFF0000) + ((*p >> 8) & 0xFF000000)
|
|
+ ((*p & 0xFF000000) << 8) + ((*p & 0xFF0000) << 24) + ((*p & 0xFF00) << 40) + (*p << 56);
|
|
}
|
|
}
|
|
|
|
template<>
|
|
inline void SwapEndianBase(int64* p, size_t nCount, bool bWriting)
|
|
{
|
|
(void)bWriting;
|
|
SwapEndianBase((uint64*)p, nCount);
|
|
}
|
|
|
|
template<>
|
|
inline void SwapEndianBase(double* p, size_t nCount, bool bWriting)
|
|
{
|
|
(void)bWriting;
|
|
SwapEndianBase((uint64*)p, nCount);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// SwapEndian functions.
|
|
// bSwapEndian argument optional, and defaults to swapping from LittleEndian format.
|
|
|
|
template<class T>
|
|
inline void SwapEndian(T* t, size_t nCount, bool bSwapEndian = eLittleEndian)
|
|
{
|
|
if (bSwapEndian)
|
|
{
|
|
SwapEndianBase(t, nCount);
|
|
}
|
|
}
|
|
|
|
// Specify int and uint as well as size_t, to resolve overload ambiguities.
|
|
template<class T>
|
|
inline void SwapEndian(T* t, int nCount, bool bSwapEndian = eLittleEndian)
|
|
{
|
|
if (bSwapEndian)
|
|
{
|
|
SwapEndianBase(t, nCount);
|
|
}
|
|
}
|
|
|
|
#if defined(PLATFORM_64BIT)
|
|
template<class T>
|
|
inline void SwapEndian(T* t, unsigned int nCount, bool bSwapEndian = eLittleEndian)
|
|
{
|
|
if (bSwapEndian)
|
|
{
|
|
SwapEndianBase(t, nCount);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
template<class T>
|
|
inline void SwapEndian(T& t, bool bSwapEndian = eLittleEndian)
|
|
{
|
|
if (bSwapEndian)
|
|
{
|
|
SwapEndianBase(&t, 1);
|
|
}
|
|
}
|
|
|
|
template<class T>
|
|
inline T SwapEndianValue(T t, bool bSwapEndian = eLittleEndian)
|
|
{
|
|
if (bSwapEndian)
|
|
{
|
|
SwapEndianBase(&t, 1);
|
|
}
|
|
return t;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Object-oriented data extraction for endian-swapping reading.
|
|
template<class T, class D>
|
|
inline T* StepData(D*& pData, size_t nCount, bool bSwapEndian)
|
|
{
|
|
T* Elems = (T*)pData;
|
|
SwapEndian(Elems, nCount, bSwapEndian);
|
|
pData = (D*)((T*)pData + nCount);
|
|
return Elems;
|
|
}
|
|
|
|
template<class T, class D>
|
|
inline T* StepData(D*& pData, bool bSwapEndian)
|
|
{
|
|
return StepData<T, D>(pData, 1, bSwapEndian);
|
|
}
|
|
|
|
template<class T, class D>
|
|
inline void StepData(T*& Result, D*& pData, size_t nCount, bool bSwapEndian)
|
|
{
|
|
Result = StepData<T, D>(pData, nCount, bSwapEndian);
|
|
}
|
|
|
|
template<class T, class D>
|
|
inline void StepDataCopy(T* Dest, D*& pData, size_t nCount, bool bSwapEndian)
|
|
{
|
|
memcpy(Dest, pData, nCount * sizeof(T));
|
|
SwapEndian(Dest, nCount, bSwapEndian);
|
|
pData = (D*)((T*)pData + nCount);
|
|
}
|
|
|
|
template<class T, class D>
|
|
inline void StepDataWrite(D*& pDest, const T* aSrc, size_t nCount, bool bSwapEndian)
|
|
{
|
|
memcpy(pDest, aSrc, nCount * sizeof(T));
|
|
if (bSwapEndian)
|
|
{
|
|
SwapEndianBase((T*)pDest, nCount, true);
|
|
}
|
|
(T*&)pDest += nCount;
|
|
}
|
|
|
|
template<class T, class D>
|
|
inline void StepDataWrite(D*& pDest, const T& Src, bool bSwapEndian)
|
|
{
|
|
StepDataWrite(pDest, &Src, 1, bSwapEndian);
|
|
}
|
|
|
|
#endif // CRYINCLUDE_CRYCOMMON_CRYENDIAN_H
|