Wireshark 4.7.3
The Wireshark network protocol analyzer
Loading...
Searching...
No Matches
pint.h
Go to the documentation of this file.
1
12
13#pragma once
14
15#include <inttypes.h>
16
17#include <glib.h>
18
19/* Routines that:
20 *
21 * take a possibly-unaligned pointer to a 16-bit, 24-bit, 32-bit,
22 * 40-bit, ... 64-bit integral value, in a particular byte order,
23 * and fetch the value and return it in host byte order, as an
24 * unsigned quantity;
25 *
26 * take a possibly-unaligned pointer to a space for a 16-bit, 24-bit,
27 * 32-bit, 40-bit, ... 64-bit integral value, in a particular byte
28 * order, and an unsigned integral value of that width or larger, and
29 * store the value in that space.
30 *
31 * The pntohuN() routines fetch big-endian unsigned values; the pletohuN()
32 * routines fetch little-endian unsigned values. The phtonuN() routines
33 * store big-endian unsigned values; the phtoleN() routines store little-
34 * endian unsigned values.
35 */
36
37/* On most architectures, accesses of 16-bit, 32-bit, and 64-bit quantities
38 * can be heavily optimized.
39 *
40 * gcc and clang recognize idioms involving shifting and masking and, at
41 * -Os and higher, optimize them appropriately to, for example, do
42 * unaligned loads and stores, and use byte-swapping instructions if
43 * the byte order isn't the host byte order, if the platform supports them)
44 * Older versions don't do as good of a job with 16-bit accesses, though.
45 *
46 * Unfortunately, MSVC and icc (both the "classic" version and the new
47 * LLVM-based Intel C Compiler) do not recognize and optimize those
48 * idioms, according to Matt Godbolt's Compiler Explorer (https://godbolt.org)
49 * as of the end of 2022. They *do* recognize and optimize a memcpy-based
50 * approach (which avoids unaligned accesses on, say, ARM32), though that
51 * requires byte-swapping appropriately.
52 */
53#if (defined(_MSC_VER) && !defined(__clang__)) || defined(__INTEL_COMPILER) || defined(__INTEL_LLVM_COMPILER)
54 /* MSVC or Intel C Compiler (Classic or new LLVM version), but not
55 * clang-cl on Windows.
56 *
57 * Unfortunately, C23 did not fully accept the N3022 Modern Bit Utilities
58 * proposal, so a standard bytereverse function has been deferred for some
59 * future version:
60 * https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3048.htm
61 * https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3022.htm
62 *
63 * So use byte-swap intrinsics
64 */
65 #define _USE_BSWAPS
66
67 /* Choose the byte-swap intrinsics we know we have. */
68 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__INTEL_LLVM_COMPILER) && !defined(__clang__)
69 /* Intel and clang-cl both define _MSC_VER when compiling on Windows for
70 * greater compatibility (just as they define __GNUC__ on other platforms).
71 * However, at least on some versions, while including the MSVC <stdlib.h>
72 * provides access to the _byteswap_ intrinsics, they are not actually
73 * optimized into a single x86 BSWAP function, unlike the gcc-style
74 * intrinsics (which both support).
75 * See: https://stackoverflow.com/q/72327906
76 */
77 #include <stdlib.h> // For MSVC _byteswap intrinsics
78 #define _pint_bswap16(x) _byteswap_ushort(x)
79 #define _pint_bswap32(x) _byteswap_ulong(x)
80 /* Hopefully MSVC never decides that a long is 64 bit. */
81 #define _pint_bswap64(x) _byteswap_uint64(x)
82 #elif defined(__INTEL_COMPILER)
83 /* The (deprecated) Intel C++ Compiler Classic has these byteswap
84 * intrinsics.
85 *
86 * It also has the GCC-style intrinsics, though __builtin_bswap16 wasn't
87 * added until some point after icc 13.0 but at least by 16.0, reflecting
88 * that it wasn't added to gcc until 4.8.
89 */
90 #define _pint_bswap16(x) _bswap16(x)
91 #define _pint_bswap32(x) _bswap32(x)
92 #define _pint_bswap64(x) _bswap64(x)
93 #else
94 /* GCC-style _bswap intrinsics.
95 *
96 * The new LLVM-based Intel C++ Compiler doesn't have the above intrinsics,
97 * but it always has all the GCC intrinsics.
98 *
99 * __builtin_bswap32 and __builtin_bswap64 intrinsics have been supported
100 * for a long time on gcc (4.1), and clang (pre 3.0), versions that predate
101 * C11 and C+11 support, which we require, so we could assume we have them.
102 *
103 * __builtin_bswap16 was added a bit later, gcc 4.8, and clang 3.2. While
104 * those versions or later are required for full C11 and C++11 support,
105 * some earlier versions claim to support C11 and C++11 in ways that might
106 * allow them to get past CMake. We don't use this codepath for those
107 * compilers because they heavily optimize the portable versions, though.
108 */
109 #define _pint_bswap16(x) __builtin_bswap16(x)
110 #define _pint_bswap32(x) __builtin_bswap32(x)
111 #define _pint_bswap64(x) __builtin_bswap64(x)
112 #endif
113
114 /* Now define host-to-{big,little}-endian and {big,little}-endian-to-host
115 * macros based on them and on the host byte order.
116 */
117 #if G_BYTE_ORDER == G_BIG_ENDIAN
118 /* Big-to-host and host-to-big are no-ops.
119 * Little-to-host and host-to-little are byte-swaps.
120 */
121 #define _pint_betoh16(x) (x)
122 #define _pint_betoh32(x) (x)
123 #define _pint_betoh64(x) (x)
124 #define _pint_htobe16(x) (x)
125 #define _pint_htobe32(x) (x)
126 #define _pint_htobe64(x) (x)
127 #define _pint_letoh16(x) _pint_bswap16(x)
128 #define _pint_letoh32(x) _pint_bswap32(x)
129 #define _pint_letoh64(x) _pint_bswap64(x)
130 #define _pint_htole16(x) _pint_bswap16(x)
131 #define _pint_htole32(x) _pint_bswap32(x)
132 #define _pint_htole64(x) _pint_bswap64(x)
133 #elif G_BYTE_ORDER == G_LITTLE_ENDIAN
134 /* Little-to-host and host-to-little are no-ops.
135 * Big-to-host and host-to-big are byte-swaps.
136 */
137 #define _pint_letoh16(x) (x)
138 #define _pint_letoh32(x) (x)
139 #define _pint_letoh64(x) (x)
140 #define _pint_htole16(x) (x)
141 #define _pint_htole32(x) (x)
142 #define _pint_htole64(x) (x)
143 #define _pint_betoh16(x) _pint_bswap16(x)
144 #define _pint_betoh32(x) _pint_bswap32(x)
145 #define _pint_betoh64(x) _pint_bswap64(x)
146 #define _pint_htobe16(x) _pint_bswap16(x)
147 #define _pint_htobe32(x) _pint_bswap32(x)
148 #define _pint_htobe64(x) _pint_bswap64(x)
149 #else
150 #error "Sorry, we don't support byte orders other than big- and little-endian"
151 #endif
152#endif
153
162static inline uint16_t pntohu16(const void *p)
163{
164#ifdef _USE_BSWAPS
165 uint16_t ret;
166 memcpy(&ret, p, sizeof(ret));
167 return _pint_betoh16(ret);
168#else /* _USE_BSWAPS */
169 return (uint16_t)*((const uint8_t *)(p)+0)<<8|
170 (uint16_t)*((const uint8_t *)(p)+1)<<0;
171#endif /* _USE_BSWAPS */
172}
173
182static inline uint32_t pntohu32(const void *p)
183{
184#ifdef _USE_BSWAPS
185 uint32_t ret;
186 memcpy(&ret, p, sizeof(ret));
187 return _pint_betoh32(ret);
188#else /* _USE_BSWAPS */
189 return (uint32_t)*((const uint8_t *)(p)+0)<<24|
190 (uint32_t)*((const uint8_t *)(p)+1)<<16|
191 (uint32_t)*((const uint8_t *)(p)+2)<<8|
192 (uint32_t)*((const uint8_t *)(p)+3)<<0;
193#endif /* _USE_BSWAPS */
194}
195
204static inline uint64_t pntohu64(const void *p)
205{
206#ifdef _USE_BSWAPS
207 uint64_t ret;
208 memcpy(&ret, p, sizeof(ret));
209 return _pint_betoh64(ret);
210#else /* _USE_BSWAPS */
211 return (uint64_t)*((const uint8_t *)(p)+0)<<56|
212 (uint64_t)*((const uint8_t *)(p)+1)<<48|
213 (uint64_t)*((const uint8_t *)(p)+2)<<40|
214 (uint64_t)*((const uint8_t *)(p)+3)<<32|
215 (uint64_t)*((const uint8_t *)(p)+4)<<24|
216 (uint64_t)*((const uint8_t *)(p)+5)<<16|
217 (uint64_t)*((const uint8_t *)(p)+6)<<8|
218 (uint64_t)*((const uint8_t *)(p)+7)<<0;
219#endif /* _USE_BSWAPS */
220}
221
230static inline uint16_t pletohu16(const void *p)
231{
232#ifdef _USE_BSWAPS
233 uint16_t ret;
234 memcpy(&ret, p, sizeof(ret));
235 return _pint_letoh16(ret);
236#else /* _USE_BSWAPS */
237 return (uint16_t)*((const uint8_t *)(p)+1)<<8|
238 (uint16_t)*((const uint8_t *)(p)+0)<<0;
239#endif /* _USE_BSWAPS */
240}
241
250static inline uint32_t pletohu32(const void *p)
251{
252#ifdef _USE_BSWAPS
253 uint32_t ret;
254 memcpy(&ret, p, sizeof(ret));
255 return _pint_letoh32(ret);
256#else /* _USE_BSWAPS */
257 return (uint32_t)*((const uint8_t *)(p)+3)<<24|
258 (uint32_t)*((const uint8_t *)(p)+2)<<16|
259 (uint32_t)*((const uint8_t *)(p)+1)<<8|
260 (uint32_t)*((const uint8_t *)(p)+0)<<0;
261#endif /* _USE_BSWAPS */
262}
263
272static inline uint64_t pletohu64(const void *p)
273{
274#ifdef _USE_BSWAPS
275 uint64_t ret;
276 memcpy(&ret, p, sizeof(ret));
277 return _pint_letoh64(ret);
278#else /* _USE_BSWAPS */
279 return (uint64_t)*((const uint8_t *)(p)+7)<<56|
280 (uint64_t)*((const uint8_t *)(p)+6)<<48|
281 (uint64_t)*((const uint8_t *)(p)+5)<<40|
282 (uint64_t)*((const uint8_t *)(p)+4)<<32|
283 (uint64_t)*((const uint8_t *)(p)+3)<<24|
284 (uint64_t)*((const uint8_t *)(p)+2)<<16|
285 (uint64_t)*((const uint8_t *)(p)+1)<<8|
286 (uint64_t)*((const uint8_t *)(p)+0)<<0;
287#endif /* _USE_BSWAPS */
288}
289
297static inline void phtonu16(uint8_t *p, uint16_t v)
298{
299#ifdef _USE_BSWAPS
300 v = _pint_htobe16(v);
301 memcpy(p, &v, sizeof(v));
302#else /* _USE_BSWAPS */
303 p[0] = (uint8_t)(v >> 8);
304 p[1] = (uint8_t)(v >> 0);
305#endif /* _USE_BSWAPS */
306}
307
315static inline void phtonu32(uint8_t *p, uint32_t v)
316{
317#ifdef _USE_BSWAPS
318 v = _pint_htobe32(v);
319 memcpy(p, &v, sizeof(v));
320#else /* _USE_BSWAPS */
321 p[0] = (uint8_t)(v >> 24);
322 p[1] = (uint8_t)(v >> 16);
323 p[2] = (uint8_t)(v >> 8);
324 p[3] = (uint8_t)(v >> 0);
325#endif /* _USE_BSWAPS */
326}
327
335static inline void phtonu64(uint8_t *p, uint64_t v)
336{
337#ifdef _USE_BSWAPS
338 v = _pint_htobe64(v);
339 memcpy(p, &v, sizeof(v));
340#else /* _USE_BSWAPS */
341 p[0] = (uint8_t)(v >> 56);
342 p[1] = (uint8_t)(v >> 48);
343 p[2] = (uint8_t)(v >> 40);
344 p[3] = (uint8_t)(v >> 32);
345 p[4] = (uint8_t)(v >> 24);
346 p[5] = (uint8_t)(v >> 16);
347 p[6] = (uint8_t)(v >> 8);
348 p[7] = (uint8_t)(v >> 0);
349#endif /* _USE_BSWAPS */
350}
351
359static inline void phtoleu16(uint8_t *p, uint16_t v)
360{
361#ifdef _USE_BSWAPS
362 v = _pint_htole16(v);
363 memcpy(p, &v, sizeof(v));
364#else /* _USE_BSWAPS */
365 p[0] = (uint8_t)(v >> 0);
366 p[1] = (uint8_t)(v >> 8);
367#endif /* _USE_BSWAPS */
368}
369
377static inline void phtoleu32(uint8_t *p, uint32_t v)
378{
379#ifdef _USE_BSWAPS
380 v = _pint_htole32(v);
381 memcpy(p, &v, sizeof(v));
382#else /* _USE_BSWAPS */
383 p[0] = (uint8_t)(v >> 0);
384 p[1] = (uint8_t)(v >> 8);
385 p[2] = (uint8_t)(v >> 16);
386 p[3] = (uint8_t)(v >> 24);
387#endif /* _USE_BSWAPS */
388}
389
397static inline void phtoleu64(uint8_t *p, uint64_t v)
398{
399#ifdef _USE_BSWAPS
400 v = _pint_htole64(v);
401 memcpy(p, &v, sizeof(v));
402#else /* _USE_BSWAPS */
403 p[0] = (uint8_t)(v >> 0);
404 p[1] = (uint8_t)(v >> 8);
405 p[2] = (uint8_t)(v >> 16);
406 p[3] = (uint8_t)(v >> 24);
407 p[4] = (uint8_t)(v >> 32);
408 p[5] = (uint8_t)(v >> 40);
409 p[6] = (uint8_t)(v >> 48);
410 p[7] = (uint8_t)(v >> 56);
411#endif /* _USE_BSWAPS */
412}
413
414/*
415 * Single-byte versions, for completeness.
416 */
417
425static inline uint8_t pntohu8(const void *p)
426{
427 return *((const uint8_t *)(p)+0)<<0;
428}
429
437static inline uint8_t pletohu8(const void *p)
438{
439 return *((const uint8_t *)(p)+0)<<0;
440}
441
449static inline void phtonu8(uint8_t *p, uint8_t v)
450{
451 p[0] = (uint8_t)((v) >> 0);
452}
453
461static inline void phtoleu8(uint8_t *p, uint8_t v)
462{
463 p[0] = (uint8_t)((v) >> 0);
464}
465
466/*
467 * Non-power-of-2-sized versions.
468 *
469 * I don't know whether these are recognized idioms by the versions of GCC
470 * and Clang that we support.
471 *
472 * We could implement them as fetching multiple values using the above and
473 * combining them and storing multiple values after breaking them apart
474 * and putting them in the right byte order using the above.
475 */
476
485static inline uint32_t pntohu24(const void *p)
486{
487 return (uint32_t)*((const uint8_t *)(p)+0)<<16|
488 (uint32_t)*((const uint8_t *)(p)+1)<<8|
489 (uint32_t)*((const uint8_t *)(p)+2)<<0;
490}
491
500static inline uint64_t pntohu40(const void *p)
501{
502 return (uint64_t)*((const uint8_t *)(p)+0)<<32|
503 (uint64_t)*((const uint8_t *)(p)+1)<<24|
504 (uint64_t)*((const uint8_t *)(p)+2)<<16|
505 (uint64_t)*((const uint8_t *)(p)+3)<<8|
506 (uint64_t)*((const uint8_t *)(p)+4)<<0;
507}
508
517static inline uint64_t pntohu48(const void *p)
518{
519 return (uint64_t)*((const uint8_t *)(p)+0)<<40|
520 (uint64_t)*((const uint8_t *)(p)+1)<<32|
521 (uint64_t)*((const uint8_t *)(p)+2)<<24|
522 (uint64_t)*((const uint8_t *)(p)+3)<<16|
523 (uint64_t)*((const uint8_t *)(p)+4)<<8|
524 (uint64_t)*((const uint8_t *)(p)+5)<<0;
525}
526
535static inline uint64_t pntohu56(const void *p)
536{
537 return (uint64_t)*((const uint8_t *)(p)+0)<<48|
538 (uint64_t)*((const uint8_t *)(p)+1)<<40|
539 (uint64_t)*((const uint8_t *)(p)+2)<<32|
540 (uint64_t)*((const uint8_t *)(p)+3)<<24|
541 (uint64_t)*((const uint8_t *)(p)+4)<<16|
542 (uint64_t)*((const uint8_t *)(p)+5)<<8|
543 (uint64_t)*((const uint8_t *)(p)+6)<<0;
544}
545
554static inline uint32_t pletohu24(const void *p)
555{
556 return (uint32_t)*((const uint8_t *)(p)+2)<<16|
557 (uint32_t)*((const uint8_t *)(p)+1)<<8|
558 (uint32_t)*((const uint8_t *)(p)+0)<<0;
559}
560
569static inline uint64_t pletohu40(const void *p)
570{
571 return (uint64_t)*((const uint8_t *)(p)+4)<<32|
572 (uint64_t)*((const uint8_t *)(p)+3)<<24|
573 (uint64_t)*((const uint8_t *)(p)+2)<<16|
574 (uint64_t)*((const uint8_t *)(p)+1)<<8|
575 (uint64_t)*((const uint8_t *)(p)+0)<<0;
576}
577
586static inline uint64_t pletohu48(const void *p)
587{
588 return (uint64_t)*((const uint8_t *)(p)+5)<<40|
589 (uint64_t)*((const uint8_t *)(p)+4)<<32|
590 (uint64_t)*((const uint8_t *)(p)+3)<<24|
591 (uint64_t)*((const uint8_t *)(p)+2)<<16|
592 (uint64_t)*((const uint8_t *)(p)+1)<<8|
593 (uint64_t)*((const uint8_t *)(p)+0)<<0;
594}
595
603static inline uint64_t pletohu56(const void *p)
604{
605 return (uint64_t)*((const uint8_t *)(p)+6)<<48|
606 (uint64_t)*((const uint8_t *)(p)+5)<<40|
607 (uint64_t)*((const uint8_t *)(p)+4)<<32|
608 (uint64_t)*((const uint8_t *)(p)+3)<<24|
609 (uint64_t)*((const uint8_t *)(p)+2)<<16|
610 (uint64_t)*((const uint8_t *)(p)+1)<<8|
611 (uint64_t)*((const uint8_t *)(p)+0)<<0;
612}
613
621static inline void phtonu24(uint8_t *p, uint32_t v)
622{
623 p[0] = (uint8_t)((v) >> 16);
624 p[1] = (uint8_t)((v) >> 8);
625 p[2] = (uint8_t)((v) >> 0);
626}
627
635static inline void phtonu40(uint8_t *p, uint64_t v)
636{
637 p[0] = (uint8_t)((v) >> 32);
638 p[1] = (uint8_t)((v) >> 24);
639 p[2] = (uint8_t)((v) >> 16);
640 p[3] = (uint8_t)((v) >> 8);
641 p[4] = (uint8_t)((v) >> 0);
642}
643
651static inline void phtonu48(uint8_t *p, uint64_t v)
652{
653 p[0] = (uint8_t)((v) >> 40);
654 p[1] = (uint8_t)((v) >> 32);
655 p[2] = (uint8_t)((v) >> 24);
656 p[3] = (uint8_t)((v) >> 16);
657 p[4] = (uint8_t)((v) >> 8);
658 p[5] = (uint8_t)((v) >> 0);
659}
660
668static inline void phtonu56(uint8_t *p, uint64_t v)
669{
670 p[0] = (uint8_t)((v) >> 48);
671 p[1] = (uint8_t)((v) >> 40);
672 p[2] = (uint8_t)((v) >> 32);
673 p[3] = (uint8_t)((v) >> 24);
674 p[4] = (uint8_t)((v) >> 16);
675 p[5] = (uint8_t)((v) >> 8);
676 p[6] = (uint8_t)((v) >> 0);
677}
678
686static inline void phtoleu24(uint8_t *p, uint32_t v)
687{
688 p[0] = (uint8_t)((v) >> 0);
689 p[1] = (uint8_t)((v) >> 8);
690 p[2] = (uint8_t)((v) >> 16);
691}
692
700static inline void phtoleu40(uint8_t *p, uint64_t v)
701{
702 p[0] = (uint8_t)((v) >> 0);
703 p[1] = (uint8_t)((v) >> 8);
704 p[2] = (uint8_t)((v) >> 16);
705 p[3] = (uint8_t)((v) >> 24);
706 p[4] = (uint8_t)((v) >> 32);
707}
708
716static inline void phtoleu48(uint8_t *p, uint64_t v)
717{
718 p[0] = (uint8_t)((v) >> 0);
719 p[1] = (uint8_t)((v) >> 8);
720 p[2] = (uint8_t)((v) >> 16);
721 p[3] = (uint8_t)((v) >> 24);
722 p[4] = (uint8_t)((v) >> 32);
723 p[5] = (uint8_t)((v) >> 40);
724}
725
733static inline void phtoleu56(uint8_t *p, uint64_t v)
734{
735 p[0] = (uint8_t)((v) >> 0);
736 p[1] = (uint8_t)((v) >> 8);
737 p[2] = (uint8_t)((v) >> 16);
738 p[3] = (uint8_t)((v) >> 24);
739 p[4] = (uint8_t)((v) >> 32);
740 p[5] = (uint8_t)((v) >> 40);
741 p[6] = (uint8_t)((v) >> 48);
742}
743
744/* Purge internal-to-this-header macros from the namespace */
745#undef _USE_BSWAPS
746#undef _pint_bswap16
747#undef _pint_bswap32
748#undef _pint_bswap64
749#undef _pint_betoh16
750#undef _pint_betoh32
751#undef _pint_betoh64
752#undef _pint_htobe16
753#undef _pint_htobe32
754#undef _pint_htobe64
755#undef _pint_letoh16
756#undef _pint_letoh32
757#undef _pint_letoh64
758#undef _pint_htole16
759#undef _pint_htole32
760#undef _pint_htole64
761
762/*
763 * Editor modelines - https://www.wireshark.org/tools/modelines.html
764 *
765 * Local Variables:
766 * c-basic-offset: 4
767 * tab-width: 8
768 * indent-tabs-mode: nil
769 * End:
770 *
771 * ex: set shiftwidth=4 tabstop=8 expandtab:
772 * :indentSize=4:tabSize=8:noTabs=true:
773 */