blob: 6fe33a121d2062df27fa0f0a50bdcfedd98e948c [file] [log] [blame]
Michael Eckel5c531332020-03-02 01:35:30 +01001/*============================================================================
2 Copyright (c) 2016-2018, The Linux Foundation.
3 Copyright (c) 2018-2020, Laurence Lundblade.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are
7met:
8 * Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above
11 copyright notice, this list of conditions and the following
12 disclaimer in the documentation and/or other materials provided
13 with the distribution.
14 * Neither the name of The Linux Foundation nor the names of its
15 contributors, nor the name "Laurence Lundblade" may be used to
16 endorse or promote products derived from this software without
17 specific prior written permission.
18
19THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
20WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
22ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
23BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
26BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
28OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
29IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 =============================================================================*/
31
32/*============================================================================
33 FILE: UsefulBuf.h
34
35 DESCRIPTION: General purpose input and output buffers
36
37 EDIT HISTORY FOR FILE:
38
39 This section contains comments describing changes made to the module.
40 Notice that changes are listed in reverse chronological order.
41
42 when who what, where, why
43 -------- ---- --------------------------------------------------
44 1/25/2020 llundblade Add some casts so static anlyzers don't complain.
45 5/21/2019 llundblade #define configs for efficient endianness handling.
46 5/16/2019 llundblade Add UsefulOutBuf_IsBufferNULL().
47 3/23/2019 llundblade Big documentation & style update. No interface
48 change.
49 3/6/2019 llundblade Add UsefulBuf_IsValue()
50 12/17/2018 llundblade Remove const from UsefulBuf and UsefulBufC .len
51 12/13/2018 llundblade Documentation improvements
52 09/18/2018 llundblade Cleaner distinction between UsefulBuf and
53 UsefulBufC.
54 02/02/18 llundbla Full support for integers in and out; fix pointer
55 alignment bug. Incompatible change: integers
56 in/out are now in network byte order.
57 08/12/17 llundbla Added UsefulOutBuf_AtStart and UsefulBuf_Find
58 06/27/17 llundbla Fix UsefulBuf_Compare() bug. Only affected
59 comparison for < or > for unequal length buffers.
60 Added UsefulBuf_Set() function.
61 05/30/17 llundbla Functions for NULL UsefulBufs and const / unconst
62 11/13/16 llundbla Initial Version.
63
64 =============================================================================*/
65
66#ifndef _UsefulBuf_h
67#define _UsefulBuf_h
68
69
70/*
71 Configuration Options
72
73 This code is designed so it will work correctly and completely by
74 default. No configuration is necessary to make it work. None of the
75 following #defines need to be enabled. The code works and is very
76 portable with them all turned off.
77
78 All configuration options (USEFULBUF_CONFIG_XXX)
79 1) Reduce code size
80 2) Improve efficiency
81 3) Both of the above
82
83 The efficiency improvements are not large, so the main reason really
84 is to reduce code size.
85
86 */
87
88
89/*
90 Endianness Configuration
91
92 By default, UsefulBuf does not need to know what the endianness of
93 the device is. All the code will run correctly on either big or
94 little endian CPUs.
95
96 Here's the recipe for configuring the endianness-related #defines
97 to use more efficient CPU/OS/compiler dependent features to reduce
98 code size. Note these only affect the integer arrays (tagged
99 arrays) feature of QCBOR. All other endianness handling in
100 QCBOR is integrated with code that also handles alignment and
101 preferred encoding.
102
103 The first option is to not define anything. This will work fine on
104 with all CPU's, OS's and compilers. The code for encoding
105 integers will be a little larger and slower.
106
107 If your CPU is big-endian then define USEFULBUF_CONFIG_BIG_ENDIAN. This
108 will give the most efficient code for big-endian CPUs. It will be small
109 and efficient because there will be no byte swapping.
110
111 Try defining USEFULBUF_CONFIG_HTON. This will work on most CPU's,
112 OS's and compilers, but not all. On big-endian CPUs this should give
113 the most efficient code, the same as USEFULBUF_CONFIG_BIG_ENDIAN
114 does. On little-endian CPUs it should call the system-defined byte
115 swapping method which is presumably implemented efficiently. In some
116 cases, this will be a dedicated byte swap instruction like Intel's
117 bswap.
118
119 If USEFULBUF_CONFIG_HTON works and you know your CPU is
120 little-endian, it is also good to define
121 USEFULBUF_CONFIG_LITTLE_ENDIAN.
122
123 if USEFULBUF_CONFIG_HTON doesn't work and you know your system is
124 little-endian, try defining both USEFULBUF_CONFIG_LITTLE_ENDIAN and
125 USEFULBUF_CONFIG_BSWAP. This should call the most efficient
126 system-defined byte swap method. However, note
127 https://hardwarebug.org/2010/01/14/beware-the-builtins/. Perhaps
128 this is fixed now. Often hton() and ntoh() will call the built-in
129 __builtin_bswapXX()() function, so this size issue could affect
130 USEFULBUF_CONFIG_HTON.
131
132 Last, run the tests. They must all pass.
133
134 These #define config options affect the inline implementation of
135 UsefulOutBuf_InsertUint64() and UsefulInputBuf_GetUint64(). They
136 also affect the 16-, 32-bit, float and double versions of these
Laurence Lundblade4c0883e2020-04-21 18:33:39 -0700137 instructions. Since they are inline, the size effect is not in the
Michael Eckel5c531332020-03-02 01:35:30 +0100138 UsefulBuf object code, but in the calling code.
139
140 Summary:
141 USEFULBUF_CONFIG_BIG_ENDIAN -- Force configuration to big-endian.
142 USEFULBUF_CONFIG_LITTLE_ENDIAN -- Force to little-endian.
143 USEFULBUF_CONFIG_HTON -- Use hton(), htonl(), ntohl()... to
144 handle big and little-endian with system option.
145 USEFULBUF_CONFIG_BSWAP -- With USEFULBUF_CONFIG_LITTLE_ENDIAN,
146 use __builtin_bswapXX().
147 */
148
149#if defined(USEFULBUF_CONFIG_BIG_ENDIAN) && defined(USEFULBUF_CONFIG_LITTLE_ENDIAN)
150#error "Cannot define both USEFULBUF_CONFIG_BIG_ENDIAN and USEFULBUF_CONFIG_LITTLE_ENDIAN"
151#endif
152
153
154#include <stdint.h> // for uint8_t, uint16_t....
155#include <string.h> // for strlen, memcpy, memmove, memset
156#include <stddef.h> // for size_t
157
158
159#ifdef USEFULBUF_CONFIG_HTON
160#include <arpa/inet.h> // for htons, htonl, htonll, ntohs...
161#endif
162
163#ifdef __cplusplus
164extern "C" {
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700165#if 0
166} // Keep editor indention formatting happy
167#endif
Michael Eckel5c531332020-03-02 01:35:30 +0100168#endif
169
170/**
171 @file UsefulBuf.h
172
173 The goal of this code is to make buffer and pointer manipulation
174 easier and safer when working with binary data.
175
176 The @ref UsefulBuf, @ref UsefulOutBuf and @ref UsefulInputBuf
177 structures are used to represent buffers rather than ad hoc pointers and
178 lengths.
179
180 With these it will often be possible to write code that does little
181 or no direct pointer manipulation for copying and formatting
182 data. For example, the QCBOR encoder was written using these and
183 has no less pointer manipulation.
184
185 While it is true that object code using these functions will be a
186 little larger and slower than a white-knuckle clever use of pointers
187 might be, but not by that much or enough to have an effect for most
188 use cases. For security-oriented code this is highly
189 worthwhile. Clarity, simplicity, reviewability and are more
190 important.
191
192 There are some extra sanity and double checks in this code to help
193 catch coding errors and simple memory corruption. They are helpful,
194 but not a substitute for proper code review, input validation and
195 such.
196
197 This code consists of a lot of inline functions and a few that are
198 not. It should not generate very much object code, especially with
199 the optimizer turned up to @c -Os or @c -O3.
200 */
201
202
203/**
204 @ref UsefulBufC and @ref UsefulBuf are simple data structures to hold
205 a pointer and length for binary data. In C99 this data structure can
206 be passed on the stack making a lot of code cleaner than carrying
207 around a pointer and length as two parameters.
208
209 This is also conducive to secure coding practice as the length is
210 always carried with the pointer and the convention for handling a
211 pointer and a length is clear.
212
213 While it might be possible to write buffer and pointer code more
214 efficiently in some use cases, the thought is that unless there is an
215 extreme need for performance (e.g., you are building a
216 gigabit-per-second IP router), it is probably better to have cleaner
217 code you can be most certain about the security of.
218
219 The non-const @ref UsefulBuf is usually used to refer a buffer to be
220 filled in. The length is the size of the buffer.
221
222 The const @ref UsefulBufC is usually used to refer to some data that
223 has been filled in. The length is amount of valid data pointed to.
224
225 A common use is to pass a @ref UsefulBuf to a function, the function
226 fills it in, the function returns a @ref UsefulBufC. The pointer is
227 the same in both.
228
229 A @ref UsefulBuf is null, it has no value, when @c ptr in it is @c NULL.
230
231 There are utility functions for the following:
232 - Initializing
233 - Create initialized const @ref UsefulBufC from compiler literals
234 - Create initialized const @ref UsefulBufC from NULL-terminated string
235 - Make an empty @ref UsefulBuf on the stack
236 - Checking whether a @ref UsefulBuf is null, empty or both
237 - Copying, copying with offset, copying head or tail
238 - Comparing and finding substrings
239
240 See also @ref UsefulOutBuf. It is a richer structure that has both
241 the size of the valid data and the size of the buffer.
242
243 @ref UsefulBuf is only 16 or 8 bytes on a 64- or 32-bit machine so it
244 can go on the stack and be a function parameter or return value.
245
246 Another way to look at it is this. C has the NULL-terminated string
247 as a means for handling text strings, but no means or convention for
248 binary strings. Other languages do have such means, Rust, an
249 efficient compiled language, for example.
250
251 @ref UsefulBuf is kind of like the Useful Pot Pooh gave Eeyore on his
252 birthday. Eeyore's balloon fits beautifully, "it goes in and out
253 like anything".
254*/
255typedef struct q_useful_buf_c {
256 const void *ptr;
257 size_t len;
258} UsefulBufC;
259
260
261/**
262 This non-const @ref UsefulBuf is typically used for some allocated
263 memory that is to be filled in. The @c len is the amount of memory,
264 not the length of the valid data in the buffer.
265 */
266typedef struct q_useful_buf {
267 void *ptr;
268 size_t len;
269} UsefulBuf;
270
271
272/**
273 A null @ref UsefulBufC is one that has no value in the same way a @c
274 NULL pointer has no value. A @ref UsefulBufC is @c NULL when the @c
275 ptr field is @c NULL. It doesn't matter what @c len is. See
276 UsefulBuf_IsEmpty() for the distinction between null and empty.
277 */
278#define NULLUsefulBufC ((UsefulBufC) {NULL, 0})
279
280
281/**
282 A null @ref UsefulBuf is one that has no memory associated the same
283 way @c NULL points to nothing. It does not matter what @c len is.
284 */
285#define NULLUsefulBuf ((UsefulBuf) {NULL, 0})
286
287
288/**
289 @brief Check if a @ref UsefulBuf is @ref NULLUsefulBuf or not.
290
291 @param[in] UB The UsefulBuf to check.
292
293 @return 1 if it is @ref NULLUsefulBuf, 0 if not.
294 */
295static inline int UsefulBuf_IsNULL(UsefulBuf UB);
296
297
298/**
299 @brief Check if a @ref UsefulBufC is @ref NULLUsefulBufC or not.
300
301 @param[in] UB The @ref UsefulBufC to check.
302
303 @return 1 if it is @c NULLUsefulBufC, 0 if not.
304 */
305static inline int UsefulBuf_IsNULLC(UsefulBufC UB);
306
307
308/**
309 @brief Check if a @ref UsefulBuf is empty or not.
310
311 @param[in] UB The @ref UsefulBuf to check.
312
313 @return 1 if it is empty, 0 if not.
314
315 An "empty" @ref UsefulBuf is one that has a value and can be
316 considered to be set, but that value is of zero length. It is empty
317 when @c len is zero. It doesn't matter what the @c ptr is.
318
319 A lot of uses will not need to clearly distinguish a @c NULL @ref
320 UsefulBuf from an empty one and can have the @c ptr @c NULL and the
321 @c len 0. However if a use of @ref UsefulBuf needs to make a
322 distinction then @c ptr should not be @c NULL when the @ref UsefulBuf
323 is considered empty, but not @c NULL.
324 */
325static inline int UsefulBuf_IsEmpty(UsefulBuf UB);
326
327
328/**
329 @brief Check if a @ref UsefulBufC is empty or not.
330
331 @param[in] UB The @ref UsefulBufC to check.
332
333 @return 1 if it is empty, 0 if not.
334 */
335static inline int UsefulBuf_IsEmptyC(UsefulBufC UB);
336
337
338/**
339 @brief Check if a @ref UsefulBuf is @ref NULLUsefulBuf or empty.
340
341 @param[in] UB The @ref UsefulBuf to check.
342
343 @return 1 if it is either @ref NULLUsefulBuf or empty, 0 if not.
344 */
345static inline int UsefulBuf_IsNULLOrEmpty(UsefulBuf UB);
346
347
348/**
349 @brief Check if a @ref UsefulBufC is @ref NULLUsefulBufC or empty.
350
351 @param[in] UB The @ref UsefulBufC to check.
352
353 @return 1 if it is either @ref NULLUsefulBufC or empty, 0 if not.
354 */
355static inline int UsefulBuf_IsNULLOrEmptyC(UsefulBufC UB);
356
357
358/**
359 @brief Convert a non-const @ref UsefulBuf to a const @ref UsefulBufC.
360
361 @param[in] UB The @ref UsefulBuf to convert.
362
363 @return A @ref UsefulBufC struct.
364 */
365static inline UsefulBufC UsefulBuf_Const(const UsefulBuf UB);
366
367
368/**
369 @brief Convert a const @ref UsefulBufC to a non-const @ref UsefulBuf.
370
371 @param[in] UBC The @ref UsefulBuf to convert.
372
373 @return A non-const @ref UsefulBuf struct.
374 */
375static inline UsefulBuf UsefulBuf_Unconst(const UsefulBufC UBC);
376
377
378/**
379 Convert a literal string to a @ref UsefulBufC.
380
381 @c szString must be a literal string that @c sizeof() works on. This
382 is better for literal strings than UsefulBuf_FromSZ() because it
383 generates less code. It will not work on non-literal strings.
384
385 The terminating \0 (NULL) is NOT included in the length!
386 */
387#define UsefulBuf_FROM_SZ_LITERAL(szString) \
388 ((UsefulBufC) {(szString), sizeof(szString)-1})
389
390
391/**
392 Convert a literal byte array to a @ref UsefulBufC.
393
394 @c pBytes must be a literal string that @c sizeof() works on. It
395 will not work on non-literal arrays.
396 */
397#define UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pBytes) \
398 ((UsefulBufC) {(pBytes), sizeof(pBytes)})
399
400
401/**
402 Make an automatic variable named @c name of type @ref UsefulBuf and
403 point it to a stack variable of the given @c size.
404 */
405#define UsefulBuf_MAKE_STACK_UB(name, size) \
406 uint8_t __pBuf##name[(size)];\
407 UsefulBuf name = {__pBuf##name , sizeof( __pBuf##name )}
408
409
410/**
411 Make a byte array in to a @ref UsefulBuf. This is usually used on
412 stack variables or static variables. Also see @ref
413 UsefulBuf_MAKE_STACK_UB.
414 */
415#define UsefulBuf_FROM_BYTE_ARRAY(pBytes) \
416 ((UsefulBuf) {(pBytes), sizeof(pBytes)})
417
418
419/**
420 @brief Convert a NULL-terminated string to a @ref UsefulBufC.
421
422 @param[in] szString The string to convert.
423
424 @return A @ref UsefulBufC struct.
425
426 @c UsefulBufC.ptr points to the string so its lifetime must be
427 maintained.
428
429 The terminating \0 (NULL) is NOT included in the length.
430 */
431static inline UsefulBufC UsefulBuf_FromSZ(const char *szString);
432
433
434/**
435 @brief Copy one @ref UsefulBuf into another at an offset.
436
437 @param[in] Dest Destination buffer to copy into.
438 @param[in] uOffset The byte offset in @c Dest at which to copy to.
439 @param[in] Src The bytes to copy.
440
441 @return Pointer and length of the copy or @ref NULLUsefulBufC.
442
443 This fails and returns @ref NULLUsefulBufC if @c offset is beyond the
444 size of @c Dest.
445
446 This fails and returns @ref NULLUsefulBufC if the @c Src length plus
447 @c uOffset is greater than the length of @c Dest.
448
449 The results are undefined if @c Dest and @c Src overlap.
450
451 This assumes that there is valid data in @c Dest up to @c
452 uOffset. The @ref UsefulBufC returned starts at the beginning of @c
453 Dest and goes to @c Src.len @c + @c uOffset.
454 */
455UsefulBufC UsefulBuf_CopyOffset(UsefulBuf Dest, size_t uOffset, const UsefulBufC Src);
456
457
458/**
459 @brief Copy one @ref UsefulBuf into another.
460
461 @param[in] Dest The destination buffer to copy into.
462 @param[out] Src The source to copy from.
463
464 @return Filled in @ref UsefulBufC on success, @ref NULLUsefulBufC
465 on failure.
466
467 This fails if @c Src.len is greater than @c Dest.len.
468
469 Note that like @c memcpy(), the pointers are not checked and this
470 will crash rather than return @ref NULLUsefulBufC if they are @c
471 NULL or invalid.
472
473 The results are undefined if @c Dest and @c Src overlap.
474 */
475static inline UsefulBufC UsefulBuf_Copy(UsefulBuf Dest, const UsefulBufC Src);
476
477
478/**
479 @brief Set all bytes in a @ref UsefulBuf to a value, for example to 0.
480
481 @param[in] pDest The destination buffer to copy into.
482 @param[in] value The value to set the bytes to.
483
484 Note that like @c memset(), the pointer in @c pDest is not checked
485 and this will crash if @c NULL or invalid.
486 */
487static inline UsefulBufC UsefulBuf_Set(UsefulBuf pDest, uint8_t value);
488
489
490/**
491 @brief Copy a pointer into a @ref UsefulBuf.
492
493 @param[in,out] Dest The destination buffer to copy into.
494 @param[in] ptr The source to copy from.
495 @param[in] uLen Length of the source; amount to copy.
496
497 @return 0 on success, 1 on failure.
498
499 This fails and returns @ref NULLUsefulBufC if @c uLen is greater than
500 @c pDest->len.
501
502 Note that like @c memcpy(), the pointers are not checked and this
503 will crash, rather than return 1 if they are @c NULL or invalid.
504 */
505static inline UsefulBufC UsefulBuf_CopyPtr(UsefulBuf Dest,
506 const void *ptr,
507 size_t uLen);
508
509
510/**
511 @brief Returns a truncation of a @ref UsefulBufC.
512
513 @param[in] UB The buffer to get the head of.
514 @param[in] uAmount The number of bytes in the head.
515
516 @return A @ref UsefulBufC that is the head of UB.
517 */
518static inline UsefulBufC UsefulBuf_Head(UsefulBufC UB, size_t uAmount);
519
520
521/**
522 @brief Returns bytes from the end of a @ref UsefulBufC.
523
524 @param[in] UB The buffer to get the tail of.
525 @param[in] uAmount The offset from the start where the tail is to begin.
526
527 @return A @ref UsefulBufC that is the tail of @c UB or @ref NULLUsefulBufC
528 if @c uAmount is greater than the length of the @ref UsefulBufC.
529
530 If @c UB.ptr is @c NULL, but @c UB.len is not zero, then the result will
531 be a @ref UsefulBufC with a @c NULL @c ptr and @c len with the length
532 of the tail.
533 */
534static inline UsefulBufC UsefulBuf_Tail(UsefulBufC UB, size_t uAmount);
535
536
537/**
538 @brief Compare one @ref UsefulBufC to another.
539
540 @param[in] UB1 The first buffer to compare.
541 @param[in] UB2 The second buffer to compare.
542
543 @return 0, positive or negative value.
544
545 Returns a negative value if @c UB1 if is less than @c UB2. @c UB1 is
546 less than @c UB2 if it is shorter or the first byte that is not the
547 same is less.
548
549 Returns 0 if the inputs are the same.
550
551 Returns a positive value if @c UB2 is less than @c UB1.
552
553 All that is of significance is that the result is positive, negative
554 or 0. (This doesn't return the difference between the first
555 non-matching byte like @c memcmp() ).
556 */
557int UsefulBuf_Compare(const UsefulBufC UB1, const UsefulBufC UB2);
558
559
560/**
561 @brief Find first byte that is not a particular byte value.
562
563 @param[in] UB The destination buffer for byte comparison.
564 @param[in] uValue The byte value to compare to.
565
566 @return Offset of first byte that isn't @c uValue or
567 @c SIZE_MAX if all bytes are @c uValue.
568
569 Note that unlike most comparison functions, 0
570 does not indicate a successful comparison, so the
571 test for match is:
572
573 UsefulBuf_IsValue(...) == SIZE_MAX
574
575 If @c UB is null or empty, there is no match
576 and 0 is returned.
577 */
578size_t UsefulBuf_IsValue(const UsefulBufC UB, uint8_t uValue);
579
580
581/**
582 @brief Find one @ref UsefulBufC in another.
583
584 @param[in] BytesToSearch Buffer to search through.
585 @param[in] BytesToFind Buffer with bytes to be found.
586
587 @return Position of found bytes or @c SIZE_MAX if not found.
588 */
589size_t UsefulBuf_FindBytes(UsefulBufC BytesToSearch, UsefulBufC BytesToFind);
590
591
592#if 1 // NOT_DEPRECATED
593/** Deprecated macro; use @ref UsefulBuf_FROM_SZ_LITERAL instead */
594#define SZLiteralToUsefulBufC(szString) \
595 ((UsefulBufC) {(szString), sizeof(szString)-1})
596
597/** Deprecated macro; use UsefulBuf_MAKE_STACK_UB instead */
598#define MakeUsefulBufOnStack(name, size) \
599 uint8_t __pBuf##name[(size)];\
600 UsefulBuf name = {__pBuf##name , sizeof( __pBuf##name )}
601
602/** Deprecated macro; use @ref UsefulBuf_FROM_BYTE_ARRAY_LITERAL instead */
603#define ByteArrayLiteralToUsefulBufC(pBytes) \
604 ((UsefulBufC) {(pBytes), sizeof(pBytes)})
605
606/** Deprecated function; use UsefulBuf_Unconst() instead */
607static inline UsefulBuf UsefulBufC_Unconst(const UsefulBufC UBC)
608{
609 return (UsefulBuf){(void *)UBC.ptr, UBC.len};
610}
611#endif
612
613
614
615
616/**
617 @brief Copy a @c float to a @c uint32_t.
618
619 @param[in] f Float value to copy.
620
621 @return A @c uint32_t with the float bits.
622
623 Convenience function to avoid type punning, compiler warnings and
624 such. The optimizer usually reduces this to a simple assignment. This
625 is a crusty corner of C.
626 */
627static inline uint32_t UsefulBufUtil_CopyFloatToUint32(float f);
628
629
630/**
631 @brief Copy a @c double to a @c uint64_t.
632
633 @param[in] d Double value to copy.
634
635 @return A @c uint64_t with the double bits.
636
637 Convenience function to avoid type punning, compiler warnings and
638 such. The optimizer usually reduces this to a simple assignment. This
639 is a crusty corner of C.
640 */
641static inline uint64_t UsefulBufUtil_CopyDoubleToUint64(double d);
642
643
644/**
645 @brief Copy a @c uint32_t to a @c float.
646
647 @param[in] u32 Integer value to copy.
648
649 @return The value as a @c float.
650
651 Convenience function to avoid type punning, compiler warnings and
652 such. The optimizer usually reduces this to a simple assignment. This
653 is a crusty corner of C.
654 */
655static inline float UsefulBufUtil_CopyUint32ToFloat(uint32_t u32);
656
657
658/**
659 @brief Copy a @c uint64_t to a @c double.
660
661 @param[in] u64 Integer value to copy.
662
663 @return The value as a @c double.
664
665 Convenience function to avoid type punning, compiler warnings and
666 such. The optimizer usually reduces this to a simple assignment. This
667 is a crusty corner of C.
668 */
669static inline double UsefulBufUtil_CopyUint64ToDouble(uint64_t u64);
670
671
672
673
674/**
675 UsefulOutBuf is a structure and functions (an object) for serializing
676 data into a buffer when encoding a network protocol or writing data
677 to file.
678
679 The main idea is that all the pointer manipulation is performed by
680 @ref UsefulOutBuf functions so the caller doesn't have to do any
681 pointer manipulation. The pointer manipulation is centralized. This
682 code will have been reviewed and written carefully so it spares the
683 caller of much of this work and results in safer code with less work.
684
685 The @ref UsefulOutBuf methods that add data to the output buffer
686 always check the length and will never write off the end of the
687 output buffer. If an attempt to add data that will not fit is made,
688 an internal error flag will be set and further attempts to add data
689 will not do anything.
690
691 There is no way to ever write off the end of that buffer when calling
692 the @c UsefulOutBuf_AddXxx() and @c UsefulOutBuf_InsertXxx()
693 functions.
694
695 The functions to add data do not return an error. The working model
696 is that all calls to add data are made without an error check. Errors
697 are just checked for once after all the data has been added before the
698 and before serialized data is to be used. This makes the calling code
699 cleaner.
700
701 There is a utility function to get the error status anytime along the
702 way for a special circumstance. There are functions to see how much
703 room is left and see if some data will fit too, but their use is
704 generally not necessary.
705
706 The general call flow is:
707
708 - Initialize by calling @ref UsefulOutBuf_Init(). The output
709 buffer given to it can be from the heap, stack or
710 otherwise. @ref UsefulOutBuf_MakeOnStack is a convenience macro
711 that makes a buffer on the stack and initializes it.
712
713 - Call methods like UsefulOutBuf_InsertString(),
714 UsefulOutBuf_AppendUint32() and UsefulOutBuf_InsertUsefulBuf()
715 to output data. The append calls add data to the end of the
716 valid data. The insert calls take a position argument.
717
718 - Call UsefulOutBuf_OutUBuf() or UsefulOutBuf_CopyOut() to see
719 there were no errors and to get the serialized output bytes.
720
721 @ref UsefulOutBuf can be used in a size calculation mode to calculate
722 the size of output that would be generated. This is useful to
723 calculate the size of a buffer that is to be allocated to hold the
724 output. To use @ref UsefulOutBuf in this mode, call
725 UsefulOutBuf_Init() with the @c Storage @ref UsefulBuf as
726 @c (UsefulBuf){NULL,MAX_UINT32}. Then call all the Insert and Add
727 functions. No attempt will made to actually copy data, so only the
728 lengths have to be valid for these calls.
729
730 Methods like UsefulOutBuf_InsertUint64() always output in network
731 bytes order (big endian).
732
733 The possible errors are:
734 - The @ref UsefulOutBuf was not initialized or was corrupted.
735
736 - An attempt was made to add data that will not fit.
737
738 - An attempt was made to insert data at a position beyond the end of
739 the buffer.
740
741 - An attempt was made to insert data at a position beyond the valid
742 data in the buffer.
743
744 Some inexpensive simple sanity checks are performed before every data
745 addition to guard against use of an uninitialized or corrupted
746 UsefulOutBuf.
747
748 This has been used to create a CBOR encoder. The CBOR encoder has
749 almost no pointer manipulation in it, is easier to read, and easier
750 to review.
751
752 A @ref UsefulOutBuf is small and can go on the stack:
753 - 32 bytes (27 bytes plus alignment padding) on a 64-bit machine
754 - 16 bytes (15 bytes plus alignment padding) on a 32-bit machines
755 */
756typedef struct useful_out_buf {
757 // PRIVATE DATA STRUCTURE
758 UsefulBuf UB; // Memory that is being output to
759 size_t data_len; // length of the data
760 uint16_t magic; // Used to detect corruption and lack of initialization
761 uint8_t err;
762} UsefulOutBuf;
763
764
765/**
766 @brief Initialize and supply the actual output buffer.
767
768 @param[out] pUOutBuf The @ref UsefulOutBuf to initialize.
769 @param[in] Storage Buffer to output into.
770
771 Initializes the @ref UsefulOutBuf with storage. Sets the current
772 position to the beginning of the buffer clears the error.
773
774 This must be called before the @ref UsefulOutBuf is used.
775 */
776void UsefulOutBuf_Init(UsefulOutBuf *pUOutBuf, UsefulBuf Storage);
777
778
779/**
780 Convenience macro to make a @ref UsefulOutBuf on the stack and
781 initialize it with a stack buffer of the given size. The variable
782 will be named @c name.
783 */
784#define UsefulOutBuf_MakeOnStack(name, size) \
785 uint8_t __pBuf##name[(size)];\
786 UsefulOutBuf name;\
787 UsefulOutBuf_Init(&(name), (UsefulBuf){__pBuf##name, (size)});
788
789
790/**
791 @brief Reset a @ref UsefulOutBuf for re use
792
793 @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf
794
795 This sets the amount of data in the output buffer to none and clears
796 the error state.
797
798 The output buffer is still the same one and size as from the
799 UsefulOutBuf_Init() call.
800
801 This doesn't zero the data, just resets to 0 bytes of valid data.
802 */
803static inline void UsefulOutBuf_Reset(UsefulOutBuf *pUOutBuf);
804
805
806/**
807 @brief Returns position of end of data in the @ref UsefulOutBuf.
808
809 @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
810
811 @return position of end of data.
812
813 On a freshly initialized @ref UsefulOutBuf with no data added, this
814 will return 0. After 10 bytes have been added, it will return 10 and
815 so on.
816
817 Generally callers will not need this function for most uses of @ref
818 UsefulOutBuf.
819 */
820static inline size_t UsefulOutBuf_GetEndPosition(UsefulOutBuf *pUOutBuf);
821
822
823/**
824 @brief Returns whether any data has been added to the @ref UsefulOutBuf.
825
826 @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
827
828 @return 1 if output position is at start.
829 */
830static inline int UsefulOutBuf_AtStart(UsefulOutBuf *pUOutBuf);
831
832
833/**
834 @brief Inserts bytes into the @ref UsefulOutBuf.
835
836 @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
837 @param[in] NewData The bytes to insert.
838 @param[in] uPos Index in output buffer at which to insert.
839
840 @c NewData is the pointer and length for the bytes to be added to the
841 output buffer. There must be room in the output buffer for all of @c
842 NewData or an error will occur.
843
844 The insertion point must be between 0 and the current valid data. If
845 not, an error will occur. Appending data to the output buffer is
846 achieved by inserting at the end of the valid data. This can be
847 retrieved by calling UsefulOutBuf_GetEndPosition().
848
849 When insertion is performed, the bytes between the insertion point
850 and the end of data previously added to the output buffer are slid to
851 the right to make room for the new data.
852
853 Overlapping buffers are OK. @c NewData can point to data in the
854 output buffer.
855
856 If an error occurs an error state is set in the @ref UsefulOutBuf. No
857 error is returned. All subsequent attempts to add data will do
858 nothing.
859
860 The intended use is that all additions are made without checking for
861 an error. The error will be taken into account when
862 UsefulOutBuf_OutUBuf() returns @c NullUsefulBufC.
863 UsefulOutBuf_GetError() can also be called to check for an error.
864 */
865void UsefulOutBuf_InsertUsefulBuf(UsefulOutBuf *pUOutBuf,
866 UsefulBufC NewData,
867 size_t uPos);
868
869
870/**
871 @brief Insert a data buffer into the @ref UsefulOutBuf.
872
873 @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
874 @param[in] pBytes Pointer to the bytes to insert
875 @param[in] uLen Length of the bytes to insert
876 @param[in] uPos Index in output buffer at which to insert
877
878 See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
879 the difference being a pointer and length is passed in rather than an
880 @ref UsefulBufC.
881 */
882static inline void UsefulOutBuf_InsertData(UsefulOutBuf *pUOutBuf,
883 const void *pBytes,
884 size_t uLen,
885 size_t uPos);
886
887
888/**
889 @brief Insert a NULL-terminated string into the UsefulOutBuf.
890
891 @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
892 @param[in] szString NULL-terminated string to insert.
893 @param[in] uPos Index in output buffer at which to insert.
894 */
895static inline void UsefulOutBuf_InsertString(UsefulOutBuf *pUOutBuf,
896 const char *szString,
897 size_t uPos);
898
899
900/**
901 @brief Insert a byte into the @ref UsefulOutBuf.
902
903 @param[in] pUOutBuf Pointer to the UsefulOutBuf.
904 @param[in] byte Bytes to insert.
905 @param[in] uPos Index in output buffer at which to insert.
906
907 See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
908 the difference being a single byte is to be inserted.
909 */
910static inline void UsefulOutBuf_InsertByte(UsefulOutBuf *pUOutBuf,
911 uint8_t byte,
912 size_t uPos);
913
914
915/**
916 @brief Insert a 16-bit integer into the @ref UsefulOutBuf.
917
918 @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
919 @param[in] uInteger16 Integer to insert.
920 @param[in] uPos Index in output buffer at which to insert.
921
922 See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
923 the difference being a two-byte integer is to be inserted.
924
925 The integer will be inserted in network byte order (big endian).
926 */
927static inline void UsefulOutBuf_InsertUint16(UsefulOutBuf *pUOutBuf,
928 uint16_t uInteger16,
929 size_t uPos);
930
931
932/**
933 @brief Insert a 32-bit integer into the @ref UsefulOutBuf.
934
935 @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
936 @param[in] uInteger32 Integer to insert.
937 @param[in] uPos Index in output buffer at which to insert.
938
939 See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
940 the difference being a four-byte integer is to be inserted.
941
942 The integer will be inserted in network byte order (big endian).
943 */
944static inline void UsefulOutBuf_InsertUint32(UsefulOutBuf *pUOutBuf,
945 uint32_t uInteger32,
946 size_t uPos);
947
948
949/**
950 @brief Insert a 64-bit integer into the @ref UsefulOutBuf.
951
952 @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
953 @param[in] uInteger64 Integer to insert.
954 @param[in] uPos Index in output buffer at which to insert.
955
956 See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
957 the difference being an eight-byte integer is to be inserted.
958
959 The integer will be inserted in network byte order (big endian).
960 */
961static inline void UsefulOutBuf_InsertUint64(UsefulOutBuf *pUOutBuf,
962 uint64_t uInteger64,
963 size_t uPos);
964
965
966/**
967 @brief Insert a @c float into the @ref UsefulOutBuf.
968
969 @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
970 @param[in] f @c float to insert.
971 @param[in] uPos Index in output buffer at which to insert.
972
973 See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
974 the difference being a @c float is to be inserted.
975
976 The @c float will be inserted in network byte order (big endian).
977 */
978static inline void UsefulOutBuf_InsertFloat(UsefulOutBuf *pUOutBuf,
979 float f,
980 size_t uPos);
981
982
983/**
984 @brief Insert a @c double into the @ref UsefulOutBuf.
985
986 @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
987 @param[in] d @c double to insert.
988 @param[in] uPos Index in output buffer at which to insert.
989
990 See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
991 the difference being a @c double is to be inserted.
992
993 The @c double will be inserted in network byte order (big endian).
994 */
995static inline void UsefulOutBuf_InsertDouble(UsefulOutBuf *pUOutBuf,
996 double d,
997 size_t uPos);
998
999
1000/**
1001 @brief Append a @ref UsefulBuf into the @ref UsefulOutBuf.
1002
1003 @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
1004 @param[in] NewData The @ref UsefulBuf with the bytes to append.
1005
1006 See UsefulOutBuf_InsertUsefulBuf() for details. This does the same
1007 with the insertion point at the end of the valid data.
1008*/
1009static inline void UsefulOutBuf_AppendUsefulBuf(UsefulOutBuf *pUOutBuf,
1010 UsefulBufC NewData);
1011
1012
1013/**
1014 @brief Append bytes to the @ref UsefulOutBuf.
1015
1016 @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
1017 @param[in] pBytes Pointer to bytes to append.
1018 @param[in] uLen Length of @c pBytes to append.
1019
1020 See UsefulOutBuf_InsertData() for details. This does the same
1021 with the insertion point at the end of the valid data.
1022 */
1023static inline void UsefulOutBuf_AppendData(UsefulOutBuf *pUOutBuf,
1024 const void *pBytes,
1025 size_t uLen);
1026
1027
1028/**
1029 @brief Append a NULL-terminated string to the @ref UsefulOutBuf
1030
1031 @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
1032 @param[in] szString NULL-terminated string to append.
1033 */
1034static inline void UsefulOutBuf_AppendString(UsefulOutBuf *pUOutBuf,
1035 const char *szString);
1036
1037
1038/**
1039 @brief Append a byte to the @ref UsefulOutBuf
1040
1041 @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
1042 @param[in] byte Bytes to append.
1043
1044 See UsefulOutBuf_InsertByte() for details. This does the same
1045 with the insertion point at the end of the valid data.
1046 */
1047static inline void UsefulOutBuf_AppendByte(UsefulOutBuf *pUOutBuf,
1048 uint8_t byte);
1049
1050
1051/**
1052 @brief Append an integer to the @ref UsefulOutBuf
1053
1054 @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
1055 @param[in] uInteger16 Integer to append.
1056
1057 See UsefulOutBuf_InsertUint16() for details. This does the same
1058 with the insertion point at the end of the valid data.
1059
1060 The integer will be appended in network byte order (big endian).
1061 */
1062static inline void UsefulOutBuf_AppendUint16(UsefulOutBuf *pUOutBuf,
1063 uint16_t uInteger16);
1064
1065
1066/**
1067 @brief Append an integer to the @ref UsefulOutBuf
1068
1069 @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
1070 @param[in] uInteger32 Integer to append.
1071
1072 See UsefulOutBuf_InsertUint32() for details. This does the same
1073 with the insertion point at the end of the valid data.
1074
1075 The integer will be appended in network byte order (big endian).
1076 */
1077static inline void UsefulOutBuf_AppendUint32(UsefulOutBuf *pUOutBuf,
1078 uint32_t uInteger32);
1079
1080
1081/**
1082 @brief Append an integer to the @ref UsefulOutBuf
1083
1084 @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
1085 @param[in] uInteger64 Integer to append.
1086
1087 See UsefulOutBuf_InsertUint64() for details. This does the same
1088 with the insertion point at the end of the valid data.
1089
1090 The integer will be appended in network byte order (big endian).
1091 */
1092static inline void UsefulOutBuf_AppendUint64(UsefulOutBuf *pUOutBuf,
1093 uint64_t uInteger64);
1094
1095
1096/**
1097 @brief Append a @c float to the @ref UsefulOutBuf
1098
1099 @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
1100 @param[in] f @c float to append.
1101
1102 See UsefulOutBuf_InsertFloat() for details. This does the same
1103 with the insertion point at the end of the valid data.
1104
1105 The float will be appended in network byte order (big endian).
1106 */
1107static inline void UsefulOutBuf_AppendFloat(UsefulOutBuf *pUOutBuf,
1108 float f);
1109
1110
1111/**
1112 @brief Append a @c double to the @ref UsefulOutBuf
1113
1114 @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
1115 @param[in] d @c double to append.
1116
1117 See UsefulOutBuf_InsertDouble() for details. This does the same
1118 with the insertion point at the end of the valid data.
1119
1120 The double will be appended in network byte order (big endian).
1121 */
1122static inline void UsefulOutBuf_AppendDouble(UsefulOutBuf *pUOutBuf,
1123 double d);
1124
1125
1126/**
1127 @brief Returns the current error status.
1128
1129 @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
1130
1131 @return 0 if all OK, 1 on error.
1132
1133 This is the error status since the call to either
1134 UsefulOutBuf_Reset() of UsefulOutBuf_Init(). Once it goes into error
1135 state it will stay until one of those functions is called.
1136
1137 Possible error conditions are:
1138 - bytes to be inserted will not fit
1139 - insertion point is out of buffer or past valid data
1140 - current position is off end of buffer (probably corrupted or uninitialized)
1141 - detect corruption / uninitialized by bad magic number
1142 */
1143static inline int UsefulOutBuf_GetError(UsefulOutBuf *pUOutBuf);
1144
1145
1146/**
1147 @brief Returns number of bytes unused used in the output buffer.
1148
1149 @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
1150
1151 @return Number of unused bytes or zero.
1152
1153 Because of the error handling strategy and checks in
1154 UsefulOutBuf_InsertUsefulBuf() it is usually not necessary to use
1155 this.
1156 */
1157static inline size_t UsefulOutBuf_RoomLeft(UsefulOutBuf *pUOutBuf);
1158
1159
1160/**
1161 @brief Returns 1 if some number of bytes will fit in the @ref UsefulOutBuf.
1162
1163 @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf
1164 @param[in] uLen Number of bytes for which to check
1165
1166 @return 1 if @c uLen bytes will fit, 0 if not.
1167
1168 Because of the error handling strategy and checks in
1169 UsefulOutBuf_InsertUsefulBuf() it is usually not necessary to use
1170 this.
1171 */
1172static inline int UsefulOutBuf_WillItFit(UsefulOutBuf *pUOutBuf, size_t uLen);
1173
1174
1175 /**
1176 @brief Returns 1 if buffer given to UsefulOutBuf_Init() was @c NULL.
1177
1178 @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf
1179
1180 @return 1 if buffer given to UsefulOutBuf_Init() was @c NULL.
1181
1182 Giving a @c NULL output buffer to UsefulOutBuf_Init() is used
1183 when just calculating the length of the encoded data.
1184 */
1185static inline int UsefulOutBuf_IsBufferNULL(UsefulOutBuf *pUOutBuf);
1186
1187
1188/**
1189 @brief Returns the resulting valid data in a UsefulOutBuf
1190
1191 @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
1192
1193 @return The valid data in @ref UsefulOutBuf or
1194 @ref NULLUsefulBufC if there was an error adding data.
1195
1196 The storage for the returned data is the @c Storage parameter passed
1197 to UsefulOutBuf_Init(). See also UsefulOutBuf_CopyOut().
1198
1199 This can be called anytime and many times to get intermediate
1200 results. It doesn't change the data or reset the current position
1201 so you can keep adding data.
1202 */
1203UsefulBufC UsefulOutBuf_OutUBuf(UsefulOutBuf *pUOutBuf);
1204
1205
1206/**
1207 @brief Copies the valid data into a supplied buffer
1208
1209 @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
1210 @param[out] Dest The destination buffer to copy into.
1211
1212 @return Pointer and length of copied data or @c NULLUsefulBufC
1213 if it will not fit in the @c Dest buffer.
1214
1215 This is the same as UsefulOutBuf_OutUBuf() except it copies the data
1216 to @c Dest.
1217*/
1218UsefulBufC UsefulOutBuf_CopyOut(UsefulOutBuf *pUOutBuf, UsefulBuf Dest);
1219
1220
1221
1222
1223/**
1224 @ref UsefulInputBuf is the counterpart to @ref UsefulOutBuf and is
1225 for parsing data read or received. Initialize it with the data from
1226 the network. Then use the functions here to get data chunks of
1227 various types. A position cursor is maintained internally.
1228
1229 As long as the functions here are used, there will never be a
1230 reference off the end of the given buffer. This is true even if they
1231 care called incorrectly, an attempt is made to seek of the end of the
1232 buffer, etc. This makes it easier to write safe and correct code.
1233 For example, the QCBOR decoder implementation is safer and easier to
1234 review through its use of @ref UsefulInputBuf.
1235
1236 @ref UsefulInputBuf maintains an internal error state. The
1237 intended use is that data chunks can be fetched without error
1238 checking until the end. Once data has been requested off the end of
1239 the buffer, the error state is entered. In the error state the
1240 @c UsefulInputBuf_GetXxxx() functions return 0, or @c NULL or
1241 @ref NULLUsefulBufC. As long as null are not dereferenced, the
1242 error check can be put off until the end, simplifying the calling
1243 code.
1244
1245 The integer and float parsing expects network byte order (big
1246 endian). Network byte order is what is used by TCP/IP, CBOR and most
1247 internet protocols.
1248
1249 Lots of inline functions are used to keep code size down. The code
1250 optimizer, particularly with the @c -Os or @c -O3, also reduces code
1251 size a lot. The only non-inline code is UsefulInputBuf_GetBytes()
1252 which is less than 100 bytes so use of @ref UsefulInputBuf doesn't
1253 add much code for all the messy hard-to-get right issues with parsing
1254 in C that is solves.
1255
1256 The parse context size is:
1257 - 64-bit machine: 16 + 8 + 2 + 1 (5 bytes padding to align) = 32 bytes
1258 - 32-bit machine: 8 + 4 + 2 + 1 (1 byte padding to align) = 16 bytes
1259 */
1260typedef struct useful_input_buf {
1261 // PRIVATE DATA STRUCTURE
1262 UsefulBufC UB; // Data being parsed
1263 size_t cursor; // Current offset in data being parse
1264 uint16_t magic; // Check for corrupted or uninitialized UsefulInputBuf
1265 uint8_t err; // Set request goes off end or magic number is bad
1266} UsefulInputBuf;
1267
1268#define UIB_MAGIC (0xB00F)
1269
1270
1271/**
1272 @brief Initialize the UsefulInputBuf structure before use.
1273
1274 @param[in] pUInBuf Pointer to the UsefulInputBuf instance.
1275 @param[in] UB The data to parse.
1276 */
1277static inline void UsefulInputBuf_Init(UsefulInputBuf *pUInBuf, UsefulBufC UB);
1278
1279
1280/**
1281 @brief Returns current position in input buffer.
1282
1283 @param[in] pUInBuf Pointer to the UsefulInputBuf.
1284
1285 @return Integer position of the cursor.
1286
1287 The position that the next bytes will be returned from.
1288 */
1289static size_t UsefulInputBuf_Tell(UsefulInputBuf *pUInBuf);
1290
1291
1292/**
1293 @brief Sets the current position in input buffer.
1294
1295 @param[in] pUInBuf Pointer to the UsefulInputBuf.
1296 @param[in] uPos Position to set to.
1297
1298 If the position is off the end of the input buffer, the error state
1299 is entered, and all functions will do nothing.
1300
1301 Seeking to a valid position in the buffer will not reset the error
1302 state. Only re initialization will do that.
1303 */
1304static void UsefulInputBuf_Seek(UsefulInputBuf *pUInBuf, size_t uPos);
1305
1306
1307/**
1308 @brief Returns the number of bytes from the cursor to the end of the buffer,
1309 the unconsumed bytes.
1310
1311 @param[in] pUInBuf Pointer to the UsefulInputBuf.
1312
1313 @return Number of bytes unconsumed or 0 on error.
1314
1315 This is a critical function for input length validation.
1316
1317 Returns 0 if the cursor it invalid or corruption of the structure is
1318 detected.
1319 */
1320static size_t UsefulInputBuf_BytesUnconsumed(UsefulInputBuf *pUInBuf);
1321
1322
1323/**
1324 @brief Check if there are any unconsumed bytes.
1325
1326 @param[in] pUInBuf Pointer to the UsefulInputBuf.
1327 @param[in] uLen Number of bytes to check availability for.
1328
1329 @return 1 if @c uLen bytes are available after the cursor, and 0 if not.
1330 */
1331static int UsefulInputBuf_BytesAvailable(UsefulInputBuf *pUInBuf, size_t uLen);
1332
1333
1334/**
1335 @brief Get pointer to bytes out of the input buffer.
1336
1337 @param[in] pUInBuf Pointer to the UsefulInputBuf.
1338 @param[in] uNum Number of bytes to get.
1339
1340 @return Pointer to bytes.
1341
1342 This consumes @c uNum bytes from the input buffer. It returns a
1343 pointer to the start of the @c uNum bytes.
1344
1345 If there are not @c uNum bytes in the input buffer, @c NULL will be
1346 returned and an error will be set.
1347
1348 It advances the current position by @c uNum bytes.
1349 */
1350const void * UsefulInputBuf_GetBytes(UsefulInputBuf *pUInBuf, size_t uNum);
1351
1352
1353/**
1354 @brief Get @ref UsefulBuf out of the input buffer.
1355
1356 @param[in] pUInBuf Pointer to the UsefulInputBuf.
1357 @param[in] uNum Number of bytes to get.
1358
1359 @return A @ref UsefulBufC with ptr and length of bytes consumed.
1360
1361 This consumes @c uNum bytes from the input buffer and returns the
1362 pointer and length for them as a @ref UsefulBufC. The length returned
1363 will always be @c uNum.
1364
1365 If there are not @c uNum bytes in the input buffer, @ref NULLUsefulBufC
1366 will be returned and the error state is set.
1367
1368 It advances the current position by @c uNum bytes.
1369 */
1370static inline UsefulBufC UsefulInputBuf_GetUsefulBuf(UsefulInputBuf *pUInBuf, size_t uNum);
1371
1372
1373/**
1374 @brief Get a byte out of the input buffer.
1375
1376 @param[in] pUInBuf Pointer to the @ref UsefulInputBuf.
1377
1378 @return The byte.
1379
1380 This consumes 1 byte from the input buffer. It returns the byte.
1381
1382 If there is not 1 byte in the buffer, 0 will be returned for the byte
1383 and an error set internally. You must check the error at some point
1384 to know whether the 0 was the real value or just returned in error,
1385 but you may not have to do that right away. Check the error state
1386 with UsefulInputBuf_GetError(). You can also know you are in the
1387 error state if UsefulInputBuf_GetBytes() returns @c NULL or the @c
1388 ptr from UsefulInputBuf_GetUsefulBuf() is @c NULL.
1389
1390 It advances the current position by 1 byte.
1391 */
1392static inline uint8_t UsefulInputBuf_GetByte(UsefulInputBuf *pUInBuf);
1393
1394
1395/**
1396 @brief Get a @c uint16_t out of the input buffer.
1397
1398 @param[in] pUInBuf Pointer to the UsefulInputBuf.
1399
1400 @return The @c uint16_t.
1401
1402 See UsefulInputBuf_GetByte(). This works the same, except it returns
1403 a @c uint16_t and two bytes are consumed.
1404
1405 The input bytes must be in network order (big endian).
1406 */
1407static inline uint16_t UsefulInputBuf_GetUint16(UsefulInputBuf *pUInBuf);
1408
1409
1410/**
1411 @brief Get a uint32_t out of the input buffer.
1412
1413 @param[in] pUInBuf Pointer to the UsefulInputBuf.
1414
1415 @return The @c uint32_t.
1416
1417 See UsefulInputBuf_GetByte(). This works the same, except it returns
1418 a @c uint32_t and four bytes are consumed.
1419
1420 The input bytes must be in network order (big endian).
1421 */
1422static uint32_t UsefulInputBuf_GetUint32(UsefulInputBuf *pUInBuf);
1423
1424
1425/**
1426 @brief Get a uint64_t out of the input buffer.
1427
1428 @param[in] pUInBuf Pointer to the UsefulInputBuf.
1429
1430 @return The uint64_t.
1431
1432 See UsefulInputBuf_GetByte(). This works the same, except it returns
1433 a @c uint64_t and eight bytes are consumed.
1434
1435 The input bytes must be in network order (big endian).
1436 */
1437static uint64_t UsefulInputBuf_GetUint64(UsefulInputBuf *pUInBuf);
1438
1439
1440/**
1441 @brief Get a float out of the input buffer.
1442
1443 @param[in] pUInBuf Pointer to the UsefulInputBuf.
1444
1445 @return The float.
1446
1447 See UsefulInputBuf_GetByte(). This works the same, except it returns
1448 a float and four bytes are consumed.
1449
1450 The input bytes must be in network order (big endian).
1451 */
1452static float UsefulInputBuf_GetFloat(UsefulInputBuf *pUInBuf);
1453
1454
1455/**
1456 @brief Get a double out of the input buffer.
1457
1458 @param[in] pUInBuf Pointer to the UsefulInputBuf.
1459
1460 @return The double.
1461
1462 See UsefulInputBuf_GetByte(). This works the same, except it returns
1463 a double and eight bytes are consumed.
1464
1465 The input bytes must be in network order (big endian).
1466 */
1467static double UsefulInputBuf_GetDouble(UsefulInputBuf *pUInBuf);
1468
1469
1470/**
1471 @brief Get the error status.
1472
1473 @param[in] pUInBuf Pointer to the @ref UsefulInputBuf.
1474
1475 @return 0 if there is no error, 1 if there is.
1476
1477 The error state is entered for one of these reasons:
1478 - Attempt to fetch data past the end of the buffer
1479 - Attempt to seek to a position past the end of the buffer
1480 - Attempt to get data from an uninitialized or corrupt instance
1481 of @ref UsefulInputBuf
1482
1483 Once in the error state, it can only be cleared by calling
1484 UsefulInputBuf_Init().
1485
1486 You may be able to only check the error state at the end after all
1487 the UsefulInputBuf_GetXxxx() calls have been made, but if what you
1488 get later depends on what you get sooner you cannot. For example,
1489 if you get a length or count of following items you will have to
1490 check the error.
1491 */
1492static int UsefulInputBuf_GetError(UsefulInputBuf *pUInBuf);
1493
1494
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001495/**
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07001496 @brief Gets the input buffer length.
1497
1498 @param[in] pUInBuf Pointer to the @ref UsefulInputBuf.
1499
1500 @return The length of the input buffer.
1501
1502 This returns the length of th input buffer from UsefulInputBuf_Init()
1503 of from UsefulInputBuf_SetBufferLength().
1504 */
1505static inline size_t UsefulInputBuf_GetBufferLength(UsefulInputBuf *pUInBuf);
1506
1507
1508/**
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001509 @brief Sets the input buffer length (use with caution)
1510
1511 @param[in] pUInBuf Pointer to the @ref UsefulInputBuf.
1512
1513 This changes the internal remembered length of the input buffer
1514 set when UsefulInputBuf_Init() was called. It is used by QCBOR
1515 to handle CBOR that is wrapped and embedded in CBOR.
1516
1517 Since this allows setting the length beyond the length of the
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07001518 original input buffer it allows the overall safety of UsefulInputBug to
1519 be undermined. Use it carefully.
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001520
1521 The new length given here should always be equal to or less than
1522 the length given when UsefulInputBuf_Init() was called.
1523
1524 */
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07001525static void UsefulInputBuf_SetBufferLength(UsefulInputBuf *pUInBuf, size_t uNewLen);
Michael Eckel5c531332020-03-02 01:35:30 +01001526
1527
1528/*----------------------------------------------------------
1529 Inline implementations.
1530 */
1531static inline int UsefulBuf_IsNULL(UsefulBuf UB)
1532{
1533 return !UB.ptr;
1534}
1535
1536
1537static inline int UsefulBuf_IsNULLC(UsefulBufC UB)
1538{
1539 return !UB.ptr;
1540}
1541
1542
1543static inline int UsefulBuf_IsEmpty(UsefulBuf UB)
1544{
1545 return !UB.len;
1546}
1547
1548
1549static inline int UsefulBuf_IsEmptyC(UsefulBufC UB)
1550{
1551 return !UB.len;
1552}
1553
1554
1555static inline int UsefulBuf_IsNULLOrEmpty(UsefulBuf UB)
1556{
1557 return UsefulBuf_IsEmpty(UB) || UsefulBuf_IsNULL(UB);
1558}
1559
1560
1561static inline int UsefulBuf_IsNULLOrEmptyC(UsefulBufC UB)
1562{
1563 return UsefulBuf_IsEmptyC(UB) || UsefulBuf_IsNULLC(UB);
1564}
1565
1566
1567static inline UsefulBufC UsefulBuf_Const(const UsefulBuf UB)
1568{
1569 return (UsefulBufC){UB.ptr, UB.len};
1570}
1571
1572
1573static inline UsefulBuf UsefulBuf_Unconst(const UsefulBufC UBC)
1574{
1575 return (UsefulBuf){(void *)UBC.ptr, UBC.len};
1576}
1577
1578
1579static inline UsefulBufC UsefulBuf_FromSZ(const char *szString)
1580{
1581 return ((UsefulBufC) {szString, strlen(szString)});
1582}
1583
1584
1585static inline UsefulBufC UsefulBuf_Copy(UsefulBuf Dest, const UsefulBufC Src)
1586{
1587 return UsefulBuf_CopyOffset(Dest, 0, Src);
1588}
1589
1590
1591static inline UsefulBufC UsefulBuf_Set(UsefulBuf pDest, uint8_t value)
1592{
1593 memset(pDest.ptr, value, pDest.len);
1594 return (UsefulBufC){pDest.ptr, pDest.len};
1595}
1596
1597
1598static inline UsefulBufC UsefulBuf_CopyPtr(UsefulBuf Dest, const void *ptr, size_t len)
1599{
1600 return UsefulBuf_Copy(Dest, (UsefulBufC){ptr, len});
1601}
1602
1603
1604static inline UsefulBufC UsefulBuf_Head(UsefulBufC UB, size_t uAmount)
1605{
1606 if(uAmount > UB.len) {
1607 return NULLUsefulBufC;
1608 }
1609 return (UsefulBufC){UB.ptr, uAmount};
1610}
1611
1612
1613static inline UsefulBufC UsefulBuf_Tail(UsefulBufC UB, size_t uAmount)
1614{
1615 UsefulBufC ReturnValue;
1616
1617 if(uAmount > UB.len) {
1618 ReturnValue = NULLUsefulBufC;
1619 } else if(UB.ptr == NULL) {
1620 ReturnValue = (UsefulBufC){NULL, UB.len - uAmount};
1621 } else {
1622 ReturnValue = (UsefulBufC){(uint8_t *)UB.ptr + uAmount, UB.len - uAmount};
1623 }
1624
1625 return ReturnValue;
1626}
1627
1628
1629
1630static inline uint32_t UsefulBufUtil_CopyFloatToUint32(float f)
1631{
1632 uint32_t u32;
1633 memcpy(&u32, &f, sizeof(uint32_t));
1634 return u32;
1635}
1636
1637static inline uint64_t UsefulBufUtil_CopyDoubleToUint64(double d)
1638{
1639 uint64_t u64;
1640 memcpy(&u64, &d, sizeof(uint64_t));
1641 return u64;
1642}
1643
1644static inline double UsefulBufUtil_CopyUint64ToDouble(uint64_t u64)
1645{
1646 double d;
1647 memcpy(&d, &u64, sizeof(uint64_t));
1648 return d;
1649}
1650
1651static inline float UsefulBufUtil_CopyUint32ToFloat(uint32_t u32)
1652{
1653 float f;
1654 memcpy(&f, &u32, sizeof(uint32_t));
1655 return f;
1656}
1657
1658
1659
1660
1661static inline void UsefulOutBuf_Reset(UsefulOutBuf *pMe)
1662{
1663 pMe->data_len = 0;
1664 pMe->err = 0;
1665}
1666
1667
1668static inline size_t UsefulOutBuf_GetEndPosition(UsefulOutBuf *pMe)
1669{
1670 return pMe->data_len;
1671}
1672
1673
1674static inline int UsefulOutBuf_AtStart(UsefulOutBuf *pMe)
1675{
1676 return 0 == pMe->data_len;
1677}
1678
1679
1680static inline void UsefulOutBuf_InsertData(UsefulOutBuf *pMe,
1681 const void *pBytes,
1682 size_t uLen,
1683 size_t uPos)
1684{
1685 UsefulBufC Data = {pBytes, uLen};
1686 UsefulOutBuf_InsertUsefulBuf(pMe, Data, uPos);
1687}
1688
1689
1690static inline void UsefulOutBuf_InsertString(UsefulOutBuf *pMe,
1691 const char *szString,
1692 size_t uPos)
1693{
1694 UsefulOutBuf_InsertUsefulBuf(pMe,
1695 (UsefulBufC){szString, strlen(szString)},
1696 uPos);
1697}
1698
1699
1700static inline void UsefulOutBuf_InsertByte(UsefulOutBuf *me,
1701 uint8_t byte,
1702 size_t uPos)
1703{
1704 UsefulOutBuf_InsertData(me, &byte, 1, uPos);
1705}
1706
1707
1708static inline void UsefulOutBuf_InsertUint16(UsefulOutBuf *me,
1709 uint16_t uInteger16,
1710 size_t uPos)
1711{
1712 // See UsefulOutBuf_InsertUint64() for comments on this code
1713
1714 const void *pBytes;
1715
1716#if defined(USEFULBUF_CONFIG_BIG_ENDIAN)
1717 pBytes = &uInteger16;
1718
1719#elif defined(USEFULBUF_CONFIG_HTON)
1720 uint16_t uTmp = htons(uInteger16);
1721 pBytes = &uTmp;
1722
1723#elif defined(USEFULBUF_CONFIG_LITTLE_ENDIAN) && defined(USEFULBUF_CONFIG_BSWAP)
1724 uint16_t uTmp = __builtin_bswap16(uInteger16);
1725 pBytes = &uTmp;
1726
1727#else
1728 uint8_t aTmp[2];
1729
1730 aTmp[0] = (uint8_t)((uInteger16 & 0xff00) >> 8);
1731 aTmp[1] = (uint8_t)(uInteger16 & 0xff);
1732
1733 pBytes = aTmp;
1734#endif
1735
1736 UsefulOutBuf_InsertData(me, pBytes, 2, uPos);
1737}
1738
1739
1740static inline void UsefulOutBuf_InsertUint32(UsefulOutBuf *pMe,
1741 uint32_t uInteger32,
1742 size_t uPos)
1743{
1744 // See UsefulOutBuf_InsertUint64() for comments on this code
1745
1746 const void *pBytes;
1747
1748#if defined(USEFULBUF_CONFIG_BIG_ENDIAN)
1749 pBytes = &uInteger32;
1750
1751#elif defined(USEFULBUF_CONFIG_HTON)
1752 uint32_t uTmp = htonl(uInteger32);
1753 pBytes = &uTmp;
1754
1755#elif defined(USEFULBUF_CONFIG_LITTLE_ENDIAN) && defined(USEFULBUF_CONFIG_BSWAP)
1756 uint32_t uTmp = __builtin_bswap32(uInteger32);
1757
1758 pBytes = &uTmp;
1759
1760#else
1761 uint8_t aTmp[4];
1762
1763 aTmp[0] = (uint8_t)((uInteger32 & 0xff000000) >> 24);
1764 aTmp[1] = (uint8_t)((uInteger32 & 0xff0000) >> 16);
1765 aTmp[2] = (uint8_t)((uInteger32 & 0xff00) >> 8);
1766 aTmp[3] = (uint8_t)(uInteger32 & 0xff);
1767
1768 pBytes = aTmp;
1769#endif
1770
1771 UsefulOutBuf_InsertData(pMe, pBytes, 4, uPos);
1772}
1773
1774static inline void UsefulOutBuf_InsertUint64(UsefulOutBuf *pMe,
1775 uint64_t uInteger64,
1776 size_t uPos)
1777{
1778 const void *pBytes;
1779
1780#if defined(USEFULBUF_CONFIG_BIG_ENDIAN)
1781 // We have been told explicitly we are running on a big-endian
1782 // machine. Network byte order is big endian, so just copy. There
1783 // is no issue with alignment here because uInter64 is always
1784 // aligned (and it doesn't matter if pBytes is aligned).
1785 pBytes = &uInteger64;
1786
1787#elif defined(USEFULBUF_CONFIG_HTON)
1788 // Use system function to handle big- and little-endian. This works
1789 // on both big- and little-endian machines, but hton() is not
1790 // always available or in a standard place so it is not used by
1791 // default. With some compilers and CPUs the code for this is very
1792 // compact through use of a special swap instruction and on
1793 // big-endian machines hton() will reduce to nothing.
1794 uint64_t uTmp = htonll(uInteger64);
1795
1796 pBytes = &uTmp;
1797
1798#elif defined(USEFULBUF_CONFIG_LITTLE_ENDIAN) && defined(USEFULBUF_CONFIG_BSWAP)
1799 // Use built-in function for byte swapping. This usually compiles
1800 // to an efficient special byte swap instruction. Unlike hton() it
1801 // does not do this conditionally on the CPU endianness, so this
1802 // code is also conditional on USEFULBUF_CONFIG_LITTLE_ENDIAN
1803 uint64_t uTmp = __builtin_bswap64(uInteger64);
1804
1805 pBytes = &uTmp;
1806
1807#else
1808 // Default which works on every CPU with no dependency on anything
1809 // from the CPU, compiler, libraries or OS. This always works, but
1810 // it is usually a little larger and slower than hton().
1811 uint8_t aTmp[8];
1812
1813 aTmp[0] = (uint8_t)((uInteger64 & 0xff00000000000000) >> 56);
1814 aTmp[1] = (uint8_t)((uInteger64 & 0xff000000000000) >> 48);
1815 aTmp[2] = (uint8_t)((uInteger64 & 0xff0000000000) >> 40);
1816 aTmp[3] = (uint8_t)((uInteger64 & 0xff00000000) >> 32);
1817 aTmp[4] = (uint8_t)((uInteger64 & 0xff000000) >> 24);
1818 aTmp[5] = (uint8_t)((uInteger64 & 0xff0000) >> 16);
1819 aTmp[6] = (uint8_t)((uInteger64 & 0xff00) >> 8);
1820 aTmp[7] = (uint8_t)(uInteger64 & 0xff);
1821
1822 pBytes = aTmp;
1823#endif
1824
1825 // Do the insert
1826 UsefulOutBuf_InsertData(pMe, pBytes, sizeof(uint64_t), uPos);
1827}
1828
1829
1830static inline void UsefulOutBuf_InsertFloat(UsefulOutBuf *pMe,
1831 float f,
1832 size_t uPos)
1833{
1834 UsefulOutBuf_InsertUint32(pMe, UsefulBufUtil_CopyFloatToUint32(f), uPos);
1835}
1836
1837
1838static inline void UsefulOutBuf_InsertDouble(UsefulOutBuf *pMe,
1839 double d,
1840 size_t uPos)
1841{
1842 UsefulOutBuf_InsertUint64(pMe, UsefulBufUtil_CopyDoubleToUint64(d), uPos);
1843}
1844
1845
1846static inline void UsefulOutBuf_AppendUsefulBuf(UsefulOutBuf *pMe,
1847 UsefulBufC NewData)
1848{
1849 // An append is just a insert at the end
1850 UsefulOutBuf_InsertUsefulBuf(pMe, NewData, UsefulOutBuf_GetEndPosition(pMe));
1851}
1852
1853
1854static inline void UsefulOutBuf_AppendData(UsefulOutBuf *pMe,
1855 const void *pBytes,
1856 size_t uLen)
1857{
1858 UsefulBufC Data = {pBytes, uLen};
1859 UsefulOutBuf_AppendUsefulBuf(pMe, Data);
1860}
1861
1862
1863static inline void UsefulOutBuf_AppendString(UsefulOutBuf *pMe,
1864 const char *szString)
1865{
1866 UsefulOutBuf_AppendUsefulBuf(pMe, (UsefulBufC){szString, strlen(szString)});
1867}
1868
1869
1870static inline void UsefulOutBuf_AppendByte(UsefulOutBuf *pMe,
1871 uint8_t byte)
1872{
1873 UsefulOutBuf_AppendData(pMe, &byte, 1);
1874}
1875
1876
1877static inline void UsefulOutBuf_AppendUint16(UsefulOutBuf *pMe,
1878 uint16_t uInteger16)
1879{
1880 UsefulOutBuf_InsertUint16(pMe, uInteger16, UsefulOutBuf_GetEndPosition(pMe));
1881}
1882
1883static inline void UsefulOutBuf_AppendUint32(UsefulOutBuf *pMe,
1884 uint32_t uInteger32)
1885{
1886 UsefulOutBuf_InsertUint32(pMe, uInteger32, UsefulOutBuf_GetEndPosition(pMe));
1887}
1888
1889
1890static inline void UsefulOutBuf_AppendUint64(UsefulOutBuf *pMe,
1891 uint64_t uInteger64)
1892{
1893 UsefulOutBuf_InsertUint64(pMe, uInteger64, UsefulOutBuf_GetEndPosition(pMe));
1894}
1895
1896
1897static inline void UsefulOutBuf_AppendFloat(UsefulOutBuf *pMe,
1898 float f)
1899{
1900 UsefulOutBuf_InsertFloat(pMe, f, UsefulOutBuf_GetEndPosition(pMe));
1901}
1902
1903
1904static inline void UsefulOutBuf_AppendDouble(UsefulOutBuf *pMe,
1905 double d)
1906{
1907 UsefulOutBuf_InsertDouble(pMe, d, UsefulOutBuf_GetEndPosition(pMe));
1908}
1909
1910
1911static inline int UsefulOutBuf_GetError(UsefulOutBuf *pMe)
1912{
1913 return pMe->err;
1914}
1915
1916
1917static inline size_t UsefulOutBuf_RoomLeft(UsefulOutBuf *pMe)
1918{
1919 return pMe->UB.len - pMe->data_len;
1920}
1921
1922
1923static inline int UsefulOutBuf_WillItFit(UsefulOutBuf *pMe, size_t uLen)
1924{
1925 return uLen <= UsefulOutBuf_RoomLeft(pMe);
1926}
1927
1928
1929static inline int UsefulOutBuf_IsBufferNULL(UsefulOutBuf *pMe)
1930{
1931 return pMe->UB.ptr == NULL;
1932}
1933
1934
1935
1936static inline void UsefulInputBuf_Init(UsefulInputBuf *pMe, UsefulBufC UB)
1937{
1938 pMe->cursor = 0;
1939 pMe->err = 0;
1940 pMe->magic = UIB_MAGIC;
1941 pMe->UB = UB;
1942}
1943
1944static inline size_t UsefulInputBuf_Tell(UsefulInputBuf *pMe)
1945{
1946 return pMe->cursor;
1947}
1948
1949
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07001950static inline size_t UsefulInputBuf_GetBufferLength(UsefulInputBuf *pMe)
Laurence Lundblade0750fc42020-06-20 21:02:34 -07001951{
1952 return pMe->UB.len;
1953}
1954
1955
Michael Eckel5c531332020-03-02 01:35:30 +01001956static inline void UsefulInputBuf_Seek(UsefulInputBuf *pMe, size_t uPos)
1957{
1958 if(uPos > pMe->UB.len) {
1959 pMe->err = 1;
1960 } else {
1961 pMe->cursor = uPos;
1962 }
1963}
1964
1965
1966static inline size_t UsefulInputBuf_BytesUnconsumed(UsefulInputBuf *pMe)
1967{
1968 // Code Reviewers: THIS FUNCTION DOES POINTER MATH
1969
1970 // Magic number is messed up. Either the structure got overwritten
1971 // or was never initialized.
1972 if(pMe->magic != UIB_MAGIC) {
1973 return 0;
1974 }
1975
1976 // The cursor is off the end of the input buffer given.
1977 // Presuming there are no bugs in this code, this should never happen.
1978 // If it so, the struct was corrupted. The check is retained as
1979 // as a defense in case there is a bug in this code or the struct is
1980 // corrupted.
1981 if(pMe->cursor > pMe->UB.len) {
1982 return 0;
1983 }
1984
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07001985 // subtraction can't go negative because of check above
Michael Eckel5c531332020-03-02 01:35:30 +01001986 return pMe->UB.len - pMe->cursor;
1987}
1988
1989
1990static inline int UsefulInputBuf_BytesAvailable(UsefulInputBuf *pMe, size_t uLen)
1991{
1992 return UsefulInputBuf_BytesUnconsumed(pMe) >= uLen ? 1 : 0;
1993}
1994
1995
1996static inline UsefulBufC UsefulInputBuf_GetUsefulBuf(UsefulInputBuf *pMe, size_t uNum)
1997{
1998 const void *pResult = UsefulInputBuf_GetBytes(pMe, uNum);
1999 if(!pResult) {
2000 return NULLUsefulBufC;
2001 } else {
2002 return (UsefulBufC){pResult, uNum};
2003 }
2004}
2005
2006
2007static inline uint8_t UsefulInputBuf_GetByte(UsefulInputBuf *pMe)
2008{
2009 const void *pResult = UsefulInputBuf_GetBytes(pMe, sizeof(uint8_t));
2010
2011 // The ternery operator is subject to integer promotion, because the
2012 // operands are smaller than int, so cast back to uint8_t is needed
2013 // to be completely explicit about types (for static analyzers)
2014 return (uint8_t)(pResult ? *(uint8_t *)pResult : 0);
2015}
2016
2017static inline uint16_t UsefulInputBuf_GetUint16(UsefulInputBuf *pMe)
2018{
2019 const uint8_t *pResult = (const uint8_t *)UsefulInputBuf_GetBytes(pMe, sizeof(uint16_t));
2020
2021 if(!pResult) {
2022 return 0;
2023 }
2024
2025 // See UsefulInputBuf_GetUint64() for comments on this code
2026#if defined(USEFULBUF_CONFIG_BIG_ENDIAN) || defined(USEFULBUF_CONFIG_HTON) || defined(USEFULBUF_CONFIG_BSWAP)
2027 uint16_t uTmp;
2028 memcpy(&uTmp, pResult, sizeof(uint16_t));
2029
2030#if defined(USEFULBUF_CONFIG_BIG_ENDIAN)
2031 return uTmp;
2032
2033#elif defined(USEFULBUF_CONFIG_HTON)
2034 return ntohs(uTmp);
2035
2036#else
2037 return __builtin_bswap16(uTmp);
2038
2039#endif
2040
2041#else
2042
2043 // The operations here are subject to integer promotion because the
2044 // operands are smaller than int. They will be promoted to unsigned
2045 // int for the shift and addition. The cast back to uint16_t is is needed
2046 // to be completely explicit about types (for static analyzers)
2047 return (uint16_t)((pResult[0] << 8) + pResult[1]);
2048
2049#endif
2050}
2051
2052
2053static inline uint32_t UsefulInputBuf_GetUint32(UsefulInputBuf *pMe)
2054{
2055 const uint8_t *pResult = (const uint8_t *)UsefulInputBuf_GetBytes(pMe, sizeof(uint32_t));
2056
2057 if(!pResult) {
2058 return 0;
2059 }
2060
2061 // See UsefulInputBuf_GetUint64() for comments on this code
2062#if defined(USEFULBUF_CONFIG_BIG_ENDIAN) || defined(USEFULBUF_CONFIG_HTON) || defined(USEFULBUF_CONFIG_BSWAP)
2063 uint32_t uTmp;
2064 memcpy(&uTmp, pResult, sizeof(uint32_t));
2065
2066#if defined(USEFULBUF_CONFIG_BIG_ENDIAN)
2067 return uTmp;
2068
2069#elif defined(USEFULBUF_CONFIG_HTON)
2070 return ntohl(uTmp);
2071
2072#else
2073 return __builtin_bswap32(uTmp);
2074
2075#endif
2076
2077#else
2078 return ((uint32_t)pResult[0]<<24) +
2079 ((uint32_t)pResult[1]<<16) +
2080 ((uint32_t)pResult[2]<<8) +
2081 (uint32_t)pResult[3];
2082#endif
2083}
2084
2085
2086static inline uint64_t UsefulInputBuf_GetUint64(UsefulInputBuf *pMe)
2087{
2088 const uint8_t *pResult = (const uint8_t *)UsefulInputBuf_GetBytes(pMe, sizeof(uint64_t));
2089
2090 if(!pResult) {
2091 return 0;
2092 }
2093
2094#if defined(USEFULBUF_CONFIG_BIG_ENDIAN) || defined(USEFULBUF_CONFIG_HTON) || defined(USEFULBUF_CONFIG_BSWAP)
2095 // pResult will probably not be aligned. This memcpy() moves the
2096 // bytes into a temp variable safely for CPUs that can or can't do
2097 // unaligned memory access. Many compilers will optimize the
2098 // memcpy() into a simple move instruction.
2099 uint64_t uTmp;
2100 memcpy(&uTmp, pResult, sizeof(uint64_t));
2101
2102#if defined(USEFULBUF_CONFIG_BIG_ENDIAN)
2103 // We have been told expliclity this is a big-endian CPU. Since
2104 // network byte order is big-endian, there is nothing to do.
2105
2106 return uTmp;
2107
2108#elif defined(USEFULBUF_CONFIG_HTON)
2109 // We have been told to use ntoh(), the system function to handle
2110 // big- and little-endian. This works on both big- and
2111 // little-endian machines, but ntoh() is not always available or in
2112 // a standard place so it is not used by default. On some CPUs the
2113 // code for this is very compact through use of a special swap
2114 // instruction.
2115
2116 return ntohll(uTmp);
2117
2118#else
2119 // Little-endian (since it is not USEFULBUF_CONFIG_BIG_ENDIAN) and
2120 // USEFULBUF_CONFIG_BSWAP (since it is not USEFULBUF_CONFIG_HTON).
2121 // __builtin_bswap64() and friends are not conditional on CPU
2122 // endianness so this must only be used on little-endian machines.
2123
2124 return __builtin_bswap64(uTmp);
2125
2126
2127#endif
2128
2129#else
2130 // This is the default code that works on every CPU and every
2131 // endianness with no dependency on ntoh(). This works on CPUs
2132 // that either allow or do not allow unaligned access. It will
2133 // always work, but usually is a little less efficient than ntoh().
2134
2135 return ((uint64_t)pResult[0]<<56) +
2136 ((uint64_t)pResult[1]<<48) +
2137 ((uint64_t)pResult[2]<<40) +
2138 ((uint64_t)pResult[3]<<32) +
2139 ((uint64_t)pResult[4]<<24) +
2140 ((uint64_t)pResult[5]<<16) +
2141 ((uint64_t)pResult[6]<<8) +
2142 (uint64_t)pResult[7];
2143#endif
2144}
2145
2146
2147static inline float UsefulInputBuf_GetFloat(UsefulInputBuf *pMe)
2148{
2149 uint32_t uResult = UsefulInputBuf_GetUint32(pMe);
2150
2151 return uResult ? UsefulBufUtil_CopyUint32ToFloat(uResult) : 0;
2152}
2153
2154
2155static inline double UsefulInputBuf_GetDouble(UsefulInputBuf *pMe)
2156{
2157 uint64_t uResult = UsefulInputBuf_GetUint64(pMe);
2158
2159 return uResult ? UsefulBufUtil_CopyUint64ToDouble(uResult) : 0;
2160}
2161
2162
2163static inline int UsefulInputBuf_GetError(UsefulInputBuf *pMe)
2164{
2165 return pMe->err;
2166}
2167
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002168
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07002169static inline void UsefulInputBuf_SetBufferLength(UsefulInputBuf *pMe, size_t uNewLen)
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002170{
2171 pMe->UB.len = uNewLen;
2172}
2173
2174
Michael Eckel5c531332020-03-02 01:35:30 +01002175#ifdef __cplusplus
2176}
2177#endif
2178
2179#endif // _UsefulBuf_h
2180
2181