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