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