1#ifndef AWS_COMMON_BYTE_ORDER_INL
2#define AWS_COMMON_BYTE_ORDER_INL
3
4/**
5 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
6 * SPDX-License-Identifier: Apache-2.0.
7 */
8
9#include <aws/common/byte_order.h>
10#include <aws/common/common.h>
11
12#ifdef _WIN32
13#    include <stdlib.h>
14#else
15#    include <netinet/in.h>
16#endif /* _MSC_VER */
17
18AWS_EXTERN_C_BEGIN
19
20/**
21 * Returns 1 if machine is big endian, 0 if little endian.
22 * If you compile with even -O1 optimization, this check is completely optimized
23 * out at compile time and code which calls "if (aws_is_big_endian())" will do
24 * the right thing without branching.
25 */
26AWS_STATIC_IMPL int aws_is_big_endian(void) {
27    const uint16_t z = 0x100;
28    return *(const uint8_t *)&z;
29}
30
31/**
32 * Convert 64 bit integer from host to network byte order.
33 */
34AWS_STATIC_IMPL uint64_t aws_hton64(uint64_t x) {
35    if (aws_is_big_endian()) {
36        return x;
37    }
38#if defined(__x86_64__) && (defined(__GNUC__) || defined(__clang__)) && !defined(CBMC)
39    uint64_t v;
40    __asm__("bswap %q0" : "=r"(v) : "0"(x));
41    return v;
42#elif defined(_MSC_VER)
43    return _byteswap_uint64(x);
44#else
45    uint32_t low = x & UINT32_MAX;
46    uint32_t high = (uint32_t)(x >> 32);
47    return ((uint64_t)htonl(low)) << 32 | htonl(high);
48#endif
49}
50
51/**
52 * Convert 64 bit integer from network to host byte order.
53 */
54AWS_STATIC_IMPL uint64_t aws_ntoh64(uint64_t x) {
55    return aws_hton64(x);
56}
57
58/**
59 * Convert 32 bit integer from host to network byte order.
60 */
61AWS_STATIC_IMPL uint32_t aws_hton32(uint32_t x) {
62#ifdef _WIN32
63    return aws_is_big_endian() ? x : _byteswap_ulong(x);
64#else
65    return htonl(x);
66#endif
67}
68
69/**
70 * Convert 32 bit float from host to network byte order.
71 */
72AWS_STATIC_IMPL float aws_htonf32(float x) {
73    if (aws_is_big_endian()) {
74        return x;
75    }
76
77    uint8_t *f_storage = (uint8_t *)&x;
78
79    float ret_value;
80    uint8_t *ret_storage = (uint8_t *)&ret_value;
81
82    ret_storage[0] = f_storage[3];
83    ret_storage[1] = f_storage[2];
84    ret_storage[2] = f_storage[1];
85    ret_storage[3] = f_storage[0];
86
87    return ret_value;
88}
89
90/**
91 * Convert 64 bit double from host to network byte order.
92 */
93AWS_STATIC_IMPL double aws_htonf64(double x) {
94    if (aws_is_big_endian()) {
95        return x;
96    }
97
98    uint8_t *f_storage = (uint8_t *)&x;
99
100    double ret_value;
101    uint8_t *ret_storage = (uint8_t *)&ret_value;
102
103    ret_storage[0] = f_storage[7];
104    ret_storage[1] = f_storage[6];
105    ret_storage[2] = f_storage[5];
106    ret_storage[3] = f_storage[4];
107    ret_storage[4] = f_storage[3];
108    ret_storage[5] = f_storage[2];
109    ret_storage[6] = f_storage[1];
110    ret_storage[7] = f_storage[0];
111
112    return ret_value;
113}
114
115/**
116 * Convert 32 bit integer from network to host byte order.
117 */
118AWS_STATIC_IMPL uint32_t aws_ntoh32(uint32_t x) {
119#ifdef _WIN32
120    return aws_is_big_endian() ? x : _byteswap_ulong(x);
121#else
122    return ntohl(x);
123#endif
124}
125
126/**
127 * Convert 32 bit float from network to host byte order.
128 */
129AWS_STATIC_IMPL float aws_ntohf32(float x) {
130    return aws_htonf32(x);
131}
132
133/**
134 * Convert 32 bit float from network to host byte order.
135 */
136AWS_STATIC_IMPL double aws_ntohf64(double x) {
137    return aws_htonf64(x);
138}
139
140/**
141 * Convert 16 bit integer from host to network byte order.
142 */
143AWS_STATIC_IMPL uint16_t aws_hton16(uint16_t x) {
144#ifdef _WIN32
145    return aws_is_big_endian() ? x : _byteswap_ushort(x);
146#else
147    return htons(x);
148#endif
149}
150
151/**
152 * Convert 16 bit integer from network to host byte order.
153 */
154AWS_STATIC_IMPL uint16_t aws_ntoh16(uint16_t x) {
155#ifdef _WIN32
156    return aws_is_big_endian() ? x : _byteswap_ushort(x);
157#else
158    return ntohs(x);
159#endif
160}
161
162AWS_EXTERN_C_END
163
164#endif /* AWS_COMMON_BYTE_ORDER_INL */
165