281 lines
9.0 KiB
C
281 lines
9.0 KiB
C
/*
|
|
WDL - wdlendian.h
|
|
(c) Theo Niessink 2011
|
|
<http://www.taletn.com/>
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
warranty. In no event will the authors be held liable for any damages
|
|
arising from the use of this software.
|
|
|
|
Permission is granted to anyone to use this software for any purpose,
|
|
including commercial applications, and to alter it and redistribute it
|
|
freely, subject to the following restrictions:
|
|
|
|
1. The origin of this software must not be misrepresented; you must not
|
|
claim that you wrote the original software. If you use this software
|
|
in a product, an acknowledgment in the product documentation would be
|
|
appreciated but is not required.
|
|
2. Altered source versions must be plainly marked as such, and must not be
|
|
misrepresented as being the original software.
|
|
3. This notice may not be removed or altered from any source distribution.
|
|
|
|
|
|
This file provides macros and functions for converting integer and
|
|
floating point data types from native (host) endian to little or big
|
|
endian format, and vice versa.
|
|
|
|
*/
|
|
|
|
|
|
#ifndef _WDL_ENDIAN_H_
|
|
#define _WDL_ENDIAN_H_
|
|
|
|
|
|
#include "wdltypes.h"
|
|
|
|
typedef union { float f; unsigned int int32; } WDL_EndianFloat;
|
|
typedef union { double f; WDL_UINT64 int64; } WDL_EndianDouble;
|
|
|
|
#ifdef __cplusplus
|
|
#define WDL_ENDIAN_INLINE inline
|
|
#elif defined(_MSC_VER)
|
|
#define WDL_ENDIAN_INLINE __inline
|
|
#else
|
|
#define WDL_ENDIAN_INLINE
|
|
#endif
|
|
|
|
|
|
// Windows
|
|
#ifdef _WIN32
|
|
#define WDL_LITTLE_ENDIAN
|
|
|
|
// Mac OS X
|
|
#elif defined(__APPLE__)
|
|
#if __LITTLE_ENDIAN__ // Intel
|
|
#define WDL_LITTLE_ENDIAN
|
|
#elif __BIG_ENDIAN__ // PowerPC
|
|
#define WDL_BIG_ENDIAN
|
|
|
|
#elif defined(EMSCRIPTEN)
|
|
#define WDL_LITTLE_ENDIAN
|
|
#else
|
|
#error Unknown endian
|
|
#endif
|
|
|
|
// GNU C (v4.6 or later?)
|
|
#elif __GNUC__ && defined(__BYTE_ORDER__)
|
|
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
|
#define WDL_LITTLE_ENDIAN
|
|
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
|
#define WDL_BIG_ENDIAN
|
|
#else
|
|
#error Unsupported endian
|
|
#endif
|
|
|
|
#ifndef EMSCRIPTEN
|
|
#if __FLOAT_WORD_ORDER__ != __BYTE_ORDER__
|
|
#error Unsupported float endian
|
|
#endif
|
|
#endif
|
|
|
|
// GNU C, Intel C++
|
|
#elif defined(__i386) || defined(__i386__) || defined(i386)
|
|
#define WDL_LITTLE_ENDIAN
|
|
|
|
// Intel C++
|
|
#elif defined(__x86_64) || defined(__x86_64__)
|
|
#define WDL_LITTLE_ENDIAN
|
|
|
|
#elif defined(EMSCRIPTEN)
|
|
#define WDL_LITTLE_ENDIAN
|
|
|
|
#else
|
|
#error Unknown endian
|
|
#endif
|
|
|
|
|
|
// Microsoft C
|
|
#ifdef _MSC_VER
|
|
#include <intrin.h>
|
|
#define WDL_bswap16(x) _byteswap_ushort(x)
|
|
#define WDL_bswap32(x) _byteswap_ulong(x)
|
|
#define WDL_bswap64(x) _byteswap_uint64(x)
|
|
|
|
#elif defined(__APPLE__)
|
|
#include "TargetConditionals.h"
|
|
#if defined(TARGET_OS_IPHONE) | defined(TARGET_IPHONE_SIMULATOR)
|
|
#include <libkern/OSByteOrder.h>
|
|
|
|
// iOS
|
|
#define WDL_bswap16(x) OSSwapInt16(x)
|
|
#define WDL_bswap32(x) OSSwapInt32(x)
|
|
#define WDL_bswap64(x) OSSwapInt64(x)
|
|
|
|
// Mac OS X (v10.0 and later)
|
|
#elif defined(TARGET_OS_MAC)
|
|
#include <CoreServices/CoreServices.h>
|
|
|
|
#define WDL_bswap16(x) Endian16_Swap(x)
|
|
#define WDL_bswap32(x) Endian32_Swap(x)
|
|
#define WDL_bswap64(x) Endian64_Swap(x) // (Thread-safe on) v10.3 and later (?)
|
|
#endif
|
|
|
|
|
|
// GNU C
|
|
#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
|
|
#define WDL_bswap32(x) __builtin_bswap32(x)
|
|
#define WDL_bswap64(x) __builtin_bswap64(x)
|
|
|
|
// Linux
|
|
#elif defined(__linux) || defined(__linux__) || defined(linux)
|
|
#include <endian.h>
|
|
#define WDL_bswap16(x) bswap16(x)
|
|
#define WDL_bswap32(x) bswap32(x)
|
|
#define WDL_bswap64(x) bswap64(x)
|
|
|
|
#endif // WDL_bswapXX
|
|
|
|
// If none of the supported intrinsics were found, then revert to generic C
|
|
// byte swap functions.
|
|
#ifndef WDL_bswap16
|
|
static WDL_ENDIAN_INLINE unsigned short WDL_bswap16(const unsigned short int16)
|
|
{
|
|
return int16 >> 8 |
|
|
int16 << 8;
|
|
}
|
|
#endif
|
|
|
|
#ifndef WDL_bswap32
|
|
static WDL_ENDIAN_INLINE unsigned int WDL_bswap32(const unsigned int int32)
|
|
{
|
|
return int32 >> 24 |
|
|
int32 >> 8 & 0x0000FF00 |
|
|
int32 << 8 & 0x00FF0000 |
|
|
int32 << 24;
|
|
}
|
|
#endif
|
|
|
|
#ifndef WDL_bswap64
|
|
static WDL_ENDIAN_INLINE WDL_UINT64 WDL_bswap64(const WDL_UINT64 int64)
|
|
{
|
|
return int64 >> 56 |
|
|
int64 >> 40 & 0x000000000000FF00ULL |
|
|
int64 >> 24 & 0x0000000000FF0000ULL |
|
|
int64 >> 8 & 0x00000000FF000000ULL |
|
|
int64 << 8 & 0x000000FF00000000ULL |
|
|
int64 << 24 & 0x0000FF0000000000ULL |
|
|
int64 << 40 & 0x00FF000000000000ULL |
|
|
int64 << 56;
|
|
}
|
|
#endif
|
|
|
|
|
|
// Int types
|
|
|
|
#if defined(WDL_LITTLE_ENDIAN)
|
|
|
|
#define WDL_bswap16_if_le(x) WDL_bswap16(x)
|
|
#define WDL_bswap32_if_le(x) WDL_bswap32(x)
|
|
#define WDL_bswap64_if_le(x) WDL_bswap64(x)
|
|
#define WDL_bswap16_if_be(x) ((unsigned short)(x))
|
|
#define WDL_bswap32_if_be(x) ((unsigned int)(x))
|
|
#define WDL_bswap64_if_be(x) ((WDL_UINT64)(x))
|
|
|
|
// Wrappers that convert a variable in-place, or generate no code if
|
|
// conversion is not necessary. Beware to only feed variables to these
|
|
// macros, so no fancy things like WDL_BSWAP32_IF_LE(x + y) or
|
|
// WDL_BSWAP32_IF_LE(x++). Note that these macros only change the type
|
|
// to unsigned if conversion is actually necessary.
|
|
#define WDL_BSWAP16_IF_LE(x) (x = WDL_bswap16(x))
|
|
#define WDL_BSWAP32_IF_LE(x) (x = WDL_bswap32(x))
|
|
#define WDL_BSWAP64_IF_LE(x) (x = WDL_bswap64(x))
|
|
#define WDL_BSWAP16_IF_BE(x) ((void)0)
|
|
#define WDL_BSWAP32_IF_BE(x) ((void)0)
|
|
#define WDL_BSWAP64_IF_BE(x) ((void)0)
|
|
|
|
#else // #elif defined(WDL_BIG_ENDIAN)
|
|
|
|
#define WDL_bswap16_if_be(x) WDL_bswap16(x)
|
|
#define WDL_bswap32_if_be(x) WDL_bswap32(x)
|
|
#define WDL_bswap64_if_be(x) WDL_bswap64(x)
|
|
#define WDL_bswap16_if_le(x) ((unsigned short)(x))
|
|
#define WDL_bswap32_if_le(x) ((unsigned int)(x))
|
|
#define WDL_bswap64_if_le(x) ((WDL_UINT64)(x))
|
|
|
|
// In-place wrappers (see notes above)
|
|
#define WDL_BSWAP16_IF_BE(x) (x = WDL_bswap16(x))
|
|
#define WDL_BSWAP32_IF_BE(x) (x = WDL_bswap32(x))
|
|
#define WDL_BSWAP64_IF_BE(x) (x = WDL_bswap64(x))
|
|
#define WDL_BSWAP16_IF_LE(x) ((void)0)
|
|
#define WDL_BSWAP32_IF_LE(x) ((void)0)
|
|
#define WDL_BSWAP64_IF_LE(x) ((void)0)
|
|
|
|
#endif // WDL_bswapXX_if_YY
|
|
|
|
|
|
// C++ auto-typed wrappers
|
|
|
|
#ifdef __cplusplus
|
|
|
|
static WDL_ENDIAN_INLINE unsigned short WDL_bswap_if_le(unsigned short int16) { return WDL_bswap16_if_le(int16); }
|
|
static WDL_ENDIAN_INLINE signed short WDL_bswap_if_le(signed short int16) { return WDL_bswap16_if_le(int16); }
|
|
static WDL_ENDIAN_INLINE unsigned int WDL_bswap_if_le(unsigned int int32) { return WDL_bswap32_if_le(int32); }
|
|
static WDL_ENDIAN_INLINE signed int WDL_bswap_if_le(signed int int32) { return WDL_bswap32_if_le(int32); }
|
|
static WDL_ENDIAN_INLINE WDL_UINT64 WDL_bswap_if_le(WDL_UINT64 int64) { return WDL_bswap64_if_le(int64); }
|
|
static WDL_ENDIAN_INLINE WDL_INT64 WDL_bswap_if_le(WDL_INT64 int64) { return WDL_bswap64_if_le(int64); }
|
|
|
|
static WDL_ENDIAN_INLINE unsigned short WDL_bswap_if_be(unsigned short int16) { return WDL_bswap16_if_be(int16); }
|
|
static WDL_ENDIAN_INLINE signed short WDL_bswap_if_be(signed short int16) { return WDL_bswap16_if_be(int16); }
|
|
static WDL_ENDIAN_INLINE unsigned int WDL_bswap_if_be(unsigned int int32) { return WDL_bswap32_if_be(int32); }
|
|
static WDL_ENDIAN_INLINE signed int WDL_bswap_if_be(signed int int32) { return WDL_bswap32_if_be(int32); }
|
|
static WDL_ENDIAN_INLINE WDL_UINT64 WDL_bswap_if_be(WDL_UINT64 int64) { return WDL_bswap64_if_be(int64); }
|
|
static WDL_ENDIAN_INLINE WDL_INT64 WDL_bswap_if_be(WDL_INT64 int64) { return WDL_bswap64_if_be(int64); }
|
|
|
|
// Auto-typed in-place wrappers (see notes above)
|
|
#ifdef WDL_LITTLE_ENDIAN
|
|
#define WDL_BSWAP_IF_LE(x) (x = WDL_bswap_if_le(x))
|
|
#define WDL_BSWAP_IF_BE(x) ((void)0)
|
|
#else // #elif defined(WDL_BIG_ENDIAN)
|
|
#define WDL_BSWAP_IF_BE(x) (x = WDL_bswap_if_be(x))
|
|
#define WDL_BSWAP_IF_LE(x) ((void)0)
|
|
#endif
|
|
|
|
|
|
// Map floating point types to int types.
|
|
|
|
#if defined(WDL_LITTLE_ENDIAN)
|
|
#define __WDL_bswapf_if_a WDL_bswapf_if_le
|
|
#define __WDL_bswapf_if_b WDL_bswapf_if_be
|
|
#else // #elif defined(WDL_BIG_ENDIAN)
|
|
#define __WDL_bswapf_if_a WDL_bswapf_if_be
|
|
#define __WDL_bswapf_if_b WDL_bswapf_if_le
|
|
#endif
|
|
|
|
static WDL_ENDIAN_INLINE unsigned int __WDL_bswapf_if_a(const float f) { return WDL_bswap32(*(const unsigned int*)&f); }
|
|
static WDL_ENDIAN_INLINE WDL_UINT64 __WDL_bswapf_if_a(const double f) { return WDL_bswap64(*(const WDL_UINT64 *)&f); }
|
|
|
|
static WDL_ENDIAN_INLINE float __WDL_bswapf_if_a(const unsigned int int32)
|
|
{
|
|
const unsigned int i = WDL_bswap32(int32);
|
|
return *(const float*)&i;
|
|
}
|
|
|
|
static WDL_ENDIAN_INLINE double __WDL_bswapf_if_a(const WDL_UINT64 int64)
|
|
{
|
|
const WDL_UINT64 i = WDL_bswap64(int64);
|
|
return *(const double*)&i;
|
|
}
|
|
|
|
static WDL_ENDIAN_INLINE unsigned int __WDL_bswapf_if_b(const float f) { return *(const unsigned int*)&f; }
|
|
static WDL_ENDIAN_INLINE WDL_UINT64 __WDL_bswapf_if_b(const double f) { return *(const WDL_UINT64 *)&f; }
|
|
static WDL_ENDIAN_INLINE float __WDL_bswapf_if_b(const unsigned int int32) { return *(const float *)&int32; }
|
|
static WDL_ENDIAN_INLINE double __WDL_bswapf_if_b(const WDL_UINT64 int64) { return *(const double *)&int64; }
|
|
|
|
#undef __WDL_bswapf_if_a
|
|
#undef __WDL_bswapf_if_b
|
|
|
|
#endif // __cplusplus
|
|
|
|
|
|
#endif // _WDL_ENDIAN_H_
|