aria2/src/crypto_endian.h

117 lines
3.7 KiB
C++

/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Written in 2014 by Nils Maier
#ifndef CRYPTO_ENDIAN_H
#define CRYPTO_ENDIAN_H
#include <cstdint>
#include "config.h"
namespace crypto {
#if defined(__GNUG__)
#define forceinline __attribute__((always_inline)) inline
#elif defined(_MSC_VER)
#define forceinline __forceinline
#else // ! _MSC_VER
#define forceinline inline
#endif // ! _MSC_VER
/* In order for this implementation to work your system (or you yourself) must
* define after including <sys/param.h>
* - LITTLE_ENDIAN
* - BIG_ENDIAN
* - BYTE_ORDER
* - where BYTE_ORDER == LITTLE_ENDIAN or BYTE_ORDER == BIG_ENDIAN
* Failing to conform will render this implementation utterly incorrect.
*/
#if defined(_WIN32) || defined(__INTEL_COMPILER) || defined (_MSC_VER)
// Itanium is dead!
#define LITTLE_ENDIAN 1234
#define BIG_ENDIAN 4321
#define BYTE_ORDER LITTLE_ENDIAN
#else // ! defined(_WIN32) || defined(__INTEL_COMPILER) || defined (_MSC_VER)
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif // HAVE_SYS_PARAM_H
#endif // ! defined(_WIN32) || defined(__INTEL_COMPILER) || defined (_MSC_VER)
#if !defined(LITTLE_ENDIAN) || !defined(BIG_ENDIAN) || !defined(BYTE_ORDER) || (LITTLE_ENDIAN != BYTE_ORDER && BIG_ENDIAN != BYTE_ORDER)
#error Unsupported byte order/endianess
#endif
// Lets spend some quality time mucking around with byte swap and endian-ness.
// First bswap32:
#if (defined(__i386__) || defined(__x86_64__)) && defined(__GNUG__)
#define __crypto_bswap32(p) \
({ \
uint32_t t = p; \
__asm__ __volatile__("bswap %0" : "=r"(t) : "0"(t)); \
t; \
})
#elif defined(__GNUG__)
#define __crypto_bswap32 __builtin_bswap32
#else // defined(__GNUG__)
forceinline uint32_t __crypto_bswap32(uint32_t n)
{
n = ((n << 8) & 0xff00ff00) | ((n >> 8) & 0xff00ff);
return (n << 16) | (n >> 16);
}
#endif // defined(__GNUG__)
// Next up: bswap64
#if defined(__x86_64__) && defined(__GNUG__)
#define __crypto_bswap64(p) \
({ \
uint64_t t = p; \
__asm__ __volatile__("bswapq %q0" : "=r"(t) : "0"(t)); \
t; \
})
#elif defined(__GNUG__)
#define __crypto_bswap64 __builtin_bswap64
#else // defined(__GNUG__)
forceinline uint64_t __crypto_bswap64(uint64_t n)
{
n = ((n << 8) & 0xff00ff00ff00ff00) | ((n >> 8) & 0x00ff00ff00ff00ff);
n = ((n << 16) & 0xffff0000ffff0000) | ((n >> 16) & 0x0000ffff0000ffff);
return (n << 32) | (n >> 32);
}
#endif // defined(__GNUG__)
// Time for an implementation that makes reuse easier.
namespace {
template<typename T>
inline T __crypto_bswap(T n)
{
static_assert(sizeof(T) != sizeof(T), "Not implemented");
}
template<>
inline uint32_t __crypto_bswap(uint32_t n)
{
return __crypto_bswap32(n);
}
template<>
inline uint64_t __crypto_bswap(uint64_t n)
{
return __crypto_bswap64(n);
}
} // namespace
// __crypto_le and __crypto_be depending on byte order
#if LITTLE_ENDIAN == BYTE_ORDER
#define __crypto_be(n) __crypto_bswap(n)
#define __crypto_le(n) (n)
#else // LITTLE_ENDIAN != WORD_ORDER
#define __crypto_be(n) (n)
#define __crypto_le(n) __crypto_bswap(n)
#endif
} // namespace crypto
#endif // CRYPTO_ENDIAN_H