GNU libmicrohttpd  1.0.1
mhd_bithelpers.h
Go to the documentation of this file.
1 /*
2  This file is part of libmicrohttpd
3  Copyright (C) 2019-2023 Karlson2k (Evgeny Grin)
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Lesser General Public
7  License as published by the Free Software Foundation; either
8  version 2.1 of the License, or (at your option) any later version.
9 
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Lesser General Public License for more details.
14 
15  You should have received a copy of the GNU Lesser General Public
16  License along with this library.
17  If not, see <http://www.gnu.org/licenses/>.
18 */
19 
26 #ifndef MHD_BITHELPERS_H
27 #define MHD_BITHELPERS_H 1
28 
29 #include "mhd_options.h"
30 #include <stdint.h>
31 #if defined(_MSC_FULL_VER) && (! defined(__clang__) || (defined(__c2__) && \
32  defined(__OPTIMIZE__)))
33 /* Declarations for VC & Clang/C2 built-ins */
34 #include <intrin.h>
35 #endif /* _MSC_FULL_VER */
36 #include "mhd_byteorder.h"
37 #if _MHD_BYTE_ORDER == _MHD_LITTLE_ENDIAN || _MHD_BYTE_ORDER == _MHD_BIG_ENDIAN
38 #include "mhd_align.h"
39 #endif /* _MHD_BYTE_ORDER == _MHD_LITTLE_ENDIAN ||
40  _MHD_BYTE_ORDER == _MHD_BIG_ENDIAN */
41 
42 #ifndef __has_builtin
43 /* Avoid precompiler errors with non-clang */
44 # define __has_builtin(x) 0
45 # define _MHD_has_builtin_dummy 1
46 #endif
47 
49 
50 #ifdef MHD_HAVE___BUILTIN_BSWAP32
51 #define _MHD_BYTES_SWAP32(value32) \
52  ((uint32_t) __builtin_bswap32 ((uint32_t) value32))
53 #elif defined(_MSC_FULL_VER) && (! defined(__clang__) || (defined(__c2__) && \
54  defined(__OPTIMIZE__)))
55 /* Clang/C2 may not inline this function if optimizations are turned off. */
56 #ifndef __clang__
57 #pragma intrinsic(_byteswap_ulong)
58 #endif /* ! __clang__ */
59 #define _MHD_BYTES_SWAP32(value32) \
60  ((uint32_t) _byteswap_ulong ((uint32_t) value32))
61 #elif \
62  __has_builtin (__builtin_bswap32)
63 #define _MHD_BYTES_SWAP32(value32) \
64  ((uint32_t) __builtin_bswap32 ((uint32_t) value32))
65 #else /* ! __has_builtin(__builtin_bswap32) */
66 #define _MHD_BYTES_SWAP32(value32) \
67  ( (((uint32_t) (value32)) << 24) \
68  | ((((uint32_t) (value32)) & ((uint32_t) 0x0000FF00)) << 8) \
69  | ((((uint32_t) (value32)) & ((uint32_t) 0x00FF0000)) >> 8) \
70  | (((uint32_t) (value32)) >> 24) )
71 #endif /* ! __has_builtin(__builtin_bswap32) */
72 
73 #ifdef MHD_HAVE___BUILTIN_BSWAP64
74 #define _MHD_BYTES_SWAP64(value64) \
75  ((uint64_t) __builtin_bswap64 ((uint64_t) value64))
76 #elif defined(_MSC_FULL_VER) && (! defined(__clang__) || (defined(__c2__) && \
77  defined(__OPTIMIZE__)))
78 /* Clang/C2 may not inline this function if optimizations are turned off. */
79 #ifndef __clang__
80 #pragma intrinsic(_byteswap_uint64)
81 #endif /* ! __clang__ */
82 #define _MHD_BYTES_SWAP64(value64) \
83  ((uint64_t) _byteswap_uint64 ((uint64_t) value64))
84 #elif \
85  __has_builtin (__builtin_bswap64)
86 #define _MHD_BYTES_SWAP64(value64) \
87  ((uint64_t) __builtin_bswap64 ((uint64_t) value64))
88 #else /* ! __has_builtin(__builtin_bswap64) */
89 #define _MHD_BYTES_SWAP64(value64) \
90  ( (((uint64_t) (value64)) << 56) \
91  | ((((uint64_t) (value64)) & ((uint64_t) 0x000000000000FF00)) << 40) \
92  | ((((uint64_t) (value64)) & ((uint64_t) 0x0000000000FF0000)) << 24) \
93  | ((((uint64_t) (value64)) & ((uint64_t) 0x00000000FF000000)) << 8) \
94  | ((((uint64_t) (value64)) & ((uint64_t) 0x000000FF00000000)) >> 8) \
95  | ((((uint64_t) (value64)) & ((uint64_t) 0x0000FF0000000000)) >> 24) \
96  | ((((uint64_t) (value64)) & ((uint64_t) 0x00FF000000000000)) >> 40) \
97  | (((uint64_t) (value64)) >> 56) )
98 #endif /* ! __has_builtin(__builtin_bswap64) */
99 
100 
101 /* _MHD_PUT_64BIT_LE (addr, value64)
102  * put native-endian 64-bit value64 to addr
103  * in little-endian mode.
104  */
105 /* Slow version that works with unaligned addr and with any bytes order */
106 #define _MHD_PUT_64BIT_LE_SLOW(addr, value64) do { \
107  ((uint8_t*) (addr))[0] = (uint8_t) ((uint64_t) (value64)); \
108  ((uint8_t*) (addr))[1] = (uint8_t) (((uint64_t) (value64)) >> 8); \
109  ((uint8_t*) (addr))[2] = (uint8_t) (((uint64_t) (value64)) >> 16); \
110  ((uint8_t*) (addr))[3] = (uint8_t) (((uint64_t) (value64)) >> 24); \
111  ((uint8_t*) (addr))[4] = (uint8_t) (((uint64_t) (value64)) >> 32); \
112  ((uint8_t*) (addr))[5] = (uint8_t) (((uint64_t) (value64)) >> 40); \
113  ((uint8_t*) (addr))[6] = (uint8_t) (((uint64_t) (value64)) >> 48); \
114  ((uint8_t*) (addr))[7] = (uint8_t) (((uint64_t) (value64)) >> 56); \
115 } while (0)
116 #if _MHD_BYTE_ORDER == _MHD_LITTLE_ENDIAN
117 #define _MHD_PUT_64BIT_LE(addr, value64) \
118  ((*(uint64_t*) (addr)) = (uint64_t) (value64))
119 #elif _MHD_BYTE_ORDER == _MHD_BIG_ENDIAN
120 #define _MHD_PUT_64BIT_LE(addr, value64) \
121  ((*(uint64_t*) (addr)) = _MHD_BYTES_SWAP64 (value64))
122 #else /* _MHD_BYTE_ORDER != _MHD_BIG_ENDIAN */
123 /* Endianness was not detected or non-standard like PDP-endian */
124 #define _MHD_PUT_64BIT_LE(addr, value64) do { \
125  ((uint8_t*) (addr))[0] = (uint8_t) ((uint64_t) (value64)); \
126  ((uint8_t*) (addr))[1] = (uint8_t) (((uint64_t) (value64)) >> 8); \
127  ((uint8_t*) (addr))[2] = (uint8_t) (((uint64_t) (value64)) >> 16); \
128  ((uint8_t*) (addr))[3] = (uint8_t) (((uint64_t) (value64)) >> 24); \
129  ((uint8_t*) (addr))[4] = (uint8_t) (((uint64_t) (value64)) >> 32); \
130  ((uint8_t*) (addr))[5] = (uint8_t) (((uint64_t) (value64)) >> 40); \
131  ((uint8_t*) (addr))[6] = (uint8_t) (((uint64_t) (value64)) >> 48); \
132  ((uint8_t*) (addr))[7] = (uint8_t) (((uint64_t) (value64)) >> 56); \
133 } while (0)
134 /* Indicate that _MHD_PUT_64BIT_LE does not need aligned pointer */
135 #define _MHD_PUT_64BIT_LE_UNALIGNED 1
136 #endif /* _MHD_BYTE_ORDER != _MHD_BIG_ENDIAN */
137 
138 /* Put result safely to unaligned address */
139 _MHD_static_inline void
140 _MHD_PUT_64BIT_LE_SAFE (void *dst, uint64_t value)
141 {
142 #ifndef _MHD_PUT_64BIT_LE_UNALIGNED
143  if (0 != ((uintptr_t) dst) % (_MHD_UINT64_ALIGN))
144  _MHD_PUT_64BIT_LE_SLOW (dst, value);
145  else
146 #endif /* ! _MHD_PUT_64BIT_LE_UNALIGNED */
147  _MHD_PUT_64BIT_LE (dst, value);
148 }
149 
150 
151 /* _MHD_PUT_32BIT_LE (addr, value32)
152  * put native-endian 32-bit value32 to addr
153  * in little-endian mode.
154  */
155 #if _MHD_BYTE_ORDER == _MHD_LITTLE_ENDIAN
156 #define _MHD_PUT_32BIT_LE(addr,value32) \
157  ((*(uint32_t*) (addr)) = (uint32_t) (value32))
158 #elif _MHD_BYTE_ORDER == _MHD_BIG_ENDIAN
159 #define _MHD_PUT_32BIT_LE(addr, value32) \
160  ((*(uint32_t*) (addr)) = _MHD_BYTES_SWAP32 (value32))
161 #else /* _MHD_BYTE_ORDER != _MHD_BIG_ENDIAN */
162 /* Endianness was not detected or non-standard like PDP-endian */
163 #define _MHD_PUT_32BIT_LE(addr, value32) do { \
164  ((uint8_t*) (addr))[0] = (uint8_t) ((uint32_t) (value32)); \
165  ((uint8_t*) (addr))[1] = (uint8_t) (((uint32_t) (value32)) >> 8); \
166  ((uint8_t*) (addr))[2] = (uint8_t) (((uint32_t) (value32)) >> 16); \
167  ((uint8_t*) (addr))[3] = (uint8_t) (((uint32_t) (value32)) >> 24); \
168 } while (0)
169 /* Indicate that _MHD_PUT_32BIT_LE does not need aligned pointer */
170 #define _MHD_PUT_32BIT_LE_UNALIGNED 1
171 #endif /* _MHD_BYTE_ORDER != _MHD_BIG_ENDIAN */
172 
173 /* _MHD_GET_32BIT_LE (addr)
174  * get little-endian 32-bit value storied at addr
175  * and return it in native-endian mode.
176  */
177 #if _MHD_BYTE_ORDER == _MHD_LITTLE_ENDIAN
178 #define _MHD_GET_32BIT_LE(addr) \
179  (*(const uint32_t*) (addr))
180 #elif _MHD_BYTE_ORDER == _MHD_BIG_ENDIAN
181 #define _MHD_GET_32BIT_LE(addr) \
182  _MHD_BYTES_SWAP32 (*(const uint32_t*) (addr))
183 #else /* _MHD_BYTE_ORDER != _MHD_BIG_ENDIAN */
184 /* Endianness was not detected or non-standard like PDP-endian */
185 #define _MHD_GET_32BIT_LE(addr) \
186  ( ( (uint32_t) (((const uint8_t*) addr)[0])) \
187  | (((uint32_t) (((const uint8_t*) addr)[1])) << 8) \
188  | (((uint32_t) (((const uint8_t*) addr)[2])) << 16) \
189  | (((uint32_t) (((const uint8_t*) addr)[3])) << 24) )
190 /* Indicate that _MHD_GET_32BIT_LE does not need aligned pointer */
191 #define _MHD_GET_32BIT_LE_UNALIGNED 1
192 #endif /* _MHD_BYTE_ORDER != _MHD_BIG_ENDIAN */
193 
194 
195 /* _MHD_PUT_64BIT_BE (addr, value64)
196  * put native-endian 64-bit value64 to addr
197  * in big-endian mode.
198  */
199 /* Slow version that works with unaligned addr and with any bytes order */
200 #define _MHD_PUT_64BIT_BE_SLOW(addr, value64) do { \
201  ((uint8_t*) (addr))[7] = (uint8_t) ((uint64_t) (value64)); \
202  ((uint8_t*) (addr))[6] = (uint8_t) (((uint64_t) (value64)) >> 8); \
203  ((uint8_t*) (addr))[5] = (uint8_t) (((uint64_t) (value64)) >> 16); \
204  ((uint8_t*) (addr))[4] = (uint8_t) (((uint64_t) (value64)) >> 24); \
205  ((uint8_t*) (addr))[3] = (uint8_t) (((uint64_t) (value64)) >> 32); \
206  ((uint8_t*) (addr))[2] = (uint8_t) (((uint64_t) (value64)) >> 40); \
207  ((uint8_t*) (addr))[1] = (uint8_t) (((uint64_t) (value64)) >> 48); \
208  ((uint8_t*) (addr))[0] = (uint8_t) (((uint64_t) (value64)) >> 56); \
209 } while (0)
210 #if _MHD_BYTE_ORDER == _MHD_BIG_ENDIAN
211 #define _MHD_PUT_64BIT_BE(addr, value64) \
212  ((*(uint64_t*) (addr)) = (uint64_t) (value64))
213 #elif _MHD_BYTE_ORDER == _MHD_LITTLE_ENDIAN
214 #define _MHD_PUT_64BIT_BE(addr, value64) \
215  ((*(uint64_t*) (addr)) = _MHD_BYTES_SWAP64 (value64))
216 #else /* _MHD_BYTE_ORDER != _MHD_LITTLE_ENDIAN */
217 /* Endianness was not detected or non-standard like PDP-endian */
218 #define _MHD_PUT_64BIT_BE(addr, value64) _MHD_PUT_64BIT_BE_SLOW(addr, value64)
219 /* Indicate that _MHD_PUT_64BIT_BE does not need aligned pointer */
220 #define _MHD_PUT_64BIT_BE_UNALIGNED 1
221 #endif /* _MHD_BYTE_ORDER != _MHD_LITTLE_ENDIAN */
222 
223 /* Put result safely to unaligned address */
224 _MHD_static_inline void
225 _MHD_PUT_64BIT_BE_SAFE (void *dst, uint64_t value)
226 {
227 #ifndef _MHD_PUT_64BIT_BE_UNALIGNED
228  if (0 != ((uintptr_t) dst) % (_MHD_UINT64_ALIGN))
229  _MHD_PUT_64BIT_BE_SLOW (dst, value);
230  else
231 #endif /* ! _MHD_PUT_64BIT_BE_UNALIGNED */
232  _MHD_PUT_64BIT_BE (dst, value);
233 }
234 
235 
236 /* _MHD_GET_64BIT_BE (addr)
237  * load 64-bit value located at addr in big endian mode.
238  */
239 #if _MHD_BYTE_ORDER == _MHD_BIG_ENDIAN
240 #define _MHD_GET_64BIT_BE(addr) \
241  (*(const uint64_t*) (addr))
242 #elif _MHD_BYTE_ORDER == _MHD_LITTLE_ENDIAN
243 #define _MHD_GET_64BIT_BE(addr) \
244  _MHD_BYTES_SWAP64 (*(const uint64_t*) (addr))
245 #else /* _MHD_BYTE_ORDER != _MHD_LITTLE_ENDIAN */
246 /* Endianness was not detected or non-standard like PDP-endian */
247 #define _MHD_GET_64BIT_BE(addr) \
248  ( (((uint64_t) (((const uint8_t*) addr)[0])) << 56) \
249  | (((uint64_t) (((const uint8_t*) addr)[1])) << 48) \
250  | (((uint64_t) (((const uint8_t*) addr)[2])) << 40) \
251  | (((uint64_t) (((const uint8_t*) addr)[3])) << 32) \
252  | (((uint64_t) (((const uint8_t*) addr)[4])) << 24) \
253  | (((uint64_t) (((const uint8_t*) addr)[5])) << 16) \
254  | (((uint64_t) (((const uint8_t*) addr)[6])) << 8) \
255  | ((uint64_t) (((const uint8_t*) addr)[7])) )
256 /* Indicate that _MHD_GET_64BIT_BE does not need aligned pointer */
257 #define _MHD_GET_64BIT_BE_ALLOW_UNALIGNED 1
258 #endif /* _MHD_BYTE_ORDER != _MHD_LITTLE_ENDIAN */
259 
260 
261 /* _MHD_PUT_32BIT_BE (addr, value32)
262  * put native-endian 32-bit value32 to addr
263  * in big-endian mode.
264  */
265 #if _MHD_BYTE_ORDER == _MHD_BIG_ENDIAN
266 #define _MHD_PUT_32BIT_BE(addr, value32) \
267  ((*(uint32_t*) (addr)) = (uint32_t) (value32))
268 #elif _MHD_BYTE_ORDER == _MHD_LITTLE_ENDIAN
269 #define _MHD_PUT_32BIT_BE(addr, value32) \
270  ((*(uint32_t*) (addr)) = _MHD_BYTES_SWAP32 (value32))
271 #else /* _MHD_BYTE_ORDER != _MHD_LITTLE_ENDIAN */
272 /* Endianness was not detected or non-standard like PDP-endian */
273 #define _MHD_PUT_32BIT_BE(addr, value32) do { \
274  ((uint8_t*) (addr))[3] = (uint8_t) ((uint32_t) (value32)); \
275  ((uint8_t*) (addr))[2] = (uint8_t) (((uint32_t) (value32)) >> 8); \
276  ((uint8_t*) (addr))[1] = (uint8_t) (((uint32_t) (value32)) >> 16); \
277  ((uint8_t*) (addr))[0] = (uint8_t) (((uint32_t) (value32)) >> 24); \
278 } while (0)
279 /* Indicate that _MHD_PUT_32BIT_BE does not need aligned pointer */
280 #define _MHD_PUT_32BIT_BE_UNALIGNED 1
281 #endif /* _MHD_BYTE_ORDER != _MHD_LITTLE_ENDIAN */
282 
283 /* _MHD_GET_32BIT_BE (addr)
284  * get big-endian 32-bit value storied at addr
285  * and return it in native-endian mode.
286  */
287 #if _MHD_BYTE_ORDER == _MHD_BIG_ENDIAN
288 #define _MHD_GET_32BIT_BE(addr) \
289  (*(const uint32_t*) (addr))
290 #elif _MHD_BYTE_ORDER == _MHD_LITTLE_ENDIAN
291 #define _MHD_GET_32BIT_BE(addr) \
292  _MHD_BYTES_SWAP32 (*(const uint32_t*) (addr))
293 #else /* _MHD_BYTE_ORDER != _MHD_LITTLE_ENDIAN */
294 /* Endianness was not detected or non-standard like PDP-endian */
295 #define _MHD_GET_32BIT_BE(addr) \
296  ( (((uint32_t) (((const uint8_t*) addr)[0])) << 24) \
297  | (((uint32_t) (((const uint8_t*) addr)[1])) << 16) \
298  | (((uint32_t) (((const uint8_t*) addr)[2])) << 8) \
299  | ((uint32_t) (((const uint8_t*) addr)[3])) )
300 /* Indicate that _MHD_GET_32BIT_BE does not need aligned pointer */
301 #define _MHD_GET_32BIT_BE_UNALIGNED 1
302 #endif /* _MHD_BYTE_ORDER != _MHD_LITTLE_ENDIAN */
303 
304 
309 #if defined(_MSC_FULL_VER) && (! defined(__clang__) || (defined(__c2__) && \
310  defined(__OPTIMIZE__)))
311 /* Clang/C2 do not inline this function if optimizations are turned off. */
312 #ifndef __clang__
313 #pragma intrinsic(_rotr)
314 #endif /* ! __clang__ */
315 #define _MHD_ROTR32(value32, bits) \
316  ((uint32_t) _rotr ((uint32_t) (value32),(bits)))
317 #elif __has_builtin (__builtin_rotateright32)
318 #define _MHD_ROTR32(value32, bits) \
319  ((uint32_t) __builtin_rotateright32 ((value32), (bits)))
320 #else /* ! __builtin_rotateright32 */
321 _MHD_static_inline uint32_t
322 _MHD_ROTR32 (uint32_t value32, int bits)
323 {
324  bits %= 32;
325  if (0 == bits)
326  return value32;
327  /* Defined in form which modern compiler could optimize. */
328  return (value32 >> bits) | (value32 << (32 - bits));
329 }
330 
331 
332 #endif /* ! __builtin_rotateright32 */
333 
334 
339 #if defined(_MSC_FULL_VER) && (! defined(__clang__) || (defined(__c2__) && \
340  defined(__OPTIMIZE__)))
341 /* Clang/C2 do not inline this function if optimizations are turned off. */
342 #ifndef __clang__
343 #pragma intrinsic(_rotl)
344 #endif /* ! __clang__ */
345 #define _MHD_ROTL32(value32, bits) \
346  ((uint32_t) _rotl ((uint32_t) (value32),(bits)))
347 #elif __has_builtin (__builtin_rotateleft32)
348 #define _MHD_ROTL32(value32, bits) \
349  ((uint32_t) __builtin_rotateleft32 ((value32), (bits)))
350 #else /* ! __builtin_rotateleft32 */
351 _MHD_static_inline uint32_t
352 _MHD_ROTL32 (uint32_t value32, int bits)
353 {
354  bits %= 32;
355  if (0 == bits)
356  return value32;
357  /* Defined in form which modern compiler could optimize. */
358  return (value32 << bits) | (value32 >> (32 - bits));
359 }
360 
361 
362 #endif /* ! __builtin_rotateleft32 */
363 
364 
369 #if defined(_MSC_FULL_VER) && (! defined(__clang__) || (defined(__c2__) && \
370  defined(__OPTIMIZE__)))
371 /* Clang/C2 do not inline this function if optimisations are turned off. */
372 #ifndef __clang__
373 #pragma intrinsic(_rotr64)
374 #endif /* ! __clang__ */
375 #define _MHD_ROTR64(value64, bits) \
376  ((uint64_t) _rotr64 ((uint64_t) (value64),(bits)))
377 #elif __has_builtin (__builtin_rotateright64)
378 #define _MHD_ROTR64(value64, bits) \
379  ((uint64_t) __builtin_rotateright64 ((value64), (bits)))
380 #else /* ! __builtin_rotateright64 */
381 _MHD_static_inline uint64_t
382 _MHD_ROTR64 (uint64_t value64, int bits)
383 {
384  bits %= 64;
385  if (0 == bits)
386  return value64;
387  /* Defined in form which modern compiler could optimise. */
388  return (value64 >> bits) | (value64 << (64 - bits));
389 }
390 
391 
392 #endif /* ! __builtin_rotateright64 */
393 
395 
396 #ifdef _MHD_has_builtin_dummy
397 /* Remove macro function replacement to avoid misdetection in files which
398  * include this header */
399 # undef __has_builtin
400 #endif
401 
402 #endif /* ! MHD_BITHELPERS_H */
types alignment macros
#define _MHD_UINT64_ALIGN
Definition: mhd_align.h:93
#define _MHD_PUT_64BIT_BE(addr, value64)
#define _MHD_PUT_64BIT_LE_SLOW(addr, value64)
_MHD_static_inline uint32_t _MHD_ROTR32(uint32_t value32, int bits)
_MHD_static_inline void _MHD_PUT_64BIT_BE_SAFE(void *dst, uint64_t value)
#define _MHD_PUT_64BIT_LE(addr, value64)
#define _MHD_PUT_64BIT_BE_SLOW(addr, value64)
_MHD_static_inline uint32_t _MHD_ROTL32(uint32_t value32, int bits)
_MHD_static_inline uint64_t _MHD_ROTR64(uint64_t value64, int bits)
_MHD_static_inline void _MHD_PUT_64BIT_LE_SAFE(void *dst, uint64_t value)
additional automatic macros for MHD_config.h
#define MHD_DATA_TRUNCATION_RUNTIME_CHECK_DISABLE_
Definition: mhd_options.h:176
#define MHD_DATA_TRUNCATION_RUNTIME_CHECK_RESTORE_
Definition: mhd_options.h:177
macro definitions for host byte order