mirror of https://github.com/aria2/aria2
117 lines
3.7 KiB
C++
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
|