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