// (c) Mathias Panzenböck
// http://github.com/panzi/mathfun/blob/master/examples/portable_endian.h
//

#pragma once
 
#if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && !defined(__WINDOWS__)
  
#   define __WINDOWS__
   
#endif
    
#if defined(__linux__) || defined(__CYGWIN__) || defined(__GNU__)
     
#   include <endian.h>
      
#elif defined(__APPLE__)
       
#   include <machine/endian.h>
#   include <libkern/OSByteOrder.h>
        
#   define htobe16 OSSwapHostToBigInt16
#   define htole16 OSSwapHostToLittleInt16
#   define be16toh OSSwapBigToHostInt16
#   define le16toh OSSwapLittleToHostInt16
         
#   define htobe32 OSSwapHostToBigInt32
#   define htole32 OSSwapHostToLittleInt32
#   define be32toh OSSwapBigToHostInt32
#   define le32toh OSSwapLittleToHostInt32
          
#   define htobe64 OSSwapHostToBigInt64
#   define htole64 OSSwapHostToLittleInt64
#   define be64toh OSSwapBigToHostInt64
#   define le64toh OSSwapLittleToHostInt64
           
/**
#   define __BYTE_ORDER    BYTE_ORDER
#   define __BIG_ENDIAN    BIG_ENDIAN
#   define __LITTLE_ENDIAN LITTLE_ENDIAN
#   define __PDP_ENDIAN    PDP_ENDIAN
**/
            
#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)

#   include <sys/endian.h>

#elif defined(__FreeBSD_kernel__)
     
#   include <endian.h>
      
#elif defined(__WINDOWS__)
                    
#   include <winsock2.h>
                     
#   if BYTE_ORDER == LITTLE_ENDIAN
                      
#       define htobe16 htons
#       define htole16(x) (x)
#       define be16toh ntohs
#       define le16toh(x) (x)
                       
#       define htobe32 htonl
#       define htole32(x) (x)
#       define be32toh ntohl
#       define le32toh(x) (x)
                        
#       define htole64(x) (x)
#       define le64toh(x) (x)
#   ifndef __MINGW32__
#       define be64toh ntohll
#       define htobe64 htonll
#   else
#       define be64toh(x) ((((uint64_t)ntohl((x) & 0xFFFFFFFFUL)) << 32) | ntohl((uint32_t)((x) >> 32)))
#       define htobe64(x) ((((uint64_t)htonl((x) & 0xFFFFFFFFUL)) << 32) | htonl((uint32_t)((x) >> 32)))
#   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
                                         
#endif
