/* osgEarth
 * Copyright 2025 Pelican Mapping
 * MIT License
 */

// "License": Public Domain
// I, Mathias Panzenbock, place this file hereby into the public domain. Use it at your own risk for whatever you like.
// In case there are jurisdictions that don't support putting things in the public domain you can also consider it to
// be "dual licensed" under the BSD, MIT and Apache licenses, if you want to. This code is trivial anyway. Consider it
// an example on how to get the endian conversion functions on different platforms.

#ifndef OSGEARTH_PORTABLE_ENDIAN_H__
#define OSGEARTH_PORTABLE_ENDIAN_H__

#if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && !defined(__WINDOWS__)

#   include <stdint.h>

#	define __WINDOWS__

#endif

#if defined(__linux__) || defined(__CYGWIN__)

#	include <endian.h>

#elif defined(__APPLE__)

#	include <libkern/OSByteOrder.h>

#	define htobe16(x) OSSwapHostToBigInt16(x)
#	define htole16(x) OSSwapHostToLittleInt16(x)
#	define be16toh(x) OSSwapBigToHostInt16(x)
#	define le16toh(x) OSSwapLittleToHostInt16(x)
 
#	define htobe32(x) OSSwapHostToBigInt32(x)
#	define htole32(x) OSSwapHostToLittleInt32(x)
#	define be32toh(x) OSSwapBigToHostInt32(x)
#	define le32toh(x) OSSwapLittleToHostInt32(x)
 
#	define htobe64(x) OSSwapHostToBigInt64(x)
#	define htole64(x) OSSwapHostToLittleInt64(x)
#	define be64toh(x) OSSwapBigToHostInt64(x)
#	define le64toh(x) OSSwapLittleToHostInt64(x)

#	define __BYTE_ORDER    BYTE_ORDER
#	define __BIG_ENDIAN    BIG_ENDIAN
#	define __LITTLE_ENDIAN LITTLE_ENDIAN
#	define __PDP_ENDIAN    PDP_ENDIAN

#elif defined(__OpenBSD__)

#	include <sys/endian.h>

#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)

#	include <sys/endian.h>

#	define be16toh(x) betoh16(x)
#	define le16toh(x) letoh16(x)

#	define be32toh(x) betoh32(x)
#	define le32toh(x) letoh32(x)

#	define be64toh(x) betoh64(x)
#	define le64toh(x) letoh64(x)

#elif defined(__WINDOWS__)

#	include <windows.h>

#	if BYTE_ORDER == LITTLE_ENDIAN

#		define htobe16(x) _byteswap_ushort(x)
#		define htole16(x) (x)
#		define be16toh(x) _byteswap_ushort(x)
#		define le16toh(x) (x)
 
#		define htobe32(x) _byteswap_ulong(x)
#		define htole32(x) (x)
#		define be32toh(x) _byteswap_ulong(x)
#		define le32toh(x) (x)

#		if defined(htonll) && defined(ntohll)
#			define htobe64(x) htonll(x)
#			define htole64(x) (x)
#			define be64toh(x) ntohll(x)
#			define le64toh(x) (x)
#		else
#			define htobe64(x) _byteswap_uint64(x)
#			define htole64(x) (x)
#			define be64toh(x) _byteswap_uint64(x)
#			define le64toh(x) (x)
#		endif

#	elif BYTE_ORDER == BIG_ENDIAN

		/* that would be xbox 360 */
#		define htobe16(x) (x)
#		define htole16(x) __builtin_bswap16(x)
#		define be16toh(x) (x)
#		define le16toh(x) __builtin_bswap16(x)
 
#		define htobe32(x) (x)
#		define htole32(x) __builtin_bswap32(x)
#		define be32toh(x) (x)
#		define le32toh(x) __builtin_bswap32(x)
 
#		define htobe64(x) (x)
#		define htole64(x) __builtin_bswap64(x)
#		define be64toh(x) (x)
#		define le64toh(x) __builtin_bswap64(x)

#	else

#		error byte order not supported

#	endif

#	define __BYTE_ORDER    BYTE_ORDER
#	define __BIG_ENDIAN    BIG_ENDIAN
#	define __LITTLE_ENDIAN LITTLE_ENDIAN
#	define __PDP_ENDIAN    PDP_ENDIAN

#else

//#	error platform not supported
#   define htobe16(X) X
#   define htobe32(X) X
#   define htobe64(X) X
#   define be16toh(X) X
#   define be32toh(X) X
#   define be64toh(X) X

#endif

#define OE_ENCODE_SHORT(X)  htobe16(X)
#define OE_ENCODE_INT(X)    htobe32(X)
#define OE_ENCODE_LONG(X)   htobe32(X)

inline uint32_t OE_ENCODE_FLOAT(float x) {
    return htobe32(*(uint32_t*)(&x));
}
inline uint64_t OE_ENCODE_DOUBLE(double x) {
    return htobe64(*(uint64_t*)(&x));
}

#define OE_DECODE_SHORT(X)  be16toh(X)
#define OE_DECODE_INT(X)    be32toh(X)
#define OE_DECODE_LONG(X)   be32toh(X)

inline float OE_DECODE_FLOAT(uint32_t x) {
    uint32_t temp = be32toh(x);
    float r = *(float*)(&temp);
    return r;
}
inline double OE_DECODE_DOUBLE(uint64_t x) {
    uint64_t temp = be64toh(x);
    double r = *(double*)(&temp);
    return r;
}

namespace osgEarth { namespace Util
{
    inline void byteSwapInPlace(uint32_t x) {
        unsigned char* p = (unsigned char*)&x;
        std::swap(p[0], p[3]);
        std::swap(p[1], p[2]);
    }
    inline void byteSwapInPlace(uint16_t x) {
        unsigned char* p = (unsigned char*)&x;
        std::swap(p[0], p[1]);
    }
} }

#if __BYTE_ORDER == __LITTLE_ENDIAN
    #define OE_IS_LITTLE_ENDIAN
#else
    #define OE_IS_BIG_ENDIAN
#endif

#endif // OSGEARTH_PORTABLE_ENDIAN_H__
