Line data Source code
1 : /*
2 : * libpino - endianness.c
3 : *
4 : * Copyright (c) 2025 Go Kudo
5 : *
6 : * This library is licensed under the BSD 3-Clause License.
7 : * For license details, please refer to the LICENSE file.
8 : *
9 : * SPDX-FileCopyrightText: Go Kudo <zeriyoshi@gmail.com>
10 : * SPDX-License-Identifier: BSD-3-Clause
11 : */
12 :
13 : #include <pino/endianness.h>
14 :
15 : #include <pino_internal.h>
16 :
17 : #define ENDIANNESS_UNKNOWN 0
18 : #define ENDIANNESS_LITTLE 1
19 : #define ENDIANNESS_BIG 2
20 :
21 : #if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
22 : static uint8_t g_endianness = ENDIANNESS_LITTLE;
23 : #elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
24 : static uint8_t g_endianness = ENDIANNESS_BIG;
25 : #else
26 : static uint8_t g_endianness = ENDIANNESS_UNKNOWN;
27 : #endif
28 :
29 3094 : static inline uint8_t platform_endianness(void)
30 : {
31 : uint32_t i;
32 : uint8_t *p;
33 :
34 3094 : if (g_endianness != ENDIANNESS_UNKNOWN) {
35 3094 : return g_endianness;
36 : }
37 :
38 : /* LCOV_EXCL_START */
39 :
40 : i = 1;
41 : p = (uint8_t *)&i;
42 :
43 : return g_endianness = (p[0] == 1) ? ENDIANNESS_LITTLE : ENDIANNESS_BIG;
44 :
45 : /* LCOV_EXCL_STOP */
46 : }
47 :
48 4 : static inline uint16_t bswap16(uint16_t x)
49 : {
50 4 : return ((x & 0xff) << 8) | ((x & 0xff00) >> 8);
51 : }
52 :
53 16 : static inline uint32_t bswap32(uint32_t x)
54 : {
55 16 : return ((x & 0xff) << 24) |
56 16 : ((x & 0xff00) << 8) |
57 32 : ((x & 0xff0000) >> 8) |
58 16 : ((x & 0xff000000) >> 24);
59 : }
60 :
61 6 : static inline uint64_t bswap64(uint64_t x)
62 : {
63 6 : return ((x & 0xff) << 56) |
64 6 : ((x & 0xff00) << 40) |
65 6 : ((x & 0xff0000) << 24) |
66 6 : ((x & 0xff000000) << 8) |
67 6 : ((x & 0xff00000000ULL) >> 8) |
68 6 : ((x & 0xff0000000000ULL) >> 24) |
69 12 : ((x & 0xff000000000000ULL) >> 40) |
70 6 : ((x & 0xff00000000000000ULL) >> 56);
71 : }
72 :
73 30 : static inline void *bswap_memcpy(void *dest, const void *src, size_t size, size_t elem_size)
74 : {
75 : uint8_t *dp;
76 : const uint8_t *sp;
77 : size_t i, j;
78 : uint16_t *dest16, *src16;
79 : uint32_t *dest32, *src32;
80 : uint64_t *dest64, *src64;
81 :
82 30 : dp = (uint8_t *)dest;
83 30 : sp = (const uint8_t *)src;
84 :
85 30 : if (elem_size == 1 || size == 0) {
86 2 : return pmemcpy(dest, src, size);
87 : }
88 :
89 28 : if (elem_size == 2 && (((uintptr_t)dest | (uintptr_t)src) & 0x1) == 0) {
90 4 : dest16 = (uint16_t *)dest;
91 4 : src16 = (uint16_t *)src;
92 :
93 8 : for (i = 0; i < size / 2; i++) {
94 4 : dest16[i] = bswap16(src16[i]);
95 : }
96 :
97 4 : return dest;
98 24 : } else if (elem_size == 4 && (((uintptr_t)dest | (uintptr_t)src) & 0x3) == 0) {
99 16 : dest32 = (uint32_t *)dest;
100 16 : src32 = (uint32_t *)src;
101 :
102 32 : for (i = 0; i < size / 4; i++) {
103 16 : dest32[i] = bswap32(src32[i]);
104 : }
105 :
106 16 : return dest;
107 8 : } else if (elem_size == 8 && (((uintptr_t)dest | (uintptr_t)src) & 0x7) == 0) {
108 6 : dest64 = (uint64_t *)dest;
109 6 : src64 = (uint64_t *)src;
110 :
111 12 : for (i = 0; i < size / 8; i++) {
112 6 : dest64[i] = bswap64(src64[i]);
113 : }
114 :
115 6 : return dest;
116 : }
117 :
118 4 : for (i = 0; i < size; i += elem_size) {
119 6 : for (j = 0; j < elem_size; j++) {
120 4 : dp[i + j] = sp[i + (elem_size - 1 - j)];
121 : }
122 : }
123 :
124 2 : return dest;
125 : }
126 :
127 24 : static inline size_t elem_sizeof(size_t size)
128 : {
129 24 : return (size % 8 == 0) ? 8 : (size % 4 == 0) ? 4 : (size % 2 == 0) ? 2 : 1;
130 : }
131 :
132 10 : static inline void *conv_memcpy(void *dest, const void *src, size_t size)
133 : {
134 10 : return bswap_memcpy(dest, src, size, elem_sizeof(size));
135 : }
136 :
137 3066 : static inline void *memcpy_common(void *dest, const void *src, size_t size, bool is_native)
138 : {
139 3066 : return is_native ? pmemcpy(dest, src, size) : conv_memcpy(dest, src, size);
140 : }
141 :
142 16 : static inline void *memmove_common(void *dest, const void *src, size_t size, bool is_native)
143 : {
144 : uint8_t *tmp;
145 :
146 16 : if (is_native) {
147 8 : return pmemmove(dest, src, size);
148 : } else {
149 8 : tmp = (uint8_t *)pmalloc(size);
150 : /* LCOV_EXCL_START */
151 : if (tmp == NULL) {
152 : PINO_SUPRTF("pmalloc failed");
153 : return NULL;
154 : }
155 : /* LCOV_EXCL_STOP */
156 :
157 8 : pmemcpy(tmp, src, size);
158 8 : bswap_memcpy(dest, tmp, size, elem_sizeof(size));
159 :
160 8 : pfree(tmp);
161 :
162 8 : return dest;
163 : }
164 :
165 : /* LCOV_EXCL_START */
166 : PINO_SUPUNREACH();
167 : return NULL;
168 : /* LCOV_EXCL_STOP */
169 : }
170 :
171 12 : static inline int memcmp_common(const void *s1, const void *s2, size_t size, bool is_native)
172 : {
173 : uint8_t *tmp1, *tmp2;
174 : size_t elem_size;
175 : int result;
176 :
177 12 : if (is_native) {
178 6 : return pmemcmp(s1, s2, size);
179 : } else {
180 6 : tmp1 = (uint8_t *)pmalloc(size);
181 6 : tmp2 = (uint8_t *)pmalloc(size);
182 : /* LCOV_EXCL_START */
183 : if (!tmp1 || !tmp2) {
184 : PINO_SUPRTF("pmalloc failed");
185 :
186 : if (tmp1) {
187 : pfree(tmp1);
188 : }
189 :
190 : if (tmp2) {
191 : pfree(tmp2);
192 : }
193 :
194 : return 0;
195 : }
196 : /* LCOV_EXCL_STOP */
197 :
198 6 : elem_size = elem_sizeof(size);
199 6 : bswap_memcpy(tmp1, s1, size, elem_size);
200 6 : bswap_memcpy(tmp2, s2, size, elem_size);
201 :
202 6 : result = pmemcmp(tmp1, tmp2, size);
203 :
204 6 : pfree(tmp1);
205 6 : pfree(tmp2);
206 :
207 6 : return result;
208 : }
209 :
210 : /* LCOV_EXCL_START */
211 : PINO_SUPUNREACH();
212 : return 0;
213 : /* LCOV_EXCL_STOP */
214 : }
215 :
216 1037 : extern void *pino_endianness_memcpy_le2native(void *dest, const void *src, size_t size)
217 : {
218 1037 : return memcpy_common(dest, src, size, (platform_endianness() == ENDIANNESS_LITTLE));
219 : }
220 :
221 5 : extern void *pino_endianness_memcpy_be2native(void *dest, const void *src, size_t size)
222 : {
223 5 : return memcpy_common(dest, src, size, (platform_endianness() == ENDIANNESS_BIG));
224 : }
225 :
226 2019 : extern void *pino_endianness_memcpy_native2le(void *dest, const void *src, size_t size)
227 : {
228 2019 : return memcpy_common(dest, src, size, (platform_endianness() == ENDIANNESS_LITTLE));
229 : }
230 :
231 5 : extern void *pino_endianness_memcpy_native2be(void *dest, const void *src, size_t size)
232 : {
233 5 : return memcpy_common(dest, src, size, (platform_endianness() == ENDIANNESS_BIG));
234 : }
235 :
236 4 : extern void *pino_endianness_memmove_le2native(void *dest, const void *src, size_t size)
237 : {
238 4 : return memmove_common(dest, src, size, (platform_endianness() == ENDIANNESS_LITTLE));
239 : }
240 :
241 3 : extern void *pino_endianness_memmove_be2native(void *dest, const void *src, size_t size)
242 : {
243 3 : return memmove_common(dest, src, size, (platform_endianness() == ENDIANNESS_BIG));
244 : }
245 :
246 4 : extern void *pino_endianness_memmove_native2le(void *dest, const void *src, size_t size)
247 : {
248 4 : return memmove_common(dest, src, size, (platform_endianness() == ENDIANNESS_LITTLE));
249 : }
250 :
251 5 : extern void *pino_endianness_memmove_native2be(void *dest, const void *src, size_t size)
252 : {
253 5 : return memmove_common(dest, src, size, (platform_endianness() == ENDIANNESS_BIG));
254 : }
255 :
256 3 : extern int pino_endianness_memcmp_le2native(const void *s1, const void *s2, size_t size)
257 : {
258 3 : return memcmp_common(s1, s2, size, (platform_endianness() == ENDIANNESS_LITTLE));
259 : }
260 :
261 3 : extern int pino_endianness_memcmp_be2native(const void *s1, const void *s2, size_t size)
262 : {
263 3 : return memcmp_common(s1, s2, size, (platform_endianness() == ENDIANNESS_BIG));
264 : }
265 :
266 3 : extern int pino_endianness_memcmp_native2le(const void *s1, const void *s2, size_t size)
267 : {
268 3 : return memcmp_common(s1, s2, size, (platform_endianness() == ENDIANNESS_LITTLE));
269 : }
270 :
271 3 : extern int pino_endianness_memcmp_native2be(const void *s1, const void *s2, size_t size)
272 : {
273 3 : return memcmp_common(s1, s2, size, (platform_endianness() == ENDIANNESS_BIG));
274 : }
|