blob: 2974adfcb90f2f9df257e8618fe15b90280741a1 [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 Lundbladedabaffe2021-05-11 10:47:46 -070044 5/11/2021 llundblade Improve comments and comment formatting.
Laurence Lundbladeb9702452021-03-08 21:02:57 -080045 3/6/2021 mcr/llundblade Fix warnings related to --Wcast-qual
Laurence Lundbladecf41c522021-02-20 10:19:07 -070046 2/17/2021 llundblade Add method to go from a pointer to an offset.
Michael Eckel5c531332020-03-02 01:35:30 +010047 1/25/2020 llundblade Add some casts so static anlyzers don't complain.
48 5/21/2019 llundblade #define configs for efficient endianness handling.
49 5/16/2019 llundblade Add UsefulOutBuf_IsBufferNULL().
50 3/23/2019 llundblade Big documentation & style update. No interface
51 change.
52 3/6/2019 llundblade Add UsefulBuf_IsValue()
53 12/17/2018 llundblade Remove const from UsefulBuf and UsefulBufC .len
54 12/13/2018 llundblade Documentation improvements
55 09/18/2018 llundblade Cleaner distinction between UsefulBuf and
56 UsefulBufC.
57 02/02/18 llundbla Full support for integers in and out; fix pointer
58 alignment bug. Incompatible change: integers
59 in/out are now in network byte order.
60 08/12/17 llundbla Added UsefulOutBuf_AtStart and UsefulBuf_Find
61 06/27/17 llundbla Fix UsefulBuf_Compare() bug. Only affected
62 comparison for < or > for unequal length buffers.
63 Added UsefulBuf_Set() function.
64 05/30/17 llundbla Functions for NULL UsefulBufs and const / unconst
65 11/13/16 llundbla Initial Version.
66
67 =============================================================================*/
68
69#ifndef _UsefulBuf_h
70#define _UsefulBuf_h
71
72
73/*
Laurence Lundbladedabaffe2021-05-11 10:47:46 -070074 * Endianness Configuration
75 *
76 * This code is written so it will work correctly on big- and
77 * little-endian CPUs without configuration or any auto-detection of
78 * endianness. All code here will run correctly regardless of the
79 * endianness of the CPU it is running on.
80 *
81 * There are four C preprocessor macros that can be set with #define
82 * to explicitly configure endianness handling. Setting them can
83 * reduce code size a little and improve efficiency a little.
84 *
85 * Note that most of QCBOR is unaffected by this configuration. Its
86 * endianness handling is integrated with the code that handles
87 * alignment and preferred serialization. This configuration does
88 * affect QCBOR's (planned) implementation of integer arrays (tagged
89 * arrays) and use of the functions here to serialize or deserialize
90 * integers and floating-point values.
91 *
92 * Following is the recipe for configuring the endianness-related
93 * #defines.
94 *
95 * The first option is to not define anything. This will work fine
96 * with all CPUs, OS's and compilers. The code for encoding integers
97 * may be a little larger and slower.
98 *
99 * If your CPU is big-endian then define
100 * USEFULBUF_CONFIG_BIG_ENDIAN. This will give the most efficient code
101 * for big-endian CPUs. It will be small and efficient because there
102 * will be no byte swapping.
103 *
104 * Try defining USEFULBUF_CONFIG_HTON. This will work on most CPUs,
105 * OS's and compilers, but not all. On big-endian CPUs this should
106 * give the most efficient code, the same as
107 * USEFULBUF_CONFIG_BIG_ENDIAN does. On little-endian CPUs it should
108 * call the system-defined byte swapping method which is presumably
109 * implemented efficiently. In some cases, this will be a dedicated
110 * byte swap instruction like Intel's bswap.
111 *
112 * If USEFULBUF_CONFIG_HTON works and you know your CPU is
113 * little-endian, it is also good to define
114 * USEFULBUF_CONFIG_LITTLE_ENDIAN.
115 *
116 * if USEFULBUF_CONFIG_HTON doesn't work and you know your system is
117 * little-endian, try defining both USEFULBUF_CONFIG_LITTLE_ENDIAN and
118 * USEFULBUF_CONFIG_BSWAP. This should call the most efficient
119 * system-defined byte swap method. However, note
120 * https://hardwarebug.org/2010/01/14/beware-the-builtins/. Perhaps
121 * this is fixed now. Often hton() and ntoh() will call the built-in
122 * __builtin_bswapXX()() function, so this size issue could affect
123 * USEFULBUF_CONFIG_HTON.
124 *
125 * Last, run the tests. They must all pass.
126 *
127 * These #define config options affect the inline implementation of
128 * UsefulOutBuf_InsertUint64() and UsefulInputBuf_GetUint64(). They
129 * also affect the 16-, 32-bit, float and double versions of these
130 * functions. Since they are inline, the size effect is not in the
131 * UsefulBuf object code, but in the calling code.
132 *
133 * Summary:
134 * USEFULBUF_CONFIG_BIG_ENDIAN -- Force configuration to big-endian.
135 * USEFULBUF_CONFIG_LITTLE_ENDIAN -- Force to little-endian.
136 * USEFULBUF_CONFIG_HTON -- Use hton(), htonl(), ntohl()... to
137 * handle big and little-endian with system option.
138 * USEFULBUF_CONFIG_BSWAP -- With USEFULBUF_CONFIG_LITTLE_ENDIAN,
139 * use __builtin_bswapXX().
Michael Eckel5c531332020-03-02 01:35:30 +0100140 */
141
142#if defined(USEFULBUF_CONFIG_BIG_ENDIAN) && defined(USEFULBUF_CONFIG_LITTLE_ENDIAN)
143#error "Cannot define both USEFULBUF_CONFIG_BIG_ENDIAN and USEFULBUF_CONFIG_LITTLE_ENDIAN"
144#endif
145
146
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700147#include <stdint.h> /* for uint8_t, uint16_t.... */
148#include <string.h> /* for strlen, memcpy, memmove, memset */
149#include <stddef.h> /* for size_t */
Michael Eckel5c531332020-03-02 01:35:30 +0100150
151
152#ifdef USEFULBUF_CONFIG_HTON
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700153#include <arpa/inet.h> /* for htons, htonl, htonll, ntohs... */
Michael Eckel5c531332020-03-02 01:35:30 +0100154#endif
155
156#ifdef __cplusplus
157extern "C" {
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700158#if 0
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700159} /* Keep editor indention formatting happy */
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700160#endif
Michael Eckel5c531332020-03-02 01:35:30 +0100161#endif
162
163/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700164 * @file UsefulBuf.h
165 *
166 * The goal of this code is to make buffer and pointer manipulation
167 * easier and safer when working with binary data.
168 *
169 * The @ref UsefulBuf, @ref UsefulOutBuf and @ref UsefulInputBuf
170 * structures are used to represent buffers rather than ad hoc
171 * pointers and lengths.
172 *
173 * With these it is possible to write code that does little or no
174 * direct pointer manipulation for copying and formatting data. For
175 * example, the QCBOR encoder was written using these and has less
176 * pointer manipulation.
177 *
178 * While it is true that object code using these functions will be a
179 * little larger and slower than a white-knuckle clever use of
180 * pointers might be, but not by that much or enough to have an effect
181 * for most use cases. For security-oriented code this is highly
182 * worthwhile. Clarity, simplicity, reviewability and are more
183 * important.
184 *
185 * There are some extra sanity and double checks in this code to help
186 * catch coding errors and simple memory corruption. They are helpful,
187 * but not a substitute for proper code review, input validation and
188 * such.
189 *
190 * This code consists of a lot of inline functions and a few that are
191 * not. It should not generate very much object code, especially with
192 * the optimizer turned up to @c -Os or @c -O3.
Michael Eckel5c531332020-03-02 01:35:30 +0100193 */
194
195
196/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700197 * @ref UsefulBufC and @ref UsefulBuf are simple data structures to
198 * hold a pointer and length for binary data. In C99 this data
199 * structure can be passed on the stack making a lot of code cleaner
200 * than carrying around a pointer and length as two parameters.
201 *
202 * This is also conducive to secure coding practice as the length is
203 * always carried with the pointer and the convention for handling a
204 * pointer and a length is clear.
205 *
206 * While it might be possible to write buffer and pointer code more
207 * efficiently in some use cases, the thought is that unless there is
208 * an extreme need for performance (e.g., you are building a
209 * gigabit-per-second IP router), it is probably better to have
210 * cleaner code you can be most certain about the security of.
211 *
212 * The non-const @ref UsefulBuf is usually used to refer an empty
213 * buffer to be filled in. The length is the size of the buffer.
214 *
215 * The const @ref UsefulBufC is usually used to refer to some data
216 * that has been filled in. The length is amount of valid data pointed
217 * to.
218 *
219 * A common use mode is to pass a @ref UsefulBuf to a function, the
220 * function puts some data in it, then the function returns a @ref
221 * UsefulBufC refering to the data. The @ref UsefulBuf is a non-const
222 * "in" parameter and the @ref UsefulBufC is a const "out" parameter
223 * so the constness stays correct. There is no single "in,out"
224 * parameter (if there was, it would have to be non-const). Note that
225 * the pointer returned in the @ref UsefulBufC usually ends up being
226 * the same pointer passed in as a @ref UsefulBuf, though this is not
227 * striclty required.
228 *
229 * A @ref UsefulBuf is null, it has no value, when @c ptr in it is
230 * @c NULL.
231 *
232 * There are functions and macros for the following:
233 * - Initializing
234 * - Create initialized const @ref UsefulBufC from compiler literals
235 * - Create initialized const @ref UsefulBufC from NULL-terminated string
236 * - Make an empty @ref UsefulBuf on the stack
237 * - Checking whether a @ref UsefulBuf is null, empty or both
238 * - Copying, copying with offset, copying head or tail
239 * - Comparing and finding substrings
240 *
241 * See also @ref UsefulOutBuf. It is a richer structure that has both
242 * the size of the valid data and the size of the buffer.
243 *
244 * @ref UsefulBuf is only 16 or 8 bytes on a 64- or 32-bit machine so
245 * it can go on the stack and be a function parameter or return value.
246 *
247 * Another way to look at it is this. C has the NULL-terminated string
248 * as a means for handling text strings, but no means or convention
249 * for binary strings. Other languages do have such means, Rust, an
250 * efficient compiled language, for example.
251 *
252 * @ref UsefulBuf is kind of like the Useful Pot Pooh gave Eeyore on
253 * his birthday. Eeyore's balloon fits beautifully, "it goes in and
254 * out like anything".
255 */
Michael Eckel5c531332020-03-02 01:35:30 +0100256typedef struct q_useful_buf_c {
257 const void *ptr;
258 size_t len;
259} UsefulBufC;
260
261
262/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700263 * This non-const @ref UsefulBuf is typically used for some allocated
264 * memory that is to be filled in. The @c len is the amount of memory,
265 * not the length of the valid data in the buffer.
Michael Eckel5c531332020-03-02 01:35:30 +0100266 */
267typedef struct q_useful_buf {
268 void *ptr;
269 size_t len;
270} UsefulBuf;
271
272
273/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700274 * A null @ref UsefulBufC is one that has no value in the same way a
275 * @c NULL pointer has no value. A @ref UsefulBufC is @c NULL when
276 * the @c ptr field is @c NULL. It doesn't matter what @c len is. See
277 * UsefulBuf_IsEmpty() for the distinction between null and empty.
Michael Eckel5c531332020-03-02 01:35:30 +0100278 */
279#define NULLUsefulBufC ((UsefulBufC) {NULL, 0})
280
281
282/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700283 * A null @ref UsefulBuf is one that has no memory associated the same
284 * way @c NULL points to nothing. It does not matter what @c len is.
285 **/
Michael Eckel5c531332020-03-02 01:35:30 +0100286#define NULLUsefulBuf ((UsefulBuf) {NULL, 0})
287
288
289/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700290 * @brief Check if a @ref UsefulBuf is @ref NULLUsefulBuf or not.
291 *
292 * @param[in] UB The UsefulBuf to check.
293 *
294 * @return 1 if it is @ref NULLUsefulBuf, 0 if not.
Michael Eckel5c531332020-03-02 01:35:30 +0100295 */
296static inline int UsefulBuf_IsNULL(UsefulBuf UB);
297
298
299/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700300 * @brief Check if a @ref UsefulBufC is @ref NULLUsefulBufC or not.
301 *
302 * @param[in] UB The @ref UsefulBufC to check.
303 *
304 * @return 1 if it is @c NULLUsefulBufC, 0 if not.
Michael Eckel5c531332020-03-02 01:35:30 +0100305 */
306static inline int UsefulBuf_IsNULLC(UsefulBufC UB);
307
308
309/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700310 * @brief Check if a @ref UsefulBuf is empty or not.
311 *
312 * @param[in] UB The @ref UsefulBuf to check.
313 *
314 * @return 1 if it is empty, 0 if not.
315 *
316 * An "empty" @ref UsefulBuf is one that has a value and can be
317 * considered to be set, but that value is of zero length. It is
318 * empty when @c len is zero. It doesn't matter what the @c ptr is.
319 *
320 * Many uses will not need to clearly distinguish a @c NULL @ref
321 * UsefulBuf from an empty one and can have the @c ptr @c NULL and the
322 * @c len 0. However if a use of @ref UsefulBuf needs to make a
323 * distinction then @c ptr should not be @c NULL when the @ref
324 * UsefulBuf is considered empty, but not @c NULL.
Michael Eckel5c531332020-03-02 01:35:30 +0100325 */
326static inline int UsefulBuf_IsEmpty(UsefulBuf UB);
327
328
329/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700330 * @brief Check if a @ref UsefulBufC is empty or not.
331 *
332 * @param[in] UB The @ref UsefulBufC to check.
333 *
334 * @return 1 if it is empty, 0 if not.
Michael Eckel5c531332020-03-02 01:35:30 +0100335 */
336static inline int UsefulBuf_IsEmptyC(UsefulBufC UB);
337
338
339/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700340 * @brief Check if a @ref UsefulBuf is @ref NULLUsefulBuf or empty.
341 *
342 * @param[in] UB The @ref UsefulBuf to check.
343 *
344 * @return 1 if it is either @ref NULLUsefulBuf or empty, 0 if not.
Michael Eckel5c531332020-03-02 01:35:30 +0100345 */
346static inline int UsefulBuf_IsNULLOrEmpty(UsefulBuf UB);
347
348
349/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700350 * @brief Check if a @ref UsefulBufC is @ref NULLUsefulBufC or empty.
351 *
352 * @param[in] UB The @ref UsefulBufC to check.
353 *
354 * @return 1 if it is either @ref NULLUsefulBufC or empty, 0 if not.
Michael Eckel5c531332020-03-02 01:35:30 +0100355 */
356static inline int UsefulBuf_IsNULLOrEmptyC(UsefulBufC UB);
357
358
359/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700360 * @brief Convert a non-const @ref UsefulBuf to a const @ref UsefulBufC.
361 *
362 * @param[in] UB The @ref UsefulBuf to convert.
363 *
364 * @return A @ref UsefulBufC struct.
Michael Eckel5c531332020-03-02 01:35:30 +0100365 */
366static inline UsefulBufC UsefulBuf_Const(const UsefulBuf UB);
367
368
369/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700370 * @brief Convert a const @ref UsefulBufC to a non-const @ref UsefulBuf.
371 *
372 * @param[in] UBC The @ref UsefulBuf to convert.
373 *
374 * @return A non-const @ref UsefulBuf struct.
375 *
376 * Use of this is not necessary for the intended use mode of @ref
377 * UsefulBufC and @ref UsefulBuf. In that mode, the @ref UsefulBuf is
378 * created to describe a buffer that has not had any data put in
379 * it. Then the data is put in it. Then a @ref UsefulBufC is create
380 * to describe the part with the data in it. This goes from non-const
381 * to const, so this function is not needed.
382 *
383 * If the -Wcast-qual warning is enabled, this function can be used to
384 * avoid that warning.
Michael Eckel5c531332020-03-02 01:35:30 +0100385 */
386static inline UsefulBuf UsefulBuf_Unconst(const UsefulBufC UBC);
387
388
389/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700390 * Convert a literal string to a @ref UsefulBufC.
391 *
392 * @c szString must be a literal string that @c sizeof() works on.
393 * This is better for literal strings than UsefulBuf_FromSZ() because
394 * it generates less code. It will not work on non-literal strings.
395 *
396 * The terminating \0 (NULL) is NOT included in the length!
Michael Eckel5c531332020-03-02 01:35:30 +0100397 */
398#define UsefulBuf_FROM_SZ_LITERAL(szString) \
399 ((UsefulBufC) {(szString), sizeof(szString)-1})
400
401
402/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700403 * Convert a literal byte array to a @ref UsefulBufC.
404 *
405 * @c pBytes must be a literal string that @c sizeof() works on. It
406 * will not work on non-literal arrays.
Michael Eckel5c531332020-03-02 01:35:30 +0100407 */
408#define UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pBytes) \
409 ((UsefulBufC) {(pBytes), sizeof(pBytes)})
410
411
412/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700413 * Make an automatic variable named @c name of type @ref UsefulBuf and
414 * point it to a stack variable of the given @c size.
Michael Eckel5c531332020-03-02 01:35:30 +0100415 */
416#define UsefulBuf_MAKE_STACK_UB(name, size) \
417 uint8_t __pBuf##name[(size)];\
418 UsefulBuf name = {__pBuf##name , sizeof( __pBuf##name )}
419
420
421/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700422 * Make a byte array in to a @ref UsefulBuf. This is usually used on
423 * stack variables or static variables. Also see @ref
424 * UsefulBuf_MAKE_STACK_UB.
Michael Eckel5c531332020-03-02 01:35:30 +0100425 */
426#define UsefulBuf_FROM_BYTE_ARRAY(pBytes) \
427 ((UsefulBuf) {(pBytes), sizeof(pBytes)})
428
429
430/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700431 * @brief Convert a NULL-terminated string to a @ref UsefulBufC.
432 *
433 * @param[in] szString The string to convert.
434 *
435 * @return A @ref UsefulBufC struct.
436 *
437 * @c UsefulBufC.ptr points to the string so its lifetime must be
438 * maintained.
439 *
440 * The terminating \0 (NULL) is NOT included in the length.
Michael Eckel5c531332020-03-02 01:35:30 +0100441 */
442static inline UsefulBufC UsefulBuf_FromSZ(const char *szString);
443
444
445/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700446 * @brief Copy one @ref UsefulBuf into another at an offset.
447 *
448 * @param[in] Dest Destination buffer to copy into.
449 * @param[in] uOffset The byte offset in @c Dest at which to copy to.
450 * @param[in] Src The bytes to copy.
451 *
452 * @return Pointer and length of the copy or @ref NULLUsefulBufC.
453 *
454 * This fails and returns @ref NULLUsefulBufC if @c offset is beyond the
455 * size of @c Dest.
456 *
457 * This fails and returns @ref NULLUsefulBufC if the @c Src length
458 * plus @c uOffset is greater than the length of @c Dest.
459 *
460 * The results are undefined if @c Dest and @c Src overlap.
461 *
462 * This assumes that there is valid data in @c Dest up to @c
463 * uOffset. The @ref UsefulBufC returned starts at the beginning of @c
464 * Dest and goes to @c Src.len @c + @c uOffset.
Michael Eckel5c531332020-03-02 01:35:30 +0100465 */
466UsefulBufC UsefulBuf_CopyOffset(UsefulBuf Dest, size_t uOffset, const UsefulBufC Src);
467
468
469/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700470 * @brief Copy one @ref UsefulBuf into another.
471 *
472 * @param[in] Dest The destination buffer to copy into.
473 * @param[out] Src The source to copy from.
474 *
475 * @return Filled in @ref UsefulBufC on success, @ref NULLUsefulBufC
476 * on failure.
477 *
478 * This fails if @c Src.len is greater than @c Dest.len.
479 *
480 * Note that like @c memcpy(), the pointers are not checked and this
481 * will crash rather than return @ref NULLUsefulBufC if they are @c
482 * NULL or invalid.
483 *
484 * The results are undefined if @c Dest and @c Src overlap.
Michael Eckel5c531332020-03-02 01:35:30 +0100485 */
486static inline UsefulBufC UsefulBuf_Copy(UsefulBuf Dest, const UsefulBufC Src);
487
488
489/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700490 * @brief Set all bytes in a @ref UsefulBuf to a value, for example to 0.
491 *
492 * @param[in] pDest The destination buffer to copy into.
493 * @param[in] value The value to set the bytes to.
494 *
495 * Note that like @c memset(), the pointer in @c pDest is not checked
496 * and this will crash if @c NULL or invalid.
Michael Eckel5c531332020-03-02 01:35:30 +0100497 */
498static inline UsefulBufC UsefulBuf_Set(UsefulBuf pDest, uint8_t value);
499
500
501/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700502 * @brief Copy a pointer into a @ref UsefulBuf.
503 *
504 * @param[in,out] Dest The destination buffer to copy into.
505 * @param[in] ptr The source to copy from.
506 * @param[in] uLen Length of the source; amount to copy.
507 *
508 * @return Filled in @ref UsefulBufC on success, @ref NULLUsefulBufC
509 * on failure.
510 *
511 * This fails and returns @ref NULLUsefulBufC if @c uLen is greater
512 * than @c pDest->len.
513 *
514 * Note that like @c memcpy(), the pointers are not checked and this
515 * will crash, rather than return 1 if they are @c NULL or invalid.
Michael Eckel5c531332020-03-02 01:35:30 +0100516 */
517static inline UsefulBufC UsefulBuf_CopyPtr(UsefulBuf Dest,
518 const void *ptr,
519 size_t uLen);
520
521
522/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700523 * @brief Returns a truncation of a @ref UsefulBufC.
524 *
525 * @param[in] UB The buffer to get the head of.
526 * @param[in] uAmount The number of bytes in the head.
527 *
528 * @return A @ref UsefulBufC that is the head of UB.
Michael Eckel5c531332020-03-02 01:35:30 +0100529 */
530static inline UsefulBufC UsefulBuf_Head(UsefulBufC UB, size_t uAmount);
531
532
533/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700534 * @brief Returns bytes from the end of a @ref UsefulBufC.
535 *
536 * @param[in] UB The buffer to get the tail of.
537 * @param[in] uAmount The offset from the start where the tail is to begin.
538 *
539 * @return A @ref UsefulBufC that is the tail of @c UB or @ref NULLUsefulBufC
540 * if @c uAmount is greater than the length of the @ref UsefulBufC.
541 *
542 * If @c UB.ptr is @c NULL, but @c UB.len is not zero, then the result will
543 * be a @ref UsefulBufC with a @c NULL @c ptr and @c len with the length
544 * of the tail.
Michael Eckel5c531332020-03-02 01:35:30 +0100545 */
546static inline UsefulBufC UsefulBuf_Tail(UsefulBufC UB, size_t uAmount);
547
548
549/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700550 * @brief Compare one @ref UsefulBufC to another.
551 *
552 * @param[in] UB1 The first buffer to compare.
553 * @param[in] UB2 The second buffer to compare.
554 *
555 * @return 0, positive or negative value.
556 *
557 * Returns a negative value if @c UB1 if is less than @c UB2. @c UB1 is
558 * less than @c UB2 if it is shorter or the first byte that is not the
559 * same is less.
560 *
561 * Returns 0 if the inputs are the same.
562 *
563 * Returns a positive value if @c UB2 is less than @c UB1.
564 *
565 * All that is of significance is that the result is positive, negative
566 * or 0. (This doesn't return the difference between the first
567 * non-matching byte like @c memcmp() ).
Michael Eckel5c531332020-03-02 01:35:30 +0100568 */
569int UsefulBuf_Compare(const UsefulBufC UB1, const UsefulBufC UB2);
570
571
572/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700573 * @brief Find first byte that is not a particular byte value.
574 *
575 * @param[in] UB The destination buffer for byte comparison.
576 * @param[in] uValue The byte value to compare to.
577 *
578 * @return Offset of first byte that isn't @c uValue or
579 * @c SIZE_MAX if all bytes are @c uValue.
580 *
581 * Note that unlike most comparison functions, 0
582 * does not indicate a successful comparison, so the
583 * test for match is:
584 *
585 * UsefulBuf_IsValue(...) == SIZE_MAX
586 *
587 * If @c UB is null or empty, there is no match
588 * and 0 is returned.
Michael Eckel5c531332020-03-02 01:35:30 +0100589 */
590size_t UsefulBuf_IsValue(const UsefulBufC UB, uint8_t uValue);
591
592
593/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700594 * @brief Find one @ref UsefulBufC in another.
595 *
596 * @param[in] BytesToSearch Buffer to search through.
597 * @param[in] BytesToFind Buffer with bytes to be found.
598 *
599 * @return Position of found bytes or @c SIZE_MAX if not found.
Michael Eckel5c531332020-03-02 01:35:30 +0100600 */
601size_t UsefulBuf_FindBytes(UsefulBufC BytesToSearch, UsefulBufC BytesToFind);
602
603
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700604/**
605 @brief Convert a pointer to an offset with bounds checking.
606
607 @param[in] UB Pointer to the UsefulInputBuf.
608 @param[in] p Pointer to convert to offset.
609
610 @return SIZE_MAX if @c p is out of range, the byte offset if not.
611*/
612static inline size_t UsefulBuf_PointerToOffset(UsefulBufC UB, const void *p);
613
614
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800615#ifndef USEFULBUF_DISABLE_DEPRECATED
Michael Eckel5c531332020-03-02 01:35:30 +0100616/** Deprecated macro; use @ref UsefulBuf_FROM_SZ_LITERAL instead */
617#define SZLiteralToUsefulBufC(szString) \
618 ((UsefulBufC) {(szString), sizeof(szString)-1})
619
620/** Deprecated macro; use UsefulBuf_MAKE_STACK_UB instead */
621#define MakeUsefulBufOnStack(name, size) \
622 uint8_t __pBuf##name[(size)];\
623 UsefulBuf name = {__pBuf##name , sizeof( __pBuf##name )}
624
625/** Deprecated macro; use @ref UsefulBuf_FROM_BYTE_ARRAY_LITERAL instead */
626#define ByteArrayLiteralToUsefulBufC(pBytes) \
627 ((UsefulBufC) {(pBytes), sizeof(pBytes)})
628
629/** Deprecated function; use UsefulBuf_Unconst() instead */
630static inline UsefulBuf UsefulBufC_Unconst(const UsefulBufC UBC)
631{
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800632 // See UsefulBuf_Unconst() implementation for comment on pragmas
633#pragma GCC diagnostic push
634#pragma GCC diagnostic ignored "-Wcast-qual"
Michael Eckel5c531332020-03-02 01:35:30 +0100635 return (UsefulBuf){(void *)UBC.ptr, UBC.len};
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800636#pragma GCC diagnostic pop
Michael Eckel5c531332020-03-02 01:35:30 +0100637}
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800638#endif /* USEFULBUF_DISABLE_DEPRECATED */
Michael Eckel5c531332020-03-02 01:35:30 +0100639
640
641
642
643/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700644 * @brief Copy a @c float to a @c uint32_t.
645 *
646 * @param[in] f Float value to copy.
647 *
648 * @return A @c uint32_t with the float bits.
649 *
650 * Convenience function to avoid type punning, compiler warnings and
651 * such. The optimizer usually reduces this to a simple assignment. This
652 * is a crusty corner of C.
Michael Eckel5c531332020-03-02 01:35:30 +0100653 */
654static inline uint32_t UsefulBufUtil_CopyFloatToUint32(float f);
655
656
657/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700658 * @brief Copy a @c double to a @c uint64_t.
659 *
660 * @param[in] d Double value to copy.
661 *
662 * @return A @c uint64_t with the double bits.
663 *
664 * Convenience function to avoid type punning, compiler warnings and
665 * such. The optimizer usually reduces this to a simple assignment. This
666 * is a crusty corner of C.
Michael Eckel5c531332020-03-02 01:35:30 +0100667 */
668static inline uint64_t UsefulBufUtil_CopyDoubleToUint64(double d);
669
670
671/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700672 * @brief Copy a @c uint32_t to a @c float.
673 *
674 * @param[in] u32 Integer value to copy.
675 *
676 * @return The value as a @c float.
677 *
678 * Convenience function to avoid type punning, compiler warnings and
679 * such. The optimizer usually reduces this to a simple assignment. This
680 * is a crusty corner of C.
Michael Eckel5c531332020-03-02 01:35:30 +0100681 */
682static inline float UsefulBufUtil_CopyUint32ToFloat(uint32_t u32);
683
684
685/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700686 * @brief Copy a @c uint64_t to a @c double.
687 *
688 * @param[in] u64 Integer value to copy.
689 *
690 * @return The value as a @c double.
691 *
692 * Convenience function to avoid type punning, compiler warnings and
693 * such. The optimizer usually reduces this to a simple assignment. This
694 * is a crusty corner of C.
Michael Eckel5c531332020-03-02 01:35:30 +0100695 */
696static inline double UsefulBufUtil_CopyUint64ToDouble(uint64_t u64);
697
698
699
700
701/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700702 * UsefulOutBuf is a structure and functions (an object) for
703 * serializing data into a buffer to encode for a network protocol or
704 * write data to a file.
705 *
706 * The main idea is that all the pointer manipulation is performed by
707 * @ref UsefulOutBuf functions so the caller doesn't have to do any
708 * pointer manipulation. The pointer manipulation is centralized.
709 * This code has been reviewed and written carefully so it
710 * spares the caller of much of this work and results in safer code
711 * with less effort.
712 *
713 * The @ref UsefulOutBuf methods that add data to the output buffer
714 * always check the length and will never write off the end of the
715 * output buffer. If an attempt to add data that will not fit is made,
716 * an internal error flag will be set and further attempts to add data
717 * will not do anything.
718 *
719 * There is no way to ever write off the end of that buffer when
720 * calling the @c UsefulOutBuf_AddXxx() and
721 * @c UsefulOutBuf_InsertXxx() functions.
722 *
723 * The functions to add data do not report success of failure. The
724 * caller only needs to check for an error in the final call, either
725 * UsefulOutBuf_OutUBuf() or UsefulOutBuf_CopyOut() to get the
726 * result. This makes the calling code cleaner.
727 *
728 * There is a utility function to get the error status anytime along
729 * the way for a special circumstance. There are functions to see how
730 * much room is left and see if some data will fit too, but their use
731 * is generally unnecessary.
732 *
733 * The general call flow is:
734 *
735 * - Initialize by calling @ref UsefulOutBuf_Init(). The output
736 * buffer given to it can be from the heap, stack or
737 * otherwise. @ref UsefulOutBuf_MakeOnStack is a convenience
738 * macro that makes a buffer on the stack and initializes it.
739 *
740 * - Call methods like UsefulOutBuf_InsertString(),
741 * UsefulOutBuf_AppendUint32() and UsefulOutBuf_InsertUsefulBuf()
742 * to output data. The append calls add data to the end of the
743 * valid data. The insert calls take a position argument.
744 *
745 * - Call UsefulOutBuf_OutUBuf() or UsefulOutBuf_CopyOut() to see
746 * there were no errors and to get the serialized output bytes.
747 *
748 * @ref UsefulOutBuf can be used in a size calculation mode to
749 * calculate the size of output that would be generated. This is
750 * useful to calculate the size of a buffer that is to be allocated to
751 * hold the output. To use @ref UsefulOutBuf in this mode, call
752 * UsefulOutBuf_Init() with the @c Storage @ref UsefulBuf as
753 * @c (UsefulBuf){NULL, MAX_UINT32}. Then call all the Insert and Add
754 * functions. No attempt will be made to actually copy data, so only
755 * the lengths have to be valid for inputs to these calls.
756 *
757 * Methods like UsefulOutBuf_InsertUint64() always output in network
758 * bytes order (big endian).
759 *
760 * The possible errors are:
761 *
762 * - The @ref UsefulOutBuf was not initialized or was corrupted.
763 *
764 * - An attempt was made to add data that will not fit.
765 *
766 * - An attempt was made to insert data at a position beyond the end of
767 * the buffer.
768 *
769 * - An attempt was made to insert data at a position beyond the valid
770 * data in the buffer.
771 *
772 * Some inexpensive simple sanity checks are performed before every
773 * data addition to guard against use of an uninitialized or corrupted
774 * UsefulOutBuf.
775 *
776 * @ref UsefulOutBuf has been used to create a CBOR encoder. The CBOR
777 * encoder has almost no pointer manipulation in it, is easier to
778 * read, and easier to review.
779 *
780 * A @ref UsefulOutBuf is small and can go on the stack:
781 * - 32 bytes (27 bytes plus alignment padding) on a 64-bit CPU
782 * - 16 bytes (15 bytes plus alignment padding) on a 32-bit CPU
Michael Eckel5c531332020-03-02 01:35:30 +0100783 */
784typedef struct useful_out_buf {
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700785 /* PRIVATE DATA STRUCTURE */
786 UsefulBuf UB; /* Memory that is being output to */
787 size_t data_len; /* length of the valid data, the insertion point */
788 uint16_t magic; /* Used to detect corruption and lack
789 * of initialization */
Michael Eckel5c531332020-03-02 01:35:30 +0100790 uint8_t err;
791} UsefulOutBuf;
792
793
794/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700795 * @brief Initialize and supply the actual output buffer.
796 *
797 * @param[out] pUOutBuf The @ref UsefulOutBuf to initialize.
798 * @param[in] Storage Buffer to output into.
799 *
800 * This initializes the @ref UsefulOutBuf with storage, sets the
801 * current position to the beginning of the buffer and clears the
802 * error state.
803 *
804 * This must be called before the @ref UsefulOutBuf is used.
Michael Eckel5c531332020-03-02 01:35:30 +0100805 */
806void UsefulOutBuf_Init(UsefulOutBuf *pUOutBuf, UsefulBuf Storage);
807
808
809/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700810 * 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.
Michael Eckel5c531332020-03-02 01:35:30 +0100813 */
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/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700821 * @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
826 * clears 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.
Michael Eckel5c531332020-03-02 01:35:30 +0100832 */
833static inline void UsefulOutBuf_Reset(UsefulOutBuf *pUOutBuf);
834
835
836/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700837 * @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
845 * and so on.
846 *
847 * Generally, there is no need to call this for most uses of @ref
848 * UsefulOutBuf.
Michael Eckel5c531332020-03-02 01:35:30 +0100849 */
850static inline size_t UsefulOutBuf_GetEndPosition(UsefulOutBuf *pUOutBuf);
851
852
853/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700854 * @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, 0 if not.
Michael Eckel5c531332020-03-02 01:35:30 +0100859 */
860static inline int UsefulOutBuf_AtStart(UsefulOutBuf *pUOutBuf);
861
862
863/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700864 * @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
871 * the output buffer. There must be room in the output buffer for all
872 * of @c NewData or an error will occur.
873 *
874 * The insertion point must be between 0 and the current valid
875 * data. If not, an error will occur. Appending data to the output
876 * buffer is achieved by inserting at the end of the valid data. This
877 * can be 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
881 * to 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
887 * UsefulOutBuf. No error is returned. All subsequent attempts to add
888 * data will do nothing.
889 *
890 * The intended use is that all additions are made without checking
891 * for 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.
Michael Eckel5c531332020-03-02 01:35:30 +0100894 */
895void UsefulOutBuf_InsertUsefulBuf(UsefulOutBuf *pUOutBuf,
896 UsefulBufC NewData,
897 size_t uPos);
898
899
900/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700901 * @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.
Michael Eckel5c531332020-03-02 01:35:30 +0100911 */
912static inline void UsefulOutBuf_InsertData(UsefulOutBuf *pUOutBuf,
913 const void *pBytes,
914 size_t uLen,
915 size_t uPos);
916
917
918/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700919 * @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.
Michael Eckel5c531332020-03-02 01:35:30 +0100924 */
925static inline void UsefulOutBuf_InsertString(UsefulOutBuf *pUOutBuf,
926 const char *szString,
927 size_t uPos);
928
929
930/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700931 * @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
938 * with the difference being a single byte is to be inserted.
Michael Eckel5c531332020-03-02 01:35:30 +0100939 */
940static inline void UsefulOutBuf_InsertByte(UsefulOutBuf *pUOutBuf,
941 uint8_t byte,
942 size_t uPos);
943
944
945/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700946 * @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
953 * with the difference being a two-byte integer is to be inserted.
954 *
955 * The integer will be inserted in network byte order (big endian).
Michael Eckel5c531332020-03-02 01:35:30 +0100956 */
957static inline void UsefulOutBuf_InsertUint16(UsefulOutBuf *pUOutBuf,
958 uint16_t uInteger16,
959 size_t uPos);
960
961
962/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700963 * @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
970 * with the difference being a four-byte integer is to be inserted.
971 *
972 * The integer will be inserted in network byte order (big endian).
Michael Eckel5c531332020-03-02 01:35:30 +0100973 */
974static inline void UsefulOutBuf_InsertUint32(UsefulOutBuf *pUOutBuf,
975 uint32_t uInteger32,
976 size_t uPos);
977
978
979/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700980 * @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
987 * with the difference being an eight-byte integer is to be inserted.
988 *
989 * The integer will be inserted in network byte order (big endian).
Michael Eckel5c531332020-03-02 01:35:30 +0100990 */
991static inline void UsefulOutBuf_InsertUint64(UsefulOutBuf *pUOutBuf,
992 uint64_t uInteger64,
993 size_t uPos);
994
995
996/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -0700997 * @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
1004 * with the difference being a @c float is to be inserted.
1005 *
1006 * The @c float will be inserted in network byte order (big endian).
Michael Eckel5c531332020-03-02 01:35:30 +01001007 */
1008static inline void UsefulOutBuf_InsertFloat(UsefulOutBuf *pUOutBuf,
1009 float f,
1010 size_t uPos);
1011
1012
1013/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001014 * @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
1021 * with the difference being a @c double is to be inserted.
1022 *
1023 * The @c double will be inserted in network byte order (big endian).
Michael Eckel5c531332020-03-02 01:35:30 +01001024 */
1025static inline void UsefulOutBuf_InsertDouble(UsefulOutBuf *pUOutBuf,
1026 double d,
1027 size_t uPos);
1028
1029
1030/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001031 * @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 */
Michael Eckel5c531332020-03-02 01:35:30 +01001039static inline void UsefulOutBuf_AppendUsefulBuf(UsefulOutBuf *pUOutBuf,
1040 UsefulBufC NewData);
1041
1042
1043/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001044 * @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 with
1051 * the insertion point at the end of the valid data.
Michael Eckel5c531332020-03-02 01:35:30 +01001052 */
1053static inline void UsefulOutBuf_AppendData(UsefulOutBuf *pUOutBuf,
1054 const void *pBytes,
1055 size_t uLen);
1056
1057
1058/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001059 * @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.
Michael Eckel5c531332020-03-02 01:35:30 +01001063 */
1064static inline void UsefulOutBuf_AppendString(UsefulOutBuf *pUOutBuf,
1065 const char *szString);
1066
1067
1068/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001069 * @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.
Michael Eckel5c531332020-03-02 01:35:30 +01001076 */
1077static inline void UsefulOutBuf_AppendByte(UsefulOutBuf *pUOutBuf,
1078 uint8_t byte);
1079
1080
1081/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001082 * @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).
Michael Eckel5c531332020-03-02 01:35:30 +01001091 */
1092static inline void UsefulOutBuf_AppendUint16(UsefulOutBuf *pUOutBuf,
1093 uint16_t uInteger16);
1094
1095
1096/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001097 * @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).
Michael Eckel5c531332020-03-02 01:35:30 +01001106 */
1107static inline void UsefulOutBuf_AppendUint32(UsefulOutBuf *pUOutBuf,
1108 uint32_t uInteger32);
1109
1110
1111/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001112 * @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).
Michael Eckel5c531332020-03-02 01:35:30 +01001121 */
1122static inline void UsefulOutBuf_AppendUint64(UsefulOutBuf *pUOutBuf,
1123 uint64_t uInteger64);
1124
1125
1126/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001127 * @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 with
1133 * the insertion point at the end of the valid data.
1134 *
1135 * The float will be appended in network byte order (big endian).
Michael Eckel5c531332020-03-02 01:35:30 +01001136 */
1137static inline void UsefulOutBuf_AppendFloat(UsefulOutBuf *pUOutBuf,
1138 float f);
1139
1140
1141/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001142 * @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).
Michael Eckel5c531332020-03-02 01:35:30 +01001151 */
1152static inline void UsefulOutBuf_AppendDouble(UsefulOutBuf *pUOutBuf,
1153 double d);
1154
1155
1156/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001157 * @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 returns the error status since a call to either
1164 * UsefulOutBuf_Reset() of UsefulOutBuf_Init(). Once a @ref UsefulOutBuf
1165 * goes into the error state, it will stay until one of those
1166 * functions is called.
1167 *
1168 * Possible error conditions are:
1169 * - bytes to be inserted will not fit
1170 * - insertion point is out of buffer or past valid data
1171 * - current position is off end of buffer (probably corrupted or uninitialized)
1172 * - detect corruption / uninitialized by bad magic number
Michael Eckel5c531332020-03-02 01:35:30 +01001173 */
1174static inline int UsefulOutBuf_GetError(UsefulOutBuf *pUOutBuf);
1175
1176
1177/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001178 * @brief Returns number of bytes unused used in the output buffer.
1179 *
1180 * @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
1181 *
1182 * @return Number of unused bytes or zero.
1183 *
1184 * Because of the error handling strategy and checks in
1185 * UsefulOutBuf_InsertUsefulBuf() it is usually not necessary to use
1186 * this.
Michael Eckel5c531332020-03-02 01:35:30 +01001187 */
1188static inline size_t UsefulOutBuf_RoomLeft(UsefulOutBuf *pUOutBuf);
1189
1190
1191/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001192 *@brief Returns 1 if some number of bytes will fit in the @ref UsefulOutBuf.
1193 *
1194 * @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf
1195 * @param[in] uLen Number of bytes for which to check
1196 *
1197 * @return 1 if @c uLen bytes will fit, 0 if not.
1198 *
1199 * Because of the error handling strategy and checks in
1200 * UsefulOutBuf_InsertUsefulBuf() it is usually not necessary to use
1201 * this.
Michael Eckel5c531332020-03-02 01:35:30 +01001202 */
1203static inline int UsefulOutBuf_WillItFit(UsefulOutBuf *pUOutBuf, size_t uLen);
1204
1205
1206 /**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001207 * @brief Returns 1 if buffer given to UsefulOutBuf_Init() was @c NULL.
1208 *
1209 * @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf
1210 *
1211 * @return 1 if buffer given to UsefulOutBuf_Init() was @c NULL.
1212 *
1213 * Giving a @c NULL output buffer to UsefulOutBuf_Init() is used when
1214 * just calculating the length of the encoded data.
1215 */
Michael Eckel5c531332020-03-02 01:35:30 +01001216static inline int UsefulOutBuf_IsBufferNULL(UsefulOutBuf *pUOutBuf);
1217
1218
1219/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001220 * @brief Returns the resulting valid data in a UsefulOutBuf
1221 *
1222 * @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
1223 *
1224 * @return The valid data in @ref UsefulOutBuf or
1225 * @ref NULLUsefulBufC if there was an error adding data.
1226 *
1227 * The storage for the returned data is the @c Storage parameter
1228 * passed to UsefulOutBuf_Init(). See also UsefulOutBuf_CopyOut().
1229 *
1230 * This can be called anytime and many times to get intermediate
1231 * results. It doesn't change the data or reset the current position,
1232 * so further data can be added.
Michael Eckel5c531332020-03-02 01:35:30 +01001233 */
1234UsefulBufC UsefulOutBuf_OutUBuf(UsefulOutBuf *pUOutBuf);
1235
1236
1237/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001238 * @brief Copies the valid data into a supplied buffer
1239 *
1240 * @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
1241 * @param[out] Dest The destination buffer to copy into.
1242 *
1243 * @return Pointer and length of copied data or @c NULLUsefulBufC
1244 * if it will not fit in the @c Dest buffer or the error
1245 * state was entered.
1246 *
1247 * This is the same as UsefulOutBuf_OutUBuf() except it copies the
1248 * data to @c Dest.
1249 */
Michael Eckel5c531332020-03-02 01:35:30 +01001250UsefulBufC UsefulOutBuf_CopyOut(UsefulOutBuf *pUOutBuf, UsefulBuf Dest);
1251
1252
1253
1254
1255/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001256 * @ref UsefulInputBuf is the counterpart to @ref UsefulOutBuf. It is
1257 * for parsing data received. Initialize it with the data from the
1258 * network. Then use the functions like UsefulInputBuf_GetBytes() to
1259 * get data chunks of various types. A position cursor is maintained
1260 * internally.
1261 *
1262 * As long as the functions here are used, there will never be any
1263 * reference off the end of the given buffer (except
1264 * UsefulInputBuf_SetBufferLength()). This is true even if they are
1265 * called incorrectly, an attempt is made to seek off the end of the
1266 * buffer or such. This makes it easier to write safe and correct
1267 * code. For example, the QCBOR decoder implementation is safer and
1268 * easier to review through its use of @ref UsefulInputBuf.
1269 *
1270 * @ref UsefulInputBuf maintains an internal error state. The
1271 * intended use is fetching data chunks without any error checks until
1272 * the end. If there was any error, such as an attempt to fetch data
1273 * off the end, the error state is entered and no further data will be
1274 * returned. In the error state the @c UsefulInputBuf_GetXxxx()
1275 * functions return 0, or @c NULL or @ref NULLUsefulBufC. As long as
1276 * null is not dereferenced, the error check can be put off until the
1277 * end, simplifying the calling code.
1278 *
1279 * The integer and float parsing expects network byte order (big
1280 * endian). Network byte order is what is used by TCP/IP, CBOR and
1281 * most internet protocols.
1282 *
1283 * Lots of inline functions are used to keep code size down. The
1284 * optimizer, particularly with the @c -Os or @c -O3, also reduces
1285 * code size a lot. The only non-inline code is
1286 * UsefulInputBuf_GetBytes(). It is less than 100 bytes so use of
1287 * @ref UsefulInputBuf doesn't add much code for all the messy
1288 * hard-to-get right issues with parsing binary protocols in C that it
1289 * solves.
1290 *
1291 * The parse context size is:
1292 * - 64-bit machine: 16 + 8 + 2 + 1 (+ 5 bytes padding to align) = 32 bytes
1293 * - 32-bit machine: 8 + 4 + 2 + 1 (+ 1 byte padding to align) = 16 bytes
Michael Eckel5c531332020-03-02 01:35:30 +01001294 */
1295typedef struct useful_input_buf {
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001296 /* PRIVATE DATA STRUCTURE */
1297 UsefulBufC UB; /* Data being parsed */
1298 size_t cursor; /* Current offset in data being parse */
1299 uint16_t magic; /* Check for corrupted or uninitialized UsefulInputBuf */
1300 uint8_t err; /* Set request goes off end or magic number is bad */
Michael Eckel5c531332020-03-02 01:35:30 +01001301} UsefulInputBuf;
1302
1303#define UIB_MAGIC (0xB00F)
1304
1305
1306/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001307 * @brief Initialize the @ref UsefulInputBuf structure before use.
1308 *
1309 * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf.
1310 * @param[in] UB The data to parse.
Michael Eckel5c531332020-03-02 01:35:30 +01001311 */
1312static inline void UsefulInputBuf_Init(UsefulInputBuf *pUInBuf, UsefulBufC UB);
1313
1314
1315/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001316 * @brief Returns current position in input buffer.
1317 *
1318 * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf.
1319 *
1320 * @return Integer position of the cursor.
1321 *
1322 * The position that the next bytes will be returned from.
Michael Eckel5c531332020-03-02 01:35:30 +01001323 */
1324static size_t UsefulInputBuf_Tell(UsefulInputBuf *pUInBuf);
1325
1326
1327/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001328 * @brief Sets the current position in input buffer.
1329 *
1330 * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf.
1331 * @param[in] uPos Position to set to.
1332 *
1333 * If the position is off the end of the input buffer, the error state
1334 * is entered.
1335 *
1336 * Seeking to a valid position in the buffer will not reset the error
1337 * state. Only re-initialization will do that.
Michael Eckel5c531332020-03-02 01:35:30 +01001338 */
1339static void UsefulInputBuf_Seek(UsefulInputBuf *pUInBuf, size_t uPos);
1340
1341
1342/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001343 * @brief Returns the number of bytes from the cursor to the end of the buffer,
1344 * the unconsumed bytes.
1345 *
1346 * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf.
1347 *
1348 * @return Number of bytes unconsumed or 0 on error.
1349 *
1350 * Returns 0 if the cursor is invalid or corruption of the
1351 * @ref UsefulInputBuf structure is detected.
Michael Eckel5c531332020-03-02 01:35:30 +01001352 */
1353static size_t UsefulInputBuf_BytesUnconsumed(UsefulInputBuf *pUInBuf);
1354
1355
1356/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001357 * @brief Check if there are unconsumed bytes.
1358 *
1359 * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf.
1360 * @param[in] uLen Number of bytes to check availability for.
1361 *
1362 * @return 1 if @c uLen bytes are available after the cursor, and 0 if not.
Michael Eckel5c531332020-03-02 01:35:30 +01001363 */
1364static int UsefulInputBuf_BytesAvailable(UsefulInputBuf *pUInBuf, size_t uLen);
1365
1366
1367/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001368 * @brief Convert a pointer to an offset with bounds checking.
1369 *
1370 * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf.
1371 * @param[in] p Pointer to convert to offset.
1372 *
1373 * @return SIZE_MAX if @c p is out of range, the byte offset if not.
1374 */
Laurence Lundbladecf41c522021-02-20 10:19:07 -07001375static inline size_t UsefulInputBuf_PointerToOffset(UsefulInputBuf *pUInBuf, const void *p);
1376
1377
1378/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001379 * @brief Get pointer to bytes out of the input buffer.
1380 *
1381 * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf.
1382 * @param[in] uNum Number of bytes to get.
1383 *
1384 * @return Pointer to bytes.
1385 *
1386 * This consumes @c uNum bytes from the input buffer. This returns a
1387 * pointer to the start of the @c uNum bytes.
1388 *
1389 * If there are not @c uNum bytes in the input buffer, @c NULL will be
1390 * returned and the error state is entered.
1391 *
1392 * This advances the position cursor by @c uNum bytes.
Michael Eckel5c531332020-03-02 01:35:30 +01001393 */
1394const void * UsefulInputBuf_GetBytes(UsefulInputBuf *pUInBuf, size_t uNum);
1395
1396
1397/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001398 * @brief Get @ref UsefulBuf out of the input buffer.
1399 *
1400 * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf.
1401 * @param[in] uNum Number of bytes to get.
1402 *
1403 * @return A @ref UsefulBufC with ptr and length of bytes consumed.
1404 *
1405 * This consumes @c uNum bytes from the input buffer and returns the
1406 * pointer and length for them as a @ref UsefulBufC. The length
1407 * returned will always be @c uNum. The position cursor is advanced by
1408 * @c uNum bytes.
1409 *
1410 * If there are not @c uNum bytes in the input buffer, @ref
1411 * NULLUsefulBufC will be returned and the error state is entered.
Michael Eckel5c531332020-03-02 01:35:30 +01001412 */
1413static inline UsefulBufC UsefulInputBuf_GetUsefulBuf(UsefulInputBuf *pUInBuf, size_t uNum);
1414
1415
1416/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001417 * @brief Get a byte out of the input buffer.
1418 *
1419 * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf.
1420 *
1421 * @return The byte.
1422 *
1423 * This consumes 1 byte from the input buffer, returns it and advances
1424 * the position cursor by 1.
1425 *
1426 * If there is not 1 byte in the buffer, 0 will be returned for the
1427 * byte and the error state is entered. To know if the 0 returned was
1428 * in error or the real value, the error state must be checked. If
1429 * possible, put this off until all values are retrieved to have
1430 * smaller and simpler code, but if not possible
1431 * UsefulInputBuf_GetError() can be called. Also, in the error state
1432 * UsefulInputBuf_GetBytes() returns @c NULL *or the @c ptr from
1433 * UsefulInputBuf_GetUsefulBuf() is @c NULL.
Michael Eckel5c531332020-03-02 01:35:30 +01001434 */
1435static inline uint8_t UsefulInputBuf_GetByte(UsefulInputBuf *pUInBuf);
1436
1437
1438/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001439 * @brief Get a @c uint16_t out of the input buffer.
1440 *
1441 * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf.
1442 *
1443 * @return The @c uint16_t.
1444 *
1445 * See UsefulInputBuf_GetByte(). This works the same, except it returns
1446 * a @c uint16_t and two bytes are consumed.
1447 *
1448 * The input bytes are interpreted in network order (big endian).
Michael Eckel5c531332020-03-02 01:35:30 +01001449 */
1450static inline uint16_t UsefulInputBuf_GetUint16(UsefulInputBuf *pUInBuf);
1451
1452
1453/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001454 * @brief Get a @c uint32_t out of the input buffer.
1455 *
1456 * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf.
1457 *
1458 * @return The @c uint32_t.
1459 *
1460 * See UsefulInputBuf_GetByte(). This works the same, except it
1461 * returns a @c uint32_t and four bytes are consumed.
1462 *
1463 * The input bytes are interpreted in network order (big endian).
Michael Eckel5c531332020-03-02 01:35:30 +01001464 */
1465static uint32_t UsefulInputBuf_GetUint32(UsefulInputBuf *pUInBuf);
1466
1467
1468/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001469 * @brief Get a @c uint64_t out of the input buffer.
1470 *
1471 * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf.
1472 *
1473 * @return The uint64_t.
1474 *
1475 * See UsefulInputBuf_GetByte(). This works the same, except it returns
1476 * a @c uint64_t and eight bytes are consumed.
1477 *
1478 * The input bytes are interpreted in network order (big endian).
Michael Eckel5c531332020-03-02 01:35:30 +01001479 */
1480static uint64_t UsefulInputBuf_GetUint64(UsefulInputBuf *pUInBuf);
1481
1482
1483/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001484 * @brief Get a float out of the input buffer.
1485 *
1486 * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf.
1487 *
1488 * @return The float.
1489 *
1490 * See UsefulInputBuf_GetByte(). This works the same, except it
1491 * returns a float and four bytes are consumed.
1492 *
1493 * The input bytes are interpreted in network order (big endian).
Michael Eckel5c531332020-03-02 01:35:30 +01001494 */
1495static float UsefulInputBuf_GetFloat(UsefulInputBuf *pUInBuf);
1496
1497
1498/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001499 * @brief Get a double out of the input buffer.
1500 *
1501 * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf.
1502 *
1503 * @return The double.
1504 *
1505 * See UsefulInputBuf_GetByte(). This works the same, except it
1506 * returns a double and eight bytes are consumed.
1507 *
1508 * The input bytes are interpreted in network order (big endian).
Michael Eckel5c531332020-03-02 01:35:30 +01001509 */
1510static double UsefulInputBuf_GetDouble(UsefulInputBuf *pUInBuf);
1511
1512
1513/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001514 * @brief Get the error status.
1515 *
1516 * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf.
1517 *
1518 * @return 0 if not in the error state, 1 if in the error state.
1519 *
1520 * This returns whether the @ref UsefulInputBuf is in the
1521 * error state or not.
1522 *
1523 * The error state is entered for one of these reasons:
1524 * - Attempt to fetch data past the end of the buffer
1525 * - Attempt to seek to a position past the end of the buffer
1526 * - Attempt to get data from an uninitialized or corrupt instance
1527 * of @ref UsefulInputBuf
1528 *
1529 * Once in the error state, it can only be cleared by calling
1530 * UsefulInputBuf_Init().
1531 *
1532 * For many use cases, it is possible to only call this once after all
1533 * the @c UsefulInputBuf_GetXxxx() calls have been made. This is
1534 * possible if no reference to the data returned are needed before the
1535 * error state is checked.
1536 *
1537 * In some cases UsefulInputBuf_GetUsefulBuf() or
1538 * UsefulInputBuf_GetBytes() can stand in for this because they return
1539 * @c NULL if the error state has been entered. (The others can't stand
1540 * in because they don't return a clearly distinct error value.)
Michael Eckel5c531332020-03-02 01:35:30 +01001541 */
1542static int UsefulInputBuf_GetError(UsefulInputBuf *pUInBuf);
1543
1544
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001545/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001546 * @brief Gets the input buffer length.
1547 *
1548 * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf.
1549 *
1550 * @return The length of the input buffer.
1551 *
1552 * This returns the length of the input buffer set by
1553 * UsefulInputBuf_Init() or UsefulInputBuf_SetBufferLength().
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07001554 */
1555static inline size_t UsefulInputBuf_GetBufferLength(UsefulInputBuf *pUInBuf);
1556
1557
1558/**
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001559 * @brief Alters the input buffer length (use with caution).
1560 *
1561 * @param[in] pUInBuf Pointer to the @ref UsefulInputBuf.
1562 * @param[in] uNewLen The new length of the input buffer.
1563 *
1564 * This alters the internal remembered length of the input buffer set
1565 * when UsefulInputBuf_Init() was called.
1566 *
1567 * The new length given here should always be equal to or less than
1568 * the length given when UsefulInputBuf_Init() was called. Making it
1569 * larger allows @ref UsefulInputBuf to run off the input buffer.
1570 *
1571 * The typical use is to set a length shorter than that when
1572 * initialized to constrain parsing. If
1573 * UsefulInputBuf_GetBufferLength() was called before this, then the
1574 * original length can be restored with another call to this.
1575 *
1576 * This should be used with caution. It is the only
1577 * @ref UsefulInputBuf method that can violate the safety of input
1578 * buffer parsing.
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001579 */
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07001580static void UsefulInputBuf_SetBufferLength(UsefulInputBuf *pUInBuf, size_t uNewLen);
Michael Eckel5c531332020-03-02 01:35:30 +01001581
1582
Laurence Lundbladef318d172021-08-09 21:10:54 -07001583// TODO: document this; maybe add tests...
1584#if defined(USEFULBUF_CONFIG_BSWAP)
1585#define USEFUL_SWAP32(integer) \
1586 __builtin_bswap32(integer);
1587#else
1588#define USEFUL_SWAP32(integer) \
1589 ((integer & 0xff) >> 24) + \
1590 ((integer & 0xff00) >> 16) + \
1591 ((integer & 0xff0000) >> 8) + \
1592 (integer & 0xff000000)
1593#endif
1594
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001595
1596
Michael Eckel5c531332020-03-02 01:35:30 +01001597/*----------------------------------------------------------
1598 Inline implementations.
1599 */
1600static inline int UsefulBuf_IsNULL(UsefulBuf UB)
1601{
1602 return !UB.ptr;
1603}
1604
1605
1606static inline int UsefulBuf_IsNULLC(UsefulBufC UB)
1607{
1608 return !UB.ptr;
1609}
1610
1611
1612static inline int UsefulBuf_IsEmpty(UsefulBuf UB)
1613{
1614 return !UB.len;
1615}
1616
1617
1618static inline int UsefulBuf_IsEmptyC(UsefulBufC UB)
1619{
1620 return !UB.len;
1621}
1622
1623
1624static inline int UsefulBuf_IsNULLOrEmpty(UsefulBuf UB)
1625{
1626 return UsefulBuf_IsEmpty(UB) || UsefulBuf_IsNULL(UB);
1627}
1628
1629
1630static inline int UsefulBuf_IsNULLOrEmptyC(UsefulBufC UB)
1631{
1632 return UsefulBuf_IsEmptyC(UB) || UsefulBuf_IsNULLC(UB);
1633}
1634
1635
1636static inline UsefulBufC UsefulBuf_Const(const UsefulBuf UB)
1637{
1638 return (UsefulBufC){UB.ptr, UB.len};
1639}
1640
Michael Eckel5c531332020-03-02 01:35:30 +01001641static inline UsefulBuf UsefulBuf_Unconst(const UsefulBufC UBC)
1642{
Laurence Lundbladeb9702452021-03-08 21:02:57 -08001643 /* -Wcast-qual is a good warning flag to use in general. This is
1644 * the one place in UsefulBuf where it needs to be quieted. Since
1645 * clang supports GCC pragmas, this works for clang too. */
1646#pragma GCC diagnostic push
1647#pragma GCC diagnostic ignored "-Wcast-qual"
Michael Eckel5c531332020-03-02 01:35:30 +01001648 return (UsefulBuf){(void *)UBC.ptr, UBC.len};
Laurence Lundbladeb9702452021-03-08 21:02:57 -08001649#pragma GCC diagnostic pop
Michael Eckel5c531332020-03-02 01:35:30 +01001650}
1651
1652
1653static inline UsefulBufC UsefulBuf_FromSZ(const char *szString)
1654{
1655 return ((UsefulBufC) {szString, strlen(szString)});
1656}
1657
1658
1659static inline UsefulBufC UsefulBuf_Copy(UsefulBuf Dest, const UsefulBufC Src)
1660{
1661 return UsefulBuf_CopyOffset(Dest, 0, Src);
1662}
1663
1664
1665static inline UsefulBufC UsefulBuf_Set(UsefulBuf pDest, uint8_t value)
1666{
1667 memset(pDest.ptr, value, pDest.len);
1668 return (UsefulBufC){pDest.ptr, pDest.len};
1669}
1670
1671
1672static inline UsefulBufC UsefulBuf_CopyPtr(UsefulBuf Dest, const void *ptr, size_t len)
1673{
1674 return UsefulBuf_Copy(Dest, (UsefulBufC){ptr, len});
1675}
1676
1677
1678static inline UsefulBufC UsefulBuf_Head(UsefulBufC UB, size_t uAmount)
1679{
1680 if(uAmount > UB.len) {
1681 return NULLUsefulBufC;
1682 }
1683 return (UsefulBufC){UB.ptr, uAmount};
1684}
1685
1686
1687static inline UsefulBufC UsefulBuf_Tail(UsefulBufC UB, size_t uAmount)
1688{
1689 UsefulBufC ReturnValue;
1690
1691 if(uAmount > UB.len) {
1692 ReturnValue = NULLUsefulBufC;
1693 } else if(UB.ptr == NULL) {
1694 ReturnValue = (UsefulBufC){NULL, UB.len - uAmount};
1695 } else {
Laurence Lundbladeb9702452021-03-08 21:02:57 -08001696 ReturnValue = (UsefulBufC){(const uint8_t *)UB.ptr + uAmount, UB.len - uAmount};
Michael Eckel5c531332020-03-02 01:35:30 +01001697 }
1698
1699 return ReturnValue;
1700}
1701
1702
Laurence Lundbladecf41c522021-02-20 10:19:07 -07001703static inline size_t UsefulBuf_PointerToOffset(UsefulBufC UB, const void *p)
1704{
1705 if(UB.ptr == NULL) {
1706 return SIZE_MAX;
1707 }
1708
1709 if(p < UB.ptr) {
1710 /* given pointer is before start of buffer */
1711 return SIZE_MAX;
1712 }
1713
1714 // Cast to size_t (from ptrdiff_t) is OK because of check above
Laurence Lundbladeb9702452021-03-08 21:02:57 -08001715 const size_t uOffset = (size_t)((const uint8_t *)p - (const uint8_t *)UB.ptr);
Laurence Lundbladecf41c522021-02-20 10:19:07 -07001716
1717 if(uOffset >= UB.len) {
1718 /* given pointer is off the end of the buffer */
1719 return SIZE_MAX;
1720 }
1721
1722 return uOffset;
1723}
1724
Michael Eckel5c531332020-03-02 01:35:30 +01001725
1726static inline uint32_t UsefulBufUtil_CopyFloatToUint32(float f)
1727{
1728 uint32_t u32;
1729 memcpy(&u32, &f, sizeof(uint32_t));
1730 return u32;
1731}
1732
1733static inline uint64_t UsefulBufUtil_CopyDoubleToUint64(double d)
1734{
1735 uint64_t u64;
1736 memcpy(&u64, &d, sizeof(uint64_t));
1737 return u64;
1738}
1739
1740static inline double UsefulBufUtil_CopyUint64ToDouble(uint64_t u64)
1741{
1742 double d;
1743 memcpy(&d, &u64, sizeof(uint64_t));
1744 return d;
1745}
1746
1747static inline float UsefulBufUtil_CopyUint32ToFloat(uint32_t u32)
1748{
1749 float f;
1750 memcpy(&f, &u32, sizeof(uint32_t));
1751 return f;
1752}
1753
1754
1755
1756
1757static inline void UsefulOutBuf_Reset(UsefulOutBuf *pMe)
1758{
1759 pMe->data_len = 0;
1760 pMe->err = 0;
1761}
1762
1763
1764static inline size_t UsefulOutBuf_GetEndPosition(UsefulOutBuf *pMe)
1765{
1766 return pMe->data_len;
1767}
1768
1769
1770static inline int UsefulOutBuf_AtStart(UsefulOutBuf *pMe)
1771{
1772 return 0 == pMe->data_len;
1773}
1774
1775
1776static inline void UsefulOutBuf_InsertData(UsefulOutBuf *pMe,
1777 const void *pBytes,
1778 size_t uLen,
1779 size_t uPos)
1780{
1781 UsefulBufC Data = {pBytes, uLen};
1782 UsefulOutBuf_InsertUsefulBuf(pMe, Data, uPos);
1783}
1784
1785
1786static inline void UsefulOutBuf_InsertString(UsefulOutBuf *pMe,
1787 const char *szString,
1788 size_t uPos)
1789{
1790 UsefulOutBuf_InsertUsefulBuf(pMe,
1791 (UsefulBufC){szString, strlen(szString)},
1792 uPos);
1793}
1794
1795
1796static inline void UsefulOutBuf_InsertByte(UsefulOutBuf *me,
1797 uint8_t byte,
1798 size_t uPos)
1799{
1800 UsefulOutBuf_InsertData(me, &byte, 1, uPos);
1801}
1802
1803
Laurence Lundbladef318d172021-08-09 21:10:54 -07001804
Michael Eckel5c531332020-03-02 01:35:30 +01001805static inline void UsefulOutBuf_InsertUint16(UsefulOutBuf *me,
1806 uint16_t uInteger16,
1807 size_t uPos)
1808{
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001809 /* See UsefulOutBuf_InsertUint64() for comments on this code */
Michael Eckel5c531332020-03-02 01:35:30 +01001810
1811 const void *pBytes;
1812
1813#if defined(USEFULBUF_CONFIG_BIG_ENDIAN)
1814 pBytes = &uInteger16;
1815
1816#elif defined(USEFULBUF_CONFIG_HTON)
1817 uint16_t uTmp = htons(uInteger16);
1818 pBytes = &uTmp;
1819
1820#elif defined(USEFULBUF_CONFIG_LITTLE_ENDIAN) && defined(USEFULBUF_CONFIG_BSWAP)
1821 uint16_t uTmp = __builtin_bswap16(uInteger16);
1822 pBytes = &uTmp;
1823
1824#else
1825 uint8_t aTmp[2];
1826
1827 aTmp[0] = (uint8_t)((uInteger16 & 0xff00) >> 8);
1828 aTmp[1] = (uint8_t)(uInteger16 & 0xff);
1829
1830 pBytes = aTmp;
1831#endif
1832
1833 UsefulOutBuf_InsertData(me, pBytes, 2, uPos);
1834}
1835
1836
1837static inline void UsefulOutBuf_InsertUint32(UsefulOutBuf *pMe,
1838 uint32_t uInteger32,
1839 size_t uPos)
1840{
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001841 /* See UsefulOutBuf_InsertUint64() for comments on this code */
Michael Eckel5c531332020-03-02 01:35:30 +01001842
1843 const void *pBytes;
1844
1845#if defined(USEFULBUF_CONFIG_BIG_ENDIAN)
1846 pBytes = &uInteger32;
1847
1848#elif defined(USEFULBUF_CONFIG_HTON)
1849 uint32_t uTmp = htonl(uInteger32);
1850 pBytes = &uTmp;
1851
Laurence Lundbladef318d172021-08-09 21:10:54 -07001852#elif defined(USEFULBUF_CONFIG_LITTLE_ENDIAN)
1853 uint32_t uTmp = XSWAP(uInteger32);
Michael Eckel5c531332020-03-02 01:35:30 +01001854 pBytes = &uTmp;
1855
1856#else
Michael Eckel5c531332020-03-02 01:35:30 +01001857
Laurence Lundbladef318d172021-08-09 21:10:54 -07001858 uint32_t uTmp =
1859 ((uInteger32 & 0xff) >> 24) + \
1860 ((uInteger32 & 0xff00) >> 16) + \
1861 ((uInteger32 & 0xff0000) >> 8) + \
1862 (uInteger32 & 0xff000000);
Michael Eckel5c531332020-03-02 01:35:30 +01001863
Laurence Lundbladef318d172021-08-09 21:10:54 -07001864 pBytes = &uTmp;
1865
1866
Michael Eckel5c531332020-03-02 01:35:30 +01001867#endif
1868
1869 UsefulOutBuf_InsertData(pMe, pBytes, 4, uPos);
1870}
1871
1872static inline void UsefulOutBuf_InsertUint64(UsefulOutBuf *pMe,
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001873 uint64_t uInteger64,
1874 size_t uPos)
Michael Eckel5c531332020-03-02 01:35:30 +01001875{
1876 const void *pBytes;
1877
1878#if defined(USEFULBUF_CONFIG_BIG_ENDIAN)
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001879 /* We have been told explicitly we are running on a big-endian
1880 * machine. Network byte order is big endian, so just copy. There
1881 * is no issue with alignment here because uInteger64 is always
1882 * aligned (and it doesn't matter if pBytes is aligned).
1883 */
Michael Eckel5c531332020-03-02 01:35:30 +01001884 pBytes = &uInteger64;
1885
1886#elif defined(USEFULBUF_CONFIG_HTON)
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001887 /* Use system function to handle big- and little-endian. This works
1888 * on both big- and little-endian machines, but hton() is not
1889 * always available or in a standard place so it is not used by
1890 * default. With some compilers and CPUs the code for this is very
1891 * compact through use of a special swap instruction and on
1892 * big-endian machines hton() will reduce to nothing.
1893 */
Michael Eckel5c531332020-03-02 01:35:30 +01001894 uint64_t uTmp = htonll(uInteger64);
1895
1896 pBytes = &uTmp;
1897
1898#elif defined(USEFULBUF_CONFIG_LITTLE_ENDIAN) && defined(USEFULBUF_CONFIG_BSWAP)
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001899 /* Use built-in function for byte swapping. This usually compiles
1900 * to an efficient special byte swap instruction. Unlike hton() it
1901 * does not do this conditionally on the CPU endianness, so this
1902 * code is also conditional on USEFULBUF_CONFIG_LITTLE_ENDIAN
1903 */
Michael Eckel5c531332020-03-02 01:35:30 +01001904 uint64_t uTmp = __builtin_bswap64(uInteger64);
1905
1906 pBytes = &uTmp;
1907
1908#else
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001909 /* Default which works on every CPU with no dependency on anything
1910 * from the CPU, compiler, libraries or OS. This always works, but
1911 * it is usually a little larger and slower than hton().
1912 */
Michael Eckel5c531332020-03-02 01:35:30 +01001913 uint8_t aTmp[8];
1914
1915 aTmp[0] = (uint8_t)((uInteger64 & 0xff00000000000000) >> 56);
1916 aTmp[1] = (uint8_t)((uInteger64 & 0xff000000000000) >> 48);
1917 aTmp[2] = (uint8_t)((uInteger64 & 0xff0000000000) >> 40);
1918 aTmp[3] = (uint8_t)((uInteger64 & 0xff00000000) >> 32);
1919 aTmp[4] = (uint8_t)((uInteger64 & 0xff000000) >> 24);
1920 aTmp[5] = (uint8_t)((uInteger64 & 0xff0000) >> 16);
1921 aTmp[6] = (uint8_t)((uInteger64 & 0xff00) >> 8);
1922 aTmp[7] = (uint8_t)(uInteger64 & 0xff);
1923
1924 pBytes = aTmp;
1925#endif
1926
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001927 /* Do the insert */
Michael Eckel5c531332020-03-02 01:35:30 +01001928 UsefulOutBuf_InsertData(pMe, pBytes, sizeof(uint64_t), uPos);
1929}
1930
1931
1932static inline void UsefulOutBuf_InsertFloat(UsefulOutBuf *pMe,
1933 float f,
1934 size_t uPos)
1935{
1936 UsefulOutBuf_InsertUint32(pMe, UsefulBufUtil_CopyFloatToUint32(f), uPos);
1937}
1938
1939
1940static inline void UsefulOutBuf_InsertDouble(UsefulOutBuf *pMe,
1941 double d,
1942 size_t uPos)
1943{
1944 UsefulOutBuf_InsertUint64(pMe, UsefulBufUtil_CopyDoubleToUint64(d), uPos);
1945}
1946
1947
1948static inline void UsefulOutBuf_AppendUsefulBuf(UsefulOutBuf *pMe,
1949 UsefulBufC NewData)
1950{
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07001951 /* An append is just a insert at the end */
Michael Eckel5c531332020-03-02 01:35:30 +01001952 UsefulOutBuf_InsertUsefulBuf(pMe, NewData, UsefulOutBuf_GetEndPosition(pMe));
1953}
1954
1955
1956static inline void UsefulOutBuf_AppendData(UsefulOutBuf *pMe,
1957 const void *pBytes,
1958 size_t uLen)
1959{
1960 UsefulBufC Data = {pBytes, uLen};
1961 UsefulOutBuf_AppendUsefulBuf(pMe, Data);
1962}
1963
1964
1965static inline void UsefulOutBuf_AppendString(UsefulOutBuf *pMe,
1966 const char *szString)
1967{
1968 UsefulOutBuf_AppendUsefulBuf(pMe, (UsefulBufC){szString, strlen(szString)});
1969}
1970
1971
1972static inline void UsefulOutBuf_AppendByte(UsefulOutBuf *pMe,
1973 uint8_t byte)
1974{
1975 UsefulOutBuf_AppendData(pMe, &byte, 1);
1976}
1977
1978
1979static inline void UsefulOutBuf_AppendUint16(UsefulOutBuf *pMe,
1980 uint16_t uInteger16)
1981{
1982 UsefulOutBuf_InsertUint16(pMe, uInteger16, UsefulOutBuf_GetEndPosition(pMe));
1983}
1984
1985static inline void UsefulOutBuf_AppendUint32(UsefulOutBuf *pMe,
1986 uint32_t uInteger32)
1987{
1988 UsefulOutBuf_InsertUint32(pMe, uInteger32, UsefulOutBuf_GetEndPosition(pMe));
1989}
1990
1991
1992static inline void UsefulOutBuf_AppendUint64(UsefulOutBuf *pMe,
1993 uint64_t uInteger64)
1994{
1995 UsefulOutBuf_InsertUint64(pMe, uInteger64, UsefulOutBuf_GetEndPosition(pMe));
1996}
1997
1998
1999static inline void UsefulOutBuf_AppendFloat(UsefulOutBuf *pMe,
2000 float f)
2001{
2002 UsefulOutBuf_InsertFloat(pMe, f, UsefulOutBuf_GetEndPosition(pMe));
2003}
2004
2005
2006static inline void UsefulOutBuf_AppendDouble(UsefulOutBuf *pMe,
2007 double d)
2008{
2009 UsefulOutBuf_InsertDouble(pMe, d, UsefulOutBuf_GetEndPosition(pMe));
2010}
2011
2012
2013static inline int UsefulOutBuf_GetError(UsefulOutBuf *pMe)
2014{
2015 return pMe->err;
2016}
2017
2018
2019static inline size_t UsefulOutBuf_RoomLeft(UsefulOutBuf *pMe)
2020{
2021 return pMe->UB.len - pMe->data_len;
2022}
2023
2024
2025static inline int UsefulOutBuf_WillItFit(UsefulOutBuf *pMe, size_t uLen)
2026{
2027 return uLen <= UsefulOutBuf_RoomLeft(pMe);
2028}
2029
2030
2031static inline int UsefulOutBuf_IsBufferNULL(UsefulOutBuf *pMe)
2032{
2033 return pMe->UB.ptr == NULL;
2034}
2035
2036
2037
2038static inline void UsefulInputBuf_Init(UsefulInputBuf *pMe, UsefulBufC UB)
2039{
2040 pMe->cursor = 0;
2041 pMe->err = 0;
2042 pMe->magic = UIB_MAGIC;
2043 pMe->UB = UB;
2044}
2045
2046static inline size_t UsefulInputBuf_Tell(UsefulInputBuf *pMe)
2047{
2048 return pMe->cursor;
2049}
2050
2051
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07002052static inline size_t UsefulInputBuf_GetBufferLength(UsefulInputBuf *pMe)
Laurence Lundblade0750fc42020-06-20 21:02:34 -07002053{
2054 return pMe->UB.len;
2055}
2056
2057
Michael Eckel5c531332020-03-02 01:35:30 +01002058static inline void UsefulInputBuf_Seek(UsefulInputBuf *pMe, size_t uPos)
2059{
2060 if(uPos > pMe->UB.len) {
2061 pMe->err = 1;
2062 } else {
2063 pMe->cursor = uPos;
2064 }
2065}
2066
2067
2068static inline size_t UsefulInputBuf_BytesUnconsumed(UsefulInputBuf *pMe)
2069{
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07002070 /* Code Reviewers: THIS FUNCTION DOES POINTER MATH */
Michael Eckel5c531332020-03-02 01:35:30 +01002071
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07002072 /* Magic number is messed up. Either the structure got overwritten
2073 * or was never initialized.
2074 */
Michael Eckel5c531332020-03-02 01:35:30 +01002075 if(pMe->magic != UIB_MAGIC) {
2076 return 0;
2077 }
2078
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07002079 /* The cursor is off the end of the input buffer given.
2080 * Presuming there are no bugs in this code, this should never happen.
2081 * If it so, the struct was corrupted. The check is retained as
2082 * as a defense in case there is a bug in this code or the struct is
2083 * corrupted.
2084 */
Michael Eckel5c531332020-03-02 01:35:30 +01002085 if(pMe->cursor > pMe->UB.len) {
2086 return 0;
2087 }
2088
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07002089 /* subtraction can't go negative because of check above */
Michael Eckel5c531332020-03-02 01:35:30 +01002090 return pMe->UB.len - pMe->cursor;
2091}
2092
2093
2094static inline int UsefulInputBuf_BytesAvailable(UsefulInputBuf *pMe, size_t uLen)
2095{
2096 return UsefulInputBuf_BytesUnconsumed(pMe) >= uLen ? 1 : 0;
2097}
2098
2099
Laurence Lundbladecf41c522021-02-20 10:19:07 -07002100static inline size_t UsefulInputBuf_PointerToOffset(UsefulInputBuf *pUInBuf, const void *p)
2101{
2102 return UsefulBuf_PointerToOffset(pUInBuf->UB, p);
2103}
2104
2105
Michael Eckel5c531332020-03-02 01:35:30 +01002106static inline UsefulBufC UsefulInputBuf_GetUsefulBuf(UsefulInputBuf *pMe, size_t uNum)
2107{
2108 const void *pResult = UsefulInputBuf_GetBytes(pMe, uNum);
2109 if(!pResult) {
2110 return NULLUsefulBufC;
2111 } else {
2112 return (UsefulBufC){pResult, uNum};
2113 }
2114}
2115
2116
2117static inline uint8_t UsefulInputBuf_GetByte(UsefulInputBuf *pMe)
2118{
2119 const void *pResult = UsefulInputBuf_GetBytes(pMe, sizeof(uint8_t));
2120
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07002121 /* The ternary operator is subject to integer promotion, because
2122 * the operands are smaller than int, so cast back to uint8_t is
2123 * needed to be completely explicit about types (for static
2124 * analyzers).
2125 */
Laurence Lundbladeb9702452021-03-08 21:02:57 -08002126 return (uint8_t)(pResult ? *(const uint8_t *)pResult : 0);
Michael Eckel5c531332020-03-02 01:35:30 +01002127}
2128
2129static inline uint16_t UsefulInputBuf_GetUint16(UsefulInputBuf *pMe)
2130{
2131 const uint8_t *pResult = (const uint8_t *)UsefulInputBuf_GetBytes(pMe, sizeof(uint16_t));
2132
2133 if(!pResult) {
2134 return 0;
2135 }
2136
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07002137 /* See UsefulInputBuf_GetUint64() for comments on this code */
Michael Eckel5c531332020-03-02 01:35:30 +01002138#if defined(USEFULBUF_CONFIG_BIG_ENDIAN) || defined(USEFULBUF_CONFIG_HTON) || defined(USEFULBUF_CONFIG_BSWAP)
2139 uint16_t uTmp;
2140 memcpy(&uTmp, pResult, sizeof(uint16_t));
2141
2142#if defined(USEFULBUF_CONFIG_BIG_ENDIAN)
2143 return uTmp;
2144
2145#elif defined(USEFULBUF_CONFIG_HTON)
2146 return ntohs(uTmp);
2147
2148#else
2149 return __builtin_bswap16(uTmp);
2150
2151#endif
2152
2153#else
2154
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07002155 /* The operations here are subject to integer promotion because the
2156 * operands are smaller than int. They will be promoted to unsigned
2157 * int for the shift and addition. The cast back to uint16_t is is
2158 * needed to be completely explicit about types (for static
2159 * analyzers).
2160 */
Michael Eckel5c531332020-03-02 01:35:30 +01002161 return (uint16_t)((pResult[0] << 8) + pResult[1]);
2162
2163#endif
2164}
2165
2166
2167static inline uint32_t UsefulInputBuf_GetUint32(UsefulInputBuf *pMe)
2168{
2169 const uint8_t *pResult = (const uint8_t *)UsefulInputBuf_GetBytes(pMe, sizeof(uint32_t));
2170
2171 if(!pResult) {
2172 return 0;
2173 }
2174
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07002175 /* See UsefulInputBuf_GetUint64() for comments on this code */
Michael Eckel5c531332020-03-02 01:35:30 +01002176#if defined(USEFULBUF_CONFIG_BIG_ENDIAN) || defined(USEFULBUF_CONFIG_HTON) || defined(USEFULBUF_CONFIG_BSWAP)
2177 uint32_t uTmp;
2178 memcpy(&uTmp, pResult, sizeof(uint32_t));
2179
2180#if defined(USEFULBUF_CONFIG_BIG_ENDIAN)
2181 return uTmp;
2182
2183#elif defined(USEFULBUF_CONFIG_HTON)
2184 return ntohl(uTmp);
2185
2186#else
2187 return __builtin_bswap32(uTmp);
2188
2189#endif
2190
2191#else
2192 return ((uint32_t)pResult[0]<<24) +
2193 ((uint32_t)pResult[1]<<16) +
2194 ((uint32_t)pResult[2]<<8) +
2195 (uint32_t)pResult[3];
2196#endif
2197}
2198
2199
2200static inline uint64_t UsefulInputBuf_GetUint64(UsefulInputBuf *pMe)
2201{
2202 const uint8_t *pResult = (const uint8_t *)UsefulInputBuf_GetBytes(pMe, sizeof(uint64_t));
2203
2204 if(!pResult) {
2205 return 0;
2206 }
2207
2208#if defined(USEFULBUF_CONFIG_BIG_ENDIAN) || defined(USEFULBUF_CONFIG_HTON) || defined(USEFULBUF_CONFIG_BSWAP)
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07002209 /* pResult will probably not be aligned. This memcpy() moves the
2210 * bytes into a temp variable safely for CPUs that can or can't do
2211 * unaligned memory access. Many compilers will optimize the
2212 * memcpy() into a simple move instruction.
2213 */
Michael Eckel5c531332020-03-02 01:35:30 +01002214 uint64_t uTmp;
2215 memcpy(&uTmp, pResult, sizeof(uint64_t));
2216
2217#if defined(USEFULBUF_CONFIG_BIG_ENDIAN)
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07002218 /* We have been told expliclity this is a big-endian CPU. Since
2219 * network byte order is big-endian, there is nothing to do.
2220 */
Michael Eckel5c531332020-03-02 01:35:30 +01002221
2222 return uTmp;
2223
2224#elif defined(USEFULBUF_CONFIG_HTON)
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07002225 /* We have been told to use ntoh(), the system function to handle
2226 * big- and little-endian. This works on both big- and
2227 * little-endian machines, but ntoh() is not always available or in
2228 * a standard place so it is not used by default. On some CPUs the
2229 * code for this is very compact through use of a special swap
2230 * instruction.
2231 */
Michael Eckel5c531332020-03-02 01:35:30 +01002232
2233 return ntohll(uTmp);
2234
2235#else
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07002236 /* Little-endian (since it is not USEFULBUF_CONFIG_BIG_ENDIAN) and
2237 * USEFULBUF_CONFIG_BSWAP (since it is not USEFULBUF_CONFIG_HTON).
2238 * __builtin_bswap64() and friends are not conditional on CPU
2239 * endianness so this must only be used on little-endian machines.
2240 */
Michael Eckel5c531332020-03-02 01:35:30 +01002241
2242 return __builtin_bswap64(uTmp);
2243
2244
2245#endif
2246
2247#else
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07002248 /* This is the default code that works on every CPU and every
2249 * endianness with no dependency on ntoh(). This works on CPUs
2250 * that either allow or do not allow unaligned access. It will
2251 * always work, but usually is a little less efficient than ntoh().
2252 */
Michael Eckel5c531332020-03-02 01:35:30 +01002253
2254 return ((uint64_t)pResult[0]<<56) +
2255 ((uint64_t)pResult[1]<<48) +
2256 ((uint64_t)pResult[2]<<40) +
2257 ((uint64_t)pResult[3]<<32) +
2258 ((uint64_t)pResult[4]<<24) +
2259 ((uint64_t)pResult[5]<<16) +
2260 ((uint64_t)pResult[6]<<8) +
2261 (uint64_t)pResult[7];
2262#endif
2263}
2264
2265
2266static inline float UsefulInputBuf_GetFloat(UsefulInputBuf *pMe)
2267{
2268 uint32_t uResult = UsefulInputBuf_GetUint32(pMe);
2269
2270 return uResult ? UsefulBufUtil_CopyUint32ToFloat(uResult) : 0;
2271}
2272
2273
2274static inline double UsefulInputBuf_GetDouble(UsefulInputBuf *pMe)
2275{
2276 uint64_t uResult = UsefulInputBuf_GetUint64(pMe);
2277
2278 return uResult ? UsefulBufUtil_CopyUint64ToDouble(uResult) : 0;
2279}
2280
2281
2282static inline int UsefulInputBuf_GetError(UsefulInputBuf *pMe)
2283{
2284 return pMe->err;
2285}
2286
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002287
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07002288static inline void UsefulInputBuf_SetBufferLength(UsefulInputBuf *pMe, size_t uNewLen)
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002289{
2290 pMe->UB.len = uNewLen;
2291}
2292
2293
Michael Eckel5c531332020-03-02 01:35:30 +01002294#ifdef __cplusplus
2295}
2296#endif
2297
Laurence Lundbladedabaffe2021-05-11 10:47:46 -07002298#endif /* _UsefulBuf_h */
Michael Eckel5c531332020-03-02 01:35:30 +01002299
2300