/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ // Original file Copyright Crytek GMBH or its affiliates, used under license. #ifndef CRYINCLUDE_CRYCOMMON_CRYENDIAN_H #define CRYINCLUDE_CRYCOMMON_CRYENDIAN_H #pragma once ////////////////////////////////////////////////////////////////////////// // 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 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 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 inline void SwapEndian(T* t, int nCount, bool bSwapEndian = eLittleEndian) { if (bSwapEndian) { SwapEndianBase(t, nCount); } } #if defined(PLATFORM_64BIT) template inline void SwapEndian(T* t, unsigned int nCount, bool bSwapEndian = eLittleEndian) { if (bSwapEndian) { SwapEndianBase(t, nCount); } } #endif template inline void SwapEndian(T& t, bool bSwapEndian = eLittleEndian) { if (bSwapEndian) { SwapEndianBase(&t, 1); } } template inline T SwapEndianValue(T t, bool bSwapEndian = eLittleEndian) { if (bSwapEndian) { SwapEndianBase(&t, 1); } return t; } //--------------------------------------------------------------------------- // Object-oriented data extraction for endian-swapping reading. template 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 inline T* StepData(D*& pData, bool bSwapEndian) { return StepData(pData, 1, bSwapEndian); } template inline void StepData(T*& Result, D*& pData, size_t nCount, bool bSwapEndian) { Result = StepData(pData, nCount, bSwapEndian); } template 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 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 inline void StepDataWrite(D*& pDest, const T& Src, bool bSwapEndian) { StepDataWrite(pDest, &Src, 1, bSwapEndian); } #endif // CRYINCLUDE_CRYCOMMON_CRYENDIAN_H