GNU libmicrohttpd 1.0.1
Loading...
Searching...
No Matches
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