diff --git a/configure.ac b/configure.ac index 2111c81..be6daf2 100644 --- a/configure.ac +++ b/configure.ac @@ -272,7 +272,7 @@ AC_CHECK_DECL([htobe64], [AC_CHECK_DECL([OSSwapHostToBigInt64], [AC_DEFINE([HAVE_OSX_SWAP], [1], [Define if OSSwapHostToBigInt64 and friends exist.])], - [AC_MSG_ERROR([Unable to find byte swapping functions])], + [AC_MSG_WARN([Unable to find byte swapping functions; using built-in routines.])], [[#include ]])], [[#if defined(HAVE_ENDIAN_H) #include diff --git a/src/crypto/byteorder.h b/src/crypto/byteorder.h index 549ff4d..a341427 100644 --- a/src/crypto/byteorder.h +++ b/src/crypto/byteorder.h @@ -27,12 +27,84 @@ # elif defined(HAVE_SYS_ENDIAN_H) # include # endif + #elif HAVE_OSX_SWAP # include # define htobe64 OSSwapHostToBigInt64 # define be64toh OSSwapBigToHostInt64 # define htobe16 OSSwapHostToBigInt16 # define be16toh OSSwapBigToHostInt16 + +#else + +/* Use our fallback implementation, which is correct for any endianness. */ + +#include + +/* Make sure they aren't macros */ +#undef htobe64 +#undef be64toh +#undef htobe16 +#undef be16toh + +/* Use unions rather than casts, to comply with strict aliasing rules. */ + +inline uint64_t htobe64( uint64_t x ) { + uint8_t xs[ 8 ] = { + ( x >> 56 ) & 0xFF, + ( x >> 48 ) & 0xFF, + ( x >> 40 ) & 0xFF, + ( x >> 32 ) & 0xFF, + ( x >> 24 ) & 0xFF, + ( x >> 16 ) & 0xFF, + ( x >> 8 ) & 0xFF, + x & 0xFF }; + union { + const uint8_t *p8; + const uint64_t *p64; + } u; + u.p8 = xs; + return *u.p64; +} + +inline uint64_t be64toh( uint64_t x ) { + union { + const uint8_t *p8; + const uint64_t *p64; + } u; + u.p64 = &x; + return ( uint64_t( u.p8[ 0 ] ) << 56 ) + | ( uint64_t( u.p8[ 1 ] ) << 48 ) + | ( uint64_t( u.p8[ 2 ] ) << 40 ) + | ( uint64_t( u.p8[ 3 ] ) << 32 ) + | ( uint64_t( u.p8[ 4 ] ) << 24 ) + | ( uint64_t( u.p8[ 5 ] ) << 16 ) + | ( uint64_t( u.p8[ 6 ] ) << 8 ) + | ( uint64_t( u.p8[ 7 ] ) ); +} + +inline uint16_t htobe16( uint16_t x ) { + uint8_t xs[ 2 ] = { + ( x >> 8 ) & 0xFF, + x & 0xFF }; + union { + const uint8_t *p8; + const uint16_t *p16; + } u; + u.p8 = xs; + return *u.p16; +} + +inline uint16_t be16toh( uint16_t x ) { + union { + const uint8_t *p8; + const uint16_t *p16; + } u; + u.p16 = &x; + return ( uint16_t( u.p8[ 0 ] ) << 8 ) + | ( uint16_t( u.p8[ 1 ] ) ); +} + #endif #endif