Restructured includes to be in a subfolder and added `make install`. (#33)
Signed-off-by: Michael Eckel <michael.eckel@sit.fraunhofer.de>
diff --git a/inc/UsefulBuf.h b/inc/UsefulBuf.h
index a8da83b..f14084e 100644
--- a/inc/UsefulBuf.h
+++ b/inc/UsefulBuf.h
@@ -1,2134 +1 @@
-/*============================================================================
- Copyright (c) 2016-2018, The Linux Foundation.
- Copyright (c) 2018-2020, Laurence Lundblade.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the following
- disclaimer in the documentation and/or other materials provided
- with the distribution.
- * Neither the name of The Linux Foundation nor the names of its
- contributors, nor the name "Laurence Lundblade" may be used to
- endorse or promote products derived from this software without
- specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
-WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
-BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
-OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
-IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- =============================================================================*/
-
-/*============================================================================
- FILE: UsefulBuf.h
-
- DESCRIPTION: General purpose input and output buffers
-
- EDIT HISTORY FOR FILE:
-
- This section contains comments describing changes made to the module.
- Notice that changes are listed in reverse chronological order.
-
- when who what, where, why
- -------- ---- --------------------------------------------------
- 1/25/2020 llundblade Add some casts so static anlyzers don't complain.
- 5/21/2019 llundblade #define configs for efficient endianness handling.
- 5/16/2019 llundblade Add UsefulOutBuf_IsBufferNULL().
- 3/23/2019 llundblade Big documentation & style update. No interface
- change.
- 3/6/2019 llundblade Add UsefulBuf_IsValue()
- 12/17/2018 llundblade Remove const from UsefulBuf and UsefulBufC .len
- 12/13/2018 llundblade Documentation improvements
- 09/18/2018 llundblade Cleaner distinction between UsefulBuf and
- UsefulBufC.
- 02/02/18 llundbla Full support for integers in and out; fix pointer
- alignment bug. Incompatible change: integers
- in/out are now in network byte order.
- 08/12/17 llundbla Added UsefulOutBuf_AtStart and UsefulBuf_Find
- 06/27/17 llundbla Fix UsefulBuf_Compare() bug. Only affected
- comparison for < or > for unequal length buffers.
- Added UsefulBuf_Set() function.
- 05/30/17 llundbla Functions for NULL UsefulBufs and const / unconst
- 11/13/16 llundbla Initial Version.
-
- =============================================================================*/
-
-#ifndef _UsefulBuf_h
-#define _UsefulBuf_h
-
-
-/*
- Configuration Options
-
- This code is designed so it will work correctly and completely by
- default. No configuration is necessary to make it work. None of the
- following #defines need to be enabled. The code works and is very
- portable with them all turned off.
-
- All configuration options (USEFULBUF_CONFIG_XXX)
- 1) Reduce code size
- 2) Improve efficiency
- 3) Both of the above
-
- The efficiency improvements are not large, so the main reason really
- is to reduce code size.
-
- */
-
-
-/*
- Endianness Configuration
-
- By default, UsefulBuf does not need to know what the endianness of
- the device is. All the code will run correctly on either big or
- little endian CPUs.
-
- Here's the recipe for configuring the endianness-related #defines
- to use more efficient CPU/OS/compiler dependent features to reduce
- code size. Note these only affect the integer arrays (tagged
- arrays) feature of QCBOR. All other endianness handling in
- QCBOR is integrated with code that also handles alignment and
- preferred encoding.
-
- The first option is to not define anything. This will work fine on
- with all CPU's, OS's and compilers. The code for encoding
- integers will be a little larger and slower.
-
- If your CPU is big-endian then define USEFULBUF_CONFIG_BIG_ENDIAN. This
- will give the most efficient code for big-endian CPUs. It will be small
- and efficient because there will be no byte swapping.
-
- Try defining USEFULBUF_CONFIG_HTON. This will work on most CPU's,
- OS's and compilers, but not all. On big-endian CPUs this should give
- the most efficient code, the same as USEFULBUF_CONFIG_BIG_ENDIAN
- does. On little-endian CPUs it should call the system-defined byte
- swapping method which is presumably implemented efficiently. In some
- cases, this will be a dedicated byte swap instruction like Intel's
- bswap.
-
- If USEFULBUF_CONFIG_HTON works and you know your CPU is
- little-endian, it is also good to define
- USEFULBUF_CONFIG_LITTLE_ENDIAN.
-
- if USEFULBUF_CONFIG_HTON doesn't work and you know your system is
- little-endian, try defining both USEFULBUF_CONFIG_LITTLE_ENDIAN and
- USEFULBUF_CONFIG_BSWAP. This should call the most efficient
- system-defined byte swap method. However, note
- https://hardwarebug.org/2010/01/14/beware-the-builtins/. Perhaps
- this is fixed now. Often hton() and ntoh() will call the built-in
- __builtin_bswapXX()() function, so this size issue could affect
- USEFULBUF_CONFIG_HTON.
-
- Last, run the tests. They must all pass.
-
- These #define config options affect the inline implementation of
- UsefulOutBuf_InsertUint64() and UsefulInputBuf_GetUint64(). They
- also affect the 16-, 32-bit, float and double versions of these
- instructions. Since they are inline, they size effect is not in the
- UsefulBuf object code, but in the calling code.
-
- Summary:
- USEFULBUF_CONFIG_BIG_ENDIAN -- Force configuration to big-endian.
- USEFULBUF_CONFIG_LITTLE_ENDIAN -- Force to little-endian.
- USEFULBUF_CONFIG_HTON -- Use hton(), htonl(), ntohl()... to
- handle big and little-endian with system option.
- USEFULBUF_CONFIG_BSWAP -- With USEFULBUF_CONFIG_LITTLE_ENDIAN,
- use __builtin_bswapXX().
- */
-
-#if defined(USEFULBUF_CONFIG_BIG_ENDIAN) && defined(USEFULBUF_CONFIG_LITTLE_ENDIAN)
-#error "Cannot define both USEFULBUF_CONFIG_BIG_ENDIAN and USEFULBUF_CONFIG_LITTLE_ENDIAN"
-#endif
-
-
-#include <stdint.h> // for uint8_t, uint16_t....
-#include <string.h> // for strlen, memcpy, memmove, memset
-#include <stddef.h> // for size_t
-
-
-#ifdef USEFULBUF_CONFIG_HTON
-#include <arpa/inet.h> // for htons, htonl, htonll, ntohs...
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- @file UsefulBuf.h
-
- The goal of this code is to make buffer and pointer manipulation
- easier and safer when working with binary data.
-
- The @ref UsefulBuf, @ref UsefulOutBuf and @ref UsefulInputBuf
- structures are used to represent buffers rather than ad hoc pointers and
- lengths.
-
- With these it will often be possible to write code that does little
- or no direct pointer manipulation for copying and formatting
- data. For example, the QCBOR encoder was written using these and
- has no less pointer manipulation.
-
- While it is true that object code using these functions will be a
- little larger and slower than a white-knuckle clever use of pointers
- might be, but not by that much or enough to have an effect for most
- use cases. For security-oriented code this is highly
- worthwhile. Clarity, simplicity, reviewability and are more
- important.
-
- There are some extra sanity and double checks in this code to help
- catch coding errors and simple memory corruption. They are helpful,
- but not a substitute for proper code review, input validation and
- such.
-
- This code consists of a lot of inline functions and a few that are
- not. It should not generate very much object code, especially with
- the optimizer turned up to @c -Os or @c -O3.
- */
-
-
-/**
- @ref UsefulBufC and @ref UsefulBuf are simple data structures to hold
- a pointer and length for binary data. In C99 this data structure can
- be passed on the stack making a lot of code cleaner than carrying
- around a pointer and length as two parameters.
-
- This is also conducive to secure coding practice as the length is
- always carried with the pointer and the convention for handling a
- pointer and a length is clear.
-
- While it might be possible to write buffer and pointer code more
- efficiently in some use cases, the thought is that unless there is an
- extreme need for performance (e.g., you are building a
- gigabit-per-second IP router), it is probably better to have cleaner
- code you can be most certain about the security of.
-
- The non-const @ref UsefulBuf is usually used to refer a buffer to be
- filled in. The length is the size of the buffer.
-
- The const @ref UsefulBufC is usually used to refer to some data that
- has been filled in. The length is amount of valid data pointed to.
-
- A common use is to pass a @ref UsefulBuf to a function, the function
- fills it in, the function returns a @ref UsefulBufC. The pointer is
- the same in both.
-
- A @ref UsefulBuf is null, it has no value, when @c ptr in it is @c NULL.
-
- There are utility functions for the following:
- - Initializing
- - Create initialized const @ref UsefulBufC from compiler literals
- - Create initialized const @ref UsefulBufC from NULL-terminated string
- - Make an empty @ref UsefulBuf on the stack
- - Checking whether a @ref UsefulBuf is null, empty or both
- - Copying, copying with offset, copying head or tail
- - Comparing and finding substrings
-
- See also @ref UsefulOutBuf. It is a richer structure that has both
- the size of the valid data and the size of the buffer.
-
- @ref UsefulBuf is only 16 or 8 bytes on a 64- or 32-bit machine so it
- can go on the stack and be a function parameter or return value.
-
- Another way to look at it is this. C has the NULL-terminated string
- as a means for handling text strings, but no means or convention for
- binary strings. Other languages do have such means, Rust, an
- efficient compiled language, for example.
-
- @ref UsefulBuf is kind of like the Useful Pot Pooh gave Eeyore on his
- birthday. Eeyore's balloon fits beautifully, "it goes in and out
- like anything".
-*/
-typedef struct q_useful_buf_c {
- const void *ptr;
- size_t len;
-} UsefulBufC;
-
-
-/**
- This non-const @ref UsefulBuf is typically used for some allocated
- memory that is to be filled in. The @c len is the amount of memory,
- not the length of the valid data in the buffer.
- */
-typedef struct q_useful_buf {
- void *ptr;
- size_t len;
-} UsefulBuf;
-
-
-/**
- A null @ref UsefulBufC is one that has no value in the same way a @c
- NULL pointer has no value. A @ref UsefulBufC is @c NULL when the @c
- ptr field is @c NULL. It doesn't matter what @c len is. See
- UsefulBuf_IsEmpty() for the distinction between null and empty.
- */
-#define NULLUsefulBufC ((UsefulBufC) {NULL, 0})
-
-
-/**
- A null @ref UsefulBuf is one that has no memory associated the same
- way @c NULL points to nothing. It does not matter what @c len is.
- */
-#define NULLUsefulBuf ((UsefulBuf) {NULL, 0})
-
-
-/**
- @brief Check if a @ref UsefulBuf is @ref NULLUsefulBuf or not.
-
- @param[in] UB The UsefulBuf to check.
-
- @return 1 if it is @ref NULLUsefulBuf, 0 if not.
- */
-static inline int UsefulBuf_IsNULL(UsefulBuf UB);
-
-
-/**
- @brief Check if a @ref UsefulBufC is @ref NULLUsefulBufC or not.
-
- @param[in] UB The @ref UsefulBufC to check.
-
- @return 1 if it is @c NULLUsefulBufC, 0 if not.
- */
-static inline int UsefulBuf_IsNULLC(UsefulBufC UB);
-
-
-/**
- @brief Check if a @ref UsefulBuf is empty or not.
-
- @param[in] UB The @ref UsefulBuf to check.
-
- @return 1 if it is empty, 0 if not.
-
- An "empty" @ref UsefulBuf is one that has a value and can be
- considered to be set, but that value is of zero length. It is empty
- when @c len is zero. It doesn't matter what the @c ptr is.
-
- A lot of uses will not need to clearly distinguish a @c NULL @ref
- UsefulBuf from an empty one and can have the @c ptr @c NULL and the
- @c len 0. However if a use of @ref UsefulBuf needs to make a
- distinction then @c ptr should not be @c NULL when the @ref UsefulBuf
- is considered empty, but not @c NULL.
- */
-static inline int UsefulBuf_IsEmpty(UsefulBuf UB);
-
-
-/**
- @brief Check if a @ref UsefulBufC is empty or not.
-
- @param[in] UB The @ref UsefulBufC to check.
-
- @return 1 if it is empty, 0 if not.
- */
-static inline int UsefulBuf_IsEmptyC(UsefulBufC UB);
-
-
-/**
- @brief Check if a @ref UsefulBuf is @ref NULLUsefulBuf or empty.
-
- @param[in] UB The @ref UsefulBuf to check.
-
- @return 1 if it is either @ref NULLUsefulBuf or empty, 0 if not.
- */
-static inline int UsefulBuf_IsNULLOrEmpty(UsefulBuf UB);
-
-
-/**
- @brief Check if a @ref UsefulBufC is @ref NULLUsefulBufC or empty.
-
- @param[in] UB The @ref UsefulBufC to check.
-
- @return 1 if it is either @ref NULLUsefulBufC or empty, 0 if not.
- */
-static inline int UsefulBuf_IsNULLOrEmptyC(UsefulBufC UB);
-
-
-/**
- @brief Convert a non-const @ref UsefulBuf to a const @ref UsefulBufC.
-
- @param[in] UB The @ref UsefulBuf to convert.
-
- @return A @ref UsefulBufC struct.
- */
-static inline UsefulBufC UsefulBuf_Const(const UsefulBuf UB);
-
-
-/**
- @brief Convert a const @ref UsefulBufC to a non-const @ref UsefulBuf.
-
- @param[in] UBC The @ref UsefulBuf to convert.
-
- @return A non-const @ref UsefulBuf struct.
- */
-static inline UsefulBuf UsefulBuf_Unconst(const UsefulBufC UBC);
-
-
-/**
- Convert a literal string to a @ref UsefulBufC.
-
- @c szString must be a literal string that @c sizeof() works on. This
- is better for literal strings than UsefulBuf_FromSZ() because it
- generates less code. It will not work on non-literal strings.
-
- The terminating \0 (NULL) is NOT included in the length!
- */
-#define UsefulBuf_FROM_SZ_LITERAL(szString) \
- ((UsefulBufC) {(szString), sizeof(szString)-1})
-
-
-/**
- Convert a literal byte array to a @ref UsefulBufC.
-
- @c pBytes must be a literal string that @c sizeof() works on. It
- will not work on non-literal arrays.
- */
-#define UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pBytes) \
- ((UsefulBufC) {(pBytes), sizeof(pBytes)})
-
-
-/**
- Make an automatic variable named @c name of type @ref UsefulBuf and
- point it to a stack variable of the given @c size.
- */
-#define UsefulBuf_MAKE_STACK_UB(name, size) \
- uint8_t __pBuf##name[(size)];\
- UsefulBuf name = {__pBuf##name , sizeof( __pBuf##name )}
-
-
-/**
- Make a byte array in to a @ref UsefulBuf. This is usually used on
- stack variables or static variables. Also see @ref
- UsefulBuf_MAKE_STACK_UB.
- */
-#define UsefulBuf_FROM_BYTE_ARRAY(pBytes) \
- ((UsefulBuf) {(pBytes), sizeof(pBytes)})
-
-
-/**
- @brief Convert a NULL-terminated string to a @ref UsefulBufC.
-
- @param[in] szString The string to convert.
-
- @return A @ref UsefulBufC struct.
-
- @c UsefulBufC.ptr points to the string so its lifetime must be
- maintained.
-
- The terminating \0 (NULL) is NOT included in the length.
- */
-static inline UsefulBufC UsefulBuf_FromSZ(const char *szString);
-
-
-/**
- @brief Copy one @ref UsefulBuf into another at an offset.
-
- @param[in] Dest Destination buffer to copy into.
- @param[in] uOffset The byte offset in @c Dest at which to copy to.
- @param[in] Src The bytes to copy.
-
- @return Pointer and length of the copy or @ref NULLUsefulBufC.
-
- This fails and returns @ref NULLUsefulBufC if @c offset is beyond the
- size of @c Dest.
-
- This fails and returns @ref NULLUsefulBufC if the @c Src length plus
- @c uOffset is greater than the length of @c Dest.
-
- The results are undefined if @c Dest and @c Src overlap.
-
- This assumes that there is valid data in @c Dest up to @c
- uOffset. The @ref UsefulBufC returned starts at the beginning of @c
- Dest and goes to @c Src.len @c + @c uOffset.
- */
-UsefulBufC UsefulBuf_CopyOffset(UsefulBuf Dest, size_t uOffset, const UsefulBufC Src);
-
-
-/**
- @brief Copy one @ref UsefulBuf into another.
-
- @param[in] Dest The destination buffer to copy into.
- @param[out] Src The source to copy from.
-
- @return Filled in @ref UsefulBufC on success, @ref NULLUsefulBufC
- on failure.
-
- This fails if @c Src.len is greater than @c Dest.len.
-
- Note that like @c memcpy(), the pointers are not checked and this
- will crash rather than return @ref NULLUsefulBufC if they are @c
- NULL or invalid.
-
- The results are undefined if @c Dest and @c Src overlap.
- */
-static inline UsefulBufC UsefulBuf_Copy(UsefulBuf Dest, const UsefulBufC Src);
-
-
-/**
- @brief Set all bytes in a @ref UsefulBuf to a value, for example to 0.
-
- @param[in] pDest The destination buffer to copy into.
- @param[in] value The value to set the bytes to.
-
- Note that like @c memset(), the pointer in @c pDest is not checked
- and this will crash if @c NULL or invalid.
- */
-static inline UsefulBufC UsefulBuf_Set(UsefulBuf pDest, uint8_t value);
-
-
-/**
- @brief Copy a pointer into a @ref UsefulBuf.
-
- @param[in,out] Dest The destination buffer to copy into.
- @param[in] ptr The source to copy from.
- @param[in] uLen Length of the source; amount to copy.
-
- @return 0 on success, 1 on failure.
-
- This fails and returns @ref NULLUsefulBufC if @c uLen is greater than
- @c pDest->len.
-
- Note that like @c memcpy(), the pointers are not checked and this
- will crash, rather than return 1 if they are @c NULL or invalid.
- */
-static inline UsefulBufC UsefulBuf_CopyPtr(UsefulBuf Dest,
- const void *ptr,
- size_t uLen);
-
-
-/**
- @brief Returns a truncation of a @ref UsefulBufC.
-
- @param[in] UB The buffer to get the head of.
- @param[in] uAmount The number of bytes in the head.
-
- @return A @ref UsefulBufC that is the head of UB.
- */
-static inline UsefulBufC UsefulBuf_Head(UsefulBufC UB, size_t uAmount);
-
-
-/**
- @brief Returns bytes from the end of a @ref UsefulBufC.
-
- @param[in] UB The buffer to get the tail of.
- @param[in] uAmount The offset from the start where the tail is to begin.
-
- @return A @ref UsefulBufC that is the tail of @c UB or @ref NULLUsefulBufC
- if @c uAmount is greater than the length of the @ref UsefulBufC.
-
- If @c UB.ptr is @c NULL, but @c UB.len is not zero, then the result will
- be a @ref UsefulBufC with a @c NULL @c ptr and @c len with the length
- of the tail.
- */
-static inline UsefulBufC UsefulBuf_Tail(UsefulBufC UB, size_t uAmount);
-
-
-/**
- @brief Compare one @ref UsefulBufC to another.
-
- @param[in] UB1 The first buffer to compare.
- @param[in] UB2 The second buffer to compare.
-
- @return 0, positive or negative value.
-
- Returns a negative value if @c UB1 if is less than @c UB2. @c UB1 is
- less than @c UB2 if it is shorter or the first byte that is not the
- same is less.
-
- Returns 0 if the inputs are the same.
-
- Returns a positive value if @c UB2 is less than @c UB1.
-
- All that is of significance is that the result is positive, negative
- or 0. (This doesn't return the difference between the first
- non-matching byte like @c memcmp() ).
- */
-int UsefulBuf_Compare(const UsefulBufC UB1, const UsefulBufC UB2);
-
-
-/**
- @brief Find first byte that is not a particular byte value.
-
- @param[in] UB The destination buffer for byte comparison.
- @param[in] uValue The byte value to compare to.
-
- @return Offset of first byte that isn't @c uValue or
- @c SIZE_MAX if all bytes are @c uValue.
-
- Note that unlike most comparison functions, 0
- does not indicate a successful comparison, so the
- test for match is:
-
- UsefulBuf_IsValue(...) == SIZE_MAX
-
- If @c UB is null or empty, there is no match
- and 0 is returned.
- */
-size_t UsefulBuf_IsValue(const UsefulBufC UB, uint8_t uValue);
-
-
-/**
- @brief Find one @ref UsefulBufC in another.
-
- @param[in] BytesToSearch Buffer to search through.
- @param[in] BytesToFind Buffer with bytes to be found.
-
- @return Position of found bytes or @c SIZE_MAX if not found.
- */
-size_t UsefulBuf_FindBytes(UsefulBufC BytesToSearch, UsefulBufC BytesToFind);
-
-
-#if 1 // NOT_DEPRECATED
-/** Deprecated macro; use @ref UsefulBuf_FROM_SZ_LITERAL instead */
-#define SZLiteralToUsefulBufC(szString) \
- ((UsefulBufC) {(szString), sizeof(szString)-1})
-
-/** Deprecated macro; use UsefulBuf_MAKE_STACK_UB instead */
-#define MakeUsefulBufOnStack(name, size) \
- uint8_t __pBuf##name[(size)];\
- UsefulBuf name = {__pBuf##name , sizeof( __pBuf##name )}
-
-/** Deprecated macro; use @ref UsefulBuf_FROM_BYTE_ARRAY_LITERAL instead */
-#define ByteArrayLiteralToUsefulBufC(pBytes) \
- ((UsefulBufC) {(pBytes), sizeof(pBytes)})
-
-/** Deprecated function; use UsefulBuf_Unconst() instead */
-static inline UsefulBuf UsefulBufC_Unconst(const UsefulBufC UBC)
-{
- return (UsefulBuf){(void *)UBC.ptr, UBC.len};
-}
-#endif
-
-
-
-
-/**
- @brief Copy a @c float to a @c uint32_t.
-
- @param[in] f Float value to copy.
-
- @return A @c uint32_t with the float bits.
-
- Convenience function to avoid type punning, compiler warnings and
- such. The optimizer usually reduces this to a simple assignment. This
- is a crusty corner of C.
- */
-static inline uint32_t UsefulBufUtil_CopyFloatToUint32(float f);
-
-
-/**
- @brief Copy a @c double to a @c uint64_t.
-
- @param[in] d Double value to copy.
-
- @return A @c uint64_t with the double bits.
-
- Convenience function to avoid type punning, compiler warnings and
- such. The optimizer usually reduces this to a simple assignment. This
- is a crusty corner of C.
- */
-static inline uint64_t UsefulBufUtil_CopyDoubleToUint64(double d);
-
-
-/**
- @brief Copy a @c uint32_t to a @c float.
-
- @param[in] u32 Integer value to copy.
-
- @return The value as a @c float.
-
- Convenience function to avoid type punning, compiler warnings and
- such. The optimizer usually reduces this to a simple assignment. This
- is a crusty corner of C.
- */
-static inline float UsefulBufUtil_CopyUint32ToFloat(uint32_t u32);
-
-
-/**
- @brief Copy a @c uint64_t to a @c double.
-
- @param[in] u64 Integer value to copy.
-
- @return The value as a @c double.
-
- Convenience function to avoid type punning, compiler warnings and
- such. The optimizer usually reduces this to a simple assignment. This
- is a crusty corner of C.
- */
-static inline double UsefulBufUtil_CopyUint64ToDouble(uint64_t u64);
-
-
-
-
-/**
- UsefulOutBuf is a structure and functions (an object) for serializing
- data into a buffer when encoding a network protocol or writing data
- to file.
-
- The main idea is that all the pointer manipulation is performed by
- @ref UsefulOutBuf functions so the caller doesn't have to do any
- pointer manipulation. The pointer manipulation is centralized. This
- code will have been reviewed and written carefully so it spares the
- caller of much of this work and results in safer code with less work.
-
- The @ref UsefulOutBuf methods that add data to the output buffer
- always check the length and will never write off the end of the
- output buffer. If an attempt to add data that will not fit is made,
- an internal error flag will be set and further attempts to add data
- will not do anything.
-
- There is no way to ever write off the end of that buffer when calling
- the @c UsefulOutBuf_AddXxx() and @c UsefulOutBuf_InsertXxx()
- functions.
-
- The functions to add data do not return an error. The working model
- is that all calls to add data are made without an error check. Errors
- are just checked for once after all the data has been added before the
- and before serialized data is to be used. This makes the calling code
- cleaner.
-
- There is a utility function to get the error status anytime along the
- way for a special circumstance. There are functions to see how much
- room is left and see if some data will fit too, but their use is
- generally not necessary.
-
- The general call flow is:
-
- - Initialize by calling @ref UsefulOutBuf_Init(). The output
- buffer given to it can be from the heap, stack or
- otherwise. @ref UsefulOutBuf_MakeOnStack is a convenience macro
- that makes a buffer on the stack and initializes it.
-
- - Call methods like UsefulOutBuf_InsertString(),
- UsefulOutBuf_AppendUint32() and UsefulOutBuf_InsertUsefulBuf()
- to output data. The append calls add data to the end of the
- valid data. The insert calls take a position argument.
-
- - Call UsefulOutBuf_OutUBuf() or UsefulOutBuf_CopyOut() to see
- there were no errors and to get the serialized output bytes.
-
- @ref UsefulOutBuf can be used in a size calculation mode to calculate
- the size of output that would be generated. This is useful to
- calculate the size of a buffer that is to be allocated to hold the
- output. To use @ref UsefulOutBuf in this mode, call
- UsefulOutBuf_Init() with the @c Storage @ref UsefulBuf as
- @c (UsefulBuf){NULL,MAX_UINT32}. Then call all the Insert and Add
- functions. No attempt will made to actually copy data, so only the
- lengths have to be valid for these calls.
-
- Methods like UsefulOutBuf_InsertUint64() always output in network
- bytes order (big endian).
-
- The possible errors are:
- - The @ref UsefulOutBuf was not initialized or was corrupted.
-
- - An attempt was made to add data that will not fit.
-
- - An attempt was made to insert data at a position beyond the end of
- the buffer.
-
- - An attempt was made to insert data at a position beyond the valid
- data in the buffer.
-
- Some inexpensive simple sanity checks are performed before every data
- addition to guard against use of an uninitialized or corrupted
- UsefulOutBuf.
-
- This has been used to create a CBOR encoder. The CBOR encoder has
- almost no pointer manipulation in it, is easier to read, and easier
- to review.
-
- A @ref UsefulOutBuf is small and can go on the stack:
- - 32 bytes (27 bytes plus alignment padding) on a 64-bit machine
- - 16 bytes (15 bytes plus alignment padding) on a 32-bit machines
- */
-typedef struct useful_out_buf {
- // PRIVATE DATA STRUCTURE
- UsefulBuf UB; // Memory that is being output to
- size_t data_len; // length of the data
- uint16_t magic; // Used to detect corruption and lack of initialization
- uint8_t err;
-} UsefulOutBuf;
-
-
-/**
- @brief Initialize and supply the actual output buffer.
-
- @param[out] pUOutBuf The @ref UsefulOutBuf to initialize.
- @param[in] Storage Buffer to output into.
-
- Initializes the @ref UsefulOutBuf with storage. Sets the current
- position to the beginning of the buffer clears the error.
-
- This must be called before the @ref UsefulOutBuf is used.
- */
-void UsefulOutBuf_Init(UsefulOutBuf *pUOutBuf, UsefulBuf Storage);
-
-
-/**
- Convenience macro to make a @ref UsefulOutBuf on the stack and
- initialize it with a stack buffer of the given size. The variable
- will be named @c name.
- */
-#define UsefulOutBuf_MakeOnStack(name, size) \
- uint8_t __pBuf##name[(size)];\
- UsefulOutBuf name;\
- UsefulOutBuf_Init(&(name), (UsefulBuf){__pBuf##name, (size)});
-
-
-/**
- @brief Reset a @ref UsefulOutBuf for re use
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf
-
- This sets the amount of data in the output buffer to none and clears
- the error state.
-
- The output buffer is still the same one and size as from the
- UsefulOutBuf_Init() call.
-
- This doesn't zero the data, just resets to 0 bytes of valid data.
- */
-static inline void UsefulOutBuf_Reset(UsefulOutBuf *pUOutBuf);
-
-
-/**
- @brief Returns position of end of data in the @ref UsefulOutBuf.
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
-
- @return position of end of data.
-
- On a freshly initialized @ref UsefulOutBuf with no data added, this
- will return 0. After 10 bytes have been added, it will return 10 and
- so on.
-
- Generally callers will not need this function for most uses of @ref
- UsefulOutBuf.
- */
-static inline size_t UsefulOutBuf_GetEndPosition(UsefulOutBuf *pUOutBuf);
-
-
-/**
- @brief Returns whether any data has been added to the @ref UsefulOutBuf.
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
-
- @return 1 if output position is at start.
- */
-static inline int UsefulOutBuf_AtStart(UsefulOutBuf *pUOutBuf);
-
-
-/**
- @brief Inserts bytes into the @ref UsefulOutBuf.
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
- @param[in] NewData The bytes to insert.
- @param[in] uPos Index in output buffer at which to insert.
-
- @c NewData is the pointer and length for the bytes to be added to the
- output buffer. There must be room in the output buffer for all of @c
- NewData or an error will occur.
-
- The insertion point must be between 0 and the current valid data. If
- not, an error will occur. Appending data to the output buffer is
- achieved by inserting at the end of the valid data. This can be
- retrieved by calling UsefulOutBuf_GetEndPosition().
-
- When insertion is performed, the bytes between the insertion point
- and the end of data previously added to the output buffer are slid to
- the right to make room for the new data.
-
- Overlapping buffers are OK. @c NewData can point to data in the
- output buffer.
-
- If an error occurs an error state is set in the @ref UsefulOutBuf. No
- error is returned. All subsequent attempts to add data will do
- nothing.
-
- The intended use is that all additions are made without checking for
- an error. The error will be taken into account when
- UsefulOutBuf_OutUBuf() returns @c NullUsefulBufC.
- UsefulOutBuf_GetError() can also be called to check for an error.
- */
-void UsefulOutBuf_InsertUsefulBuf(UsefulOutBuf *pUOutBuf,
- UsefulBufC NewData,
- size_t uPos);
-
-
-/**
- @brief Insert a data buffer into the @ref UsefulOutBuf.
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
- @param[in] pBytes Pointer to the bytes to insert
- @param[in] uLen Length of the bytes to insert
- @param[in] uPos Index in output buffer at which to insert
-
- See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
- the difference being a pointer and length is passed in rather than an
- @ref UsefulBufC.
- */
-static inline void UsefulOutBuf_InsertData(UsefulOutBuf *pUOutBuf,
- const void *pBytes,
- size_t uLen,
- size_t uPos);
-
-
-/**
- @brief Insert a NULL-terminated string into the UsefulOutBuf.
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
- @param[in] szString NULL-terminated string to insert.
- @param[in] uPos Index in output buffer at which to insert.
- */
-static inline void UsefulOutBuf_InsertString(UsefulOutBuf *pUOutBuf,
- const char *szString,
- size_t uPos);
-
-
-/**
- @brief Insert a byte into the @ref UsefulOutBuf.
-
- @param[in] pUOutBuf Pointer to the UsefulOutBuf.
- @param[in] byte Bytes to insert.
- @param[in] uPos Index in output buffer at which to insert.
-
- See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
- the difference being a single byte is to be inserted.
- */
-static inline void UsefulOutBuf_InsertByte(UsefulOutBuf *pUOutBuf,
- uint8_t byte,
- size_t uPos);
-
-
-/**
- @brief Insert a 16-bit integer into the @ref UsefulOutBuf.
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
- @param[in] uInteger16 Integer to insert.
- @param[in] uPos Index in output buffer at which to insert.
-
- See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
- the difference being a two-byte integer is to be inserted.
-
- The integer will be inserted in network byte order (big endian).
- */
-static inline void UsefulOutBuf_InsertUint16(UsefulOutBuf *pUOutBuf,
- uint16_t uInteger16,
- size_t uPos);
-
-
-/**
- @brief Insert a 32-bit integer into the @ref UsefulOutBuf.
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
- @param[in] uInteger32 Integer to insert.
- @param[in] uPos Index in output buffer at which to insert.
-
- See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
- the difference being a four-byte integer is to be inserted.
-
- The integer will be inserted in network byte order (big endian).
- */
-static inline void UsefulOutBuf_InsertUint32(UsefulOutBuf *pUOutBuf,
- uint32_t uInteger32,
- size_t uPos);
-
-
-/**
- @brief Insert a 64-bit integer into the @ref UsefulOutBuf.
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
- @param[in] uInteger64 Integer to insert.
- @param[in] uPos Index in output buffer at which to insert.
-
- See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
- the difference being an eight-byte integer is to be inserted.
-
- The integer will be inserted in network byte order (big endian).
- */
-static inline void UsefulOutBuf_InsertUint64(UsefulOutBuf *pUOutBuf,
- uint64_t uInteger64,
- size_t uPos);
-
-
-/**
- @brief Insert a @c float into the @ref UsefulOutBuf.
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
- @param[in] f @c float to insert.
- @param[in] uPos Index in output buffer at which to insert.
-
- See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
- the difference being a @c float is to be inserted.
-
- The @c float will be inserted in network byte order (big endian).
- */
-static inline void UsefulOutBuf_InsertFloat(UsefulOutBuf *pUOutBuf,
- float f,
- size_t uPos);
-
-
-/**
- @brief Insert a @c double into the @ref UsefulOutBuf.
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
- @param[in] d @c double to insert.
- @param[in] uPos Index in output buffer at which to insert.
-
- See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
- the difference being a @c double is to be inserted.
-
- The @c double will be inserted in network byte order (big endian).
- */
-static inline void UsefulOutBuf_InsertDouble(UsefulOutBuf *pUOutBuf,
- double d,
- size_t uPos);
-
-
-/**
- @brief Append a @ref UsefulBuf into the @ref UsefulOutBuf.
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
- @param[in] NewData The @ref UsefulBuf with the bytes to append.
-
- See UsefulOutBuf_InsertUsefulBuf() for details. This does the same
- with the insertion point at the end of the valid data.
-*/
-static inline void UsefulOutBuf_AppendUsefulBuf(UsefulOutBuf *pUOutBuf,
- UsefulBufC NewData);
-
-
-/**
- @brief Append bytes to the @ref UsefulOutBuf.
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
- @param[in] pBytes Pointer to bytes to append.
- @param[in] uLen Length of @c pBytes to append.
-
- See UsefulOutBuf_InsertData() for details. This does the same
- with the insertion point at the end of the valid data.
- */
-static inline void UsefulOutBuf_AppendData(UsefulOutBuf *pUOutBuf,
- const void *pBytes,
- size_t uLen);
-
-
-/**
- @brief Append a NULL-terminated string to the @ref UsefulOutBuf
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
- @param[in] szString NULL-terminated string to append.
- */
-static inline void UsefulOutBuf_AppendString(UsefulOutBuf *pUOutBuf,
- const char *szString);
-
-
-/**
- @brief Append a byte to the @ref UsefulOutBuf
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
- @param[in] byte Bytes to append.
-
- See UsefulOutBuf_InsertByte() for details. This does the same
- with the insertion point at the end of the valid data.
- */
-static inline void UsefulOutBuf_AppendByte(UsefulOutBuf *pUOutBuf,
- uint8_t byte);
-
-
-/**
- @brief Append an integer to the @ref UsefulOutBuf
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
- @param[in] uInteger16 Integer to append.
-
- See UsefulOutBuf_InsertUint16() for details. This does the same
- with the insertion point at the end of the valid data.
-
- The integer will be appended in network byte order (big endian).
- */
-static inline void UsefulOutBuf_AppendUint16(UsefulOutBuf *pUOutBuf,
- uint16_t uInteger16);
-
-
-/**
- @brief Append an integer to the @ref UsefulOutBuf
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
- @param[in] uInteger32 Integer to append.
-
- See UsefulOutBuf_InsertUint32() for details. This does the same
- with the insertion point at the end of the valid data.
-
- The integer will be appended in network byte order (big endian).
- */
-static inline void UsefulOutBuf_AppendUint32(UsefulOutBuf *pUOutBuf,
- uint32_t uInteger32);
-
-
-/**
- @brief Append an integer to the @ref UsefulOutBuf
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
- @param[in] uInteger64 Integer to append.
-
- See UsefulOutBuf_InsertUint64() for details. This does the same
- with the insertion point at the end of the valid data.
-
- The integer will be appended in network byte order (big endian).
- */
-static inline void UsefulOutBuf_AppendUint64(UsefulOutBuf *pUOutBuf,
- uint64_t uInteger64);
-
-
-/**
- @brief Append a @c float to the @ref UsefulOutBuf
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
- @param[in] f @c float to append.
-
- See UsefulOutBuf_InsertFloat() for details. This does the same
- with the insertion point at the end of the valid data.
-
- The float will be appended in network byte order (big endian).
- */
-static inline void UsefulOutBuf_AppendFloat(UsefulOutBuf *pUOutBuf,
- float f);
-
-
-/**
- @brief Append a @c double to the @ref UsefulOutBuf
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
- @param[in] d @c double to append.
-
- See UsefulOutBuf_InsertDouble() for details. This does the same
- with the insertion point at the end of the valid data.
-
- The double will be appended in network byte order (big endian).
- */
-static inline void UsefulOutBuf_AppendDouble(UsefulOutBuf *pUOutBuf,
- double d);
-
-
-/**
- @brief Returns the current error status.
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
-
- @return 0 if all OK, 1 on error.
-
- This is the error status since the call to either
- UsefulOutBuf_Reset() of UsefulOutBuf_Init(). Once it goes into error
- state it will stay until one of those functions is called.
-
- Possible error conditions are:
- - bytes to be inserted will not fit
- - insertion point is out of buffer or past valid data
- - current position is off end of buffer (probably corrupted or uninitialized)
- - detect corruption / uninitialized by bad magic number
- */
-static inline int UsefulOutBuf_GetError(UsefulOutBuf *pUOutBuf);
-
-
-/**
- @brief Returns number of bytes unused used in the output buffer.
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
-
- @return Number of unused bytes or zero.
-
- Because of the error handling strategy and checks in
- UsefulOutBuf_InsertUsefulBuf() it is usually not necessary to use
- this.
- */
-static inline size_t UsefulOutBuf_RoomLeft(UsefulOutBuf *pUOutBuf);
-
-
-/**
- @brief Returns 1 if some number of bytes will fit in the @ref UsefulOutBuf.
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf
- @param[in] uLen Number of bytes for which to check
-
- @return 1 if @c uLen bytes will fit, 0 if not.
-
- Because of the error handling strategy and checks in
- UsefulOutBuf_InsertUsefulBuf() it is usually not necessary to use
- this.
- */
-static inline int UsefulOutBuf_WillItFit(UsefulOutBuf *pUOutBuf, size_t uLen);
-
-
- /**
- @brief Returns 1 if buffer given to UsefulOutBuf_Init() was @c NULL.
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf
-
- @return 1 if buffer given to UsefulOutBuf_Init() was @c NULL.
-
- Giving a @c NULL output buffer to UsefulOutBuf_Init() is used
- when just calculating the length of the encoded data.
- */
-static inline int UsefulOutBuf_IsBufferNULL(UsefulOutBuf *pUOutBuf);
-
-
-/**
- @brief Returns the resulting valid data in a UsefulOutBuf
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
-
- @return The valid data in @ref UsefulOutBuf or
- @ref NULLUsefulBufC if there was an error adding data.
-
- The storage for the returned data is the @c Storage parameter passed
- to UsefulOutBuf_Init(). See also UsefulOutBuf_CopyOut().
-
- This can be called anytime and many times to get intermediate
- results. It doesn't change the data or reset the current position
- so you can keep adding data.
- */
-UsefulBufC UsefulOutBuf_OutUBuf(UsefulOutBuf *pUOutBuf);
-
-
-/**
- @brief Copies the valid data into a supplied buffer
-
- @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
- @param[out] Dest The destination buffer to copy into.
-
- @return Pointer and length of copied data or @c NULLUsefulBufC
- if it will not fit in the @c Dest buffer.
-
- This is the same as UsefulOutBuf_OutUBuf() except it copies the data
- to @c Dest.
-*/
-UsefulBufC UsefulOutBuf_CopyOut(UsefulOutBuf *pUOutBuf, UsefulBuf Dest);
-
-
-
-
-/**
- @ref UsefulInputBuf is the counterpart to @ref UsefulOutBuf and is
- for parsing data read or received. Initialize it with the data from
- the network. Then use the functions here to get data chunks of
- various types. A position cursor is maintained internally.
-
- As long as the functions here are used, there will never be a
- reference off the end of the given buffer. This is true even if they
- care called incorrectly, an attempt is made to seek of the end of the
- buffer, etc. This makes it easier to write safe and correct code.
- For example, the QCBOR decoder implementation is safer and easier to
- review through its use of @ref UsefulInputBuf.
-
- @ref UsefulInputBuf maintains an internal error state. The
- intended use is that data chunks can be fetched without error
- checking until the end. Once data has been requested off the end of
- the buffer, the error state is entered. In the error state the
- @c UsefulInputBuf_GetXxxx() functions return 0, or @c NULL or
- @ref NULLUsefulBufC. As long as null are not dereferenced, the
- error check can be put off until the end, simplifying the calling
- code.
-
- The integer and float parsing expects network byte order (big
- endian). Network byte order is what is used by TCP/IP, CBOR and most
- internet protocols.
-
- Lots of inline functions are used to keep code size down. The code
- optimizer, particularly with the @c -Os or @c -O3, also reduces code
- size a lot. The only non-inline code is UsefulInputBuf_GetBytes()
- which is less than 100 bytes so use of @ref UsefulInputBuf doesn't
- add much code for all the messy hard-to-get right issues with parsing
- in C that is solves.
-
- The parse context size is:
- - 64-bit machine: 16 + 8 + 2 + 1 (5 bytes padding to align) = 32 bytes
- - 32-bit machine: 8 + 4 + 2 + 1 (1 byte padding to align) = 16 bytes
- */
-typedef struct useful_input_buf {
- // PRIVATE DATA STRUCTURE
- UsefulBufC UB; // Data being parsed
- size_t cursor; // Current offset in data being parse
- uint16_t magic; // Check for corrupted or uninitialized UsefulInputBuf
- uint8_t err; // Set request goes off end or magic number is bad
-} UsefulInputBuf;
-
-#define UIB_MAGIC (0xB00F)
-
-
-/**
- @brief Initialize the UsefulInputBuf structure before use.
-
- @param[in] pUInBuf Pointer to the UsefulInputBuf instance.
- @param[in] UB The data to parse.
- */
-static inline void UsefulInputBuf_Init(UsefulInputBuf *pUInBuf, UsefulBufC UB);
-
-
-/**
- @brief Returns current position in input buffer.
-
- @param[in] pUInBuf Pointer to the UsefulInputBuf.
-
- @return Integer position of the cursor.
-
- The position that the next bytes will be returned from.
- */
-static size_t UsefulInputBuf_Tell(UsefulInputBuf *pUInBuf);
-
-
-/**
- @brief Sets the current position in input buffer.
-
- @param[in] pUInBuf Pointer to the UsefulInputBuf.
- @param[in] uPos Position to set to.
-
- If the position is off the end of the input buffer, the error state
- is entered, and all functions will do nothing.
-
- Seeking to a valid position in the buffer will not reset the error
- state. Only re initialization will do that.
- */
-static void UsefulInputBuf_Seek(UsefulInputBuf *pUInBuf, size_t uPos);
-
-
-/**
- @brief Returns the number of bytes from the cursor to the end of the buffer,
- the unconsumed bytes.
-
- @param[in] pUInBuf Pointer to the UsefulInputBuf.
-
- @return Number of bytes unconsumed or 0 on error.
-
- This is a critical function for input length validation.
-
- Returns 0 if the cursor it invalid or corruption of the structure is
- detected.
- */
-static size_t UsefulInputBuf_BytesUnconsumed(UsefulInputBuf *pUInBuf);
-
-
-/**
- @brief Check if there are any unconsumed bytes.
-
- @param[in] pUInBuf Pointer to the UsefulInputBuf.
- @param[in] uLen Number of bytes to check availability for.
-
- @return 1 if @c uLen bytes are available after the cursor, and 0 if not.
- */
-static int UsefulInputBuf_BytesAvailable(UsefulInputBuf *pUInBuf, size_t uLen);
-
-
-/**
- @brief Get pointer to bytes out of the input buffer.
-
- @param[in] pUInBuf Pointer to the UsefulInputBuf.
- @param[in] uNum Number of bytes to get.
-
- @return Pointer to bytes.
-
- This consumes @c uNum bytes from the input buffer. It returns a
- pointer to the start of the @c uNum bytes.
-
- If there are not @c uNum bytes in the input buffer, @c NULL will be
- returned and an error will be set.
-
- It advances the current position by @c uNum bytes.
- */
-const void * UsefulInputBuf_GetBytes(UsefulInputBuf *pUInBuf, size_t uNum);
-
-
-/**
- @brief Get @ref UsefulBuf out of the input buffer.
-
- @param[in] pUInBuf Pointer to the UsefulInputBuf.
- @param[in] uNum Number of bytes to get.
-
- @return A @ref UsefulBufC with ptr and length of bytes consumed.
-
- This consumes @c uNum bytes from the input buffer and returns the
- pointer and length for them as a @ref UsefulBufC. The length returned
- will always be @c uNum.
-
- If there are not @c uNum bytes in the input buffer, @ref NULLUsefulBufC
- will be returned and the error state is set.
-
- It advances the current position by @c uNum bytes.
- */
-static inline UsefulBufC UsefulInputBuf_GetUsefulBuf(UsefulInputBuf *pUInBuf, size_t uNum);
-
-
-/**
- @brief Get a byte out of the input buffer.
-
- @param[in] pUInBuf Pointer to the @ref UsefulInputBuf.
-
- @return The byte.
-
- This consumes 1 byte from the input buffer. It returns the byte.
-
- If there is not 1 byte in the buffer, 0 will be returned for the byte
- and an error set internally. You must check the error at some point
- to know whether the 0 was the real value or just returned in error,
- but you may not have to do that right away. Check the error state
- with UsefulInputBuf_GetError(). You can also know you are in the
- error state if UsefulInputBuf_GetBytes() returns @c NULL or the @c
- ptr from UsefulInputBuf_GetUsefulBuf() is @c NULL.
-
- It advances the current position by 1 byte.
- */
-static inline uint8_t UsefulInputBuf_GetByte(UsefulInputBuf *pUInBuf);
-
-
-/**
- @brief Get a @c uint16_t out of the input buffer.
-
- @param[in] pUInBuf Pointer to the UsefulInputBuf.
-
- @return The @c uint16_t.
-
- See UsefulInputBuf_GetByte(). This works the same, except it returns
- a @c uint16_t and two bytes are consumed.
-
- The input bytes must be in network order (big endian).
- */
-static inline uint16_t UsefulInputBuf_GetUint16(UsefulInputBuf *pUInBuf);
-
-
-/**
- @brief Get a uint32_t out of the input buffer.
-
- @param[in] pUInBuf Pointer to the UsefulInputBuf.
-
- @return The @c uint32_t.
-
- See UsefulInputBuf_GetByte(). This works the same, except it returns
- a @c uint32_t and four bytes are consumed.
-
- The input bytes must be in network order (big endian).
- */
-static uint32_t UsefulInputBuf_GetUint32(UsefulInputBuf *pUInBuf);
-
-
-/**
- @brief Get a uint64_t out of the input buffer.
-
- @param[in] pUInBuf Pointer to the UsefulInputBuf.
-
- @return The uint64_t.
-
- See UsefulInputBuf_GetByte(). This works the same, except it returns
- a @c uint64_t and eight bytes are consumed.
-
- The input bytes must be in network order (big endian).
- */
-static uint64_t UsefulInputBuf_GetUint64(UsefulInputBuf *pUInBuf);
-
-
-/**
- @brief Get a float out of the input buffer.
-
- @param[in] pUInBuf Pointer to the UsefulInputBuf.
-
- @return The float.
-
- See UsefulInputBuf_GetByte(). This works the same, except it returns
- a float and four bytes are consumed.
-
- The input bytes must be in network order (big endian).
- */
-static float UsefulInputBuf_GetFloat(UsefulInputBuf *pUInBuf);
-
-
-/**
- @brief Get a double out of the input buffer.
-
- @param[in] pUInBuf Pointer to the UsefulInputBuf.
-
- @return The double.
-
- See UsefulInputBuf_GetByte(). This works the same, except it returns
- a double and eight bytes are consumed.
-
- The input bytes must be in network order (big endian).
- */
-static double UsefulInputBuf_GetDouble(UsefulInputBuf *pUInBuf);
-
-
-/**
- @brief Get the error status.
-
- @param[in] pUInBuf Pointer to the @ref UsefulInputBuf.
-
- @return 0 if there is no error, 1 if there is.
-
- The error state is entered for one of these reasons:
- - Attempt to fetch data past the end of the buffer
- - Attempt to seek to a position past the end of the buffer
- - Attempt to get data from an uninitialized or corrupt instance
- of @ref UsefulInputBuf
-
- Once in the error state, it can only be cleared by calling
- UsefulInputBuf_Init().
-
- You may be able to only check the error state at the end after all
- the UsefulInputBuf_GetXxxx() calls have been made, but if what you
- get later depends on what you get sooner you cannot. For example,
- if you get a length or count of following items you will have to
- check the error.
- */
-static int UsefulInputBuf_GetError(UsefulInputBuf *pUInBuf);
-
-
-
-
-/*----------------------------------------------------------
- Inline implementations.
- */
-static inline int UsefulBuf_IsNULL(UsefulBuf UB)
-{
- return !UB.ptr;
-}
-
-
-static inline int UsefulBuf_IsNULLC(UsefulBufC UB)
-{
- return !UB.ptr;
-}
-
-
-static inline int UsefulBuf_IsEmpty(UsefulBuf UB)
-{
- return !UB.len;
-}
-
-
-static inline int UsefulBuf_IsEmptyC(UsefulBufC UB)
-{
- return !UB.len;
-}
-
-
-static inline int UsefulBuf_IsNULLOrEmpty(UsefulBuf UB)
-{
- return UsefulBuf_IsEmpty(UB) || UsefulBuf_IsNULL(UB);
-}
-
-
-static inline int UsefulBuf_IsNULLOrEmptyC(UsefulBufC UB)
-{
- return UsefulBuf_IsEmptyC(UB) || UsefulBuf_IsNULLC(UB);
-}
-
-
-static inline UsefulBufC UsefulBuf_Const(const UsefulBuf UB)
-{
- return (UsefulBufC){UB.ptr, UB.len};
-}
-
-
-static inline UsefulBuf UsefulBuf_Unconst(const UsefulBufC UBC)
-{
- return (UsefulBuf){(void *)UBC.ptr, UBC.len};
-}
-
-
-static inline UsefulBufC UsefulBuf_FromSZ(const char *szString)
-{
- return ((UsefulBufC) {szString, strlen(szString)});
-}
-
-
-static inline UsefulBufC UsefulBuf_Copy(UsefulBuf Dest, const UsefulBufC Src)
-{
- return UsefulBuf_CopyOffset(Dest, 0, Src);
-}
-
-
-static inline UsefulBufC UsefulBuf_Set(UsefulBuf pDest, uint8_t value)
-{
- memset(pDest.ptr, value, pDest.len);
- return (UsefulBufC){pDest.ptr, pDest.len};
-}
-
-
-static inline UsefulBufC UsefulBuf_CopyPtr(UsefulBuf Dest, const void *ptr, size_t len)
-{
- return UsefulBuf_Copy(Dest, (UsefulBufC){ptr, len});
-}
-
-
-static inline UsefulBufC UsefulBuf_Head(UsefulBufC UB, size_t uAmount)
-{
- if(uAmount > UB.len) {
- return NULLUsefulBufC;
- }
- return (UsefulBufC){UB.ptr, uAmount};
-}
-
-
-static inline UsefulBufC UsefulBuf_Tail(UsefulBufC UB, size_t uAmount)
-{
- UsefulBufC ReturnValue;
-
- if(uAmount > UB.len) {
- ReturnValue = NULLUsefulBufC;
- } else if(UB.ptr == NULL) {
- ReturnValue = (UsefulBufC){NULL, UB.len - uAmount};
- } else {
- ReturnValue = (UsefulBufC){(uint8_t *)UB.ptr + uAmount, UB.len - uAmount};
- }
-
- return ReturnValue;
-}
-
-
-
-static inline uint32_t UsefulBufUtil_CopyFloatToUint32(float f)
-{
- uint32_t u32;
- memcpy(&u32, &f, sizeof(uint32_t));
- return u32;
-}
-
-static inline uint64_t UsefulBufUtil_CopyDoubleToUint64(double d)
-{
- uint64_t u64;
- memcpy(&u64, &d, sizeof(uint64_t));
- return u64;
-}
-
-static inline double UsefulBufUtil_CopyUint64ToDouble(uint64_t u64)
-{
- double d;
- memcpy(&d, &u64, sizeof(uint64_t));
- return d;
-}
-
-static inline float UsefulBufUtil_CopyUint32ToFloat(uint32_t u32)
-{
- float f;
- memcpy(&f, &u32, sizeof(uint32_t));
- return f;
-}
-
-
-
-
-static inline void UsefulOutBuf_Reset(UsefulOutBuf *pMe)
-{
- pMe->data_len = 0;
- pMe->err = 0;
-}
-
-
-static inline size_t UsefulOutBuf_GetEndPosition(UsefulOutBuf *pMe)
-{
- return pMe->data_len;
-}
-
-
-static inline int UsefulOutBuf_AtStart(UsefulOutBuf *pMe)
-{
- return 0 == pMe->data_len;
-}
-
-
-static inline void UsefulOutBuf_InsertData(UsefulOutBuf *pMe,
- const void *pBytes,
- size_t uLen,
- size_t uPos)
-{
- UsefulBufC Data = {pBytes, uLen};
- UsefulOutBuf_InsertUsefulBuf(pMe, Data, uPos);
-}
-
-
-static inline void UsefulOutBuf_InsertString(UsefulOutBuf *pMe,
- const char *szString,
- size_t uPos)
-{
- UsefulOutBuf_InsertUsefulBuf(pMe,
- (UsefulBufC){szString, strlen(szString)},
- uPos);
-}
-
-
-static inline void UsefulOutBuf_InsertByte(UsefulOutBuf *me,
- uint8_t byte,
- size_t uPos)
-{
- UsefulOutBuf_InsertData(me, &byte, 1, uPos);
-}
-
-
-static inline void UsefulOutBuf_InsertUint16(UsefulOutBuf *me,
- uint16_t uInteger16,
- size_t uPos)
-{
- // See UsefulOutBuf_InsertUint64() for comments on this code
-
- const void *pBytes;
-
-#if defined(USEFULBUF_CONFIG_BIG_ENDIAN)
- pBytes = &uInteger16;
-
-#elif defined(USEFULBUF_CONFIG_HTON)
- uint16_t uTmp = htons(uInteger16);
- pBytes = &uTmp;
-
-#elif defined(USEFULBUF_CONFIG_LITTLE_ENDIAN) && defined(USEFULBUF_CONFIG_BSWAP)
- uint16_t uTmp = __builtin_bswap16(uInteger16);
- pBytes = &uTmp;
-
-#else
- uint8_t aTmp[2];
-
- aTmp[0] = (uint8_t)((uInteger16 & 0xff00) >> 8);
- aTmp[1] = (uint8_t)(uInteger16 & 0xff);
-
- pBytes = aTmp;
-#endif
-
- UsefulOutBuf_InsertData(me, pBytes, 2, uPos);
-}
-
-
-static inline void UsefulOutBuf_InsertUint32(UsefulOutBuf *pMe,
- uint32_t uInteger32,
- size_t uPos)
-{
- // See UsefulOutBuf_InsertUint64() for comments on this code
-
- const void *pBytes;
-
-#if defined(USEFULBUF_CONFIG_BIG_ENDIAN)
- pBytes = &uInteger32;
-
-#elif defined(USEFULBUF_CONFIG_HTON)
- uint32_t uTmp = htonl(uInteger32);
- pBytes = &uTmp;
-
-#elif defined(USEFULBUF_CONFIG_LITTLE_ENDIAN) && defined(USEFULBUF_CONFIG_BSWAP)
- uint32_t uTmp = __builtin_bswap32(uInteger32);
-
- pBytes = &uTmp;
-
-#else
- uint8_t aTmp[4];
-
- aTmp[0] = (uint8_t)((uInteger32 & 0xff000000) >> 24);
- aTmp[1] = (uint8_t)((uInteger32 & 0xff0000) >> 16);
- aTmp[2] = (uint8_t)((uInteger32 & 0xff00) >> 8);
- aTmp[3] = (uint8_t)(uInteger32 & 0xff);
-
- pBytes = aTmp;
-#endif
-
- UsefulOutBuf_InsertData(pMe, pBytes, 4, uPos);
-}
-
-static inline void UsefulOutBuf_InsertUint64(UsefulOutBuf *pMe,
- uint64_t uInteger64,
- size_t uPos)
-{
- const void *pBytes;
-
-#if defined(USEFULBUF_CONFIG_BIG_ENDIAN)
- // We have been told explicitly we are running on a big-endian
- // machine. Network byte order is big endian, so just copy. There
- // is no issue with alignment here because uInter64 is always
- // aligned (and it doesn't matter if pBytes is aligned).
- pBytes = &uInteger64;
-
-#elif defined(USEFULBUF_CONFIG_HTON)
- // Use system function to handle big- and little-endian. This works
- // on both big- and little-endian machines, but hton() is not
- // always available or in a standard place so it is not used by
- // default. With some compilers and CPUs the code for this is very
- // compact through use of a special swap instruction and on
- // big-endian machines hton() will reduce to nothing.
- uint64_t uTmp = htonll(uInteger64);
-
- pBytes = &uTmp;
-
-#elif defined(USEFULBUF_CONFIG_LITTLE_ENDIAN) && defined(USEFULBUF_CONFIG_BSWAP)
- // Use built-in function for byte swapping. This usually compiles
- // to an efficient special byte swap instruction. Unlike hton() it
- // does not do this conditionally on the CPU endianness, so this
- // code is also conditional on USEFULBUF_CONFIG_LITTLE_ENDIAN
- uint64_t uTmp = __builtin_bswap64(uInteger64);
-
- pBytes = &uTmp;
-
-#else
- // Default which works on every CPU with no dependency on anything
- // from the CPU, compiler, libraries or OS. This always works, but
- // it is usually a little larger and slower than hton().
- uint8_t aTmp[8];
-
- aTmp[0] = (uint8_t)((uInteger64 & 0xff00000000000000) >> 56);
- aTmp[1] = (uint8_t)((uInteger64 & 0xff000000000000) >> 48);
- aTmp[2] = (uint8_t)((uInteger64 & 0xff0000000000) >> 40);
- aTmp[3] = (uint8_t)((uInteger64 & 0xff00000000) >> 32);
- aTmp[4] = (uint8_t)((uInteger64 & 0xff000000) >> 24);
- aTmp[5] = (uint8_t)((uInteger64 & 0xff0000) >> 16);
- aTmp[6] = (uint8_t)((uInteger64 & 0xff00) >> 8);
- aTmp[7] = (uint8_t)(uInteger64 & 0xff);
-
- pBytes = aTmp;
-#endif
-
- // Do the insert
- UsefulOutBuf_InsertData(pMe, pBytes, sizeof(uint64_t), uPos);
-}
-
-
-static inline void UsefulOutBuf_InsertFloat(UsefulOutBuf *pMe,
- float f,
- size_t uPos)
-{
- UsefulOutBuf_InsertUint32(pMe, UsefulBufUtil_CopyFloatToUint32(f), uPos);
-}
-
-
-static inline void UsefulOutBuf_InsertDouble(UsefulOutBuf *pMe,
- double d,
- size_t uPos)
-{
- UsefulOutBuf_InsertUint64(pMe, UsefulBufUtil_CopyDoubleToUint64(d), uPos);
-}
-
-
-static inline void UsefulOutBuf_AppendUsefulBuf(UsefulOutBuf *pMe,
- UsefulBufC NewData)
-{
- // An append is just a insert at the end
- UsefulOutBuf_InsertUsefulBuf(pMe, NewData, UsefulOutBuf_GetEndPosition(pMe));
-}
-
-
-static inline void UsefulOutBuf_AppendData(UsefulOutBuf *pMe,
- const void *pBytes,
- size_t uLen)
-{
- UsefulBufC Data = {pBytes, uLen};
- UsefulOutBuf_AppendUsefulBuf(pMe, Data);
-}
-
-
-static inline void UsefulOutBuf_AppendString(UsefulOutBuf *pMe,
- const char *szString)
-{
- UsefulOutBuf_AppendUsefulBuf(pMe, (UsefulBufC){szString, strlen(szString)});
-}
-
-
-static inline void UsefulOutBuf_AppendByte(UsefulOutBuf *pMe,
- uint8_t byte)
-{
- UsefulOutBuf_AppendData(pMe, &byte, 1);
-}
-
-
-static inline void UsefulOutBuf_AppendUint16(UsefulOutBuf *pMe,
- uint16_t uInteger16)
-{
- UsefulOutBuf_InsertUint16(pMe, uInteger16, UsefulOutBuf_GetEndPosition(pMe));
-}
-
-static inline void UsefulOutBuf_AppendUint32(UsefulOutBuf *pMe,
- uint32_t uInteger32)
-{
- UsefulOutBuf_InsertUint32(pMe, uInteger32, UsefulOutBuf_GetEndPosition(pMe));
-}
-
-
-static inline void UsefulOutBuf_AppendUint64(UsefulOutBuf *pMe,
- uint64_t uInteger64)
-{
- UsefulOutBuf_InsertUint64(pMe, uInteger64, UsefulOutBuf_GetEndPosition(pMe));
-}
-
-
-static inline void UsefulOutBuf_AppendFloat(UsefulOutBuf *pMe,
- float f)
-{
- UsefulOutBuf_InsertFloat(pMe, f, UsefulOutBuf_GetEndPosition(pMe));
-}
-
-
-static inline void UsefulOutBuf_AppendDouble(UsefulOutBuf *pMe,
- double d)
-{
- UsefulOutBuf_InsertDouble(pMe, d, UsefulOutBuf_GetEndPosition(pMe));
-}
-
-
-static inline int UsefulOutBuf_GetError(UsefulOutBuf *pMe)
-{
- return pMe->err;
-}
-
-
-static inline size_t UsefulOutBuf_RoomLeft(UsefulOutBuf *pMe)
-{
- return pMe->UB.len - pMe->data_len;
-}
-
-
-static inline int UsefulOutBuf_WillItFit(UsefulOutBuf *pMe, size_t uLen)
-{
- return uLen <= UsefulOutBuf_RoomLeft(pMe);
-}
-
-
-static inline int UsefulOutBuf_IsBufferNULL(UsefulOutBuf *pMe)
-{
- return pMe->UB.ptr == NULL;
-}
-
-
-
-static inline void UsefulInputBuf_Init(UsefulInputBuf *pMe, UsefulBufC UB)
-{
- pMe->cursor = 0;
- pMe->err = 0;
- pMe->magic = UIB_MAGIC;
- pMe->UB = UB;
-}
-
-static inline size_t UsefulInputBuf_Tell(UsefulInputBuf *pMe)
-{
- return pMe->cursor;
-}
-
-
-static inline void UsefulInputBuf_Seek(UsefulInputBuf *pMe, size_t uPos)
-{
- if(uPos > pMe->UB.len) {
- pMe->err = 1;
- } else {
- pMe->cursor = uPos;
- }
-}
-
-
-static inline size_t UsefulInputBuf_BytesUnconsumed(UsefulInputBuf *pMe)
-{
- // Code Reviewers: THIS FUNCTION DOES POINTER MATH
-
- // Magic number is messed up. Either the structure got overwritten
- // or was never initialized.
- if(pMe->magic != UIB_MAGIC) {
- return 0;
- }
-
- // The cursor is off the end of the input buffer given.
- // Presuming there are no bugs in this code, this should never happen.
- // If it so, the struct was corrupted. The check is retained as
- // as a defense in case there is a bug in this code or the struct is
- // corrupted.
- if(pMe->cursor > pMe->UB.len) {
- return 0;
- }
-
- // subtraction can't go neative because of check above
- return pMe->UB.len - pMe->cursor;
-}
-
-
-static inline int UsefulInputBuf_BytesAvailable(UsefulInputBuf *pMe, size_t uLen)
-{
- return UsefulInputBuf_BytesUnconsumed(pMe) >= uLen ? 1 : 0;
-}
-
-
-static inline UsefulBufC UsefulInputBuf_GetUsefulBuf(UsefulInputBuf *pMe, size_t uNum)
-{
- const void *pResult = UsefulInputBuf_GetBytes(pMe, uNum);
- if(!pResult) {
- return NULLUsefulBufC;
- } else {
- return (UsefulBufC){pResult, uNum};
- }
-}
-
-
-static inline uint8_t UsefulInputBuf_GetByte(UsefulInputBuf *pMe)
-{
- const void *pResult = UsefulInputBuf_GetBytes(pMe, sizeof(uint8_t));
-
- // The ternery operator is subject to integer promotion, because the
- // operands are smaller than int, so cast back to uint8_t is needed
- // to be completely explicit about types (for static analyzers)
- return (uint8_t)(pResult ? *(uint8_t *)pResult : 0);
-}
-
-static inline uint16_t UsefulInputBuf_GetUint16(UsefulInputBuf *pMe)
-{
- const uint8_t *pResult = (const uint8_t *)UsefulInputBuf_GetBytes(pMe, sizeof(uint16_t));
-
- if(!pResult) {
- return 0;
- }
-
- // See UsefulInputBuf_GetUint64() for comments on this code
-#if defined(USEFULBUF_CONFIG_BIG_ENDIAN) || defined(USEFULBUF_CONFIG_HTON) || defined(USEFULBUF_CONFIG_BSWAP)
- uint16_t uTmp;
- memcpy(&uTmp, pResult, sizeof(uint16_t));
-
-#if defined(USEFULBUF_CONFIG_BIG_ENDIAN)
- return uTmp;
-
-#elif defined(USEFULBUF_CONFIG_HTON)
- return ntohs(uTmp);
-
-#else
- return __builtin_bswap16(uTmp);
-
-#endif
-
-#else
-
- // The operations here are subject to integer promotion because the
- // operands are smaller than int. They will be promoted to unsigned
- // int for the shift and addition. The cast back to uint16_t is is needed
- // to be completely explicit about types (for static analyzers)
- return (uint16_t)((pResult[0] << 8) + pResult[1]);
-
-#endif
-}
-
-
-static inline uint32_t UsefulInputBuf_GetUint32(UsefulInputBuf *pMe)
-{
- const uint8_t *pResult = (const uint8_t *)UsefulInputBuf_GetBytes(pMe, sizeof(uint32_t));
-
- if(!pResult) {
- return 0;
- }
-
- // See UsefulInputBuf_GetUint64() for comments on this code
-#if defined(USEFULBUF_CONFIG_BIG_ENDIAN) || defined(USEFULBUF_CONFIG_HTON) || defined(USEFULBUF_CONFIG_BSWAP)
- uint32_t uTmp;
- memcpy(&uTmp, pResult, sizeof(uint32_t));
-
-#if defined(USEFULBUF_CONFIG_BIG_ENDIAN)
- return uTmp;
-
-#elif defined(USEFULBUF_CONFIG_HTON)
- return ntohl(uTmp);
-
-#else
- return __builtin_bswap32(uTmp);
-
-#endif
-
-#else
- return ((uint32_t)pResult[0]<<24) +
- ((uint32_t)pResult[1]<<16) +
- ((uint32_t)pResult[2]<<8) +
- (uint32_t)pResult[3];
-#endif
-}
-
-
-static inline uint64_t UsefulInputBuf_GetUint64(UsefulInputBuf *pMe)
-{
- const uint8_t *pResult = (const uint8_t *)UsefulInputBuf_GetBytes(pMe, sizeof(uint64_t));
-
- if(!pResult) {
- return 0;
- }
-
-#if defined(USEFULBUF_CONFIG_BIG_ENDIAN) || defined(USEFULBUF_CONFIG_HTON) || defined(USEFULBUF_CONFIG_BSWAP)
- // pResult will probably not be aligned. This memcpy() moves the
- // bytes into a temp variable safely for CPUs that can or can't do
- // unaligned memory access. Many compilers will optimize the
- // memcpy() into a simple move instruction.
- uint64_t uTmp;
- memcpy(&uTmp, pResult, sizeof(uint64_t));
-
-#if defined(USEFULBUF_CONFIG_BIG_ENDIAN)
- // We have been told expliclity this is a big-endian CPU. Since
- // network byte order is big-endian, there is nothing to do.
-
- return uTmp;
-
-#elif defined(USEFULBUF_CONFIG_HTON)
- // We have been told to use ntoh(), the system function to handle
- // big- and little-endian. This works on both big- and
- // little-endian machines, but ntoh() is not always available or in
- // a standard place so it is not used by default. On some CPUs the
- // code for this is very compact through use of a special swap
- // instruction.
-
- return ntohll(uTmp);
-
-#else
- // Little-endian (since it is not USEFULBUF_CONFIG_BIG_ENDIAN) and
- // USEFULBUF_CONFIG_BSWAP (since it is not USEFULBUF_CONFIG_HTON).
- // __builtin_bswap64() and friends are not conditional on CPU
- // endianness so this must only be used on little-endian machines.
-
- return __builtin_bswap64(uTmp);
-
-
-#endif
-
-#else
- // This is the default code that works on every CPU and every
- // endianness with no dependency on ntoh(). This works on CPUs
- // that either allow or do not allow unaligned access. It will
- // always work, but usually is a little less efficient than ntoh().
-
- return ((uint64_t)pResult[0]<<56) +
- ((uint64_t)pResult[1]<<48) +
- ((uint64_t)pResult[2]<<40) +
- ((uint64_t)pResult[3]<<32) +
- ((uint64_t)pResult[4]<<24) +
- ((uint64_t)pResult[5]<<16) +
- ((uint64_t)pResult[6]<<8) +
- (uint64_t)pResult[7];
-#endif
-}
-
-
-static inline float UsefulInputBuf_GetFloat(UsefulInputBuf *pMe)
-{
- uint32_t uResult = UsefulInputBuf_GetUint32(pMe);
-
- return uResult ? UsefulBufUtil_CopyUint32ToFloat(uResult) : 0;
-}
-
-
-static inline double UsefulInputBuf_GetDouble(UsefulInputBuf *pMe)
-{
- uint64_t uResult = UsefulInputBuf_GetUint64(pMe);
-
- return uResult ? UsefulBufUtil_CopyUint64ToDouble(uResult) : 0;
-}
-
-
-static inline int UsefulInputBuf_GetError(UsefulInputBuf *pMe)
-{
- return pMe->err;
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // _UsefulBuf_h
-
-
+#include "qcbor/UsefulBuf.h"
diff --git a/inc/qcbor.h b/inc/qcbor.h
index 41b8e16..e5b23e6 100644
--- a/inc/qcbor.h
+++ b/inc/qcbor.h
@@ -1,3586 +1 @@
-/*==============================================================================
- Copyright (c) 2016-2018, The Linux Foundation.
- Copyright (c) 2018-2020, Laurence Lundblade.
- All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the following
- disclaimer in the documentation and/or other materials provided
- with the distribution.
- * Neither the name of The Linux Foundation nor the names of its
- contributors, nor the name "Laurence Lundblade" may be used to
- endorse or promote products derived from this software without
- specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
-WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
-BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
-OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
-IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- =============================================================================*/
-
-
-/*=============================================================================
- FILE: qcbor.h
-
- DESCRIPTION: This is the full public API and data structures for QCBOR
-
- EDIT HISTORY FOR FILE:
-
- This section contains comments describing changes made to the module.
- Notice that changes are listed in reverse chronological order.
-
- when who what, where, why
- -------- ---- ---------------------------------------------------
- 02/07/2020 llundblade QCBOREncode_EncodeHead() and other for bstr hashing.
- 01/25/2020 llundblade Cleaner handling of too-long encoded string input.
- 01/08/2020 llundblade Documentation corrections & improved code formatting.
- 12/30/19 llundblade Add support for decimal fractions and bigfloats.
- 08/7/19 llundblade Better handling of not well-formed encode and decode.
- 07/31/19 llundblade New error code for better end of data handling.
- 7/25/19 janjongboom Add indefinite length encoding for maps and arrays.
- 05/26/19 llundblade Add QCBOREncode_GetErrorState() and _IsBufferNULL().
- 04/26/19 llundblade Big documentation & style update. No interface change.
- 02/16/19 llundblade Redesign MemPool to fix memory access alignment bug.
- 12/18/18 llundblade Move decode malloc optional code to separate repo.
- 12/13/18 llundblade Documentatation improvements.
- 11/29/18 llundblade Rework to simpler handling of tags and labels.
- 11/9/18 llundblade Error codes are now enums.
- 11/1/18 llundblade Floating support.
- 10/31/18 llundblade Switch to one license that is almost BSD-3.
- 10/15/18 llundblade indefinite-length maps and arrays supported
- 10/8/18 llundblade indefinite-length strings supported
- 09/28/18 llundblade Added bstr wrapping feature for COSE implementation.
- 07/05/17 llundbla Add bstr wrapping of maps/arrays for COSE.
- 03/01/17 llundbla More data types; decoding improvements and fixes.
- 11/13/16 llundbla Integrate most TZ changes back into github version.
- 09/30/16 gkanike Porting to TZ.
- 03/15/16 llundbla Initial Version.
-
- =============================================================================*/
-
-#ifndef __QCBOR__qcbor__
-#define __QCBOR__qcbor__
-
-
-/* ===========================================================================
- BEGINNING OF PRIVATE PART OF THIS FILE
-
- Caller of QCBOR should not reference any of the details below up until
- the start of the public part.
- ========================================================================== */
-
-/*
- Standard integer types are used in the interface to be precise about
- sizes to be better at preventing underflow/overflow errors.
- */
-#include <stdint.h>
-#include <stdbool.h>
-#include "UsefulBuf.h"
-
-#ifdef __cplusplus
-extern "C" {
-#ifdef 0
-} // Keep editor indention formatting happy
-#endif
-#endif
-
-/*
- The maxium nesting of arrays and maps when encoding or decoding.
- (Further down in the file there is a definition that refers to this
- that is public. This is done this way so there can be a nice
- separation of public and private parts in this file.
-*/
-#define QCBOR_MAX_ARRAY_NESTING1 15 // Do not increase this over 255
-
-
-/* The largest offset to the start of an array or map. It is slightly
- less than UINT32_MAX so the error condition can be tests on 32-bit machines.
- UINT32_MAX comes from uStart in QCBORTrackNesting being a uin32_t.
-
- This will cause trouble on a machine where size_t is less than 32-bits.
- */
-#define QCBOR_MAX_ARRAY_OFFSET (UINT32_MAX - 100)
-
-/*
- PRIVATE DATA STRUCTURE
-
- Holds the data for tracking array and map nesting during encoding. Pairs up
- with the Nesting_xxx functions to make an "object" to handle nesting encoding.
-
- uStart is a uint32_t instead of a size_t to keep the size of this
- struct down so it can be on the stack without any concern. It would be about
- double if size_t was used instead.
-
- Size approximation (varies with CPU/compiler):
- 64-bit machine: (15 + 1) * (4 + 2 + 1 + 1 pad) + 8 = 136 bytes
- 32-bit machine: (15 + 1) * (4 + 2 + 1 + 1 pad) + 4 = 132 bytes
-*/
-typedef struct __QCBORTrackNesting {
- // PRIVATE DATA STRUCTURE
- struct {
- // See function QCBOREncode_OpenMapOrArray() for details on how this works
- uint32_t uStart; // uStart is the byte position where the array starts
- uint16_t uCount; // Number of items in the arrary or map; counts items
- // in a map, not pairs of items
- uint8_t uMajorType; // Indicates if item is a map or an array
- } pArrays[QCBOR_MAX_ARRAY_NESTING1+1], // stored state for the nesting levels
- *pCurrentNesting; // the current nesting level
-} QCBORTrackNesting;
-
-
-/*
- PRIVATE DATA STRUCTURE
-
- Context / data object for encoding some CBOR. Used by all encode functions to
- form a public "object" that does the job of encdoing.
-
- Size approximation (varies with CPU/compiler):
- 64-bit machine: 27 + 1 (+ 4 padding) + 136 = 32 + 136 = 168 bytes
- 32-bit machine: 15 + 1 + 132 = 148 bytes
-*/
-struct _QCBOREncodeContext {
- // PRIVATE DATA STRUCTURE
- UsefulOutBuf OutBuf; // Pointer to output buffer, its length and
- // position in it
- uint8_t uError; // Error state, always from QCBORError enum
- QCBORTrackNesting nesting; // Keep track of array and map nesting
-};
-
-
-/*
- PRIVATE DATA STRUCTURE
-
- Holds the data for array and map nesting for decoding work. This structure
- and the DecodeNesting_xxx functions form an "object" that does the work
- for arrays and maps.
-
- Size approximation (varies with CPU/compiler):
- 64-bit machine: 4 * 16 + 8 = 72
- 32-bit machine: 4 * 16 + 4 = 68
- */
-typedef struct __QCBORDecodeNesting {
- // PRIVATE DATA STRUCTURE
- struct {
- uint16_t uCount;
- uint8_t uMajorType;
- } pMapsAndArrays[QCBOR_MAX_ARRAY_NESTING1+1],
- *pCurrent;
-} QCBORDecodeNesting;
-
-
-typedef struct {
- // PRIVATE DATA STRUCTURE
- void *pAllocateCxt;
- UsefulBuf (* pfAllocator)(void *pAllocateCxt, void *pOldMem, size_t uNewSize);
-} QCORInternalAllocator;
-
-
-/*
- PRIVATE DATA STRUCTURE
-
- The decode context. This data structure plus the public QCBORDecode_xxx
- functions form an "object" that does CBOR decoding.
-
- Size approximation (varies with CPU/compiler):
- 64-bit machine: 32 + 1 + 1 + 6 bytes padding + 72 + 16 + 8 + 8 = 144 bytes
- 32-bit machine: 16 + 1 + 1 + 2 bytes padding + 68 + 8 + 8 + 4 = 108 bytes
- */
-struct _QCBORDecodeContext {
- // PRIVATE DATA STRUCTURE
- UsefulInputBuf InBuf;
-
- uint8_t uDecodeMode;
- uint8_t bStringAllocateAll;
-
- QCBORDecodeNesting nesting;
-
- // If a string allocator is configured for indefinite-length
- // strings, it is configured here.
- QCORInternalAllocator StringAllocator;
-
- // These are special for the internal MemPool allocator.
- // They are not used otherwise. We tried packing these
- // in the MemPool itself, but there are issues
- // with memory alignment.
- uint32_t uMemPoolSize;
- uint32_t uMemPoolFreeOffset;
-
- // This is NULL or points to QCBORTagList.
- // It is type void for the same reason as above.
- const void *pCallerConfiguredTagList;
-};
-
-// Used internally in the impementation here
-// Must not conflict with any of the official CBOR types
-#define CBOR_MAJOR_NONE_TYPE_RAW 9
-#define CBOR_MAJOR_NONE_TAG_LABEL_REORDER 10
-#define CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY 11
-#define CBOR_MAJOR_NONE_TYPE_ARRAY_INDEFINITE_LEN 12
-#define CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN 13
-
-
-/* ==========================================================================
- END OF PRIVATE PART OF THIS FILE
-
- BEGINNING OF PUBLIC PART OF THIS FILE
- ========================================================================== */
-
-
-
-/* ==========================================================================
- BEGINNING OF CONSTANTS THAT COME FROM THE CBOR STANDARD, RFC 7049
-
- It is not necessary to use these directly when encoding or decoding
- CBOR with this implementation.
- ========================================================================== */
-
-/* Standard CBOR Major type for positive integers of various lengths */
-#define CBOR_MAJOR_TYPE_POSITIVE_INT 0
-
-/* Standard CBOR Major type for negative integer of various lengths */
-#define CBOR_MAJOR_TYPE_NEGATIVE_INT 1
-
-/* Standard CBOR Major type for an array of arbitrary 8-bit bytes. */
-#define CBOR_MAJOR_TYPE_BYTE_STRING 2
-
-/* Standard CBOR Major type for a UTF-8 string. Note this is true 8-bit UTF8
- with no encoding and no NULL termination */
-#define CBOR_MAJOR_TYPE_TEXT_STRING 3
-
-/* Standard CBOR Major type for an ordered array of other CBOR data items */
-#define CBOR_MAJOR_TYPE_ARRAY 4
-
-/* Standard CBOR Major type for CBOR MAP. Maps an array of pairs. The
- first item in the pair is the "label" (key, name or identfier) and the second
- item is the value. */
-#define CBOR_MAJOR_TYPE_MAP 5
-
-/* Standard CBOR optional tagging. This tags things like dates and URLs */
-#define CBOR_MAJOR_TYPE_OPTIONAL 6
-
-/* Standard CBOR extra simple types like floats and the values true and false */
-#define CBOR_MAJOR_TYPE_SIMPLE 7
-
-
-/*
- These are special values for the AdditionalInfo bits that are part of
- the first byte. Mostly they encode the length of the data item.
- */
-#define LEN_IS_ONE_BYTE 24
-#define LEN_IS_TWO_BYTES 25
-#define LEN_IS_FOUR_BYTES 26
-#define LEN_IS_EIGHT_BYTES 27
-#define ADDINFO_RESERVED1 28
-#define ADDINFO_RESERVED2 29
-#define ADDINFO_RESERVED3 30
-#define LEN_IS_INDEFINITE 31
-
-
-/*
- 24 is a special number for CBOR. Integers and lengths
- less than it are encoded in the same byte as the major type.
- */
-#define CBOR_TWENTY_FOUR 24
-
-
-/*
- Tags that are used with CBOR_MAJOR_TYPE_OPTIONAL. These
- are types defined in RFC 7049 and some additional ones
- in the IANA CBOR tags registry.
- */
-/** See QCBOREncode_AddDateString(). */
-#define CBOR_TAG_DATE_STRING 0
-/** See QCBOREncode_AddDateEpoch(). */
-#define CBOR_TAG_DATE_EPOCH 1
-/** See QCBOREncode_AddPositiveBignum(). */
-#define CBOR_TAG_POS_BIGNUM 2
-/** See QCBOREncode_AddNegativeBignum(). */
-#define CBOR_TAG_NEG_BIGNUM 3
-/** CBOR tag for a two-element array representing a fraction with a
- mantissa and base-10 scaling factor. See QCBOREncode_AddDecimalFraction()
- and @ref expAndMantissa.
- */
-#define CBOR_TAG_DECIMAL_FRACTION 4
-/** CBOR tag for a two-element array representing a fraction with a
- mantissa and base-2 scaling factor. See QCBOREncode_AddBigFloat()
- and @ref expAndMantissa. */
-#define CBOR_TAG_BIGFLOAT 5
-/** Tag for COSE format encryption with no recipient
- identification. See [RFC 8152, COSE]
- (https://tools.ietf.org/html/rfc8152). No API is provided for this
- tag. */
-#define CBOR_TAG_COSE_ENCRYPTO 16
-/** Tag for COSE format MAC'd data with no recipient
- identification. See [RFC 8152, COSE]
- (https://tools.ietf.org/html/rfc8152). No API is provided for this
- tag.*/
-#define CBOR_TAG_COSE_MAC0 17
-/** Tag for COSE format single signature signing. No API is provided
- for this tag. See [RFC 8152, COSE]
- (https://tools.ietf.org/html/rfc8152). */
-#define CBOR_TAG_COSE_SIGN1 18
-/** A hint that the following byte string should be encoded in
- Base64URL when converting to JSON or similar text-based
- representations. Call @c
- QCBOREncode_AddTag(pCtx,CBOR_TAG_ENC_AS_B64URL) before the call to
- QCBOREncode_AddBytes(). */
-#define CBOR_TAG_ENC_AS_B64URL 21
-/** A hint that the following byte string should be encoded in Base64
- when converting to JSON or similar text-based
- representations. Call @c
- QCBOREncode_AddTag(pCtx,CBOR_TAG_ENC_AS_B64) before the call to
- QCBOREncode_AddBytes(). */
-#define CBOR_TAG_ENC_AS_B64 22
-/** A hint that the following byte string should be encoded in base-16
- format per [RFC 4648] (https://tools.ietf.org/html/rfc4648) when
- converting to JSON or similar text-based
- representations. Essentially, Base-16 encoding is the standard
- case- insensitive hex encoding and may be referred to as
- "hex". Call @c QCBOREncode_AddTag(pCtx,CBOR_TAG_ENC_AS_B16) before
- the call to QCBOREncode_AddBytes(). */
-#define CBOR_TAG_ENC_AS_B16 23
-/** Tag to indicate a byte string contains encoded CBOR. No API is
- provided for this tag. */
-#define CBOR_TAG_CBOR 24
-/** See QCBOREncode_AddURI(). */
-#define CBOR_TAG_URI 32
-/** See QCBOREncode_AddB64URLText(). */
-#define CBOR_TAG_B64URL 33
-/** See QCBOREncode_AddB64Text(). */
-#define CBOR_TAG_B64 34
-/** See QCBOREncode_AddRegex(). */
-#define CBOR_TAG_REGEX 35
-/** See QCBOREncode_AddMIMEData(). */
-#define CBOR_TAG_MIME 36
-/** See QCBOREncode_AddBinaryUUID(). */
-#define CBOR_TAG_BIN_UUID 37
-/** The data is a CBOR Web Token per [RFC 8392]
- (https://tools.ietf.org/html/rfc8932). No API is provided for this
- tag. */
-#define CBOR_TAG_CWT 61
-/** Tag for COSE format encryption. See [RFC 8152, COSE]
- (https://tools.ietf.org/html/rfc8152). No API is provided for this
- tag. */
-#define CBOR_TAG_ENCRYPT 96
-/** Tag for COSE format MAC. See [RFC 8152, COSE]
- (https://tools.ietf.org/html/rfc8152). No API is provided for this
- tag. */
-#define CBOR_TAG_MAC 97
-/** Tag for COSE format signed data. See [RFC 8152, COSE]
- (https://tools.ietf.org/html/rfc8152). No API is provided for this
- tag. */
-#define CBOR_TAG_SIGN 98
-/** World geographic coordinates. See ISO 6709, [RFC 5870]
- (https://tools.ietf.org/html/rfc5870) and WGS-84. No API is
- provided for this tag. */
-#define CBOR_TAG_GEO_COORD 103
-/** The magic number, self-described CBOR. No API is provided for this
- tag. */
-#define CBOR_TAG_CBOR_MAGIC 55799
-
-#define CBOR_TAG_NONE UINT64_MAX
-
-
-/*
- Values for the 5 bits for items of major type 7
- */
-#define CBOR_SIMPLEV_FALSE 20
-#define CBOR_SIMPLEV_TRUE 21
-#define CBOR_SIMPLEV_NULL 22
-#define CBOR_SIMPLEV_UNDEF 23
-#define CBOR_SIMPLEV_ONEBYTE 24
-#define HALF_PREC_FLOAT 25
-#define SINGLE_PREC_FLOAT 26
-#define DOUBLE_PREC_FLOAT 27
-#define CBOR_SIMPLE_BREAK 31
-#define CBOR_SIMPLEV_RESERVED_START CBOR_SIMPLEV_ONEBYTE
-#define CBOR_SIMPLEV_RESERVED_END CBOR_SIMPLE_BREAK
-
-
-
-/* ===========================================================================
-
- END OF CONSTANTS THAT COME FROM THE CBOR STANDARD, RFC 7049
-
- BEGINNING OF PUBLIC INTERFACE FOR QCBOR ENCODER / DECODER
-
- =========================================================================== */
-
-/**
-
- @file qcbor.h
-
- Q C B O R E n c o d e / D e c o d e
-
- This implements CBOR -- Concise Binary Object Representation as
- defined in [RFC 7049] (https://tools.ietf.org/html/rfc7049). More
- info is at http://cbor.io. This is a near-complete implementation of
- the specification. Limitations are listed further down.
-
- CBOR is intentionally designed to be translatable to JSON, but not
- all CBOR can convert to JSON. See RFC 7049 for more info on how to
- construct CBOR that is the most JSON friendly.
-
- The memory model for encoding and decoding is that encoded CBOR must
- be in a contiguous buffer in memory. During encoding the caller must
- supply an output buffer and if the encoding would go off the end of
- the buffer an error is returned. During decoding the caller supplies
- the encoded CBOR in a contiguous buffer and the decoder returns
- pointers and lengths into that buffer for strings.
-
- This implementation does not require malloc. All data structures
- passed in/out of the APIs can fit on the stack.
-
- Decoding of indefinite-length strings is a special case that requires
- a "string allocator" to allocate memory into which the segments of
- the string are coalesced. Without this, decoding will error out if an
- indefinite-length string is encountered (indefinite-length maps and
- arrays do not require the string allocator). A simple string
- allocator called MemPool is built-in and will work if supplied with a
- block of memory to allocate. The string allocator can optionally use
- malloc() or some other custom scheme.
-
- Here are some terms and definitions:
-
- - "Item", "Data Item": An integer or string or such. The basic "thing" that
- CBOR is about. An array is an item itself that contains some items.
-
- - "Array": An ordered sequence of items, the same as JSON.
-
- - "Map": A collection of label/value pairs. Each pair is a data
- item. A JSON "object" is the same as a CBOR "map".
-
- - "Label": The data item in a pair in a map that names or identifies
- the pair, not the value. This implementation refers to it as a
- "label". JSON refers to it as the "name". The CBOR RFC refers to it
- this as a "key". This implementation chooses label instead because
- key is too easily confused with a cryptographic key. The COSE
- standard, which uses CBOR, has also chosen to use the term "label"
- rather than "key" for this same reason.
-
- - "Key": See "Label" above.
-
- - "Tag": Optional integer that can be added before each data item
- usually to indicate it is new or more specific data type. For
- example, a tag can indicate an integer is a date, or that a map is to
- be considered a type (analogous to a typedef in C).
-
- - "Initial Byte": The first byte of an encoded item. Encoding and
- decoding of this byte is taken care of by the implementation.
-
- - "Additional Info": In addition to the major type, all data items
- have some other info. This is usually the length of the data but can
- be several other things. Encoding and decoding of this is taken care
- of by the implementation.
-
- CBOR has two mechanisms for tagging and labeling the data values like
- integers and strings. For example, an integer that represents
- someone's birthday in epoch seconds since Jan 1, 1970 could be
- encoded like this:
-
- - First it is CBOR_MAJOR_TYPE_POSITIVE_INT (@ref QCBOR_TYPE_INT64),
- the primitive positive integer.
-
- - Next it has a "tag" @ref CBOR_TAG_DATE_EPOCH indicating the integer
- represents a date in the form of the number of seconds since Jan 1,
- 1970.
-
- - Last it has a string "label" like "BirthDate" indicating the
- meaning of the data.
-
- The encoded binary looks like this:
-
- a1 # Map of 1 item
- 69 # Indicates text string of 9 bytes
- 426972746844617465 # The text "BirthDate"
- c1 # Tags next integer as epoch date
- 1a # Indicates a 4-byte integer
- 580d4172 # unsigned integer date 1477263730
-
- Implementors using this API will primarily work with
- labels. Generally, tags are only needed for making up new data
- types. This implementation covers most of the data types defined in
- the RFC using tags. It also, allows for the use of custom tags if
- necessary.
-
- This implementation explicitly supports labels that are text strings
- and integers. Text strings translate nicely into JSON objects and are
- very readable. Integer labels are much less readable but can be very
- compact. If they are in the range of 0 to 23, they take up only one
- byte.
-
- CBOR allows a label to be any type of data including an array or a
- map. It is possible to use this API to construct and parse such
- labels, but it is not explicitly supported.
-
- A common encoding usage mode is to invoke the encoding twice. First
- with no output buffer to compute the length of the needed output
- buffer. Then the correct sized output buffer is allocated. Last the
- encoder is invoked again, this time with the output buffer.
-
- The double invocation is not required if the maximum output buffer
- size can be predicted. This is usually possible for simple CBOR
- structures. If the double invocation is implemented, it can be in a
- loop or function as in the example code so that the code doesn't have
- to actually be written twice, saving code size.
-
- If a buffer too small to hold the encoded output is given, the error
- @ref QCBOR_ERR_BUFFER_TOO_SMALL will be returned. Data will never be
- written off the end of the output buffer no matter which functions
- here are called or what parameters are passed to them.
-
- The encoding error handling is simple. The only possible errors are
- trying to encode structures that are too large or too complex. There
- are no internal malloc calls so there will be no failures for out of
- memory. The error state is tracked internally, so there is no need
- to check for errors when encoding. Only the return code from
- QCBOREncode_Finish() need be checked as once an error happens, the
- encoder goes into an error state and calls to it to add more data
- will do nothing. An error check is not needed after every data item
- is added.
-
- Encoding generally proceeds by calling QCBOREncode_Init(), calling
- lots of @c QCBOREncode_AddXxx() functions and calling
- QCBOREncode_Finish(). There are many @c QCBOREncode_AddXxx()
- functions for various data types. The input buffers need only to be
- valid during the @c QCBOREncode_AddXxx() calls as the data is copied
- into the output buffer.
-
- There are three `Add` functions for each data type. The first / main
- one for the type is for adding the data item to an array. The second
- one's name ends in `ToMap`, is used for adding data items to maps and
- takes a string argument that is its label in the map. The third one
- ends in `ToMapN`, is also used for adding data items to maps, and
- takes an integer argument that is its label in the map.
-
- The simplest aggregate type is an array, which is a simple ordered
- set of items without labels the same as JSON arrays. Call
- QCBOREncode_OpenArray() to open a new array, then various @c
- QCBOREncode_AddXxx() functions to put items in the array and then
- QCBOREncode_CloseArray(). Nesting to the limit @ref
- QCBOR_MAX_ARRAY_NESTING is allowed. All opens must be matched by
- closes or an encoding error will be returned.
-
- The other aggregate type is a map which does use labels. The `Add`
- functions that end in `ToMap` and `ToMapN` are convenient ways to add
- labeled data items to a map. You can also call any type of `Add`
- function once to add a label of any time and then call any type of
- `Add` again to add its value.
-
- Note that when you nest arrays or maps in a map, the nested array or
- map has a label.
-
- @anchor Tags-Overview
- Any CBOR data item can be tagged to add semantics, define a new data
- type or such. Some tags are fully standardized and some are just
- registered. Others are not registered and used in a proprietary way.
-
- Encoding and decoding of many of the registered tags is fully
- implemented by QCBOR. It is also possible to encode and decode tags
- that are not directly supported. For many use cases the built-in tag
- support should be adequate.
-
- For example, the registered epoch date tag is supported in encoding
- by QCBOREncode_AddDateEpoch() and in decoding by @ref
- QCBOR_TYPE_DATE_EPOCH and the @c epochDate member of @ref
- QCBORItem. This is typical of the built-in tag support. There is an
- API to encode data for it and a @c QCBOR_TYPE_XXX when it is decoded.
-
- Tags are registered in the [IANA CBOR Tags Registry]
- (https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml). There
- are roughly three options to create a new tag. First, a public
- specification can be created and the new tag registered with IANA.
- This is the most formal. Second, the new tag can be registered with
- IANA with just a short description rather than a full specification.
- These tags must be greater than 256. Third, a tag can be used without
- any IANA registration, though the registry should be checked to see
- that the new value doesn't collide with one that is registered. The
- value of these tags must be 256 or larger.
-
- The encoding side of tags not built-in is handled by
- QCBOREncode_AddTag() and is relatively simple. Tag decoding is more
- complex and mainly handled by QCBORDecode_GetNext(). Decoding of the
- structure of tagged data not built-in (if there is any) has to be
- implemented by the caller.
-
- Summary Limits of this implementation:
- - The entire encoded CBOR must fit into contiguous memory.
- - Max size of encoded / decoded CBOR data is @c UINT32_MAX (4GB).
- - Max array / map nesting level when encoding / decoding is
- @ref QCBOR_MAX_ARRAY_NESTING (this is typically 15).
- - Max items in an array or map when encoding / decoding is
- @ref QCBOR_MAX_ITEMS_IN_ARRAY (typically 65,536).
- - Does not directly support labels in maps other than text strings & integers.
- - Does not directly support integer labels greater than @c INT64_MAX.
- - Epoch dates limited to @c INT64_MAX (+/- 292 billion years).
- - Exponents for bigfloats and decimal integers are limited to @c INT64_MAX.
- - Tags on labels are ignored during decoding.
- - There is no duplicate detection of map labels (but duplicates are passed on).
- - Works only on 32- and 64-bit CPUs (modifications could make it work
- on 16-bit CPUs).
-
- The public interface uses @c size_t for all lengths. Internally the
- implementation uses 32-bit lengths by design to use less memory and
- fit structures on the stack. This limits the encoded CBOR it can work
- with to size @c UINT32_MAX (4GB) which should be enough.
-
- This implementation assumes two's compliment integer machines. @c
- <stdint.h> also requires this. It is possible to modify this
- implementation for another integer representation, but all modern
- machines seem to be two's compliment.
-
- */
-
-
-/**
- The maximum number of items in a single array or map when encoding of
- decoding.
-*/
-// -1 is because the value UINT16_MAX is used to track indefinite-length arrays
-#define QCBOR_MAX_ITEMS_IN_ARRAY (UINT16_MAX-1)
-
-/**
- The maximum nesting of arrays and maps when encoding or decoding. The
- error @ref QCBOR_ERR_ARRAY_NESTING_TOO_DEEP will be returned on
- encoding of decoding if it is exceeded.
-*/
-#define QCBOR_MAX_ARRAY_NESTING QCBOR_MAX_ARRAY_NESTING1
-
-/**
- The maximum number of tags that can be in @ref QCBORTagListIn and passed to
- QCBORDecode_SetCallerConfiguredTagList()
- */
-#define QCBOR_MAX_CUSTOM_TAGS 16
-
-/*
- The size of the buffer to be passed to QCBOREncode_EncodeHead(). It is one
- byte larger than sizeof(uint64_t) + 1, the actual maximum size of the
- head of a CBOR data item. because QCBOREncode_EncodeHead() needs
- one extra byte to work.
- */
-#define QCBOR_HEAD_BUFFER_SIZE (sizeof(uint64_t) + 2)
-
-/**
- Error codes returned by QCBOR Encoder and Decoder.
- */
-typedef enum {
- /** The encode or decode completely correctly. */
- QCBOR_SUCCESS = 0,
-
- /** The buffer provided for the encoded output when doing encoding
- was too small and the encoded output will not fit. Also, when
- the buffer given to QCBORDecode_SetMemPool() is too small. */
- QCBOR_ERR_BUFFER_TOO_SMALL = 1,
-
- /** During encoding or decoding, the array or map nesting was
- deeper than this implementation can handle. Note that in the
- interest of code size and memory use, this implementation has a
- hard limit on array nesting. The limit is defined as the
- constant @ref QCBOR_MAX_ARRAY_NESTING. */
- QCBOR_ERR_ARRAY_NESTING_TOO_DEEP = 2,
-
- /** During decoding or encoding, the array or map had too many
- items in it. This limit @ref QCBOR_MAX_ITEMS_IN_ARRAY,
- typically 65,535. */
- QCBOR_ERR_ARRAY_TOO_LONG = 3,
-
- /** During encoding, more arrays or maps were closed than
- opened. This is a coding error on the part of the caller of the
- encoder. */
- QCBOR_ERR_TOO_MANY_CLOSES = 4,
-
- /** During decoding, some CBOR construct was encountered that this
- decoder doesn't support, primarily this is the reserved
- additional info values, 28 through 30. During encoding,
- an attempt to create simple value between 24 and 31. */
- QCBOR_ERR_UNSUPPORTED = 5,
-
- /** During decoding, hit the end of the given data to decode. For
- example, a byte string of 100 bytes was expected, but the end
- of the input was hit before finding those 100 bytes. Corrupted
- CBOR input will often result in this error. See also @ref
- QCBOR_ERR_NO_MORE_ITEMS.
- */
- QCBOR_ERR_HIT_END = 6,
-
- /** During encoding, the length of the encoded CBOR exceeded @c
- UINT32_MAX. */
- QCBOR_ERR_BUFFER_TOO_LARGE = 7,
-
- /** During decoding, an integer smaller than INT64_MIN was received
- (CBOR can represent integers smaller than INT64_MIN, but C
- cannot). */
- QCBOR_ERR_INT_OVERFLOW = 8,
-
- /** During decoding, the label for a map entry is bad. What causes
- this error depends on the decoding mode. */
- QCBOR_ERR_MAP_LABEL_TYPE = 9,
-
- /** During encoding or decoding, the number of array or map opens
- was not matched by the number of closes. */
- QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN = 10,
-
- /** During decoding, a date greater than +- 292 billion years from
- Jan 1 1970 encountered during parsing. */
- QCBOR_ERR_DATE_OVERFLOW = 11,
-
- /** During decoding, the CBOR is not valid, primarily a simple type
- is encoded in a prohibited way. */
- QCBOR_ERR_BAD_TYPE_7 = 12,
-
- /** Optional tagging that doesn't make sense (an integer is tagged
- as a date string) or can't be handled. */
- QCBOR_ERR_BAD_OPT_TAG = 13,
-
- /** Returned by QCBORDecode_Finish() if all the inputs bytes have
- not been consumed. */
- QCBOR_ERR_EXTRA_BYTES = 14,
-
- /** During encoding, @c QCBOREncode_CloseXxx() called with a
- different type than is currently open. */
- QCBOR_ERR_CLOSE_MISMATCH = 15,
-
- /** Unable to decode an indefinite-length string because no string
- allocator was configured. See QCBORDecode_SetMemPool() or
- QCBORDecode_SetUpAllocator(). */
- QCBOR_ERR_NO_STRING_ALLOCATOR = 16,
-
- /** One of the chunks in an indefinite-length string is not of the
- type of the start of the string. */
- QCBOR_ERR_INDEFINITE_STRING_CHUNK = 17,
-
- /** Error allocating space for a string, usually for an
- indefinite-length string. */
- QCBOR_ERR_STRING_ALLOCATE = 18,
-
- /** During decoding, a break occurred outside an indefinite-length
- item. */
- QCBOR_ERR_BAD_BREAK = 19,
-
- /** During decoding, too many tags in the caller-configured tag
- list, or not enough space in @ref QCBORTagListOut. */
- QCBOR_ERR_TOO_MANY_TAGS = 20,
-
- /** An integer type is encoded with a bad length (an indefinite length) */
- QCBOR_ERR_BAD_INT = 21,
-
- /** All well-formed data items have been consumed and there are no
- more. If parsing a CBOR stream this indicates the non-error
- end of the stream. If parsing a CBOR stream / sequence, this
- probably indicates that some data items expected are not present.
- See also @ref QCBOR_ERR_HIT_END. */
- QCBOR_ERR_NO_MORE_ITEMS = 22,
-
- /** Something is wrong with a decimal fraction or bigfloat such as
- it not consisting of an array with two integers */
- QCBOR_ERR_BAD_EXP_AND_MANTISSA = 23,
-
- /** When decoding, a string's size is greater than size_t. In all but some
- very strange situations this is because of corrupt input CBOR and
- should be treated as such. The strange situation is a CPU with a very
- small size_t (e.g., a 16-bit CPU) and a large string (e.g., > 65KB).
- */
- QCBOR_ERR_STRING_TOO_LONG = 24
-
-} QCBORError;
-
-
-/**
- The decode mode options.
- */
-typedef enum {
- /** See QCBORDecode_Init() */
- QCBOR_DECODE_MODE_NORMAL = 0,
- /** See QCBORDecode_Init() */
- QCBOR_DECODE_MODE_MAP_STRINGS_ONLY = 1,
- /** See QCBORDecode_Init() */
- QCBOR_DECODE_MODE_MAP_AS_ARRAY = 2
-} QCBORDecodeMode;
-
-
-
-
-
-/* Do not renumber these. Code depends on some of these values. */
-/** The data type is unknown, unset or invalid. */
-#define QCBOR_TYPE_NONE 0
-/** Type for an integer that decoded either between @c INT64_MIN and
- @c INT32_MIN or @c INT32_MAX and @c INT64_MAX. Data is in member
- @c val.int64. */
-#define QCBOR_TYPE_INT64 2
-/** Type for an integer that decoded to a more than @c INT64_MAX and
- @c UINT64_MAX. Data is in member @c val.uint64. */
-#define QCBOR_TYPE_UINT64 3
-/** Type for an array. The number of items in the array is in @c
- val.uCount. */
-#define QCBOR_TYPE_ARRAY 4
-/** Type for a map; number of items in map is in @c val.uCount. */
-#define QCBOR_TYPE_MAP 5
-/** Type for a buffer full of bytes. Data is in @c val.string. */
-#define QCBOR_TYPE_BYTE_STRING 6
-/** Type for a UTF-8 string. It is not NULL-terminated. Data is in @c
- val.string. */
-#define QCBOR_TYPE_TEXT_STRING 7
-/** Type for a positive big number. Data is in @c val.bignum, a
- pointer and a length. */
-#define QCBOR_TYPE_POSBIGNUM 9
-/** Type for a negative big number. Data is in @c val.bignum, a
- pointer and a length. */
-#define QCBOR_TYPE_NEGBIGNUM 10
-/** Type for [RFC 3339] (https://tools.ietf.org/html/rfc3339) date
- string, possibly with time zone. Data is in @c val.dateString */
-#define QCBOR_TYPE_DATE_STRING 11
-/** Type for integer seconds since Jan 1970 + floating-point
- fraction. Data is in @c val.epochDate */
-#define QCBOR_TYPE_DATE_EPOCH 12
-/** A simple type that this CBOR implementation doesn't know about;
- Type is in @c val.uSimple. */
-#define QCBOR_TYPE_UKNOWN_SIMPLE 13
-
-/** A decimal fraction made of decimal exponent and integer mantissa.
- See @ref expAndMantissa and QCBOREncode_AddDecimalFraction(). */
-#define QCBOR_TYPE_DECIMAL_FRACTION 14
-
-/** A decimal fraction made of decimal exponent and positive big
- number mantissa. See @ref expAndMantissa and
- QCBOREncode_AddDecimalFractionBigNum(). */
-#define QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM 15
-
-/** A decimal fraction made of decimal exponent and negative big
- number mantissa. See @ref expAndMantissa and
- QCBOREncode_AddDecimalFractionBigNum(). */
-#define QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM 16
-
-/** A floating-point number made of base-2 exponent and integer
- mantissa. See @ref expAndMantissa and
- QCBOREncode_AddBigFloat(). */
-#define QCBOR_TYPE_BIGFLOAT 17
-
-/** A floating-point number made of base-2 exponent and positive big
- number mantissa. See @ref expAndMantissa and
- QCBOREncode_AddBigFloatBigNum(). */
-#define QCBOR_TYPE_BIGFLOAT_POS_BIGNUM 18
-
-/** A floating-point number made of base-2 exponent and negative big
- number mantissa. See @ref expAndMantissa and
- QCBOREncode_AddBigFloatBigNum(). */
-#define QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM 19
-
-/** Type for the value false. */
-#define QCBOR_TYPE_FALSE 20
-/** Type for the value true. */
-#define QCBOR_TYPE_TRUE 21
-/** Type for the value null. */
-#define QCBOR_TYPE_NULL 22
-/** Type for the value undef. */
-#define QCBOR_TYPE_UNDEF 23
-/** Type for a floating-point number. Data is in @c val.float. */
-#define QCBOR_TYPE_FLOAT 26
-/** Type for a double floating-point number. Data is in @c val.double. */
-#define QCBOR_TYPE_DOUBLE 27
-/** For @ref QCBOR_DECODE_MODE_MAP_AS_ARRAY decode mode, a map that is
- being traversed as an array. See QCBORDecode_Init() */
-#define QCBOR_TYPE_MAP_AS_ARRAY 32
-
-#define QCBOR_TYPE_BREAK 31 // Used internally; never returned
-
-#define QCBOR_TYPE_OPTTAG 254 // Used internally; never returned
-
-
-
-/*
- Approx Size of this:
- 8 + 8 + 1 + 1 + 1 + (1 padding) + (4 padding) = 24 for first part
- (20 on a 32-bit machine)
- 16 bytes for the val union
- 16 bytes for label union
- total = 56 bytes (52 bytes on 32-bit machine)
- */
-
-/**
- The main data structure that holds the type, value and other info for
- a decoded item returned by QCBORDecode_GetNext() and
- QCBORDecode_GetNextWithTags().
- */
-typedef struct _QCBORItem {
- /** Tells what element of the @c val union to use. One of @c
- QCBOR_TYPE_XXXX */
- uint8_t uDataType;
- /** How deep the nesting from arrays and maps are. 0 is the top
- level with no arrays or maps entered. */
- uint8_t uNestingLevel;
- /** Tells what element of the label union to use. */
- uint8_t uLabelType;
- /** 1 if allocated with string allocator, 0 if not. See
- QCBORDecode_SetMemPool() or QCBORDecode_SetUpAllocator() */
- uint8_t uDataAlloc;
- /** Like @c uDataAlloc, but for label. */
- uint8_t uLabelAlloc;
- /** If not equal to @c uNestingLevel, this item closed out at least
- one map/array */
- uint8_t uNextNestLevel;
-
- /** The union holding the item's value. Select union member based
- on @c uDataType */
- union {
- /** The value for @c uDataType @ref QCBOR_TYPE_INT64. */
- int64_t int64;
- /** The value for uDataType @ref QCBOR_TYPE_UINT64. */
- uint64_t uint64;
- /** The value for @c uDataType @ref QCBOR_TYPE_BYTE_STRING and
- @ref QCBOR_TYPE_TEXT_STRING. */
- UsefulBufC string;
- /** The "value" for @c uDataType @ref QCBOR_TYPE_ARRAY or @ref
- QCBOR_TYPE_MAP -- the number of items in the array or map.
- It is @c UINT16_MAX when decoding indefinite-lengths maps
- and arrays. */
- uint16_t uCount;
- /** The value for @c uDataType @ref QCBOR_TYPE_DOUBLE. */
- double dfnum;
- /** The value for @c uDataType @ref QCBOR_TYPE_DATE_EPOCH. */
- struct {
- int64_t nSeconds;
- double fSecondsFraction;
- } epochDate;
- /** The value for @c uDataType @ref QCBOR_TYPE_DATE_STRING. */
- UsefulBufC dateString;
- /** The value for @c uDataType @ref QCBOR_TYPE_POSBIGNUM and
- @ref QCBOR_TYPE_NEGBIGNUM. */
- UsefulBufC bigNum;
- /** The integer value for unknown simple types. */
- uint8_t uSimple;
-#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
- /** @anchor expAndMantissa
-
- The value for bigfloats and decimal fractions. The use of the
- fields in this structure depend on @c uDataType.
-
- When @c uDataType is a @c DECIMAL_FRACTION, the exponent is
- base-10. When it is a @c BIG_FLOAT it is base-2.
-
- When @c uDataType is a @c POS_BIGNUM or a @c NEG_BIGNUM then the
- @c bigNum part of @c Mantissa is valid. Otherwise the
- @c nInt part of @c Mantissa is valid.
-
- See @ref QCBOR_TYPE_DECIMAL_FRACTION,
- @ref QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
- @ref QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM,
- @ref QCBOR_TYPE_BIGFLOAT, @ref QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
- and @ref QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM.
-
- Also see QCBOREncode_AddDecimalFraction(), QCBOREncode_AddBigFloat(),
- QCBOREncode_AddDecimalFractionBigNum() and
- QCBOREncode_AddBigFloatBigNum().
- */
- struct {
- int64_t nExponent;
- union {
- int64_t nInt;
- UsefulBufC bigNum;
- } Mantissa;
- } expAndMantissa;
-#endif
- uint64_t uTagV; // Used internally during decoding
- } val;
-
- /** Union holding the different label types selected based on @c
- uLabelType */
- union {
- /** The label for @c uLabelType @ref QCBOR_TYPE_BYTE_STRING and
- @ref QCBOR_TYPE_TEXT_STRING */
- UsefulBufC string;
- /** The label for @c uLabelType for @ref QCBOR_TYPE_INT64 */
- int64_t int64;
- /** The label for @c uLabelType for @ref QCBOR_TYPE_UINT64 */
- uint64_t uint64;
- } label;
-
- /** Bit indicating which tags (major type 6) on this item. See
- QCBORDecode_IsTagged(). */
- uint64_t uTagBits;
-
-} QCBORItem;
-
-
-
-/**
- @brief The type defining what a string allocator function must do.
-
- @param[in] pAllocateCxt Pointer to context for the particular
- allocator implementation What is in the
- context is dependent on how a particular
- string allocator works. Typically, it
- will contain a pointer to the memory pool
- and some booking keeping data.
- @param[in] pOldMem Points to some memory allocated by the
- allocator that is either to be freed or
- to be reallocated to be larger. It is
- @c NULL for new allocations and when called as
- a destructor to clean up the whole
- allocation.
- @param[in] uNewSize Size of memory to be allocated or new
- size of chunk to be reallocated. Zero for
- a new allocation or when called as a
- destructor.
-
- @return Either the allocated buffer is returned, or @ref
- NULLUsefulBufC. @ref NULLUsefulBufC is returned on a failed
- allocation and in the two cases where there is nothing to
- return.
-
- This is called in one of four modes:
-
- Allocate -- @c uNewSize is the amount to allocate. @c pOldMem is @c
- NULL.
-
- Free -- @c uNewSize is 0. @c pOldMem points to the memory to be
- freed. When the decoder calls this, it will always be the most
- recent block that was either allocated or reallocated.
-
- Reallocate -- @c pOldMem is the block to reallocate. @c uNewSize is
- its new size. When the decoder calls this, it will always be the
- most recent block that was either allocated or reallocated.
-
- Destruct -- @c pOldMem is @c NULL and @c uNewSize is 0. This is called
- when the decoding is complete by QCBORDecode_Finish(). Usually the
- strings allocated by a string allocator are in use after the decoding
- is completed so this usually will not free those strings. Many string
- allocators will not need to do anything in this mode.
-
- The strings allocated by this will have @c uDataAlloc set to true in
- the @ref QCBORItem when they are returned. The user of the strings
- will have to free them. How they free them, depends on the string
- allocator.
-
- If QCBORDecode_SetMemPool() is called, the internal MemPool will be
- used. It has its own internal implementation of this function, so
- one does not need to be implemented.
- */
-typedef UsefulBuf (* QCBORStringAllocate)(void *pAllocateCxt, void *pOldMem, size_t uNewSize);
-
-
-/**
- This only matters if you use the built-in string allocator by setting
- it up with QCBORDecode_SetMemPool(). This is the size of the overhead
- needed by QCBORDecode_SetMemPool(). The amount of memory available
- for decoded strings will be the size of the buffer given to
- QCBORDecode_SetMemPool() less this amount.
-
- If you write your own string allocator or use the separately
- available malloc based string allocator, this size will not apply.
- */
-#define QCBOR_DECODE_MIN_MEM_POOL_SIZE 8
-
-
-/**
- This is used by QCBORDecode_SetCallerConfiguredTagList() to set a
- list of tags beyond the built-in ones.
-
- See also QCBORDecode_GetNext() for general description of tag
- decoding.
- */
-typedef struct {
- /** The number of tags in the @c puTags. The maximum size is @ref
- QCBOR_MAX_CUSTOM_TAGS. */
- uint8_t uNumTags;
- /** An array of tags to add to recognize in addition to the
- built-in ones. */
- const uint64_t *puTags;
-} QCBORTagListIn;
-
-
-/**
- This is for QCBORDecode_GetNextWithTags() to be able to return the
- full list of tags on an item. It is not needed for most CBOR protocol
- implementations. Its primary use is for pretty-printing CBOR or
- protocol conversion to another format.
-
- On input, @c puTags points to a buffer to be filled in and
- uNumAllocated is the number of @c uint64_t values in the buffer.
-
- On output the buffer contains the tags for the item. @c uNumUsed
- tells how many there are.
- */
-typedef struct {
- uint8_t uNumUsed;
- uint8_t uNumAllocated;
- uint64_t *puTags;
-} QCBORTagListOut;
-
-
-/**
- QCBOREncodeContext is the data type that holds context for all the
- encoding functions. It is less than 200 bytes, so it can go on the
- stack. The contents are opaque, and the caller should not access
- internal members. A context may be re used serially as long as it is
- re initialized.
- */
-typedef struct _QCBOREncodeContext QCBOREncodeContext;
-
-
-/**
- Initialize the encoder to prepare to encode some CBOR.
-
- @param[in,out] pCtx The encoder context to initialize.
- @param[in] Storage The buffer into which this encoded result
- will be placed.
-
- Call this once at the start of an encoding of a CBOR structure. Then
- call the various @c QCBOREncode_AddXxx() functions to add the data
- items. Then call QCBOREncode_Finish().
-
- The maximum output buffer is @c UINT32_MAX (4GB). This is not a
- practical limit in any way and reduces the memory needed by the
- implementation. The error @ref QCBOR_ERR_BUFFER_TOO_LARGE will be
- returned by QCBOREncode_Finish() if a larger buffer length is passed
- in.
-
- If this is called with @c Storage.ptr as @c NULL and @c Storage.len a
- large value like @c UINT32_MAX, all the QCBOREncode_AddXxx()
- functions and QCBOREncode_Finish() can still be called. No data will
- be encoded, but the length of what would be encoded will be
- calculated. The length of the encoded structure will be handed back
- in the call to QCBOREncode_Finish(). You can then allocate a buffer
- of that size and call all the encoding again, this time to fill in
- the buffer.
-
- A @ref QCBOREncodeContext can be reused over and over as long as
- QCBOREncode_Init() is called.
- */
-void QCBOREncode_Init(QCBOREncodeContext *pCtx, UsefulBuf Storage);
-
-
-/**
- @brief Add a signed 64-bit integer to the encoded output.
-
- @param[in] pCtx The encoding context to add the integer to.
- @param[in] nNum The integer to add.
-
- The integer will be encoded and added to the CBOR output.
-
- This function figures out the size and the sign and encodes in the
- correct minimal CBOR. Specifically, it will select CBOR major type 0
- or 1 based on sign and will encode to 1, 2, 4 or 8 bytes depending on
- the value of the integer. Values less than 24 effectively encode to
- one byte because they are encoded in with the CBOR major type. This
- is a neat and efficient characteristic of CBOR that can be taken
- advantage of when designing CBOR-based protocols. If integers like
- tags can be kept between -23 and 23 they will be encoded in one byte
- including the major type.
-
- If you pass a smaller int, say an @c int16_t or a small value, say
- 100, the encoding will still be CBOR's most compact that can
- represent the value. For example, CBOR always encodes the value 0 as
- one byte, 0x00. The representation as 0x00 includes identification of
- the type as an integer too as the major type for an integer is 0. See
- [RFC 7049] (https://tools.ietf.org/html/rfc7049) Appendix A for more
- examples of CBOR encoding. This compact encoding is also canonical
- CBOR as per section 3.9 in RFC 7049.
-
- There are no functions to add @c int16_t or @c int32_t because they
- are not necessary because this always encodes to the smallest number
- of bytes based on the value (If this code is running on a 32-bit
- machine having a way to add 32-bit integers would reduce code size
- some).
-
- If the encoding context is in an error state, this will do
- nothing. If an error occurs when adding this integer, the internal
- error flag will be set, and the error will be returned when
- QCBOREncode_Finish() is called.
-
- See also QCBOREncode_AddUInt64().
- */
-void QCBOREncode_AddInt64(QCBOREncodeContext *pCtx, int64_t nNum);
-
-static void QCBOREncode_AddInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, int64_t uNum);
-
-static void QCBOREncode_AddInt64ToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, int64_t uNum);
-
-
-/**
- @brief Add an unsigned 64-bit integer to the encoded output.
-
- @param[in] pCtx The encoding context to add the integer to.
- @param[in] uNum The integer to add.
-
- The integer will be encoded and added to the CBOR output.
-
- The only reason so use this function is for integers larger than @c
- INT64_MAX and smaller than @c UINT64_MAX. Otherwise
- QCBOREncode_AddInt64() will work fine.
-
- Error handling is the same as for QCBOREncode_AddInt64().
- */
-void QCBOREncode_AddUInt64(QCBOREncodeContext *pCtx, uint64_t uNum);
-
-static void QCBOREncode_AddUInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, uint64_t uNum);
-
-static void QCBOREncode_AddUInt64ToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, uint64_t uNum);
-
-
-/**
- @brief Add a UTF-8 text string to the encoded output.
-
- @param[in] pCtx The encoding context to add the text to.
- @param[in] Text Pointer and length of text to add.
-
- The text passed in must be unencoded UTF-8 according to [RFC 3629]
- (https://tools.ietf.org/html/rfc3629). There is no NULL
- termination. The text is added as CBOR major type 3.
-
- If called with @c nBytesLen equal to 0, an empty string will be
- added. When @c nBytesLen is 0, @c pBytes may be @c NULL.
-
- Note that the restriction of the buffer length to a @c uint32_t is
- entirely intentional as this encoder is not capable of encoding
- lengths greater. This limit to 4GB for a text string should not be a
- problem.
-
- Error handling is the same as QCBOREncode_AddInt64().
- */
-static void QCBOREncode_AddText(QCBOREncodeContext *pCtx, UsefulBufC Text);
-
-static void QCBOREncode_AddTextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Text);
-
-static void QCBOREncode_AddTextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Text);
-
-
-/**
- @brief Add a UTF-8 text string to the encoded output.
-
- @param[in] pCtx The encoding context to add the text to.
- @param[in] szString Null-terminated text to add.
-
- This works the same as QCBOREncode_AddText().
- */
-static void QCBOREncode_AddSZString(QCBOREncodeContext *pCtx, const char *szString);
-
-static void QCBOREncode_AddSZStringToMap(QCBOREncodeContext *pCtx, const char *szLabel, const char *szString);
-
-static void QCBOREncode_AddSZStringToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, const char *szString);
-
-
-/**
- @brief Add a floating-point number to the encoded output.
-
- @param[in] pCtx The encoding context to add the double to.
- @param[in] dNum The double-precision number to add.
-
- This outputs a floating-point number with CBOR major type 7.
-
- This will selectively encode the double-precision floating-point
- number as either double-precision, single-precision or
- half-precision. It will always encode infinity, NaN and 0 has half
- precision. If no precision will be lost in the conversion to
- half-precision, then it will be converted and encoded. If not and no
- precision will be lost in conversion to single-precision, then it
- will be converted and encoded. If not, then no conversion is
- performed, and it encoded as a double.
-
- Half-precision floating-point numbers take up 2 bytes, half that of
- single-precision, one quarter of double-precision
-
- This automatically reduces the size of encoded messages a lot, maybe
- even by four if most of values are 0, infinity or NaN.
-
- On decode, these will always be returned as a double.
-
- Error handling is the same as QCBOREncode_AddInt64().
- */
-void QCBOREncode_AddDouble(QCBOREncodeContext *pCtx, double dNum);
-
-static void QCBOREncode_AddDoubleToMap(QCBOREncodeContext *pCtx, const char *szLabel, double dNum);
-
-static void QCBOREncode_AddDoubleToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, double dNum);
-
-
-/**
- @brief Add an optional tag.
-
- @param[in] pCtx The encoding context to add the tag to.
- @param[in] uTag The tag to add
-
- This outputs a CBOR major type 6 item that tags the next data item
- that is output usually to indicate it is some new data type.
-
- For many of the common standard tags, a function to encode data using
- it is provided and this is not needed. For example,
- QCBOREncode_AddDateEpoch() already exists to output integers
- representing dates with the right tag.
-
- The tag is applied to the next data item added to the encoded
- output. That data item that is to be tagged can be of any major CBOR
- type. Any number of tags can be added to a data item by calling this
- multiple times before the data item is added.
-
- See @ref Tags-Overview for discussion of creating new non-standard
- tags. See QCBORDecode_GetNext() for discussion of decoding custom
- tags.
-*/
-void QCBOREncode_AddTag(QCBOREncodeContext *pCtx,uint64_t uTag);
-
-
-/**
- @brief Add an epoch-based date.
-
- @param[in] pCtx The encoding context to add the date to.
- @param[in] date Number of seconds since 1970-01-01T00:00Z in UTC time.
-
- As per RFC 7049 this is similar to UNIX/Linux/POSIX dates. This is
- the most compact way to specify a date and time in CBOR. Note that
- this is always UTC and does not include the time zone. Use
- QCBOREncode_AddDateString() if you want to include the time zone.
-
- The integer encoding rules apply here so the date will be encoded in
- a minimal number of bytes. Until about the year 2106 these dates will
- encode in 6 bytes -- one byte for the tag, one byte for the type and
- 4 bytes for the integer. After that it will encode to 10 bytes.
-
- Negative values are supported for dates before 1970.
-
- If you care about leap-seconds and that level of accuracy, make sure
- the system you are running this code on does it correctly. This code
- just takes the value passed in.
-
- This implementation cannot encode fractional seconds using float or
- double even though that is allowed by CBOR, but you can encode them
- if you want to by calling QCBOREncode_AddDouble() and
- QCBOREncode_AddTag().
-
- Error handling is the same as QCBOREncode_AddInt64().
- */
-static void QCBOREncode_AddDateEpoch(QCBOREncodeContext *pCtx, int64_t date);
-
-static void QCBOREncode_AddDateEpochToMap(QCBOREncodeContext *pCtx, const char *szLabel, int64_t date);
-
-static void QCBOREncode_AddDateEpochToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, int64_t date);
-
-
-/**
- @brief Add a byte string to the encoded output.
-
- @param[in] pCtx The encoding context to add the bytes to.
- @param[in] Bytes Pointer and length of the input data.
-
- Simply adds the bytes to the encoded output as CBOR major type 2.
-
- If called with @c Bytes.len equal to 0, an empty string will be
- added. When @c Bytes.len is 0, @c Bytes.ptr may be @c NULL.
-
- Error handling is the same as QCBOREncode_AddInt64().
- */
-static void QCBOREncode_AddBytes(QCBOREncodeContext *pCtx, UsefulBufC Bytes);
-
-static void QCBOREncode_AddBytesToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes);
-
-static void QCBOREncode_AddBytesToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes);
-
-
-
-/**
- @brief Add a binary UUID to the encoded output.
-
- @param[in] pCtx The encoding context to add the UUID to.
- @param[in] Bytes Pointer and length of the binary UUID.
-
- A binary UUID as defined in [RFC 4122]
- (https://tools.ietf.org/html/rfc4122) is added to the output.
-
- It is output as CBOR major type 2, a binary string, with tag @ref
- CBOR_TAG_BIN_UUID indicating the binary string is a UUID.
- */
-static void QCBOREncode_AddBinaryUUID(QCBOREncodeContext *pCtx, UsefulBufC Bytes);
-
-static void QCBOREncode_AddBinaryUUIDToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes);
-
-static void QCBOREncode_AddBinaryUUIDToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes);
-
-
-/**
- @brief Add a positive big number to the encoded output.
-
- @param[in] pCtx The encoding context to add the big number to.
- @param[in] Bytes Pointer and length of the big number.
-
- Big numbers are integers larger than 64-bits. Their format is
- described in [RFC 7049] (https://tools.ietf.org/html/rfc7049).
-
- It is output as CBOR major type 2, a binary string, with tag @ref
- CBOR_TAG_POS_BIGNUM indicating the binary string is a positive big
- number.
-
- Often big numbers are used to represent cryptographic keys, however,
- COSE which defines representations for keys chose not to use this
- particular type.
- */
-static void QCBOREncode_AddPositiveBignum(QCBOREncodeContext *pCtx, UsefulBufC Bytes);
-
-static void QCBOREncode_AddPositiveBignumToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes);
-
-static void QCBOREncode_AddPositiveBignumToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes);
-
-
-/**
- @brief Add a negative big number to the encoded output.
-
- @param[in] pCtx The encoding context to add the big number to.
- @param[in] Bytes Pointer and length of the big number.
-
- Big numbers are integers larger than 64-bits. Their format is
- described in [RFC 7049] (https://tools.ietf.org/html/rfc7049).
-
- It is output as CBOR major type 2, a binary string, with tag @ref
- CBOR_TAG_NEG_BIGNUM indicating the binary string is a negative big
- number.
-
- Often big numbers are used to represent cryptographic keys, however,
- COSE which defines representations for keys chose not to use this
- particular type.
- */
-static void QCBOREncode_AddNegativeBignum(QCBOREncodeContext *pCtx, UsefulBufC Bytes);
-
-static void QCBOREncode_AddNegativeBignumToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes);
-
-static void QCBOREncode_AddNegativeBignumToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes);
-
-
-#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
-/**
- @brief Add a decimal fraction to the encoded output.
-
- @param[in] pCtx The encoding context to add the decimal fraction to.
- @param[in] nMantissa The mantissa.
- @param[in] nBase10Exponent The exponent.
-
- The value is nMantissa * 10 ^ nBase10Exponent.
-
- A decimal fraction is good for exact representation of some values
- that can't be represented exactly with standard C (IEEE 754)
- floating-point numbers. Much larger and much smaller numbers can
- also be represented than floating-point because of the larger number
- of bits in the exponent.
-
- The decimal fraction is conveyed as two integers, a mantissa and a
- base-10 scaling factor.
-
- For example, 273.15 is represented by the two integers 27315 and -2.
-
- The exponent and mantissa have the range from @c INT64_MIN to
- @c INT64_MAX for both encoding and decoding (CBOR allows @c -UINT64_MAX
- to @c UINT64_MAX, but this implementation doesn't support this range to
- reduce code size and interface complexity a little).
-
- CBOR Preferred encoding of the integers is used, thus they will be encoded
- in the smallest number of bytes possible.
-
- See also QCBOREncode_AddDecimalFractionBigNum() for a decimal
- fraction with arbitrarily large precision and QCBOREncode_AddBigFloat().
-
- There is no representation of positive or negative infinity or NaN
- (Not a Number). Use QCBOREncode_AddDouble() to encode them.
-
- See @ref expAndMantissa for decoded representation.
- */
-static void QCBOREncode_AddDecimalFraction(QCBOREncodeContext *pCtx,
- int64_t nMantissa,
- int64_t nBase10Exponent);
-
-static void QCBOREncode_AddDecimalFractionToMap(QCBOREncodeContext *pCtx,
- const char *szLabel,
- int64_t nMantissa,
- int64_t nBase10Exponent);
-
-static void QCBOREncode_AddDecimalFractionToMapN(QCBOREncodeContext *pCtx,
- int64_t nLabel,
- int64_t nMantissa,
- int64_t nBase10Exponent);
-
-/**
- @brief Add a decimal fraction with a big number mantissa to the encoded output.
-
- @param[in] pCtx The encoding context to add the decimal fraction to.
- @param[in] Mantissa The mantissa.
- @param[in] bIsNegative false if mantissa is positive, true if negative.
- @param[in] nBase10Exponent The exponent.
-
- This is the same as QCBOREncode_AddDecimalFraction() except the
- mantissa is a big number (See QCBOREncode_AddPositiveBignum())
- allowing for arbitrarily large precision.
-
- See @ref expAndMantissa for decoded representation.
- */
-static void QCBOREncode_AddDecimalFractionBigNum(QCBOREncodeContext *pCtx,
- UsefulBufC Mantissa,
- bool bIsNegative,
- int64_t nBase10Exponent);
-
-static void QCBOREncode_AddDecimalFractionBigNumToMap(QCBOREncodeContext *pCtx,
- const char *szLabel,
- UsefulBufC Mantissa,
- bool bIsNegative,
- int64_t nBase10Exponent);
-
-static void QCBOREncode_AddDecimalFractionBigNumToMapN(QCBOREncodeContext *pCtx,
- int64_t nLabel,
- UsefulBufC Mantissa,
- bool bIsNegative,
- int64_t nBase10Exponent);
-
-/**
- @brief Add a big floating-point number to the encoded output.
-
- @param[in] pCtx The encoding context to add the bigfloat to.
- @param[in] nMantissa The mantissa.
- @param[in] nBase2Exponent The exponent.
-
- The value is nMantissa * 2 ^ nBase2Exponent.
-
- "Bigfloats", as CBOR terms them, are similar to IEEE floating-point
- numbers in having a mantissa and base-2 exponent, but they are not
- supported by hardware or encoded the same. They explicitly use two
- CBOR-encoded integers to convey the mantissa and exponent, each of which
- can be 8, 16, 32 or 64 bits. With both the mantissa and exponent
- 64 bits they can express more precision and a larger range than an
- IEEE double floating-point number. See
- QCBOREncode_AddBigFloatBigNum() for even more precision.
-
- For example, 1.5 would be represented by a mantissa of 3 and an
- exponent of -1.
-
- The exponent and mantissa have the range from @c INT64_MIN to
- @c INT64_MAX for both encoding and decoding (CBOR allows @c -UINT64_MAX
- to @c UINT64_MAX, but this implementation doesn't support this range to
- reduce code size and interface complexity a little).
-
- CBOR Preferred encoding of the integers is used, thus they will be encoded
- in the smallest number of bytes possible.
-
- This can also be used to represent floating-point numbers in
- environments that don't support IEEE 754.
-
- See @ref expAndMantissa for decoded representation.
- */
-static void QCBOREncode_AddBigFloat(QCBOREncodeContext *pCtx,
- int64_t nMantissa,
- int64_t nBase2Exponent);
-
-static void QCBOREncode_AddBigFloatToMap(QCBOREncodeContext *pCtx,
- const char *szLabel,
- int64_t nMantissa,
- int64_t nBase2Exponent);
-
-static void QCBOREncode_AddBigFloatToMapN(QCBOREncodeContext *pCtx,
- int64_t nLabel,
- int64_t nMantissa,
- int64_t nBase2Exponent);
-
-
-/**
- @brief Add a big floating-point number with a big number mantissa to
- the encoded output.
-
- @param[in] pCtx The encoding context to add the bigfloat to.
- @param[in] Mantissa The mantissa.
- @param[in] bIsNegative false if mantissa is positive, true if negative.
- @param[in] nBase2Exponent The exponent.
-
- This is the same as QCBOREncode_AddBigFloat() except the mantissa is
- a big number (See QCBOREncode_AddPositiveBignum()) allowing for
- arbitrary precision.
-
- See @ref expAndMantissa for decoded representation.
- */
-static void QCBOREncode_AddBigFloatBigNum(QCBOREncodeContext *pCtx,
- UsefulBufC Mantissa,
- bool bIsNegative,
- int64_t nBase2Exponent);
-
-static void QCBOREncode_AddBigFloatBigNumToMap(QCBOREncodeContext *pCtx,
- const char *szLabel,
- UsefulBufC Mantissa,
- bool bIsNegative,
- int64_t nBase2Exponent);
-
-static void QCBOREncode_AddBigFloatBigNumToMapN(QCBOREncodeContext *pCtx,
- int64_t nLabel,
- UsefulBufC Mantissa,
- bool bIsNegative,
- int64_t nBase2Exponent);
-#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
-
-
-/**
- @brief Add a text URI to the encoded output.
-
- @param[in] pCtx The encoding context to add the URI to.
- @param[in] URI Pointer and length of the URI.
-
- The format of URI must be per [RFC 3986]
- (https://tools.ietf.org/html/rfc3986).
-
- It is output as CBOR major type 3, a text string, with tag @ref
- CBOR_TAG_URI indicating the text string is a URI.
-
- A URI in a NULL-terminated string, @c szURI, can be easily added with
- this code:
-
- QCBOREncode_AddURI(pCtx, UsefulBuf_FromSZ(szURI));
- */
-static void QCBOREncode_AddURI(QCBOREncodeContext *pCtx, UsefulBufC URI);
-
-static void QCBOREncode_AddURIToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC URI);
-
-static void QCBOREncode_AddURIToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC URI);
-
-
-/**
- @brief Add Base64-encoded text to encoded output.
-
- @param[in] pCtx The encoding context to add the base-64 text to.
- @param[in] B64Text Pointer and length of the base-64 encoded text.
-
- The text content is Base64 encoded data per [RFC 4648]
- (https://tools.ietf.org/html/rfc4648).
-
- It is output as CBOR major type 3, a text string, with tag @ref
- CBOR_TAG_B64 indicating the text string is Base64 encoded.
- */
-static void QCBOREncode_AddB64Text(QCBOREncodeContext *pCtx, UsefulBufC B64Text);
-
-static void QCBOREncode_AddB64TextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC B64Text);
-
-static void QCBOREncode_AddB64TextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC B64Text);
-
-
-/**
- @brief Add base64url encoded data to encoded output.
-
- @param[in] pCtx The encoding context to add the base64url to.
- @param[in] B64Text Pointer and length of the base64url encoded text.
-
- The text content is base64URL encoded text as per [RFC 4648]
- (https://tools.ietf.org/html/rfc4648).
-
- It is output as CBOR major type 3, a text string, with tag @ref
- CBOR_TAG_B64URL indicating the text string is a Base64url encoded.
- */
-static void QCBOREncode_AddB64URLText(QCBOREncodeContext *pCtx, UsefulBufC B64Text);
-
-static void QCBOREncode_AddB64URLTextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC B64Text);
-
-static void QCBOREncode_AddB64URLTextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC B64Text);
-
-
-/**
- @brief Add Perl Compatible Regular Expression.
-
- @param[in] pCtx The encoding context to add the regular expression to.
- @param[in] Regex Pointer and length of the regular expression.
-
- The text content is Perl Compatible Regular
- Expressions (PCRE) / JavaScript syntax [ECMA262].
-
- It is output as CBOR major type 3, a text string, with tag @ref
- CBOR_TAG_REGEX indicating the text string is a regular expression.
- */
-static void QCBOREncode_AddRegex(QCBOREncodeContext *pCtx, UsefulBufC Regex);
-
-static void QCBOREncode_AddRegexToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Regex);
-
-static void QCBOREncode_AddRegexToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Regex);
-
-
-/**
- @brief MIME encoded text to the encoded output.
-
- @param[in] pCtx The encoding context to add the MIME data to.
- @param[in] MIMEData Pointer and length of the regular expression.
-
- The text content is in MIME format per [RFC 2045]
- (https://tools.ietf.org/html/rfc2045) including the headers. Note
- that this only supports text-format MIME. Binary MIME is not
- supported.
-
- It is output as CBOR major type 3, a text string, with tag
- @ref CBOR_TAG_MIME indicating the text string is MIME data.
- */
-static void QCBOREncode_AddMIMEData(QCBOREncodeContext *pCtx, UsefulBufC MIMEData);
-
-static void QCBOREncode_AddMIMEDataToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC MIMEData);
-
-static void QCBOREncode_AddMIMEDataToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC MIMEData);
-
-
-/**
- @brief Add an RFC 3339 date string
-
- @param[in] pCtx The encoding context to add the date to.
- @param[in] szDate Null-terminated string with date to add.
-
- The string szDate should be in the form of [RFC 3339]
- (https://tools.ietf.org/html/rfc3339) as defined by section 3.3 in
- [RFC 4287] (https://tools.ietf.org/html/rfc4287). This is as
- described in section 2.4.1 in [RFC 7049]
- (https://tools.ietf.org/html/rfc7049).
-
- Note that this function doesn't validate the format of the date string
- at all. If you add an incorrect format date string, the generated
- CBOR will be incorrect and the receiver may not be able to handle it.
-
- Error handling is the same as QCBOREncode_AddInt64().
- */
-static void QCBOREncode_AddDateString(QCBOREncodeContext *pCtx, const char *szDate);
-
-static void QCBOREncode_AddDateStringToMap(QCBOREncodeContext *pCtx, const char *szLabel, const char *szDate);
-
-static void QCBOREncode_AddDateStringToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, const char *szDate);
-
-
-/**
- @brief Add a standard Boolean.
-
- @param[in] pCtx The encoding context to add the Boolean to.
- @param[in] b true or false from @c <stdbool.h>.
-
- Adds a Boolean value as CBOR major type 7.
-
- Error handling is the same as QCBOREncode_AddInt64().
- */
-static void QCBOREncode_AddBool(QCBOREncodeContext *pCtx, bool b);
-
-static void QCBOREncode_AddBoolToMap(QCBOREncodeContext *pCtx, const char *szLabel, bool b);
-
-static void QCBOREncode_AddBoolToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, bool b);
-
-
-
-/**
- @brief Add a NULL to the encoded output.
-
- @param[in] pCtx The encoding context to add the NULL to.
-
- Adds the NULL value as CBOR major type 7.
-
- This NULL doesn't have any special meaning in CBOR such as a
- terminating value for a string or an empty value.
-
- Error handling is the same as QCBOREncode_AddInt64().
- */
-static void QCBOREncode_AddNULL(QCBOREncodeContext *pCtx);
-
-static void QCBOREncode_AddNULLToMap(QCBOREncodeContext *pCtx, const char *szLabel);
-
-static void QCBOREncode_AddNULLToMapN(QCBOREncodeContext *pCtx, int64_t nLabel);
-
-
-/**
- @brief Add an "undef" to the encoded output.
-
- @param[in] pCtx The encoding context to add the "undef" to.
-
- Adds the undef value as CBOR major type 7.
-
- Note that this value will not translate to JSON.
-
- This Undef doesn't have any special meaning in CBOR such as a
- terminating value for a string or an empty value.
-
- Error handling is the same as QCBOREncode_AddInt64().
- */
-static void QCBOREncode_AddUndef(QCBOREncodeContext *pCtx);
-
-static void QCBOREncode_AddUndefToMap(QCBOREncodeContext *pCtx, const char *szLabel);
-
-static void QCBOREncode_AddUndefToMapN(QCBOREncodeContext *pCtx, int64_t nLabel);
-
-
-/**
- @brief Indicates that the next items added are in an array.
-
- @param[in] pCtx The encoding context to open the array in.
-
- Arrays are the basic CBOR aggregate or structure type. Call this
- function to start or open an array. Then call the various @c
- QCBOREncode_AddXxx() functions to add the items that go into the
- array. Then call QCBOREncode_CloseArray() when all items have been
- added. The data items in the array can be of any type and can be of
- mixed types.
-
- Nesting of arrays and maps is allowed and supported just by calling
- QCBOREncode_OpenArray() again before calling
- QCBOREncode_CloseArray(). While CBOR has no limit on nesting, this
- implementation does in order to keep it smaller and simpler. The
- limit is @ref QCBOR_MAX_ARRAY_NESTING. This is the max number of
- times this can be called without calling
- QCBOREncode_CloseArray(). QCBOREncode_Finish() will return @ref
- QCBOR_ERR_ARRAY_NESTING_TOO_DEEP when it is called as this function
- just sets an error state and returns no value when this occurs.
-
- If you try to add more than @ref QCBOR_MAX_ITEMS_IN_ARRAY items to a
- single array or map, @ref QCBOR_ERR_ARRAY_TOO_LONG will be returned
- when QCBOREncode_Finish() is called.
-
- An array itself must have a label if it is being added to a map.
- Note that array elements do not have labels (but map elements do).
-
- An array itself may be tagged by calling QCBOREncode_AddTag() before this call.
- */
-static void QCBOREncode_OpenArray(QCBOREncodeContext *pCtx);
-
-static void QCBOREncode_OpenArrayInMap(QCBOREncodeContext *pCtx, const char *szLabel);
-
-static void QCBOREncode_OpenArrayInMapN(QCBOREncodeContext *pCtx, int64_t nLabel);
-
-
-/**
- @brief Close an open array.
-
- @param[in] pCtx The encoding context to close the array in.
-
- The closes an array opened by QCBOREncode_OpenArray(). It reduces
- nesting level by one. All arrays (and maps) must be closed before
- calling QCBOREncode_Finish().
-
- When an error occurs as a result of this call, the encoder records
- the error and enters the error state. The error will be returned when
- QCBOREncode_Finish() is called.
-
- If this has been called more times than QCBOREncode_OpenArray(), then
- @ref QCBOR_ERR_TOO_MANY_CLOSES will be returned when QCBOREncode_Finish()
- is called.
-
- If this is called and it is not an array that is currently open, @ref
- QCBOR_ERR_CLOSE_MISMATCH will be returned when QCBOREncode_Finish()
- is called.
- */
-static void QCBOREncode_CloseArray(QCBOREncodeContext *pCtx);
-
-
-/**
- @brief Indicates that the next items added are in a map.
-
- @param[in] pCtx The encoding context to open the map in.
-
- See QCBOREncode_OpenArray() for more information, particularly error
- handling.
-
- CBOR maps are an aggregate type where each item in the map consists
- of a label and a value. They are similar to JSON objects.
-
- The value can be any CBOR type including another map.
-
- The label can also be any CBOR type, but in practice they are
- typically, integers as this gives the most compact output. They might
- also be text strings which gives readability and translation to JSON.
-
- Every @c QCBOREncode_AddXxx() call has one version that ends with @c
- InMap for adding items to maps with string labels and one that ends
- with @c InMapN that is for adding with integer labels.
-
- RFC 7049 uses the term "key" instead of "label".
-
- If you wish to use map labels that are neither integer labels nor
- text strings, then just call the QCBOREncode_AddXxx() function
- explicitly to add the label. Then call it again to add the value.
-
- See the [RFC 7049] (https://tools.ietf.org/html/rfc7049) for a lot
- more information on creating maps.
- */
-static void QCBOREncode_OpenMap(QCBOREncodeContext *pCtx);
-
-static void QCBOREncode_OpenMapInMap(QCBOREncodeContext *pCtx, const char *szLabel);
-
-static void QCBOREncode_OpenMapInMapN(QCBOREncodeContext *pCtx, int64_t nLabel);
-
-
-
-/**
- @brief Close an open map.
-
- @param[in] pCtx The encoding context to close the map in .
-
- This closes a map opened by QCBOREncode_OpenMap(). It reduces nesting
- level by one.
-
- When an error occurs as a result of this call, the encoder records
- the error and enters the error state. The error will be returned when
- QCBOREncode_Finish() is called.
-
- If this has been called more times than QCBOREncode_OpenMap(),
- then @ref QCBOR_ERR_TOO_MANY_CLOSES will be returned when
- QCBOREncode_Finish() is called.
-
- If this is called and it is not a map that is currently open, @ref
- QCBOR_ERR_CLOSE_MISMATCH will be returned when QCBOREncode_Finish()
- is called.
- */
-static void QCBOREncode_CloseMap(QCBOREncodeContext *pCtx);
-
-
-/**
- @brief Indicate start of encoded CBOR to be wrapped in a bstr.
-
- @param[in] pCtx The encoding context to open the bstr-wrapped CBOR in.
-
- All added encoded items between this call and a call to
- QCBOREncode_CloseBstrWrap2() will be wrapped in a bstr. They will
- appear in the final output as a byte string. That byte string will
- contain encoded CBOR. This increases nesting level by one.
-
- The typical use case is for encoded CBOR that is to be
- cryptographically hashed, as part of a [RFC 8152, COSE]
- (https://tools.ietf.org/html/rfc8152) implementation.
-
- Using QCBOREncode_BstrWrap() and QCBOREncode_CloseBstrWrap2() avoids
- having to encode the items first in one buffer (e.g., the COSE
- payload) and then add that buffer as a bstr to another encoding
- (e.g. the COSE to-be-signed bytes, the @c Sig_structure) potentially
- halving the memory needed.
-
- RFC 7049 states the purpose of this wrapping is to prevent code
- relaying the signed data but not verifying it from tampering with the
- signed data thus making the signature unverifiable. It is also quite
- beneficial for the signature verification code. Standard CBOR
- decoders usually do not give access to partially decoded CBOR as
- would be needed to check the signature of some CBOR. With this
- wrapping, standard CBOR decoders can be used to get to all the data
- needed for a signature verification.
- */
-static void QCBOREncode_BstrWrap(QCBOREncodeContext *pCtx);
-
-static void QCBOREncode_BstrWrapInMap(QCBOREncodeContext *pCtx, const char *szLabel);
-
-static void QCBOREncode_BstrWrapInMapN(QCBOREncodeContext *pCtx, int64_t nLabel);
-
-
-/**
- @brief Close a wrapping bstr.
-
- @param[in] pCtx The encoding context to close of bstr wrapping in.
- @param[in] bIncludeCBORHead Include the encoded CBOR head of the bstr
- as well as the bytes in @c pWrappedCBOR.
- @param[out] pWrappedCBOR A @ref UsefulBufC containing wrapped bytes.
-
- The closes a wrapping bstr opened by QCBOREncode_BstrWrap(). It reduces
- nesting level by one.
-
- A pointer and length of the enclosed encoded CBOR is returned in @c
- *pWrappedCBOR if it is not @c NULL. The main purpose of this is so
- this data can be hashed (e.g., with SHA-256) as part of a [RFC 8152,
- COSE] (https://tools.ietf.org/html/rfc8152)
- implementation. **WARNING**, this pointer and length should be used
- right away before any other calls to @c QCBOREncode_CloseXxx() as
- they will move data around and the pointer and length will no longer
- be to the correct encoded CBOR.
-
- When an error occurs as a result of this call, the encoder records
- the error and enters the error state. The error will be returned when
- QCBOREncode_Finish() is called.
-
- If this has been called more times than QCBOREncode_BstrWrap(), then
- @ref QCBOR_ERR_TOO_MANY_CLOSES will be returned when
- QCBOREncode_Finish() is called.
-
- If this is called and it is not a wrapping bstr that is currently
- open, @ref QCBOR_ERR_CLOSE_MISMATCH will be returned when
- QCBOREncode_Finish() is called.
-
- QCBOREncode_CloseBstrWrap() is a deprecated version of this function
- that is equivalent to the call with @c bIncludeCBORHead @c true.
- */
-void QCBOREncode_CloseBstrWrap2(QCBOREncodeContext *pCtx, bool bIncludeCBORHead, UsefulBufC *pWrappedCBOR);
-
-static void QCBOREncode_CloseBstrWrap(QCBOREncodeContext *pCtx, UsefulBufC *pWrappedCBOR);
-
-
-/**
- @brief Add some already-encoded CBOR bytes.
-
- @param[in] pCtx The encoding context to add the already-encode CBOR to.
- @param[in] Encoded The already-encoded CBOR to add to the context.
-
- The encoded CBOR being added must be fully conforming CBOR. It must
- be complete with no arrays or maps that are incomplete. While this
- encoder doesn't ever produce indefinite lengths, it is OK for the
- raw CBOR added here to have indefinite lengths.
-
- The raw CBOR added here is not checked in anyway. If it is not
- conforming or has open arrays or such, the final encoded CBOR
- will probably be wrong or not what was intended.
-
- If the encoded CBOR being added here contains multiple items, they
- must be enclosed in a map or array. At the top level the raw
- CBOR must be a single data item.
- */
-static void QCBOREncode_AddEncoded(QCBOREncodeContext *pCtx, UsefulBufC Encoded);
-
-static void QCBOREncode_AddEncodedToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Encoded);
-
-static void QCBOREncode_AddEncodedToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Encoded);
-
-
-/**
- @brief Get the encoded result.
-
- @param[in] pCtx The context to finish encoding with.
- @param[out] pEncodedCBOR Pointer and length of encoded CBOR.
-
- @retval QCBOR_ERR_TOO_MANY_CLOSES Nesting error
-
- @retval QCBOR_ERR_CLOSE_MISMATCH Nesting error
-
- @retval QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN Nesting error
-
- @retval QCBOR_ERR_BUFFER_TOO_LARGE Encoded output buffer size
-
- @retval QCBOR_ERR_BUFFER_TOO_SMALL Encoded output buffer size
-
- @retval QCBOR_ERR_ARRAY_NESTING_TOO_DEEP Implementation limit
-
- @retval QCBOR_ERR_ARRAY_TOO_LONG Implementation limit
-
- If this returns success @ref QCBOR_SUCCESS the encoding was a success
- and the return length is correct and complete.
-
- If no buffer was passed to QCBOREncode_Init(), then only the length
- was computed. If a buffer was passed, then the encoded CBOR is in the
- buffer.
-
- Encoding errors primarily manifest here as most other encoding function
- do no return an error. They just set the error state in the encode
- context after which no encoding function does anything.
-
- Three types of errors manifest here. The first type are nesting
- errors where the number of @c QCBOREncode_OpenXxx() calls do not
- match the number @c QCBOREncode_CloseXxx() calls. The solution is to
- fix the calling code.
-
- The second type of error is because the buffer given is either too
- small or too large. The remedy is to give a correctly sized buffer.
-
- The third type are due to limits in this implementation. @ref
- QCBOR_ERR_ARRAY_NESTING_TOO_DEEP can be worked around by encoding the
- CBOR in two (or more) phases and adding the CBOR from the first phase
- to the second with @c QCBOREncode_AddEncoded().
-
- If an error is returned, the buffer may have partially encoded
- incorrect CBOR in it and it should not be used. Likewise, the length
- may be incorrect and should not be used.
-
- Note that the error could have occurred in one of the many @c
- QCBOREncode_AddXxx() calls long before QCBOREncode_Finish() was
- called. This error handling reduces the CBOR implementation size but
- makes debugging harder.
-
- This may be called multiple times. It will always return the same. It
- can also be interleaved with calls to QCBOREncode_FinishGetSize().
-
- QCBOREncode_GetErrorState() can be called to get the current
- error state and abort encoding early as an optimization, but is
- is never required.
- */
-QCBORError QCBOREncode_Finish(QCBOREncodeContext *pCtx, UsefulBufC *pEncodedCBOR);
-
-
-/**
- @brief Get the encoded CBOR and error status.
-
- @param[in] pCtx The context to finish encoding with.
- @param[out] uEncodedLen The length of the encoded or potentially
- encoded CBOR in bytes.
-
- @return The same errors as QCBOREncode_Finish().
-
- This functions the same as QCBOREncode_Finish(), but only returns the
- size of the encoded output.
- */
-QCBORError QCBOREncode_FinishGetSize(QCBOREncodeContext *pCtx, size_t *uEncodedLen);
-
-
-/**
- @brief Indicate whether output buffer is NULL or not.
-
- @param[in] pCtx The encoding context.
-
- @return 1 if the output buffer is @c NULL.
-
- Sometimes a @c NULL input buffer is given to QCBOREncode_Init() so
- that the size of the generated CBOR can be calculated without
- allocating a buffer for it. This returns 1 when the output buffer is
- NULL and 0 when it is not.
-*/
-static int QCBOREncode_IsBufferNULL(QCBOREncodeContext *pCtx);
-
- /**
- @brief Get the encoding error state.
-
- @param[in] pCtx The encoding context.
-
- @return One of \ref QCBORError. See return values from
- QCBOREncode_Finish()
-
- Normally encoding errors need only be handled at the end of encoding
- when QCBOREncode_Finish() is called. This can be called to get the
- error result before finish should there be a need to halt encoding
- before QCBOREncode_Finish() is called.
-*/
-static QCBORError QCBOREncode_GetErrorState(QCBOREncodeContext *pCtx);
-
-
-/**
- Encode the "head" of a CBOR data item.
-
- @param buffer Buffer to output the encoded head to; must be
- @ref QCBOR_HEAD_BUFFER_SIZE bytes in size.
- @param uMajorType One of CBOR_MAJOR_TYPE_XX.
- @param uMinLen The minimum number of bytes to encode uNumber. Almost always
- this is 0 to use preferred minimal encoding. If this is 4,
- then even the values 0xffff and smaller will be encoded
- as in 4 bytes. This is used primarily when encoding a
- float or double put into uNumber as the leading zero bytes
- for them must be encoded.
- @param uNumber The numeric argument part of the CBOR head.
- @return Pointer and length of the encoded head or
- @NULLUsefulBufC if the output buffer is too small.
-
- Callers to need to call this for normal CBOR encoding. Note that it doesn't even
- take a @ref QCBOREncodeContext argument.
-
- This encodes the major type and argument part of a data item. The
- argument is an integer that is usually either the value or the length
- of the data item.
-
- This is exposed in the public interface to allow hashing of some CBOR
- data types, bstr in particular, a chunk at a time so the full CBOR
- doesn't have to be encoded in a contiguous buffer.
-
- For example, if you have a 100,000 byte binary blob in a buffer that
- needs to be a bstr encoded and then hashed. You could allocate a
- 100,010 byte buffer and encode it normally. Alternatively, you can
- encode the head in a 10 byte buffer with this function, hash that and
- then hash the 100,000 bytes using the same hash context.
-
- See also QCBOREncode_AddBytesLenOnly();
- */
-UsefulBufC QCBOREncode_EncodeHead(UsefulBuf buffer,
- uint8_t uMajorType,
- uint8_t uMinLen,
- uint64_t uNumber);
-
-
-/**
- QCBORDecodeContext is the data type that holds context decoding the
- data items for some received CBOR. It is about 100 bytes, so it can
- go on the stack. The contents are opaque, and the caller should not
- access any internal items. A context may be re used serially as long
- as it is re initialized.
- */
-typedef struct _QCBORDecodeContext QCBORDecodeContext;
-
-
-/**
- Initialize the CBOR decoder context.
-
- @param[in] pCtx The context to initialize.
- @param[in] EncodedCBOR The buffer with CBOR encoded bytes to be decoded.
- @param[in] nMode See below and @ref QCBORDecodeMode.
-
- Initialize context for a pre-order traversal of the encoded CBOR
- tree.
-
- Most CBOR decoding can be completed by calling this function to start
- and QCBORDecode_GetNext() in a loop.
-
- If indefinite-length strings are to be decoded, then
- QCBORDecode_SetMemPool() or QCBORDecode_SetUpAllocator() must be
- called to set up a string allocator.
-
- If tags other than built-in tags are to be recognized and recorded in
- @c uTagBits, then QCBORDecode_SetCallerConfiguredTagList() must be
- called. The built-in tags are those for which a macro of the form @c
- CBOR_TAG_XXX is defined.
-
- Three decoding modes are supported. In normal mode, @ref
- QCBOR_DECODE_MODE_NORMAL, maps are decoded and strings and integers
- are accepted as map labels. If a label is other than these, the error
- @ref QCBOR_ERR_MAP_LABEL_TYPE is returned by QCBORDecode_GetNext().
-
- In strings-only mode, @ref QCBOR_DECODE_MODE_MAP_STRINGS_ONLY, only
- text strings are accepted for map labels. This lines up with CBOR
- that converts to JSON. The error @ref QCBOR_ERR_MAP_LABEL_TYPE is
- returned by QCBORDecode_GetNext() if anything but a text string label
- is encountered.
-
- In @ref QCBOR_DECODE_MODE_MAP_AS_ARRAY maps are treated as special
- arrays. They will be return with special @c uDataType @ref
- QCBOR_TYPE_MAP_AS_ARRAY and @c uCount, the number of items, will be
- double what it would be for a normal map because the labels are also
- counted. This mode is useful for decoding CBOR that has labels that
- are not integers or text strings, but the caller must manage much of
- the map decoding.
- */
-void QCBORDecode_Init(QCBORDecodeContext *pCtx, UsefulBufC EncodedCBOR, QCBORDecodeMode nMode);
-
-
-/**
- @brief Set up the MemPool string allocator for indefinite-length strings.
-
- @param[in] pCtx The decode context.
- @param[in] MemPool The pointer and length of the memory pool.
- @param[in] bAllStrings If true, all strings, even of definite
- length, will be allocated with the string
- allocator.
-
- @return Error if the MemPool was less than @ref QCBOR_DECODE_MIN_MEM_POOL_SIZE.
-
- indefinite-length strings (text and byte) cannot be decoded unless
- there is a string allocator configured. MemPool is a simple built-in
- string allocator that allocates bytes from a memory pool handed to it
- by calling this function. The memory pool is just a pointer and
- length for some block of memory that is to be used for string
- allocation. It can come from the stack, heap or other.
-
- The memory pool must be @ref QCBOR_DECODE_MIN_MEM_POOL_SIZE plus
- space for all the strings allocated. There is no overhead per string
- allocated. A conservative way to size this buffer is to make it the
- same size as the CBOR being decoded plus @ref
- QCBOR_DECODE_MIN_MEM_POOL_SIZE.
-
- This memory pool is used for all indefinite-length strings that are
- text strings or byte strings, including strings used as labels.
-
- The pointers to strings in @ref QCBORItem will point into the memory
- pool set here. They do not need to be individually freed. Just
- discard the buffer when they are no longer needed.
-
- If @c bAllStrings is set, then the size will be the overhead plus the
- space to hold **all** strings, definite and indefinite-length, value
- or label. The advantage of this is that after the decode is complete,
- the original memory holding the encoded CBOR does not need to remain
- valid.
-
- If this function is never called because there is no need to support
- indefinite-length strings, the internal MemPool implementation should
- be dead-stripped by the loader and not add to code size.
- */
-QCBORError QCBORDecode_SetMemPool(QCBORDecodeContext *pCtx, UsefulBuf MemPool, bool bAllStrings);
-
-
-/**
- @brief Sets up a custom string allocator for indefinite-length strings
-
- @param[in] pCtx The decoder context to set up an
- allocator for.
- @param[in] pfAllocateFunction Pointer to function that will be
- called by QCBOR for allocations and
- frees.
- @param[in] pAllocateContext Context passed to @c
- pfAllocateFunction.
- @param[in] bAllStrings If true, all strings, even of definite
- length, will be allocated with the
- string allocator.
-
- indefinite-length strings (text and byte) cannot be decoded unless
- there a string allocator is configured. QCBORDecode_SetUpAllocator()
- allows the caller to configure an external string allocator
- implementation if the internal string allocator is not suitable. See
- QCBORDecode_SetMemPool() to configure the internal allocator. Note
- that the internal allocator is not automatically set up.
-
- The string allocator configured here can be a custom one designed and
- implemented by the caller. See @ref QCBORStringAllocate for the
- requirements for a string allocator implementation.
-
- A malloc-based string external allocator can be obtained by calling
- @c QCBORDecode_MakeMallocStringAllocator(). It will return a function
- and pointer that can be given here as @c pAllocatorFunction and @c
- pAllocatorContext. It uses standard @c malloc() so @c free() must be
- called on all strings marked by @c uDataAlloc @c == @c 1 or @c
- uLabelAlloc @c == @c 1 in @ref QCBORItem.
-
- Note that an older version of this function took an allocator
- structure, rather than single function and pointer. The older
- version @c QCBORDecode_MakeMallocStringAllocator() also implemented
- the older interface.
- */
-void QCBORDecode_SetUpAllocator(QCBORDecodeContext *pCtx,
- QCBORStringAllocate pfAllocateFunction,
- void *pAllocateContext,
- bool bAllStrings);
-
-/**
- @brief Configure list of caller-selected tags to be recognized.
-
- @param[in] pCtx The decode context.
- @param[out] pTagList Structure holding the list of tags to configure.
-
- This is used to tell the decoder about tags beyond those that are
- built-in that should be recognized. The built-in tags are those with
- macros of the form @c CBOR_TAG_XXX.
-
- The list pointed to by @c pTagList must persist during decoding. No
- copy of it is made.
-
- The maximum number of tags that can be added is @ref
- QCBOR_MAX_CUSTOM_TAGS. If a list larger than this is given, the
- error will be returned when QCBORDecode_GetNext() is called, not
- here.
-
- See description of @ref QCBORTagListIn.
- */
-void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pCtx, const QCBORTagListIn *pTagList);
-
-
-/**
- @brief Gets the next item (integer, byte string, array...) in
- preorder traversal of CBOR tree.
-
- @param[in] pCtx The decoder context.
- @param[out] pDecodedItem Holds the CBOR item just decoded.
-
- @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Not well-formed, one of the
- chunks in indefinite-length
- string is wrong type.
-
- @retval QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN Not well-formed, array or map
- not closed.
-
- @retval QCBOR_ERR_UNSUPPORTED Not well-formed, input contains
- unsupported CBOR.
-
- @retval QCBOR_ERR_HIT_END Not well-formed, unexpectedly ran out
- of bytes.
-
- @retval QCBOR_ERR_BAD_TYPE_7 Not well-formed, bad simple type value.
-
- @retval QCBOR_ERR_BAD_BREAK Not well-formed, break occurs where
- not allowed.
-
- @retval QCBOR_ERR_EXTRA_BYTES Not well-formed, unprocessed bytes at
- the end.
-
- @retval QCBOR_ERR_BAD_INT Not well-formed, length of integer is
- bad.
-
- @retval QCBOR_ERR_BAD_OPT_TAG Invalid CBOR, tag on wrong type.
-
- @retval QCBOR_ERR_ARRAY_TOO_LONG Implementation limit, array or map
- too long.
-
- @retval QCBOR_ERR_INT_OVERFLOW Implementation limit, negative
- integer too large.
-
- @retval QCBOR_ERR_DATE_OVERFLOW Implementation limit, date larger
- than can be handled.
-
- @retval QCBOR_ERR_ARRAY_NESTING_TOO_DEEP Implementation limit, nesting
- too deep.
-
- @retval QCBOR_ERR_STRING_ALLOCATE Resource exhaustion, string allocator
- failed.
-
- @retval QCBOR_ERR_MAP_LABEL_TYPE Configuration error / Implementation
- limit encountered a map label this is
- not a string on an integer.
-
- @retval QCBOR_ERR_NO_STRING_ALLOCATOR Configuration error, encountered
- indefinite-length string with no
- allocator configured.
- @retval QCBOR_ERR_NO_MORE_ITEMS No more bytes to decode. The previous
- item was successfully decoded. This
- is usually how the non-error end of
- a CBOR stream / sequence is detected.
-
- @c pDecodedItem is filled in with the value parsed. Generally, the
- following data is returned in the structure:
-
- - @c uDataType which indicates which member of the @c val union the
- data is in. This decoder figures out the type based on the CBOR
- major type, the CBOR "additionalInfo", the CBOR optional tags and
- the value of the integer.
-
- - The value of the item, which might be an integer, a pointer and a
- length, the count of items in an array, a floating-point number or
- other.
-
- - The nesting level for maps and arrays.
-
- - The label for an item in a map, which may be a text or byte string
- or an integer.
-
- - The CBOR optional tag or tags.
-
- See documentation on in the data type @ref _QCBORItem for all the
- details on what is returned.
-
- This function handles arrays and maps. When first encountered a @ref
- QCBORItem will be returned with major type @ref QCBOR_TYPE_ARRAY or
- @ref QCBOR_TYPE_MAP. @c QCBORItem.val.uCount will indicate the number
- of Items in the array or map. Typically, an implementation will call
- QCBORDecode_GetNext() in a for loop to fetch them all. When decoding
- indefinite-length maps and arrays, @c QCBORItem.val.uCount is @c
- UINT16_MAX and @c uNextNestLevel must be used to know when the end of
- a map or array is reached.
-
- Nesting level 0 is the outside top-most nesting level. For example,
- in a CBOR structure with two items, an integer and a byte string
- only, both would be at nesting level 0. A CBOR structure with an
- array open, an integer and a byte string, would have the integer and
- byte string as nesting level 1.
-
- Here is an example of how the nesting level is reported with no arrays
- or maps at all.
-
- @verbatim
- CBOR Structure Nesting Level
- Integer 0
- Byte String 0
- @endverbatim
-
- Here is an example of how the nesting level is reported with a simple
- array and some top-level items.
-
- @verbatim
- Integer 0
- Array (with 2 items) 0
- Byte String 1
- Byte string 1
- Integer 0
- @endverbatim
-
-
- Here's a more complex example
- @verbatim
-
- Map with 2 items 0
- Text string 1
- Array with 3 integers 1
- integer 2
- integer 2
- integer 2
- text string 1
- byte string 1
- @endverbatim
-
- In @ref _QCBORItem, @c uNextNestLevel is the nesting level for the
- next call to QCBORDecode_GetNext(). It indicates if any maps or
- arrays were closed out during the processing of the just-fetched @ref
- QCBORItem. This processing includes a look-ahead for any breaks that
- close out indefinite-length arrays or maps. This value is needed to
- be able to understand the hierarchical structure. If @c
- uNextNestLevel is not equal to @c uNestLevel the end of the current
- map or array has been encountered. This works the same for both
- definite and indefinite-length arrays.
-
- This decoder support CBOR type 6 tagging. The decoding of particular
- given tag value may be supported in one of three different ways.
-
- First, some common tags are fully and transparently supported by
- automatically decoding them and returning them in a @ref QCBORItem.
- These tags have a @c QCBOR_TYPE_XXX associated with them and manifest
- pretty much the same as a standard CBOR type. @ref
- QCBOR_TYPE_DATE_EPOCH and the @c epochDate member of @ref QCBORItem
- is an example.
-
- Second are tags that are automatically recognized, but not decoded.
- These are tags that have a @c \#define of the form @c CBOR_TAG_XXX.
- These are recorded in the @c uTagBits member of @ref QCBORItem. There
- is an internal table that maps each bit to a particular tag value
- allowing up to 64 tags on an individual item to be reported (it is
- rare to have more than one or two). To find out if a particular tag
- value is set call QCBORDecode_IsTagged() on the @ref QCBORItem. See
- also QCBORDecode_GetNextWithTags().
-
- Third are tags that are not automatically recognized, because they
- are proprietary, custom or more recently registered with [IANA]
- (https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml). The
- internal mapping table has to be configured to recognize these. Call
- QCBORDecode_SetCallerConfiguredTagList() to do that. Then
- QCBORDecode_IsTagged() will work with them.
-
- The actual decoding of tags supported in the second and third way
- must be handled by the caller. Often this is simply verifying that
- the expected tag is present on a map, byte string or such. In other
- cases, there might a complicated map structure to decode.
-
- See @ref Tags-Overview for a description of how to go about creating
- custom tags.
-
- This tag decoding design is to be open-ended and flexible to be able
- to handle newly defined tags, while using very little memory, in
- particular keeping @ref QCBORItem as small as possible.
-
- If any error occurs, \c uDataType and \c uLabelType will be set
- to \ref QCBOR_TYPE_NONE. If there is no need to know the specific
- error, \ref QCBOR_TYPE_NONE can be checked for and the return value
- ignored.
-
- Errors fall in several categories as noted in list above:
-
- - Not well-formed errors are those where there is something
- syntactically and fundamentally wrong with the CBOR being
- decoded. Encoding should stop completely.
-
- - Invalid CBOR is well-formed, but still not correct. It is probably
- best to stop decoding, but not necessary.
-
- - This implementation has some size limits. They should rarely be
- encountered. If they are it may because something is wrong with the
- CBOR, for example an array size is incorrect.
-
- - Resource exhaustion. This only occurs when a string allocator is
- configured to handle indefinite-length strings as other than that,
- this implementation does no dynamic memory allocation.
-
- - There are a few CBOR constructs that are not handled without some
- extra configuration. These are indefinite length strings and maps
- with labels that are not strings or integers. See QCBORDecode_Init().
-
- */
-QCBORError QCBORDecode_GetNext(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem);
-
-
-/**
- @brief Gets the next item including full list of tags for item.
-
- @param[in] pCtx The decoder context.
- @param[out] pDecodedItem Holds the CBOR item just decoded.
- @param[in,out] pTagList On input array to put tags in; on output
- the tags on this item. See
- @ref QCBORTagListOut.
-
- @return See return values for QCBORDecode_GetNext().
-
- @retval QCBOR_ERR_TOO_MANY_TAGS The size of @c pTagList is too small.
-
- This works the same as QCBORDecode_GetNext() except that it also
- returns the full list of tags for the data item. This function should
- only be needed when parsing CBOR to print it out or convert it to
- some other format. It should not be needed to implement a CBOR-based
- protocol. See QCBORDecode_GetNext() for the main description of tag
- decoding.
-
- Tags will be returned here whether or not they are in the built-in or
- caller-configured tag lists.
-
- CBOR has no upper bound of limit on the number of tags that can be
- associated with a data item though in practice the number of tags on
- an item will usually be small, perhaps less than five. This will
- return @ref QCBOR_ERR_TOO_MANY_TAGS if the array in @c pTagList is
- too small to hold all the tags for the item.
-
- (This function is separate from QCBORDecode_GetNext() so as to not
- have to make @ref QCBORItem large enough to be able to hold a full
- list of tags. Even a list of five tags would nearly double its size
- because tags can be a @c uint64_t ).
- */
-QCBORError QCBORDecode_GetNextWithTags(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem, QCBORTagListOut *pTagList);
-
-
-/**
- @brief Determine if a CBOR item was tagged with a particular tag
-
- @param[in] pCtx The decoder context.
- @param[in] pItem The CBOR item to check.
- @param[in] uTag The tag to check, one of @c CBOR_TAG_XXX.
-
- @return 1 if it was tagged, 0 if not
-
- See QCBORDecode_GetNext() for the main description of tag
- handling. For tags that are not fully decoded a bit corresponding to
- the tag is set in in @c uTagBits in the @ref QCBORItem. The
- particular bit depends on an internal mapping table. This function
- checks for set bits against the mapping table.
-
- Typically, a protocol implementation just wants to know if a
- particular tag is present. That is what this provides. To get the
- full list of tags on a data item, see QCBORDecode_GetNextWithTags().
-
- Also see QCBORDecode_SetCallerConfiguredTagList() for the means to
- add new tags to the internal list so they can be checked for with
- this function.
- */
-int QCBORDecode_IsTagged(QCBORDecodeContext *pCtx, const QCBORItem *pItem, uint64_t uTag);
-
-
-/**
- Check whether all the bytes have been decoded and maps and arrays closed.
-
- @param[in] pCtx The context to check.
-
- @return An error or @ref QCBOR_SUCCESS.
-
- This tells you if all the bytes given to QCBORDecode_Init() have been
- consumed and whether all maps and arrays were closed. The decode is
- considered to be incorrect or incomplete if not and an error will be
- returned.
- */
-QCBORError QCBORDecode_Finish(QCBORDecodeContext *pCtx);
-
-
-
-
-/**
- @brief Convert int64_t to smaller integers safely.
-
- @param [in] src An @c int64_t.
- @param [out] dest A smaller sized integer to convert to.
-
- @return 0 on success -1 if not
-
- When decoding an integer, the CBOR decoder will return the value as
- an int64_t unless the integer is in the range of @c INT64_MAX and @c
- UINT64_MAX. That is, unless the value is so large that it can only be
- represented as a @c uint64_t, it will be an @c int64_t.
-
- CBOR itself doesn't size the individual integers it carries at
- all. The only limits it puts on the major integer types is that they
- are 8 bytes or less in length. Then encoders like this one use the
- smallest number of 1, 2, 4 or 8 bytes to represent the integer based
- on its value. There is thus no notion that one data item in CBOR is
- a 1-byte integer and another is a 4-byte integer.
-
- The interface to this CBOR encoder only uses 64-bit integers. Some
- CBOR protocols or implementations of CBOR protocols may not want to
- work with something smaller than a 64-bit integer. Perhaps an array
- of 1000 integers needs to be sent and none has a value larger than
- 50,000 and are represented as @c uint16_t.
-
- The sending / encoding side is easy. Integers are temporarily widened
- to 64-bits as a parameter passing through QCBOREncode_AddInt64() and
- encoded in the smallest way possible for their value, possibly in
- less than an @c uint16_t.
-
- On the decoding side the integers will be returned at @c int64_t even if
- they are small and were represented by only 1 or 2 bytes in the
- encoded CBOR. The functions here will convert integers to a small
- representation with an overflow check.
-
- (The decoder could have support 8 different integer types and
- represented the integer with the smallest type automatically, but
- this would have made the decoder more complex and code calling the
- decoder more complex in most use cases. In most use cases on 64-bit
- machines it is no burden to carry around even small integers as
- 64-bit values).
- */
-static inline int QCBOR_Int64ToInt32(int64_t src, int32_t *dest)
-{
- if(src > INT32_MAX || src < INT32_MIN) {
- return -1;
- } else {
- *dest = (int32_t) src;
- }
- return 0;
-}
-
-static inline int QCBOR_Int64ToInt16(int64_t src, int16_t *dest)
-{
- if(src > INT16_MAX || src < INT16_MIN) {
- return -1;
- } else {
- *dest = (int16_t) src;
- }
- return 0;
-}
-
-static inline int QCBOR_Int64ToInt8(int64_t src, int8_t *dest)
-{
- if(src > INT8_MAX || src < INT8_MIN) {
- return -1;
- } else {
- *dest = (int8_t) src;
- }
- return 0;
-}
-
-static inline int QCBOR_Int64ToUInt32(int64_t src, uint32_t *dest)
-{
- if(src > UINT32_MAX || src < 0) {
- return -1;
- } else {
- *dest = (uint32_t) src;
- }
- return 0;
-}
-
-static inline int QCBOR_Int64UToInt16(int64_t src, uint16_t *dest)
-{
- if(src > UINT16_MAX || src < 0) {
- return -1;
- } else {
- *dest = (uint16_t) src;
- }
- return 0;
-}
-
-static inline int QCBOR_Int64ToUInt8(int64_t src, uint8_t *dest)
-{
- if(src > UINT8_MAX || src < 0) {
- return -1;
- } else {
- *dest = (uint8_t) src;
- }
- return 0;
-}
-
-static inline int QCBOR_Int64ToUInt64(int64_t src, uint64_t *dest)
-{
- if(src > 0) {
- return -1;
- } else {
- *dest = (uint64_t) src;
- }
- return 0;
-}
-
-
-
-
-
-/* ===========================================================================
- BEGINNING OF PRIVATE INLINE IMPLEMENTATION
-
- =========================================================================== */
-
-/**
- @brief Semi-private method to add a buffer full of bytes to encoded output
-
- @param[in] pCtx The encoding context to add the integer to.
- @param[in] uMajorType The CBOR major type of the bytes.
- @param[in] Bytes The bytes to add.
-
- Use QCBOREncode_AddText() or QCBOREncode_AddBytes() or
- QCBOREncode_AddEncoded() instead. They are inline functions that call
- this and supply the correct major type. This function is public to
- make the inline functions work to keep the overall code size down and
- because the C language has no way to make it private.
-
- If this is called the major type should be @c
- CBOR_MAJOR_TYPE_TEXT_STRING, @c CBOR_MAJOR_TYPE_BYTE_STRING or @c
- CBOR_MAJOR_NONE_TYPE_RAW. The last one is special for adding
- already-encoded CBOR.
- */
-void QCBOREncode_AddBuffer(QCBOREncodeContext *pCtx, uint8_t uMajorType, UsefulBufC Bytes);
-
-
-/**
- @brief Semi-private method to open a map, array or bstr-wrapped CBOR
-
- @param[in] pCtx The context to add to.
- @param[in] uMajorType The major CBOR type to close
-
- Call QCBOREncode_OpenArray(), QCBOREncode_OpenMap() or
- QCBOREncode_BstrWrap() instead of this.
- */
-void QCBOREncode_OpenMapOrArray(QCBOREncodeContext *pCtx, uint8_t uMajorType);
-
-
-/**
- @brief Semi-private method to open a map, array with indefinite length
-
- @param[in] pCtx The context to add to.
- @param[in] uMajorType The major CBOR type to close
-
- Call QCBOREncode_OpenArrayIndefiniteLength() or
- QCBOREncode_OpenMapIndefiniteLength() instead of this.
- */
-void QCBOREncode_OpenMapOrArrayIndefiniteLength(QCBOREncodeContext *pCtx, uint8_t uMajorType);
-
-
-/**
- @brief Semi-private method to close a map, array or bstr wrapped CBOR
-
- @param[in] pCtx The context to add to.
- @param[in] uMajorType The major CBOR type to close.
-
- Call QCBOREncode_CloseArray() or QCBOREncode_CloseMap() instead of this.
- */
-void QCBOREncode_CloseMapOrArray(QCBOREncodeContext *pCtx, uint8_t uMajorType);
-
-
-/**
- @brief Semi-private method to close a map, array with indefinite length
-
- @param[in] pCtx The context to add to.
- @param[in] uMajorType The major CBOR type to close.
-
- Call QCBOREncode_CloseArrayIndefiniteLength() or
- QCBOREncode_CloseMapIndefiniteLength() instead of this.
- */
-void QCBOREncode_CloseMapOrArrayIndefiniteLength(QCBOREncodeContext *pCtx,
- uint8_t uMajorType);
-
-
-/**
- @brief Semi-private method to add simple types.
-
- @param[in] pCtx The encoding context to add the simple value to.
- @param[in] uMinLen Minimum encoding size for uNum. Usually 0.
- @param[in] uNum One of CBOR_SIMPLEV_FALSE through _UNDEF or other.
-
- This is used to add simple types like true and false.
-
- Call QCBOREncode_AddBool(), QCBOREncode_AddNULL(),
- QCBOREncode_AddUndef() instead of this.
-
- This function can add simple values that are not defined by CBOR
- yet. This expansion point in CBOR should not be used unless they are
- standardized.
-
- Error handling is the same as QCBOREncode_AddInt64().
- */
-void QCBOREncode_AddType7(QCBOREncodeContext *pCtx, uint8_t uMinLen, uint64_t uNum);
-
-
-/**
- @brief Semi-private method to add bigfloats and decimal fractions.
-
- @param[in] pCtx The encoding context to add the value to.
- @param[in] uTag The type 6 tag indicating what this is to be
- @param[in] BigNumMantissa Is @ref NULLUsefulBufC if mantissa is an
- @c int64_t or the actual big number mantissa
- if not.
- @param[in] nMantissa The @c int64_t mantissa if it is not a big number.
- @param[in] nExponent The exponent.
-
- This adds a tagged array with two members, the mantissa and exponent. The
- mantissa can be either a big number or an @c int64_t.
-
- Typically, QCBOREncode_AddDecimalFraction(), QCBOREncode_AddBigFloat(),
- QCBOREncode_AddDecimalFractionBigNum() or QCBOREncode_AddBigFloatBigNum()
- is called instead of this.
- */
-void QCBOREncode_AddExponentAndMantissa(QCBOREncodeContext *pCtx,
- uint64_t uTag,
- UsefulBufC BigNumMantissa,
- bool bBigNumIsNegative,
- int64_t nMantissa,
- int64_t nExponent);
-
-/**
- @brief Semi-private method to add only the type and length of a byte string.
-
- @param[in] pCtx The context to initialize.
- @param[in] Bytes Pointer and length of the input data.
-
- This is the same as QCBOREncode_AddBytes() except it only adds the
- CBOR encoding for the type and the length. It doesn't actually add
- the bytes. You can't actually produce correct CBOR with this and the
- rest of this API. It is only used for a special case where
- the valid CBOR is created manually by putting this type and length in
- and then adding the actual bytes. In particular, when only a hash of
- the encoded CBOR is needed, where the type and header are hashed
- separately and then the bytes is hashed. This makes it possible to
- implement COSE Sign1 with only one copy of the payload in the output
- buffer, rather than two, roughly cutting memory use in half.
-
- This is only used for this odd case, but this is a supported
- tested function.
-
- See also QCBOREncode_EncodeHead().
-*/
-static inline void QCBOREncode_AddBytesLenOnly(QCBOREncodeContext *pCtx, UsefulBufC Bytes);
-
-static inline void QCBOREncode_AddBytesLenOnlyToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes);
-
-static inline void QCBOREncode_AddBytesLenOnlyToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes);
-
-
-
-
-
-static inline void QCBOREncode_AddInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, int64_t uNum)
-{
- // Use _AddBuffer() because _AddSZString() is defined below, not above
- QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_TYPE_TEXT_STRING, UsefulBuf_FromSZ(szLabel));
- QCBOREncode_AddInt64(pCtx, uNum);
-}
-
-static inline void QCBOREncode_AddInt64ToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, int64_t uNum)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddInt64(pCtx, uNum);
-}
-
-
-static inline void QCBOREncode_AddUInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, uint64_t uNum)
-{
- // Use _AddBuffer() because _AddSZString() is defined below, not above
- QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_TYPE_TEXT_STRING, UsefulBuf_FromSZ(szLabel));
- QCBOREncode_AddUInt64(pCtx, uNum);
-}
-
-static inline void QCBOREncode_AddUInt64ToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, uint64_t uNum)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddUInt64(pCtx, uNum);
-}
-
-
-static inline void QCBOREncode_AddText(QCBOREncodeContext *pCtx, UsefulBufC Text)
-{
- QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_TYPE_TEXT_STRING, Text);
-}
-
-static inline void QCBOREncode_AddTextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Text)
-{
- // Use _AddBuffer() because _AddSZString() is defined below, not above
- QCBOREncode_AddText(pCtx, UsefulBuf_FromSZ(szLabel));
- QCBOREncode_AddText(pCtx, Text);
-}
-
-static inline void QCBOREncode_AddTextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Text)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddText(pCtx, Text);
-}
-
-
-inline static void QCBOREncode_AddSZString(QCBOREncodeContext *pCtx, const char *szString)
-{
- QCBOREncode_AddText(pCtx, UsefulBuf_FromSZ(szString));
-}
-
-static inline void QCBOREncode_AddSZStringToMap(QCBOREncodeContext *pCtx, const char *szLabel, const char *szString)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddSZString(pCtx, szString);
-}
-
-static inline void QCBOREncode_AddSZStringToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, const char *szString)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddSZString(pCtx, szString);
-}
-
-
-static inline void QCBOREncode_AddDoubleToMap(QCBOREncodeContext *pCtx, const char *szLabel, double dNum)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddDouble(pCtx, dNum);
-}
-
-static inline void QCBOREncode_AddDoubleToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, double dNum)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddDouble(pCtx, dNum);
-}
-
-
-static inline void QCBOREncode_AddDateEpoch(QCBOREncodeContext *pCtx, int64_t date)
-{
- QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_EPOCH);
- QCBOREncode_AddInt64(pCtx, date);
-}
-
-static inline void QCBOREncode_AddDateEpochToMap(QCBOREncodeContext *pCtx, const char *szLabel, int64_t date)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_EPOCH);
- QCBOREncode_AddInt64(pCtx, date);
-}
-
-static inline void QCBOREncode_AddDateEpochToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, int64_t date)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_EPOCH);
- QCBOREncode_AddInt64(pCtx, date);
-}
-
-
-static inline void QCBOREncode_AddBytes(QCBOREncodeContext *pCtx, UsefulBufC Bytes)
-{
- QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_TYPE_BYTE_STRING, Bytes);
-}
-
-static inline void QCBOREncode_AddBytesToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddBytes(pCtx, Bytes);
-}
-
-static inline void QCBOREncode_AddBytesToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddBytes(pCtx, Bytes);
-}
-
-static inline void QCBOREncode_AddBytesLenOnly(QCBOREncodeContext *pCtx, UsefulBufC Bytes)
-{
- QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY, Bytes);
-}
-
-static inline void QCBOREncode_AddBytesLenOnlyToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddBytesLenOnly(pCtx, Bytes);
-}
-
-static inline void QCBOREncode_AddBytesLenOnlyToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddBytesLenOnly(pCtx, Bytes);
-}
-
-static inline void QCBOREncode_AddBinaryUUID(QCBOREncodeContext *pCtx, UsefulBufC Bytes)
-{
- QCBOREncode_AddTag(pCtx, CBOR_TAG_BIN_UUID);
- QCBOREncode_AddBytes(pCtx, Bytes);
-}
-
-static inline void QCBOREncode_AddBinaryUUIDToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_BIN_UUID);
- QCBOREncode_AddBytes(pCtx, Bytes);
-}
-
-static inline void QCBOREncode_AddBinaryUUIDToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_BIN_UUID);
- QCBOREncode_AddBytes(pCtx, Bytes);
-}
-
-
-static inline void QCBOREncode_AddPositiveBignum(QCBOREncodeContext *pCtx, UsefulBufC Bytes)
-{
- QCBOREncode_AddTag(pCtx, CBOR_TAG_POS_BIGNUM);
- QCBOREncode_AddBytes(pCtx, Bytes);
-}
-
-static inline void QCBOREncode_AddPositiveBignumToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_POS_BIGNUM);
- QCBOREncode_AddBytes(pCtx, Bytes);
-}
-
-static inline void QCBOREncode_AddPositiveBignumToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_POS_BIGNUM);
- QCBOREncode_AddBytes(pCtx, Bytes);
-}
-
-
-static inline void QCBOREncode_AddNegativeBignum(QCBOREncodeContext *pCtx, UsefulBufC Bytes)
-{
- QCBOREncode_AddTag(pCtx, CBOR_TAG_NEG_BIGNUM);
- QCBOREncode_AddBytes(pCtx, Bytes);
-}
-
-static inline void QCBOREncode_AddNegativeBignumToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_NEG_BIGNUM);
- QCBOREncode_AddBytes(pCtx, Bytes);
-}
-
-static inline void QCBOREncode_AddNegativeBignumToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_NEG_BIGNUM);
- QCBOREncode_AddBytes(pCtx, Bytes);
-}
-
-
-#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
-
-static inline void QCBOREncode_AddDecimalFraction(QCBOREncodeContext *pCtx,
- int64_t nMantissa,
- int64_t nBase10Exponent)
-{
- QCBOREncode_AddExponentAndMantissa(pCtx,
- CBOR_TAG_DECIMAL_FRACTION,
- NULLUsefulBufC,
- false,
- nMantissa,
- nBase10Exponent);
-}
-
-static inline void QCBOREncode_AddDecimalFractionToMap(QCBOREncodeContext *pCtx,
- const char *szLabel,
- int64_t nMantissa,
- int64_t nBase10Exponent)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddDecimalFraction(pCtx, nMantissa, nBase10Exponent);
-}
-
-static inline void QCBOREncode_AddDecimalFractionToMapN(QCBOREncodeContext *pCtx,
- int64_t nLabel,
- int64_t nMantissa,
- int64_t nBase10Exponent)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddDecimalFraction(pCtx, nMantissa, nBase10Exponent);
-}
-
-static inline void QCBOREncode_AddDecimalFractionBigNum(QCBOREncodeContext *pCtx,
- UsefulBufC Mantissa,
- bool bIsNegative,
- int64_t nBase10Exponent)
-{
- QCBOREncode_AddExponentAndMantissa(pCtx,
- CBOR_TAG_DECIMAL_FRACTION,
- Mantissa, bIsNegative,
- 0,
- nBase10Exponent);
-}
-
-static inline void QCBOREncode_AddDecimalFractionBigNumToMap(QCBOREncodeContext *pCtx,
- const char *szLabel,
- UsefulBufC Mantissa,
- bool bIsNegative,
- int64_t nBase10Exponent)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddDecimalFractionBigNum(pCtx, Mantissa, bIsNegative, nBase10Exponent);
-}
-
-static inline void QCBOREncode_AddDecimalFractionBigNumToMapN(QCBOREncodeContext *pCtx,
- int64_t nLabel,
- UsefulBufC Mantissa,
- bool bIsNegative,
- int64_t nBase2Exponent)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddDecimalFractionBigNum(pCtx, Mantissa, bIsNegative, nBase2Exponent);
-}
-
-static inline void QCBOREncode_AddBigFloat(QCBOREncodeContext *pCtx,
- int64_t nMantissa,
- int64_t nBase2Exponent)
-{
- QCBOREncode_AddExponentAndMantissa(pCtx, CBOR_TAG_BIGFLOAT, NULLUsefulBufC, false, nMantissa, nBase2Exponent);
-}
-
-static inline void QCBOREncode_AddBigFloatToMap(QCBOREncodeContext *pCtx,
- const char *szLabel,
- int64_t nMantissa,
- int64_t nBase2Exponent)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddBigFloat(pCtx, nMantissa, nBase2Exponent);
-}
-
-static inline void QCBOREncode_AddBigFloatToMapN(QCBOREncodeContext *pCtx,
- int64_t nLabel,
- int64_t nMantissa,
- int64_t nBase2Exponent)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddBigFloat(pCtx, nMantissa, nBase2Exponent);
-}
-
-static inline void QCBOREncode_AddBigFloatBigNum(QCBOREncodeContext *pCtx,
- UsefulBufC Mantissa,
- bool bIsNegative,
- int64_t nBase2Exponent)
-{
- QCBOREncode_AddExponentAndMantissa(pCtx, CBOR_TAG_BIGFLOAT, Mantissa, bIsNegative, 0, nBase2Exponent);
-}
-
-static inline void QCBOREncode_AddBigFloatBigNumToMap(QCBOREncodeContext *pCtx,
- const char *szLabel,
- UsefulBufC Mantissa,
- bool bIsNegative,
- int64_t nBase2Exponent)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddBigFloatBigNum(pCtx, Mantissa, bIsNegative, nBase2Exponent);
-}
-
-static inline void QCBOREncode_AddBigFloatBigNumToMapN(QCBOREncodeContext *pCtx,
- int64_t nLabel,
- UsefulBufC Mantissa,
- bool bIsNegative,
- int64_t nBase2Exponent)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddBigFloatBigNum(pCtx, Mantissa, bIsNegative, nBase2Exponent);
-}
-#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
-
-
-static inline void QCBOREncode_AddURI(QCBOREncodeContext *pCtx, UsefulBufC URI)
-{
- QCBOREncode_AddTag(pCtx, CBOR_TAG_URI);
- QCBOREncode_AddText(pCtx, URI);
-}
-
-static inline void QCBOREncode_AddURIToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC URI)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_URI);
- QCBOREncode_AddText(pCtx, URI);
-}
-
-static inline void QCBOREncode_AddURIToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC URI)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_URI);
- QCBOREncode_AddText(pCtx, URI);
-}
-
-
-
-static inline void QCBOREncode_AddB64Text(QCBOREncodeContext *pCtx, UsefulBufC B64Text)
-{
- QCBOREncode_AddTag(pCtx, CBOR_TAG_B64);
- QCBOREncode_AddText(pCtx, B64Text);
-}
-
-static inline void QCBOREncode_AddB64TextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC B64Text)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_B64);
- QCBOREncode_AddText(pCtx, B64Text);
-}
-
-static inline void QCBOREncode_AddB64TextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC B64Text)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_B64);
- QCBOREncode_AddText(pCtx, B64Text);
-}
-
-
-static inline void QCBOREncode_AddB64URLText(QCBOREncodeContext *pCtx, UsefulBufC B64Text)
-{
- QCBOREncode_AddTag(pCtx, CBOR_TAG_B64URL);
- QCBOREncode_AddText(pCtx, B64Text);
-}
-
-static inline void QCBOREncode_AddB64URLTextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC B64Text)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_B64URL);
- QCBOREncode_AddText(pCtx, B64Text);
-}
-
-static inline void QCBOREncode_AddB64URLTextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC B64Text)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_B64URL);
- QCBOREncode_AddText(pCtx, B64Text);
-}
-
-
-static inline void QCBOREncode_AddRegex(QCBOREncodeContext *pCtx, UsefulBufC Bytes)
-{
- QCBOREncode_AddTag(pCtx, CBOR_TAG_REGEX);
- QCBOREncode_AddText(pCtx, Bytes);
-}
-
-static inline void QCBOREncode_AddRegexToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_REGEX);
- QCBOREncode_AddText(pCtx, Bytes);
-}
-
-static inline void QCBOREncode_AddRegexToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_REGEX);
- QCBOREncode_AddText(pCtx, Bytes);
-}
-
-
-static inline void QCBOREncode_AddMIMEData(QCBOREncodeContext *pCtx, UsefulBufC MIMEData)
-{
- QCBOREncode_AddTag(pCtx, CBOR_TAG_MIME);
- QCBOREncode_AddText(pCtx, MIMEData);
-}
-
-static inline void QCBOREncode_AddMIMEDataToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC MIMEData)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_MIME);
- QCBOREncode_AddText(pCtx, MIMEData);
-}
-
-static inline void QCBOREncode_AddMIMEDataToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC MIMEData)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_MIME);
- QCBOREncode_AddText(pCtx, MIMEData);
-}
-
-
-static inline void QCBOREncode_AddDateString(QCBOREncodeContext *pCtx, const char *szDate)
-{
- QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_STRING);
- QCBOREncode_AddSZString(pCtx, szDate);
-}
-
-static inline void QCBOREncode_AddDateStringToMap(QCBOREncodeContext *pCtx, const char *szLabel, const char *szDate)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_STRING);
- QCBOREncode_AddSZString(pCtx, szDate);
-}
-
-static inline void QCBOREncode_AddDateStringToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, const char *szDate)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_STRING);
- QCBOREncode_AddSZString(pCtx, szDate);
-}
-
-
-static inline void QCBOREncode_AddSimple(QCBOREncodeContext *pCtx, uint64_t uNum)
-{
- QCBOREncode_AddType7(pCtx, 0, uNum);
-}
-
-static inline void QCBOREncode_AddSimpleToMap(QCBOREncodeContext *pCtx, const char *szLabel, uint8_t uSimple)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddSimple(pCtx, uSimple);
-}
-
-static inline void QCBOREncode_AddSimpleToMapN(QCBOREncodeContext *pCtx, int nLabel, uint8_t uSimple)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddSimple(pCtx, uSimple);
-}
-
-
-static inline void QCBOREncode_AddBool(QCBOREncodeContext *pCtx, bool b)
-{
- uint8_t uSimple = CBOR_SIMPLEV_FALSE;
- if(b) {
- uSimple = CBOR_SIMPLEV_TRUE;
- }
- QCBOREncode_AddSimple(pCtx, uSimple);
-}
-
-static inline void QCBOREncode_AddBoolToMap(QCBOREncodeContext *pCtx, const char *szLabel, bool b)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddBool(pCtx, b);
-}
-
-static inline void QCBOREncode_AddBoolToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, bool b)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddBool(pCtx, b);
-}
-
-
-static inline void QCBOREncode_AddNULL(QCBOREncodeContext *pCtx)
-{
- QCBOREncode_AddSimple(pCtx, CBOR_SIMPLEV_NULL);
-}
-
-static inline void QCBOREncode_AddNULLToMap(QCBOREncodeContext *pCtx, const char *szLabel)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddNULL(pCtx);
-}
-
-static inline void QCBOREncode_AddNULLToMapN(QCBOREncodeContext *pCtx, int64_t nLabel)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddNULL(pCtx);
-}
-
-
-static inline void QCBOREncode_AddUndef(QCBOREncodeContext *pCtx)
-{
- QCBOREncode_AddSimple(pCtx, CBOR_SIMPLEV_UNDEF);
-}
-
-static inline void QCBOREncode_AddUndefToMap(QCBOREncodeContext *pCtx, const char *szLabel)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddUndef(pCtx);
-}
-
-static inline void QCBOREncode_AddUndefToMapN(QCBOREncodeContext *pCtx, int64_t nLabel)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddUndef(pCtx);
-}
-
-
-static inline void QCBOREncode_OpenArray(QCBOREncodeContext *pCtx)
-{
- QCBOREncode_OpenMapOrArray(pCtx, CBOR_MAJOR_TYPE_ARRAY);
-}
-
-static inline void QCBOREncode_OpenArrayInMap(QCBOREncodeContext *pCtx, const char *szLabel)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_OpenArray(pCtx);
-}
-
-static inline void QCBOREncode_OpenArrayInMapN(QCBOREncodeContext *pCtx, int64_t nLabel)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_OpenArray(pCtx);
-}
-
-static inline void QCBOREncode_CloseArray(QCBOREncodeContext *pCtx)
-{
- QCBOREncode_CloseMapOrArray(pCtx, CBOR_MAJOR_TYPE_ARRAY);
-}
-
-
-static inline void QCBOREncode_OpenMap(QCBOREncodeContext *pCtx)
-{
- QCBOREncode_OpenMapOrArray(pCtx, CBOR_MAJOR_TYPE_MAP);
-}
-
-static inline void QCBOREncode_OpenMapInMap(QCBOREncodeContext *pCtx, const char *szLabel)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_OpenMap(pCtx);
-}
-
-static inline void QCBOREncode_OpenMapInMapN(QCBOREncodeContext *pCtx, int64_t nLabel)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_OpenMap(pCtx);
-}
-
-static inline void QCBOREncode_CloseMap(QCBOREncodeContext *pCtx)
-{
- QCBOREncode_CloseMapOrArray(pCtx, CBOR_MAJOR_TYPE_MAP);
-}
-
-static inline void QCBOREncode_OpenArrayIndefiniteLength(QCBOREncodeContext *pCtx)
-{
- QCBOREncode_OpenMapOrArrayIndefiniteLength(pCtx, CBOR_MAJOR_NONE_TYPE_ARRAY_INDEFINITE_LEN);
-}
-
-static inline void QCBOREncode_OpenArrayIndefiniteLengthInMap(QCBOREncodeContext *pCtx, const char *szLabel)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_OpenArrayIndefiniteLength(pCtx);
-}
-
-static inline void QCBOREncode_OpenArrayIndefiniteLengthInMapN(QCBOREncodeContext *pCtx, int64_t nLabel)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_OpenArrayIndefiniteLength(pCtx);
-}
-
-static inline void QCBOREncode_CloseArrayIndefiniteLength(QCBOREncodeContext *pCtx)
-{
- QCBOREncode_CloseMapOrArrayIndefiniteLength(pCtx, CBOR_MAJOR_NONE_TYPE_ARRAY_INDEFINITE_LEN);
-}
-
-
-static inline void QCBOREncode_OpenMapIndefiniteLength(QCBOREncodeContext *pCtx)
-{
- QCBOREncode_OpenMapOrArrayIndefiniteLength(pCtx, CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN);
-}
-
-static inline void QCBOREncode_OpenMapIndefiniteLengthInMap(QCBOREncodeContext *pCtx, const char *szLabel)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_OpenMapIndefiniteLength(pCtx);
-}
-
-static inline void QCBOREncode_OpenMapIndefiniteLengthInMapN(QCBOREncodeContext *pCtx, int64_t nLabel)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_OpenMapIndefiniteLength(pCtx);
-}
-
-static inline void QCBOREncode_CloseMapIndefiniteLength(QCBOREncodeContext *pCtx)
-{
- QCBOREncode_CloseMapOrArrayIndefiniteLength(pCtx, CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN);
-}
-
-
-static inline void QCBOREncode_BstrWrap(QCBOREncodeContext *pCtx)
-{
- QCBOREncode_OpenMapOrArray(pCtx, CBOR_MAJOR_TYPE_BYTE_STRING);
-}
-
-static inline void QCBOREncode_BstrWrapInMap(QCBOREncodeContext *pCtx, const char *szLabel)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_BstrWrap(pCtx);
-}
-
-static inline void QCBOREncode_BstrWrapInMapN(QCBOREncodeContext *pCtx, int64_t nLabel)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_BstrWrap(pCtx);
-}
-
-static inline void QCBOREncode_CloseBstrWrap(QCBOREncodeContext *pCtx, UsefulBufC *pWrappedCBOR)
-{
- QCBOREncode_CloseBstrWrap2(pCtx, true, pWrappedCBOR);
-}
-
-
-static inline void QCBOREncode_AddEncoded(QCBOREncodeContext *pCtx, UsefulBufC Encoded)
-{
- QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_NONE_TYPE_RAW, Encoded);
-}
-
-static inline void QCBOREncode_AddEncodedToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Encoded)
-{
- QCBOREncode_AddSZString(pCtx, szLabel);
- QCBOREncode_AddEncoded(pCtx, Encoded);
-}
-
-static inline void QCBOREncode_AddEncodedToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Encoded)
-{
- QCBOREncode_AddInt64(pCtx, nLabel);
- QCBOREncode_AddEncoded(pCtx, Encoded);
-}
-
-
-static inline int QCBOREncode_IsBufferNULL(QCBOREncodeContext *pCtx)
-{
- return UsefulOutBuf_IsBufferNULL(&(pCtx->OutBuf));
-}
-
-static inline QCBORError QCBOREncode_GetErrorState(QCBOREncodeContext *pCtx)
-{
- if(UsefulOutBuf_GetError(&(pCtx->OutBuf))) {
- // Items didn't fit in the buffer.
- // This check catches this condition for all the appends and inserts
- // so checks aren't needed when the appends and inserts are performed.
- // And of course UsefulBuf will never overrun the input buffer given
- // to it. No complex analysis of the error handling in this file is
- // needed to know that is true. Just read the UsefulBuf code.
- pCtx->uError = QCBOR_ERR_BUFFER_TOO_SMALL;
- // QCBOR_ERR_BUFFER_TOO_SMALL masks other errors, but that is
- // OK. Once the caller fixes this, they'll be unmasked.
- }
-
- return (QCBORError)pCtx->uError;
-}
-
-
-/* ===========================================================================
- END OF PRIVATE INLINE IMPLEMENTATION
-
- =========================================================================== */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* defined(__QCBOR__qcbor__) */
+#include "qcbor/qcbor.h"
diff --git a/inc/qcbor/UsefulBuf.h b/inc/qcbor/UsefulBuf.h
new file mode 100644
index 0000000..a8da83b
--- /dev/null
+++ b/inc/qcbor/UsefulBuf.h
@@ -0,0 +1,2134 @@
+/*============================================================================
+ Copyright (c) 2016-2018, The Linux Foundation.
+ Copyright (c) 2018-2020, Laurence Lundblade.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors, nor the name "Laurence Lundblade" may be used to
+ endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ =============================================================================*/
+
+/*============================================================================
+ FILE: UsefulBuf.h
+
+ DESCRIPTION: General purpose input and output buffers
+
+ EDIT HISTORY FOR FILE:
+
+ This section contains comments describing changes made to the module.
+ Notice that changes are listed in reverse chronological order.
+
+ when who what, where, why
+ -------- ---- --------------------------------------------------
+ 1/25/2020 llundblade Add some casts so static anlyzers don't complain.
+ 5/21/2019 llundblade #define configs for efficient endianness handling.
+ 5/16/2019 llundblade Add UsefulOutBuf_IsBufferNULL().
+ 3/23/2019 llundblade Big documentation & style update. No interface
+ change.
+ 3/6/2019 llundblade Add UsefulBuf_IsValue()
+ 12/17/2018 llundblade Remove const from UsefulBuf and UsefulBufC .len
+ 12/13/2018 llundblade Documentation improvements
+ 09/18/2018 llundblade Cleaner distinction between UsefulBuf and
+ UsefulBufC.
+ 02/02/18 llundbla Full support for integers in and out; fix pointer
+ alignment bug. Incompatible change: integers
+ in/out are now in network byte order.
+ 08/12/17 llundbla Added UsefulOutBuf_AtStart and UsefulBuf_Find
+ 06/27/17 llundbla Fix UsefulBuf_Compare() bug. Only affected
+ comparison for < or > for unequal length buffers.
+ Added UsefulBuf_Set() function.
+ 05/30/17 llundbla Functions for NULL UsefulBufs and const / unconst
+ 11/13/16 llundbla Initial Version.
+
+ =============================================================================*/
+
+#ifndef _UsefulBuf_h
+#define _UsefulBuf_h
+
+
+/*
+ Configuration Options
+
+ This code is designed so it will work correctly and completely by
+ default. No configuration is necessary to make it work. None of the
+ following #defines need to be enabled. The code works and is very
+ portable with them all turned off.
+
+ All configuration options (USEFULBUF_CONFIG_XXX)
+ 1) Reduce code size
+ 2) Improve efficiency
+ 3) Both of the above
+
+ The efficiency improvements are not large, so the main reason really
+ is to reduce code size.
+
+ */
+
+
+/*
+ Endianness Configuration
+
+ By default, UsefulBuf does not need to know what the endianness of
+ the device is. All the code will run correctly on either big or
+ little endian CPUs.
+
+ Here's the recipe for configuring the endianness-related #defines
+ to use more efficient CPU/OS/compiler dependent features to reduce
+ code size. Note these only affect the integer arrays (tagged
+ arrays) feature of QCBOR. All other endianness handling in
+ QCBOR is integrated with code that also handles alignment and
+ preferred encoding.
+
+ The first option is to not define anything. This will work fine on
+ with all CPU's, OS's and compilers. The code for encoding
+ integers will be a little larger and slower.
+
+ If your CPU is big-endian then define USEFULBUF_CONFIG_BIG_ENDIAN. This
+ will give the most efficient code for big-endian CPUs. It will be small
+ and efficient because there will be no byte swapping.
+
+ Try defining USEFULBUF_CONFIG_HTON. This will work on most CPU's,
+ OS's and compilers, but not all. On big-endian CPUs this should give
+ the most efficient code, the same as USEFULBUF_CONFIG_BIG_ENDIAN
+ does. On little-endian CPUs it should call the system-defined byte
+ swapping method which is presumably implemented efficiently. In some
+ cases, this will be a dedicated byte swap instruction like Intel's
+ bswap.
+
+ If USEFULBUF_CONFIG_HTON works and you know your CPU is
+ little-endian, it is also good to define
+ USEFULBUF_CONFIG_LITTLE_ENDIAN.
+
+ if USEFULBUF_CONFIG_HTON doesn't work and you know your system is
+ little-endian, try defining both USEFULBUF_CONFIG_LITTLE_ENDIAN and
+ USEFULBUF_CONFIG_BSWAP. This should call the most efficient
+ system-defined byte swap method. However, note
+ https://hardwarebug.org/2010/01/14/beware-the-builtins/. Perhaps
+ this is fixed now. Often hton() and ntoh() will call the built-in
+ __builtin_bswapXX()() function, so this size issue could affect
+ USEFULBUF_CONFIG_HTON.
+
+ Last, run the tests. They must all pass.
+
+ These #define config options affect the inline implementation of
+ UsefulOutBuf_InsertUint64() and UsefulInputBuf_GetUint64(). They
+ also affect the 16-, 32-bit, float and double versions of these
+ instructions. Since they are inline, they size effect is not in the
+ UsefulBuf object code, but in the calling code.
+
+ Summary:
+ USEFULBUF_CONFIG_BIG_ENDIAN -- Force configuration to big-endian.
+ USEFULBUF_CONFIG_LITTLE_ENDIAN -- Force to little-endian.
+ USEFULBUF_CONFIG_HTON -- Use hton(), htonl(), ntohl()... to
+ handle big and little-endian with system option.
+ USEFULBUF_CONFIG_BSWAP -- With USEFULBUF_CONFIG_LITTLE_ENDIAN,
+ use __builtin_bswapXX().
+ */
+
+#if defined(USEFULBUF_CONFIG_BIG_ENDIAN) && defined(USEFULBUF_CONFIG_LITTLE_ENDIAN)
+#error "Cannot define both USEFULBUF_CONFIG_BIG_ENDIAN and USEFULBUF_CONFIG_LITTLE_ENDIAN"
+#endif
+
+
+#include <stdint.h> // for uint8_t, uint16_t....
+#include <string.h> // for strlen, memcpy, memmove, memset
+#include <stddef.h> // for size_t
+
+
+#ifdef USEFULBUF_CONFIG_HTON
+#include <arpa/inet.h> // for htons, htonl, htonll, ntohs...
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ @file UsefulBuf.h
+
+ The goal of this code is to make buffer and pointer manipulation
+ easier and safer when working with binary data.
+
+ The @ref UsefulBuf, @ref UsefulOutBuf and @ref UsefulInputBuf
+ structures are used to represent buffers rather than ad hoc pointers and
+ lengths.
+
+ With these it will often be possible to write code that does little
+ or no direct pointer manipulation for copying and formatting
+ data. For example, the QCBOR encoder was written using these and
+ has no less pointer manipulation.
+
+ While it is true that object code using these functions will be a
+ little larger and slower than a white-knuckle clever use of pointers
+ might be, but not by that much or enough to have an effect for most
+ use cases. For security-oriented code this is highly
+ worthwhile. Clarity, simplicity, reviewability and are more
+ important.
+
+ There are some extra sanity and double checks in this code to help
+ catch coding errors and simple memory corruption. They are helpful,
+ but not a substitute for proper code review, input validation and
+ such.
+
+ This code consists of a lot of inline functions and a few that are
+ not. It should not generate very much object code, especially with
+ the optimizer turned up to @c -Os or @c -O3.
+ */
+
+
+/**
+ @ref UsefulBufC and @ref UsefulBuf are simple data structures to hold
+ a pointer and length for binary data. In C99 this data structure can
+ be passed on the stack making a lot of code cleaner than carrying
+ around a pointer and length as two parameters.
+
+ This is also conducive to secure coding practice as the length is
+ always carried with the pointer and the convention for handling a
+ pointer and a length is clear.
+
+ While it might be possible to write buffer and pointer code more
+ efficiently in some use cases, the thought is that unless there is an
+ extreme need for performance (e.g., you are building a
+ gigabit-per-second IP router), it is probably better to have cleaner
+ code you can be most certain about the security of.
+
+ The non-const @ref UsefulBuf is usually used to refer a buffer to be
+ filled in. The length is the size of the buffer.
+
+ The const @ref UsefulBufC is usually used to refer to some data that
+ has been filled in. The length is amount of valid data pointed to.
+
+ A common use is to pass a @ref UsefulBuf to a function, the function
+ fills it in, the function returns a @ref UsefulBufC. The pointer is
+ the same in both.
+
+ A @ref UsefulBuf is null, it has no value, when @c ptr in it is @c NULL.
+
+ There are utility functions for the following:
+ - Initializing
+ - Create initialized const @ref UsefulBufC from compiler literals
+ - Create initialized const @ref UsefulBufC from NULL-terminated string
+ - Make an empty @ref UsefulBuf on the stack
+ - Checking whether a @ref UsefulBuf is null, empty or both
+ - Copying, copying with offset, copying head or tail
+ - Comparing and finding substrings
+
+ See also @ref UsefulOutBuf. It is a richer structure that has both
+ the size of the valid data and the size of the buffer.
+
+ @ref UsefulBuf is only 16 or 8 bytes on a 64- or 32-bit machine so it
+ can go on the stack and be a function parameter or return value.
+
+ Another way to look at it is this. C has the NULL-terminated string
+ as a means for handling text strings, but no means or convention for
+ binary strings. Other languages do have such means, Rust, an
+ efficient compiled language, for example.
+
+ @ref UsefulBuf is kind of like the Useful Pot Pooh gave Eeyore on his
+ birthday. Eeyore's balloon fits beautifully, "it goes in and out
+ like anything".
+*/
+typedef struct q_useful_buf_c {
+ const void *ptr;
+ size_t len;
+} UsefulBufC;
+
+
+/**
+ This non-const @ref UsefulBuf is typically used for some allocated
+ memory that is to be filled in. The @c len is the amount of memory,
+ not the length of the valid data in the buffer.
+ */
+typedef struct q_useful_buf {
+ void *ptr;
+ size_t len;
+} UsefulBuf;
+
+
+/**
+ A null @ref UsefulBufC is one that has no value in the same way a @c
+ NULL pointer has no value. A @ref UsefulBufC is @c NULL when the @c
+ ptr field is @c NULL. It doesn't matter what @c len is. See
+ UsefulBuf_IsEmpty() for the distinction between null and empty.
+ */
+#define NULLUsefulBufC ((UsefulBufC) {NULL, 0})
+
+
+/**
+ A null @ref UsefulBuf is one that has no memory associated the same
+ way @c NULL points to nothing. It does not matter what @c len is.
+ */
+#define NULLUsefulBuf ((UsefulBuf) {NULL, 0})
+
+
+/**
+ @brief Check if a @ref UsefulBuf is @ref NULLUsefulBuf or not.
+
+ @param[in] UB The UsefulBuf to check.
+
+ @return 1 if it is @ref NULLUsefulBuf, 0 if not.
+ */
+static inline int UsefulBuf_IsNULL(UsefulBuf UB);
+
+
+/**
+ @brief Check if a @ref UsefulBufC is @ref NULLUsefulBufC or not.
+
+ @param[in] UB The @ref UsefulBufC to check.
+
+ @return 1 if it is @c NULLUsefulBufC, 0 if not.
+ */
+static inline int UsefulBuf_IsNULLC(UsefulBufC UB);
+
+
+/**
+ @brief Check if a @ref UsefulBuf is empty or not.
+
+ @param[in] UB The @ref UsefulBuf to check.
+
+ @return 1 if it is empty, 0 if not.
+
+ An "empty" @ref UsefulBuf is one that has a value and can be
+ considered to be set, but that value is of zero length. It is empty
+ when @c len is zero. It doesn't matter what the @c ptr is.
+
+ A lot of uses will not need to clearly distinguish a @c NULL @ref
+ UsefulBuf from an empty one and can have the @c ptr @c NULL and the
+ @c len 0. However if a use of @ref UsefulBuf needs to make a
+ distinction then @c ptr should not be @c NULL when the @ref UsefulBuf
+ is considered empty, but not @c NULL.
+ */
+static inline int UsefulBuf_IsEmpty(UsefulBuf UB);
+
+
+/**
+ @brief Check if a @ref UsefulBufC is empty or not.
+
+ @param[in] UB The @ref UsefulBufC to check.
+
+ @return 1 if it is empty, 0 if not.
+ */
+static inline int UsefulBuf_IsEmptyC(UsefulBufC UB);
+
+
+/**
+ @brief Check if a @ref UsefulBuf is @ref NULLUsefulBuf or empty.
+
+ @param[in] UB The @ref UsefulBuf to check.
+
+ @return 1 if it is either @ref NULLUsefulBuf or empty, 0 if not.
+ */
+static inline int UsefulBuf_IsNULLOrEmpty(UsefulBuf UB);
+
+
+/**
+ @brief Check if a @ref UsefulBufC is @ref NULLUsefulBufC or empty.
+
+ @param[in] UB The @ref UsefulBufC to check.
+
+ @return 1 if it is either @ref NULLUsefulBufC or empty, 0 if not.
+ */
+static inline int UsefulBuf_IsNULLOrEmptyC(UsefulBufC UB);
+
+
+/**
+ @brief Convert a non-const @ref UsefulBuf to a const @ref UsefulBufC.
+
+ @param[in] UB The @ref UsefulBuf to convert.
+
+ @return A @ref UsefulBufC struct.
+ */
+static inline UsefulBufC UsefulBuf_Const(const UsefulBuf UB);
+
+
+/**
+ @brief Convert a const @ref UsefulBufC to a non-const @ref UsefulBuf.
+
+ @param[in] UBC The @ref UsefulBuf to convert.
+
+ @return A non-const @ref UsefulBuf struct.
+ */
+static inline UsefulBuf UsefulBuf_Unconst(const UsefulBufC UBC);
+
+
+/**
+ Convert a literal string to a @ref UsefulBufC.
+
+ @c szString must be a literal string that @c sizeof() works on. This
+ is better for literal strings than UsefulBuf_FromSZ() because it
+ generates less code. It will not work on non-literal strings.
+
+ The terminating \0 (NULL) is NOT included in the length!
+ */
+#define UsefulBuf_FROM_SZ_LITERAL(szString) \
+ ((UsefulBufC) {(szString), sizeof(szString)-1})
+
+
+/**
+ Convert a literal byte array to a @ref UsefulBufC.
+
+ @c pBytes must be a literal string that @c sizeof() works on. It
+ will not work on non-literal arrays.
+ */
+#define UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pBytes) \
+ ((UsefulBufC) {(pBytes), sizeof(pBytes)})
+
+
+/**
+ Make an automatic variable named @c name of type @ref UsefulBuf and
+ point it to a stack variable of the given @c size.
+ */
+#define UsefulBuf_MAKE_STACK_UB(name, size) \
+ uint8_t __pBuf##name[(size)];\
+ UsefulBuf name = {__pBuf##name , sizeof( __pBuf##name )}
+
+
+/**
+ Make a byte array in to a @ref UsefulBuf. This is usually used on
+ stack variables or static variables. Also see @ref
+ UsefulBuf_MAKE_STACK_UB.
+ */
+#define UsefulBuf_FROM_BYTE_ARRAY(pBytes) \
+ ((UsefulBuf) {(pBytes), sizeof(pBytes)})
+
+
+/**
+ @brief Convert a NULL-terminated string to a @ref UsefulBufC.
+
+ @param[in] szString The string to convert.
+
+ @return A @ref UsefulBufC struct.
+
+ @c UsefulBufC.ptr points to the string so its lifetime must be
+ maintained.
+
+ The terminating \0 (NULL) is NOT included in the length.
+ */
+static inline UsefulBufC UsefulBuf_FromSZ(const char *szString);
+
+
+/**
+ @brief Copy one @ref UsefulBuf into another at an offset.
+
+ @param[in] Dest Destination buffer to copy into.
+ @param[in] uOffset The byte offset in @c Dest at which to copy to.
+ @param[in] Src The bytes to copy.
+
+ @return Pointer and length of the copy or @ref NULLUsefulBufC.
+
+ This fails and returns @ref NULLUsefulBufC if @c offset is beyond the
+ size of @c Dest.
+
+ This fails and returns @ref NULLUsefulBufC if the @c Src length plus
+ @c uOffset is greater than the length of @c Dest.
+
+ The results are undefined if @c Dest and @c Src overlap.
+
+ This assumes that there is valid data in @c Dest up to @c
+ uOffset. The @ref UsefulBufC returned starts at the beginning of @c
+ Dest and goes to @c Src.len @c + @c uOffset.
+ */
+UsefulBufC UsefulBuf_CopyOffset(UsefulBuf Dest, size_t uOffset, const UsefulBufC Src);
+
+
+/**
+ @brief Copy one @ref UsefulBuf into another.
+
+ @param[in] Dest The destination buffer to copy into.
+ @param[out] Src The source to copy from.
+
+ @return Filled in @ref UsefulBufC on success, @ref NULLUsefulBufC
+ on failure.
+
+ This fails if @c Src.len is greater than @c Dest.len.
+
+ Note that like @c memcpy(), the pointers are not checked and this
+ will crash rather than return @ref NULLUsefulBufC if they are @c
+ NULL or invalid.
+
+ The results are undefined if @c Dest and @c Src overlap.
+ */
+static inline UsefulBufC UsefulBuf_Copy(UsefulBuf Dest, const UsefulBufC Src);
+
+
+/**
+ @brief Set all bytes in a @ref UsefulBuf to a value, for example to 0.
+
+ @param[in] pDest The destination buffer to copy into.
+ @param[in] value The value to set the bytes to.
+
+ Note that like @c memset(), the pointer in @c pDest is not checked
+ and this will crash if @c NULL or invalid.
+ */
+static inline UsefulBufC UsefulBuf_Set(UsefulBuf pDest, uint8_t value);
+
+
+/**
+ @brief Copy a pointer into a @ref UsefulBuf.
+
+ @param[in,out] Dest The destination buffer to copy into.
+ @param[in] ptr The source to copy from.
+ @param[in] uLen Length of the source; amount to copy.
+
+ @return 0 on success, 1 on failure.
+
+ This fails and returns @ref NULLUsefulBufC if @c uLen is greater than
+ @c pDest->len.
+
+ Note that like @c memcpy(), the pointers are not checked and this
+ will crash, rather than return 1 if they are @c NULL or invalid.
+ */
+static inline UsefulBufC UsefulBuf_CopyPtr(UsefulBuf Dest,
+ const void *ptr,
+ size_t uLen);
+
+
+/**
+ @brief Returns a truncation of a @ref UsefulBufC.
+
+ @param[in] UB The buffer to get the head of.
+ @param[in] uAmount The number of bytes in the head.
+
+ @return A @ref UsefulBufC that is the head of UB.
+ */
+static inline UsefulBufC UsefulBuf_Head(UsefulBufC UB, size_t uAmount);
+
+
+/**
+ @brief Returns bytes from the end of a @ref UsefulBufC.
+
+ @param[in] UB The buffer to get the tail of.
+ @param[in] uAmount The offset from the start where the tail is to begin.
+
+ @return A @ref UsefulBufC that is the tail of @c UB or @ref NULLUsefulBufC
+ if @c uAmount is greater than the length of the @ref UsefulBufC.
+
+ If @c UB.ptr is @c NULL, but @c UB.len is not zero, then the result will
+ be a @ref UsefulBufC with a @c NULL @c ptr and @c len with the length
+ of the tail.
+ */
+static inline UsefulBufC UsefulBuf_Tail(UsefulBufC UB, size_t uAmount);
+
+
+/**
+ @brief Compare one @ref UsefulBufC to another.
+
+ @param[in] UB1 The first buffer to compare.
+ @param[in] UB2 The second buffer to compare.
+
+ @return 0, positive or negative value.
+
+ Returns a negative value if @c UB1 if is less than @c UB2. @c UB1 is
+ less than @c UB2 if it is shorter or the first byte that is not the
+ same is less.
+
+ Returns 0 if the inputs are the same.
+
+ Returns a positive value if @c UB2 is less than @c UB1.
+
+ All that is of significance is that the result is positive, negative
+ or 0. (This doesn't return the difference between the first
+ non-matching byte like @c memcmp() ).
+ */
+int UsefulBuf_Compare(const UsefulBufC UB1, const UsefulBufC UB2);
+
+
+/**
+ @brief Find first byte that is not a particular byte value.
+
+ @param[in] UB The destination buffer for byte comparison.
+ @param[in] uValue The byte value to compare to.
+
+ @return Offset of first byte that isn't @c uValue or
+ @c SIZE_MAX if all bytes are @c uValue.
+
+ Note that unlike most comparison functions, 0
+ does not indicate a successful comparison, so the
+ test for match is:
+
+ UsefulBuf_IsValue(...) == SIZE_MAX
+
+ If @c UB is null or empty, there is no match
+ and 0 is returned.
+ */
+size_t UsefulBuf_IsValue(const UsefulBufC UB, uint8_t uValue);
+
+
+/**
+ @brief Find one @ref UsefulBufC in another.
+
+ @param[in] BytesToSearch Buffer to search through.
+ @param[in] BytesToFind Buffer with bytes to be found.
+
+ @return Position of found bytes or @c SIZE_MAX if not found.
+ */
+size_t UsefulBuf_FindBytes(UsefulBufC BytesToSearch, UsefulBufC BytesToFind);
+
+
+#if 1 // NOT_DEPRECATED
+/** Deprecated macro; use @ref UsefulBuf_FROM_SZ_LITERAL instead */
+#define SZLiteralToUsefulBufC(szString) \
+ ((UsefulBufC) {(szString), sizeof(szString)-1})
+
+/** Deprecated macro; use UsefulBuf_MAKE_STACK_UB instead */
+#define MakeUsefulBufOnStack(name, size) \
+ uint8_t __pBuf##name[(size)];\
+ UsefulBuf name = {__pBuf##name , sizeof( __pBuf##name )}
+
+/** Deprecated macro; use @ref UsefulBuf_FROM_BYTE_ARRAY_LITERAL instead */
+#define ByteArrayLiteralToUsefulBufC(pBytes) \
+ ((UsefulBufC) {(pBytes), sizeof(pBytes)})
+
+/** Deprecated function; use UsefulBuf_Unconst() instead */
+static inline UsefulBuf UsefulBufC_Unconst(const UsefulBufC UBC)
+{
+ return (UsefulBuf){(void *)UBC.ptr, UBC.len};
+}
+#endif
+
+
+
+
+/**
+ @brief Copy a @c float to a @c uint32_t.
+
+ @param[in] f Float value to copy.
+
+ @return A @c uint32_t with the float bits.
+
+ Convenience function to avoid type punning, compiler warnings and
+ such. The optimizer usually reduces this to a simple assignment. This
+ is a crusty corner of C.
+ */
+static inline uint32_t UsefulBufUtil_CopyFloatToUint32(float f);
+
+
+/**
+ @brief Copy a @c double to a @c uint64_t.
+
+ @param[in] d Double value to copy.
+
+ @return A @c uint64_t with the double bits.
+
+ Convenience function to avoid type punning, compiler warnings and
+ such. The optimizer usually reduces this to a simple assignment. This
+ is a crusty corner of C.
+ */
+static inline uint64_t UsefulBufUtil_CopyDoubleToUint64(double d);
+
+
+/**
+ @brief Copy a @c uint32_t to a @c float.
+
+ @param[in] u32 Integer value to copy.
+
+ @return The value as a @c float.
+
+ Convenience function to avoid type punning, compiler warnings and
+ such. The optimizer usually reduces this to a simple assignment. This
+ is a crusty corner of C.
+ */
+static inline float UsefulBufUtil_CopyUint32ToFloat(uint32_t u32);
+
+
+/**
+ @brief Copy a @c uint64_t to a @c double.
+
+ @param[in] u64 Integer value to copy.
+
+ @return The value as a @c double.
+
+ Convenience function to avoid type punning, compiler warnings and
+ such. The optimizer usually reduces this to a simple assignment. This
+ is a crusty corner of C.
+ */
+static inline double UsefulBufUtil_CopyUint64ToDouble(uint64_t u64);
+
+
+
+
+/**
+ UsefulOutBuf is a structure and functions (an object) for serializing
+ data into a buffer when encoding a network protocol or writing data
+ to file.
+
+ The main idea is that all the pointer manipulation is performed by
+ @ref UsefulOutBuf functions so the caller doesn't have to do any
+ pointer manipulation. The pointer manipulation is centralized. This
+ code will have been reviewed and written carefully so it spares the
+ caller of much of this work and results in safer code with less work.
+
+ The @ref UsefulOutBuf methods that add data to the output buffer
+ always check the length and will never write off the end of the
+ output buffer. If an attempt to add data that will not fit is made,
+ an internal error flag will be set and further attempts to add data
+ will not do anything.
+
+ There is no way to ever write off the end of that buffer when calling
+ the @c UsefulOutBuf_AddXxx() and @c UsefulOutBuf_InsertXxx()
+ functions.
+
+ The functions to add data do not return an error. The working model
+ is that all calls to add data are made without an error check. Errors
+ are just checked for once after all the data has been added before the
+ and before serialized data is to be used. This makes the calling code
+ cleaner.
+
+ There is a utility function to get the error status anytime along the
+ way for a special circumstance. There are functions to see how much
+ room is left and see if some data will fit too, but their use is
+ generally not necessary.
+
+ The general call flow is:
+
+ - Initialize by calling @ref UsefulOutBuf_Init(). The output
+ buffer given to it can be from the heap, stack or
+ otherwise. @ref UsefulOutBuf_MakeOnStack is a convenience macro
+ that makes a buffer on the stack and initializes it.
+
+ - Call methods like UsefulOutBuf_InsertString(),
+ UsefulOutBuf_AppendUint32() and UsefulOutBuf_InsertUsefulBuf()
+ to output data. The append calls add data to the end of the
+ valid data. The insert calls take a position argument.
+
+ - Call UsefulOutBuf_OutUBuf() or UsefulOutBuf_CopyOut() to see
+ there were no errors and to get the serialized output bytes.
+
+ @ref UsefulOutBuf can be used in a size calculation mode to calculate
+ the size of output that would be generated. This is useful to
+ calculate the size of a buffer that is to be allocated to hold the
+ output. To use @ref UsefulOutBuf in this mode, call
+ UsefulOutBuf_Init() with the @c Storage @ref UsefulBuf as
+ @c (UsefulBuf){NULL,MAX_UINT32}. Then call all the Insert and Add
+ functions. No attempt will made to actually copy data, so only the
+ lengths have to be valid for these calls.
+
+ Methods like UsefulOutBuf_InsertUint64() always output in network
+ bytes order (big endian).
+
+ The possible errors are:
+ - The @ref UsefulOutBuf was not initialized or was corrupted.
+
+ - An attempt was made to add data that will not fit.
+
+ - An attempt was made to insert data at a position beyond the end of
+ the buffer.
+
+ - An attempt was made to insert data at a position beyond the valid
+ data in the buffer.
+
+ Some inexpensive simple sanity checks are performed before every data
+ addition to guard against use of an uninitialized or corrupted
+ UsefulOutBuf.
+
+ This has been used to create a CBOR encoder. The CBOR encoder has
+ almost no pointer manipulation in it, is easier to read, and easier
+ to review.
+
+ A @ref UsefulOutBuf is small and can go on the stack:
+ - 32 bytes (27 bytes plus alignment padding) on a 64-bit machine
+ - 16 bytes (15 bytes plus alignment padding) on a 32-bit machines
+ */
+typedef struct useful_out_buf {
+ // PRIVATE DATA STRUCTURE
+ UsefulBuf UB; // Memory that is being output to
+ size_t data_len; // length of the data
+ uint16_t magic; // Used to detect corruption and lack of initialization
+ uint8_t err;
+} UsefulOutBuf;
+
+
+/**
+ @brief Initialize and supply the actual output buffer.
+
+ @param[out] pUOutBuf The @ref UsefulOutBuf to initialize.
+ @param[in] Storage Buffer to output into.
+
+ Initializes the @ref UsefulOutBuf with storage. Sets the current
+ position to the beginning of the buffer clears the error.
+
+ This must be called before the @ref UsefulOutBuf is used.
+ */
+void UsefulOutBuf_Init(UsefulOutBuf *pUOutBuf, UsefulBuf Storage);
+
+
+/**
+ Convenience macro to make a @ref UsefulOutBuf on the stack and
+ initialize it with a stack buffer of the given size. The variable
+ will be named @c name.
+ */
+#define UsefulOutBuf_MakeOnStack(name, size) \
+ uint8_t __pBuf##name[(size)];\
+ UsefulOutBuf name;\
+ UsefulOutBuf_Init(&(name), (UsefulBuf){__pBuf##name, (size)});
+
+
+/**
+ @brief Reset a @ref UsefulOutBuf for re use
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf
+
+ This sets the amount of data in the output buffer to none and clears
+ the error state.
+
+ The output buffer is still the same one and size as from the
+ UsefulOutBuf_Init() call.
+
+ This doesn't zero the data, just resets to 0 bytes of valid data.
+ */
+static inline void UsefulOutBuf_Reset(UsefulOutBuf *pUOutBuf);
+
+
+/**
+ @brief Returns position of end of data in the @ref UsefulOutBuf.
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+
+ @return position of end of data.
+
+ On a freshly initialized @ref UsefulOutBuf with no data added, this
+ will return 0. After 10 bytes have been added, it will return 10 and
+ so on.
+
+ Generally callers will not need this function for most uses of @ref
+ UsefulOutBuf.
+ */
+static inline size_t UsefulOutBuf_GetEndPosition(UsefulOutBuf *pUOutBuf);
+
+
+/**
+ @brief Returns whether any data has been added to the @ref UsefulOutBuf.
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+
+ @return 1 if output position is at start.
+ */
+static inline int UsefulOutBuf_AtStart(UsefulOutBuf *pUOutBuf);
+
+
+/**
+ @brief Inserts bytes into the @ref UsefulOutBuf.
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+ @param[in] NewData The bytes to insert.
+ @param[in] uPos Index in output buffer at which to insert.
+
+ @c NewData is the pointer and length for the bytes to be added to the
+ output buffer. There must be room in the output buffer for all of @c
+ NewData or an error will occur.
+
+ The insertion point must be between 0 and the current valid data. If
+ not, an error will occur. Appending data to the output buffer is
+ achieved by inserting at the end of the valid data. This can be
+ retrieved by calling UsefulOutBuf_GetEndPosition().
+
+ When insertion is performed, the bytes between the insertion point
+ and the end of data previously added to the output buffer are slid to
+ the right to make room for the new data.
+
+ Overlapping buffers are OK. @c NewData can point to data in the
+ output buffer.
+
+ If an error occurs an error state is set in the @ref UsefulOutBuf. No
+ error is returned. All subsequent attempts to add data will do
+ nothing.
+
+ The intended use is that all additions are made without checking for
+ an error. The error will be taken into account when
+ UsefulOutBuf_OutUBuf() returns @c NullUsefulBufC.
+ UsefulOutBuf_GetError() can also be called to check for an error.
+ */
+void UsefulOutBuf_InsertUsefulBuf(UsefulOutBuf *pUOutBuf,
+ UsefulBufC NewData,
+ size_t uPos);
+
+
+/**
+ @brief Insert a data buffer into the @ref UsefulOutBuf.
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+ @param[in] pBytes Pointer to the bytes to insert
+ @param[in] uLen Length of the bytes to insert
+ @param[in] uPos Index in output buffer at which to insert
+
+ See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
+ the difference being a pointer and length is passed in rather than an
+ @ref UsefulBufC.
+ */
+static inline void UsefulOutBuf_InsertData(UsefulOutBuf *pUOutBuf,
+ const void *pBytes,
+ size_t uLen,
+ size_t uPos);
+
+
+/**
+ @brief Insert a NULL-terminated string into the UsefulOutBuf.
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+ @param[in] szString NULL-terminated string to insert.
+ @param[in] uPos Index in output buffer at which to insert.
+ */
+static inline void UsefulOutBuf_InsertString(UsefulOutBuf *pUOutBuf,
+ const char *szString,
+ size_t uPos);
+
+
+/**
+ @brief Insert a byte into the @ref UsefulOutBuf.
+
+ @param[in] pUOutBuf Pointer to the UsefulOutBuf.
+ @param[in] byte Bytes to insert.
+ @param[in] uPos Index in output buffer at which to insert.
+
+ See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
+ the difference being a single byte is to be inserted.
+ */
+static inline void UsefulOutBuf_InsertByte(UsefulOutBuf *pUOutBuf,
+ uint8_t byte,
+ size_t uPos);
+
+
+/**
+ @brief Insert a 16-bit integer into the @ref UsefulOutBuf.
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+ @param[in] uInteger16 Integer to insert.
+ @param[in] uPos Index in output buffer at which to insert.
+
+ See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
+ the difference being a two-byte integer is to be inserted.
+
+ The integer will be inserted in network byte order (big endian).
+ */
+static inline void UsefulOutBuf_InsertUint16(UsefulOutBuf *pUOutBuf,
+ uint16_t uInteger16,
+ size_t uPos);
+
+
+/**
+ @brief Insert a 32-bit integer into the @ref UsefulOutBuf.
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+ @param[in] uInteger32 Integer to insert.
+ @param[in] uPos Index in output buffer at which to insert.
+
+ See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
+ the difference being a four-byte integer is to be inserted.
+
+ The integer will be inserted in network byte order (big endian).
+ */
+static inline void UsefulOutBuf_InsertUint32(UsefulOutBuf *pUOutBuf,
+ uint32_t uInteger32,
+ size_t uPos);
+
+
+/**
+ @brief Insert a 64-bit integer into the @ref UsefulOutBuf.
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+ @param[in] uInteger64 Integer to insert.
+ @param[in] uPos Index in output buffer at which to insert.
+
+ See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
+ the difference being an eight-byte integer is to be inserted.
+
+ The integer will be inserted in network byte order (big endian).
+ */
+static inline void UsefulOutBuf_InsertUint64(UsefulOutBuf *pUOutBuf,
+ uint64_t uInteger64,
+ size_t uPos);
+
+
+/**
+ @brief Insert a @c float into the @ref UsefulOutBuf.
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+ @param[in] f @c float to insert.
+ @param[in] uPos Index in output buffer at which to insert.
+
+ See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
+ the difference being a @c float is to be inserted.
+
+ The @c float will be inserted in network byte order (big endian).
+ */
+static inline void UsefulOutBuf_InsertFloat(UsefulOutBuf *pUOutBuf,
+ float f,
+ size_t uPos);
+
+
+/**
+ @brief Insert a @c double into the @ref UsefulOutBuf.
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+ @param[in] d @c double to insert.
+ @param[in] uPos Index in output buffer at which to insert.
+
+ See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
+ the difference being a @c double is to be inserted.
+
+ The @c double will be inserted in network byte order (big endian).
+ */
+static inline void UsefulOutBuf_InsertDouble(UsefulOutBuf *pUOutBuf,
+ double d,
+ size_t uPos);
+
+
+/**
+ @brief Append a @ref UsefulBuf into the @ref UsefulOutBuf.
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+ @param[in] NewData The @ref UsefulBuf with the bytes to append.
+
+ See UsefulOutBuf_InsertUsefulBuf() for details. This does the same
+ with the insertion point at the end of the valid data.
+*/
+static inline void UsefulOutBuf_AppendUsefulBuf(UsefulOutBuf *pUOutBuf,
+ UsefulBufC NewData);
+
+
+/**
+ @brief Append bytes to the @ref UsefulOutBuf.
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+ @param[in] pBytes Pointer to bytes to append.
+ @param[in] uLen Length of @c pBytes to append.
+
+ See UsefulOutBuf_InsertData() for details. This does the same
+ with the insertion point at the end of the valid data.
+ */
+static inline void UsefulOutBuf_AppendData(UsefulOutBuf *pUOutBuf,
+ const void *pBytes,
+ size_t uLen);
+
+
+/**
+ @brief Append a NULL-terminated string to the @ref UsefulOutBuf
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+ @param[in] szString NULL-terminated string to append.
+ */
+static inline void UsefulOutBuf_AppendString(UsefulOutBuf *pUOutBuf,
+ const char *szString);
+
+
+/**
+ @brief Append a byte to the @ref UsefulOutBuf
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+ @param[in] byte Bytes to append.
+
+ See UsefulOutBuf_InsertByte() for details. This does the same
+ with the insertion point at the end of the valid data.
+ */
+static inline void UsefulOutBuf_AppendByte(UsefulOutBuf *pUOutBuf,
+ uint8_t byte);
+
+
+/**
+ @brief Append an integer to the @ref UsefulOutBuf
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+ @param[in] uInteger16 Integer to append.
+
+ See UsefulOutBuf_InsertUint16() for details. This does the same
+ with the insertion point at the end of the valid data.
+
+ The integer will be appended in network byte order (big endian).
+ */
+static inline void UsefulOutBuf_AppendUint16(UsefulOutBuf *pUOutBuf,
+ uint16_t uInteger16);
+
+
+/**
+ @brief Append an integer to the @ref UsefulOutBuf
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+ @param[in] uInteger32 Integer to append.
+
+ See UsefulOutBuf_InsertUint32() for details. This does the same
+ with the insertion point at the end of the valid data.
+
+ The integer will be appended in network byte order (big endian).
+ */
+static inline void UsefulOutBuf_AppendUint32(UsefulOutBuf *pUOutBuf,
+ uint32_t uInteger32);
+
+
+/**
+ @brief Append an integer to the @ref UsefulOutBuf
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+ @param[in] uInteger64 Integer to append.
+
+ See UsefulOutBuf_InsertUint64() for details. This does the same
+ with the insertion point at the end of the valid data.
+
+ The integer will be appended in network byte order (big endian).
+ */
+static inline void UsefulOutBuf_AppendUint64(UsefulOutBuf *pUOutBuf,
+ uint64_t uInteger64);
+
+
+/**
+ @brief Append a @c float to the @ref UsefulOutBuf
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+ @param[in] f @c float to append.
+
+ See UsefulOutBuf_InsertFloat() for details. This does the same
+ with the insertion point at the end of the valid data.
+
+ The float will be appended in network byte order (big endian).
+ */
+static inline void UsefulOutBuf_AppendFloat(UsefulOutBuf *pUOutBuf,
+ float f);
+
+
+/**
+ @brief Append a @c double to the @ref UsefulOutBuf
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+ @param[in] d @c double to append.
+
+ See UsefulOutBuf_InsertDouble() for details. This does the same
+ with the insertion point at the end of the valid data.
+
+ The double will be appended in network byte order (big endian).
+ */
+static inline void UsefulOutBuf_AppendDouble(UsefulOutBuf *pUOutBuf,
+ double d);
+
+
+/**
+ @brief Returns the current error status.
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+
+ @return 0 if all OK, 1 on error.
+
+ This is the error status since the call to either
+ UsefulOutBuf_Reset() of UsefulOutBuf_Init(). Once it goes into error
+ state it will stay until one of those functions is called.
+
+ Possible error conditions are:
+ - bytes to be inserted will not fit
+ - insertion point is out of buffer or past valid data
+ - current position is off end of buffer (probably corrupted or uninitialized)
+ - detect corruption / uninitialized by bad magic number
+ */
+static inline int UsefulOutBuf_GetError(UsefulOutBuf *pUOutBuf);
+
+
+/**
+ @brief Returns number of bytes unused used in the output buffer.
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+
+ @return Number of unused bytes or zero.
+
+ Because of the error handling strategy and checks in
+ UsefulOutBuf_InsertUsefulBuf() it is usually not necessary to use
+ this.
+ */
+static inline size_t UsefulOutBuf_RoomLeft(UsefulOutBuf *pUOutBuf);
+
+
+/**
+ @brief Returns 1 if some number of bytes will fit in the @ref UsefulOutBuf.
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf
+ @param[in] uLen Number of bytes for which to check
+
+ @return 1 if @c uLen bytes will fit, 0 if not.
+
+ Because of the error handling strategy and checks in
+ UsefulOutBuf_InsertUsefulBuf() it is usually not necessary to use
+ this.
+ */
+static inline int UsefulOutBuf_WillItFit(UsefulOutBuf *pUOutBuf, size_t uLen);
+
+
+ /**
+ @brief Returns 1 if buffer given to UsefulOutBuf_Init() was @c NULL.
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf
+
+ @return 1 if buffer given to UsefulOutBuf_Init() was @c NULL.
+
+ Giving a @c NULL output buffer to UsefulOutBuf_Init() is used
+ when just calculating the length of the encoded data.
+ */
+static inline int UsefulOutBuf_IsBufferNULL(UsefulOutBuf *pUOutBuf);
+
+
+/**
+ @brief Returns the resulting valid data in a UsefulOutBuf
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+
+ @return The valid data in @ref UsefulOutBuf or
+ @ref NULLUsefulBufC if there was an error adding data.
+
+ The storage for the returned data is the @c Storage parameter passed
+ to UsefulOutBuf_Init(). See also UsefulOutBuf_CopyOut().
+
+ This can be called anytime and many times to get intermediate
+ results. It doesn't change the data or reset the current position
+ so you can keep adding data.
+ */
+UsefulBufC UsefulOutBuf_OutUBuf(UsefulOutBuf *pUOutBuf);
+
+
+/**
+ @brief Copies the valid data into a supplied buffer
+
+ @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+ @param[out] Dest The destination buffer to copy into.
+
+ @return Pointer and length of copied data or @c NULLUsefulBufC
+ if it will not fit in the @c Dest buffer.
+
+ This is the same as UsefulOutBuf_OutUBuf() except it copies the data
+ to @c Dest.
+*/
+UsefulBufC UsefulOutBuf_CopyOut(UsefulOutBuf *pUOutBuf, UsefulBuf Dest);
+
+
+
+
+/**
+ @ref UsefulInputBuf is the counterpart to @ref UsefulOutBuf and is
+ for parsing data read or received. Initialize it with the data from
+ the network. Then use the functions here to get data chunks of
+ various types. A position cursor is maintained internally.
+
+ As long as the functions here are used, there will never be a
+ reference off the end of the given buffer. This is true even if they
+ care called incorrectly, an attempt is made to seek of the end of the
+ buffer, etc. This makes it easier to write safe and correct code.
+ For example, the QCBOR decoder implementation is safer and easier to
+ review through its use of @ref UsefulInputBuf.
+
+ @ref UsefulInputBuf maintains an internal error state. The
+ intended use is that data chunks can be fetched without error
+ checking until the end. Once data has been requested off the end of
+ the buffer, the error state is entered. In the error state the
+ @c UsefulInputBuf_GetXxxx() functions return 0, or @c NULL or
+ @ref NULLUsefulBufC. As long as null are not dereferenced, the
+ error check can be put off until the end, simplifying the calling
+ code.
+
+ The integer and float parsing expects network byte order (big
+ endian). Network byte order is what is used by TCP/IP, CBOR and most
+ internet protocols.
+
+ Lots of inline functions are used to keep code size down. The code
+ optimizer, particularly with the @c -Os or @c -O3, also reduces code
+ size a lot. The only non-inline code is UsefulInputBuf_GetBytes()
+ which is less than 100 bytes so use of @ref UsefulInputBuf doesn't
+ add much code for all the messy hard-to-get right issues with parsing
+ in C that is solves.
+
+ The parse context size is:
+ - 64-bit machine: 16 + 8 + 2 + 1 (5 bytes padding to align) = 32 bytes
+ - 32-bit machine: 8 + 4 + 2 + 1 (1 byte padding to align) = 16 bytes
+ */
+typedef struct useful_input_buf {
+ // PRIVATE DATA STRUCTURE
+ UsefulBufC UB; // Data being parsed
+ size_t cursor; // Current offset in data being parse
+ uint16_t magic; // Check for corrupted or uninitialized UsefulInputBuf
+ uint8_t err; // Set request goes off end or magic number is bad
+} UsefulInputBuf;
+
+#define UIB_MAGIC (0xB00F)
+
+
+/**
+ @brief Initialize the UsefulInputBuf structure before use.
+
+ @param[in] pUInBuf Pointer to the UsefulInputBuf instance.
+ @param[in] UB The data to parse.
+ */
+static inline void UsefulInputBuf_Init(UsefulInputBuf *pUInBuf, UsefulBufC UB);
+
+
+/**
+ @brief Returns current position in input buffer.
+
+ @param[in] pUInBuf Pointer to the UsefulInputBuf.
+
+ @return Integer position of the cursor.
+
+ The position that the next bytes will be returned from.
+ */
+static size_t UsefulInputBuf_Tell(UsefulInputBuf *pUInBuf);
+
+
+/**
+ @brief Sets the current position in input buffer.
+
+ @param[in] pUInBuf Pointer to the UsefulInputBuf.
+ @param[in] uPos Position to set to.
+
+ If the position is off the end of the input buffer, the error state
+ is entered, and all functions will do nothing.
+
+ Seeking to a valid position in the buffer will not reset the error
+ state. Only re initialization will do that.
+ */
+static void UsefulInputBuf_Seek(UsefulInputBuf *pUInBuf, size_t uPos);
+
+
+/**
+ @brief Returns the number of bytes from the cursor to the end of the buffer,
+ the unconsumed bytes.
+
+ @param[in] pUInBuf Pointer to the UsefulInputBuf.
+
+ @return Number of bytes unconsumed or 0 on error.
+
+ This is a critical function for input length validation.
+
+ Returns 0 if the cursor it invalid or corruption of the structure is
+ detected.
+ */
+static size_t UsefulInputBuf_BytesUnconsumed(UsefulInputBuf *pUInBuf);
+
+
+/**
+ @brief Check if there are any unconsumed bytes.
+
+ @param[in] pUInBuf Pointer to the UsefulInputBuf.
+ @param[in] uLen Number of bytes to check availability for.
+
+ @return 1 if @c uLen bytes are available after the cursor, and 0 if not.
+ */
+static int UsefulInputBuf_BytesAvailable(UsefulInputBuf *pUInBuf, size_t uLen);
+
+
+/**
+ @brief Get pointer to bytes out of the input buffer.
+
+ @param[in] pUInBuf Pointer to the UsefulInputBuf.
+ @param[in] uNum Number of bytes to get.
+
+ @return Pointer to bytes.
+
+ This consumes @c uNum bytes from the input buffer. It returns a
+ pointer to the start of the @c uNum bytes.
+
+ If there are not @c uNum bytes in the input buffer, @c NULL will be
+ returned and an error will be set.
+
+ It advances the current position by @c uNum bytes.
+ */
+const void * UsefulInputBuf_GetBytes(UsefulInputBuf *pUInBuf, size_t uNum);
+
+
+/**
+ @brief Get @ref UsefulBuf out of the input buffer.
+
+ @param[in] pUInBuf Pointer to the UsefulInputBuf.
+ @param[in] uNum Number of bytes to get.
+
+ @return A @ref UsefulBufC with ptr and length of bytes consumed.
+
+ This consumes @c uNum bytes from the input buffer and returns the
+ pointer and length for them as a @ref UsefulBufC. The length returned
+ will always be @c uNum.
+
+ If there are not @c uNum bytes in the input buffer, @ref NULLUsefulBufC
+ will be returned and the error state is set.
+
+ It advances the current position by @c uNum bytes.
+ */
+static inline UsefulBufC UsefulInputBuf_GetUsefulBuf(UsefulInputBuf *pUInBuf, size_t uNum);
+
+
+/**
+ @brief Get a byte out of the input buffer.
+
+ @param[in] pUInBuf Pointer to the @ref UsefulInputBuf.
+
+ @return The byte.
+
+ This consumes 1 byte from the input buffer. It returns the byte.
+
+ If there is not 1 byte in the buffer, 0 will be returned for the byte
+ and an error set internally. You must check the error at some point
+ to know whether the 0 was the real value or just returned in error,
+ but you may not have to do that right away. Check the error state
+ with UsefulInputBuf_GetError(). You can also know you are in the
+ error state if UsefulInputBuf_GetBytes() returns @c NULL or the @c
+ ptr from UsefulInputBuf_GetUsefulBuf() is @c NULL.
+
+ It advances the current position by 1 byte.
+ */
+static inline uint8_t UsefulInputBuf_GetByte(UsefulInputBuf *pUInBuf);
+
+
+/**
+ @brief Get a @c uint16_t out of the input buffer.
+
+ @param[in] pUInBuf Pointer to the UsefulInputBuf.
+
+ @return The @c uint16_t.
+
+ See UsefulInputBuf_GetByte(). This works the same, except it returns
+ a @c uint16_t and two bytes are consumed.
+
+ The input bytes must be in network order (big endian).
+ */
+static inline uint16_t UsefulInputBuf_GetUint16(UsefulInputBuf *pUInBuf);
+
+
+/**
+ @brief Get a uint32_t out of the input buffer.
+
+ @param[in] pUInBuf Pointer to the UsefulInputBuf.
+
+ @return The @c uint32_t.
+
+ See UsefulInputBuf_GetByte(). This works the same, except it returns
+ a @c uint32_t and four bytes are consumed.
+
+ The input bytes must be in network order (big endian).
+ */
+static uint32_t UsefulInputBuf_GetUint32(UsefulInputBuf *pUInBuf);
+
+
+/**
+ @brief Get a uint64_t out of the input buffer.
+
+ @param[in] pUInBuf Pointer to the UsefulInputBuf.
+
+ @return The uint64_t.
+
+ See UsefulInputBuf_GetByte(). This works the same, except it returns
+ a @c uint64_t and eight bytes are consumed.
+
+ The input bytes must be in network order (big endian).
+ */
+static uint64_t UsefulInputBuf_GetUint64(UsefulInputBuf *pUInBuf);
+
+
+/**
+ @brief Get a float out of the input buffer.
+
+ @param[in] pUInBuf Pointer to the UsefulInputBuf.
+
+ @return The float.
+
+ See UsefulInputBuf_GetByte(). This works the same, except it returns
+ a float and four bytes are consumed.
+
+ The input bytes must be in network order (big endian).
+ */
+static float UsefulInputBuf_GetFloat(UsefulInputBuf *pUInBuf);
+
+
+/**
+ @brief Get a double out of the input buffer.
+
+ @param[in] pUInBuf Pointer to the UsefulInputBuf.
+
+ @return The double.
+
+ See UsefulInputBuf_GetByte(). This works the same, except it returns
+ a double and eight bytes are consumed.
+
+ The input bytes must be in network order (big endian).
+ */
+static double UsefulInputBuf_GetDouble(UsefulInputBuf *pUInBuf);
+
+
+/**
+ @brief Get the error status.
+
+ @param[in] pUInBuf Pointer to the @ref UsefulInputBuf.
+
+ @return 0 if there is no error, 1 if there is.
+
+ The error state is entered for one of these reasons:
+ - Attempt to fetch data past the end of the buffer
+ - Attempt to seek to a position past the end of the buffer
+ - Attempt to get data from an uninitialized or corrupt instance
+ of @ref UsefulInputBuf
+
+ Once in the error state, it can only be cleared by calling
+ UsefulInputBuf_Init().
+
+ You may be able to only check the error state at the end after all
+ the UsefulInputBuf_GetXxxx() calls have been made, but if what you
+ get later depends on what you get sooner you cannot. For example,
+ if you get a length or count of following items you will have to
+ check the error.
+ */
+static int UsefulInputBuf_GetError(UsefulInputBuf *pUInBuf);
+
+
+
+
+/*----------------------------------------------------------
+ Inline implementations.
+ */
+static inline int UsefulBuf_IsNULL(UsefulBuf UB)
+{
+ return !UB.ptr;
+}
+
+
+static inline int UsefulBuf_IsNULLC(UsefulBufC UB)
+{
+ return !UB.ptr;
+}
+
+
+static inline int UsefulBuf_IsEmpty(UsefulBuf UB)
+{
+ return !UB.len;
+}
+
+
+static inline int UsefulBuf_IsEmptyC(UsefulBufC UB)
+{
+ return !UB.len;
+}
+
+
+static inline int UsefulBuf_IsNULLOrEmpty(UsefulBuf UB)
+{
+ return UsefulBuf_IsEmpty(UB) || UsefulBuf_IsNULL(UB);
+}
+
+
+static inline int UsefulBuf_IsNULLOrEmptyC(UsefulBufC UB)
+{
+ return UsefulBuf_IsEmptyC(UB) || UsefulBuf_IsNULLC(UB);
+}
+
+
+static inline UsefulBufC UsefulBuf_Const(const UsefulBuf UB)
+{
+ return (UsefulBufC){UB.ptr, UB.len};
+}
+
+
+static inline UsefulBuf UsefulBuf_Unconst(const UsefulBufC UBC)
+{
+ return (UsefulBuf){(void *)UBC.ptr, UBC.len};
+}
+
+
+static inline UsefulBufC UsefulBuf_FromSZ(const char *szString)
+{
+ return ((UsefulBufC) {szString, strlen(szString)});
+}
+
+
+static inline UsefulBufC UsefulBuf_Copy(UsefulBuf Dest, const UsefulBufC Src)
+{
+ return UsefulBuf_CopyOffset(Dest, 0, Src);
+}
+
+
+static inline UsefulBufC UsefulBuf_Set(UsefulBuf pDest, uint8_t value)
+{
+ memset(pDest.ptr, value, pDest.len);
+ return (UsefulBufC){pDest.ptr, pDest.len};
+}
+
+
+static inline UsefulBufC UsefulBuf_CopyPtr(UsefulBuf Dest, const void *ptr, size_t len)
+{
+ return UsefulBuf_Copy(Dest, (UsefulBufC){ptr, len});
+}
+
+
+static inline UsefulBufC UsefulBuf_Head(UsefulBufC UB, size_t uAmount)
+{
+ if(uAmount > UB.len) {
+ return NULLUsefulBufC;
+ }
+ return (UsefulBufC){UB.ptr, uAmount};
+}
+
+
+static inline UsefulBufC UsefulBuf_Tail(UsefulBufC UB, size_t uAmount)
+{
+ UsefulBufC ReturnValue;
+
+ if(uAmount > UB.len) {
+ ReturnValue = NULLUsefulBufC;
+ } else if(UB.ptr == NULL) {
+ ReturnValue = (UsefulBufC){NULL, UB.len - uAmount};
+ } else {
+ ReturnValue = (UsefulBufC){(uint8_t *)UB.ptr + uAmount, UB.len - uAmount};
+ }
+
+ return ReturnValue;
+}
+
+
+
+static inline uint32_t UsefulBufUtil_CopyFloatToUint32(float f)
+{
+ uint32_t u32;
+ memcpy(&u32, &f, sizeof(uint32_t));
+ return u32;
+}
+
+static inline uint64_t UsefulBufUtil_CopyDoubleToUint64(double d)
+{
+ uint64_t u64;
+ memcpy(&u64, &d, sizeof(uint64_t));
+ return u64;
+}
+
+static inline double UsefulBufUtil_CopyUint64ToDouble(uint64_t u64)
+{
+ double d;
+ memcpy(&d, &u64, sizeof(uint64_t));
+ return d;
+}
+
+static inline float UsefulBufUtil_CopyUint32ToFloat(uint32_t u32)
+{
+ float f;
+ memcpy(&f, &u32, sizeof(uint32_t));
+ return f;
+}
+
+
+
+
+static inline void UsefulOutBuf_Reset(UsefulOutBuf *pMe)
+{
+ pMe->data_len = 0;
+ pMe->err = 0;
+}
+
+
+static inline size_t UsefulOutBuf_GetEndPosition(UsefulOutBuf *pMe)
+{
+ return pMe->data_len;
+}
+
+
+static inline int UsefulOutBuf_AtStart(UsefulOutBuf *pMe)
+{
+ return 0 == pMe->data_len;
+}
+
+
+static inline void UsefulOutBuf_InsertData(UsefulOutBuf *pMe,
+ const void *pBytes,
+ size_t uLen,
+ size_t uPos)
+{
+ UsefulBufC Data = {pBytes, uLen};
+ UsefulOutBuf_InsertUsefulBuf(pMe, Data, uPos);
+}
+
+
+static inline void UsefulOutBuf_InsertString(UsefulOutBuf *pMe,
+ const char *szString,
+ size_t uPos)
+{
+ UsefulOutBuf_InsertUsefulBuf(pMe,
+ (UsefulBufC){szString, strlen(szString)},
+ uPos);
+}
+
+
+static inline void UsefulOutBuf_InsertByte(UsefulOutBuf *me,
+ uint8_t byte,
+ size_t uPos)
+{
+ UsefulOutBuf_InsertData(me, &byte, 1, uPos);
+}
+
+
+static inline void UsefulOutBuf_InsertUint16(UsefulOutBuf *me,
+ uint16_t uInteger16,
+ size_t uPos)
+{
+ // See UsefulOutBuf_InsertUint64() for comments on this code
+
+ const void *pBytes;
+
+#if defined(USEFULBUF_CONFIG_BIG_ENDIAN)
+ pBytes = &uInteger16;
+
+#elif defined(USEFULBUF_CONFIG_HTON)
+ uint16_t uTmp = htons(uInteger16);
+ pBytes = &uTmp;
+
+#elif defined(USEFULBUF_CONFIG_LITTLE_ENDIAN) && defined(USEFULBUF_CONFIG_BSWAP)
+ uint16_t uTmp = __builtin_bswap16(uInteger16);
+ pBytes = &uTmp;
+
+#else
+ uint8_t aTmp[2];
+
+ aTmp[0] = (uint8_t)((uInteger16 & 0xff00) >> 8);
+ aTmp[1] = (uint8_t)(uInteger16 & 0xff);
+
+ pBytes = aTmp;
+#endif
+
+ UsefulOutBuf_InsertData(me, pBytes, 2, uPos);
+}
+
+
+static inline void UsefulOutBuf_InsertUint32(UsefulOutBuf *pMe,
+ uint32_t uInteger32,
+ size_t uPos)
+{
+ // See UsefulOutBuf_InsertUint64() for comments on this code
+
+ const void *pBytes;
+
+#if defined(USEFULBUF_CONFIG_BIG_ENDIAN)
+ pBytes = &uInteger32;
+
+#elif defined(USEFULBUF_CONFIG_HTON)
+ uint32_t uTmp = htonl(uInteger32);
+ pBytes = &uTmp;
+
+#elif defined(USEFULBUF_CONFIG_LITTLE_ENDIAN) && defined(USEFULBUF_CONFIG_BSWAP)
+ uint32_t uTmp = __builtin_bswap32(uInteger32);
+
+ pBytes = &uTmp;
+
+#else
+ uint8_t aTmp[4];
+
+ aTmp[0] = (uint8_t)((uInteger32 & 0xff000000) >> 24);
+ aTmp[1] = (uint8_t)((uInteger32 & 0xff0000) >> 16);
+ aTmp[2] = (uint8_t)((uInteger32 & 0xff00) >> 8);
+ aTmp[3] = (uint8_t)(uInteger32 & 0xff);
+
+ pBytes = aTmp;
+#endif
+
+ UsefulOutBuf_InsertData(pMe, pBytes, 4, uPos);
+}
+
+static inline void UsefulOutBuf_InsertUint64(UsefulOutBuf *pMe,
+ uint64_t uInteger64,
+ size_t uPos)
+{
+ const void *pBytes;
+
+#if defined(USEFULBUF_CONFIG_BIG_ENDIAN)
+ // We have been told explicitly we are running on a big-endian
+ // machine. Network byte order is big endian, so just copy. There
+ // is no issue with alignment here because uInter64 is always
+ // aligned (and it doesn't matter if pBytes is aligned).
+ pBytes = &uInteger64;
+
+#elif defined(USEFULBUF_CONFIG_HTON)
+ // Use system function to handle big- and little-endian. This works
+ // on both big- and little-endian machines, but hton() is not
+ // always available or in a standard place so it is not used by
+ // default. With some compilers and CPUs the code for this is very
+ // compact through use of a special swap instruction and on
+ // big-endian machines hton() will reduce to nothing.
+ uint64_t uTmp = htonll(uInteger64);
+
+ pBytes = &uTmp;
+
+#elif defined(USEFULBUF_CONFIG_LITTLE_ENDIAN) && defined(USEFULBUF_CONFIG_BSWAP)
+ // Use built-in function for byte swapping. This usually compiles
+ // to an efficient special byte swap instruction. Unlike hton() it
+ // does not do this conditionally on the CPU endianness, so this
+ // code is also conditional on USEFULBUF_CONFIG_LITTLE_ENDIAN
+ uint64_t uTmp = __builtin_bswap64(uInteger64);
+
+ pBytes = &uTmp;
+
+#else
+ // Default which works on every CPU with no dependency on anything
+ // from the CPU, compiler, libraries or OS. This always works, but
+ // it is usually a little larger and slower than hton().
+ uint8_t aTmp[8];
+
+ aTmp[0] = (uint8_t)((uInteger64 & 0xff00000000000000) >> 56);
+ aTmp[1] = (uint8_t)((uInteger64 & 0xff000000000000) >> 48);
+ aTmp[2] = (uint8_t)((uInteger64 & 0xff0000000000) >> 40);
+ aTmp[3] = (uint8_t)((uInteger64 & 0xff00000000) >> 32);
+ aTmp[4] = (uint8_t)((uInteger64 & 0xff000000) >> 24);
+ aTmp[5] = (uint8_t)((uInteger64 & 0xff0000) >> 16);
+ aTmp[6] = (uint8_t)((uInteger64 & 0xff00) >> 8);
+ aTmp[7] = (uint8_t)(uInteger64 & 0xff);
+
+ pBytes = aTmp;
+#endif
+
+ // Do the insert
+ UsefulOutBuf_InsertData(pMe, pBytes, sizeof(uint64_t), uPos);
+}
+
+
+static inline void UsefulOutBuf_InsertFloat(UsefulOutBuf *pMe,
+ float f,
+ size_t uPos)
+{
+ UsefulOutBuf_InsertUint32(pMe, UsefulBufUtil_CopyFloatToUint32(f), uPos);
+}
+
+
+static inline void UsefulOutBuf_InsertDouble(UsefulOutBuf *pMe,
+ double d,
+ size_t uPos)
+{
+ UsefulOutBuf_InsertUint64(pMe, UsefulBufUtil_CopyDoubleToUint64(d), uPos);
+}
+
+
+static inline void UsefulOutBuf_AppendUsefulBuf(UsefulOutBuf *pMe,
+ UsefulBufC NewData)
+{
+ // An append is just a insert at the end
+ UsefulOutBuf_InsertUsefulBuf(pMe, NewData, UsefulOutBuf_GetEndPosition(pMe));
+}
+
+
+static inline void UsefulOutBuf_AppendData(UsefulOutBuf *pMe,
+ const void *pBytes,
+ size_t uLen)
+{
+ UsefulBufC Data = {pBytes, uLen};
+ UsefulOutBuf_AppendUsefulBuf(pMe, Data);
+}
+
+
+static inline void UsefulOutBuf_AppendString(UsefulOutBuf *pMe,
+ const char *szString)
+{
+ UsefulOutBuf_AppendUsefulBuf(pMe, (UsefulBufC){szString, strlen(szString)});
+}
+
+
+static inline void UsefulOutBuf_AppendByte(UsefulOutBuf *pMe,
+ uint8_t byte)
+{
+ UsefulOutBuf_AppendData(pMe, &byte, 1);
+}
+
+
+static inline void UsefulOutBuf_AppendUint16(UsefulOutBuf *pMe,
+ uint16_t uInteger16)
+{
+ UsefulOutBuf_InsertUint16(pMe, uInteger16, UsefulOutBuf_GetEndPosition(pMe));
+}
+
+static inline void UsefulOutBuf_AppendUint32(UsefulOutBuf *pMe,
+ uint32_t uInteger32)
+{
+ UsefulOutBuf_InsertUint32(pMe, uInteger32, UsefulOutBuf_GetEndPosition(pMe));
+}
+
+
+static inline void UsefulOutBuf_AppendUint64(UsefulOutBuf *pMe,
+ uint64_t uInteger64)
+{
+ UsefulOutBuf_InsertUint64(pMe, uInteger64, UsefulOutBuf_GetEndPosition(pMe));
+}
+
+
+static inline void UsefulOutBuf_AppendFloat(UsefulOutBuf *pMe,
+ float f)
+{
+ UsefulOutBuf_InsertFloat(pMe, f, UsefulOutBuf_GetEndPosition(pMe));
+}
+
+
+static inline void UsefulOutBuf_AppendDouble(UsefulOutBuf *pMe,
+ double d)
+{
+ UsefulOutBuf_InsertDouble(pMe, d, UsefulOutBuf_GetEndPosition(pMe));
+}
+
+
+static inline int UsefulOutBuf_GetError(UsefulOutBuf *pMe)
+{
+ return pMe->err;
+}
+
+
+static inline size_t UsefulOutBuf_RoomLeft(UsefulOutBuf *pMe)
+{
+ return pMe->UB.len - pMe->data_len;
+}
+
+
+static inline int UsefulOutBuf_WillItFit(UsefulOutBuf *pMe, size_t uLen)
+{
+ return uLen <= UsefulOutBuf_RoomLeft(pMe);
+}
+
+
+static inline int UsefulOutBuf_IsBufferNULL(UsefulOutBuf *pMe)
+{
+ return pMe->UB.ptr == NULL;
+}
+
+
+
+static inline void UsefulInputBuf_Init(UsefulInputBuf *pMe, UsefulBufC UB)
+{
+ pMe->cursor = 0;
+ pMe->err = 0;
+ pMe->magic = UIB_MAGIC;
+ pMe->UB = UB;
+}
+
+static inline size_t UsefulInputBuf_Tell(UsefulInputBuf *pMe)
+{
+ return pMe->cursor;
+}
+
+
+static inline void UsefulInputBuf_Seek(UsefulInputBuf *pMe, size_t uPos)
+{
+ if(uPos > pMe->UB.len) {
+ pMe->err = 1;
+ } else {
+ pMe->cursor = uPos;
+ }
+}
+
+
+static inline size_t UsefulInputBuf_BytesUnconsumed(UsefulInputBuf *pMe)
+{
+ // Code Reviewers: THIS FUNCTION DOES POINTER MATH
+
+ // Magic number is messed up. Either the structure got overwritten
+ // or was never initialized.
+ if(pMe->magic != UIB_MAGIC) {
+ return 0;
+ }
+
+ // The cursor is off the end of the input buffer given.
+ // Presuming there are no bugs in this code, this should never happen.
+ // If it so, the struct was corrupted. The check is retained as
+ // as a defense in case there is a bug in this code or the struct is
+ // corrupted.
+ if(pMe->cursor > pMe->UB.len) {
+ return 0;
+ }
+
+ // subtraction can't go neative because of check above
+ return pMe->UB.len - pMe->cursor;
+}
+
+
+static inline int UsefulInputBuf_BytesAvailable(UsefulInputBuf *pMe, size_t uLen)
+{
+ return UsefulInputBuf_BytesUnconsumed(pMe) >= uLen ? 1 : 0;
+}
+
+
+static inline UsefulBufC UsefulInputBuf_GetUsefulBuf(UsefulInputBuf *pMe, size_t uNum)
+{
+ const void *pResult = UsefulInputBuf_GetBytes(pMe, uNum);
+ if(!pResult) {
+ return NULLUsefulBufC;
+ } else {
+ return (UsefulBufC){pResult, uNum};
+ }
+}
+
+
+static inline uint8_t UsefulInputBuf_GetByte(UsefulInputBuf *pMe)
+{
+ const void *pResult = UsefulInputBuf_GetBytes(pMe, sizeof(uint8_t));
+
+ // The ternery operator is subject to integer promotion, because the
+ // operands are smaller than int, so cast back to uint8_t is needed
+ // to be completely explicit about types (for static analyzers)
+ return (uint8_t)(pResult ? *(uint8_t *)pResult : 0);
+}
+
+static inline uint16_t UsefulInputBuf_GetUint16(UsefulInputBuf *pMe)
+{
+ const uint8_t *pResult = (const uint8_t *)UsefulInputBuf_GetBytes(pMe, sizeof(uint16_t));
+
+ if(!pResult) {
+ return 0;
+ }
+
+ // See UsefulInputBuf_GetUint64() for comments on this code
+#if defined(USEFULBUF_CONFIG_BIG_ENDIAN) || defined(USEFULBUF_CONFIG_HTON) || defined(USEFULBUF_CONFIG_BSWAP)
+ uint16_t uTmp;
+ memcpy(&uTmp, pResult, sizeof(uint16_t));
+
+#if defined(USEFULBUF_CONFIG_BIG_ENDIAN)
+ return uTmp;
+
+#elif defined(USEFULBUF_CONFIG_HTON)
+ return ntohs(uTmp);
+
+#else
+ return __builtin_bswap16(uTmp);
+
+#endif
+
+#else
+
+ // The operations here are subject to integer promotion because the
+ // operands are smaller than int. They will be promoted to unsigned
+ // int for the shift and addition. The cast back to uint16_t is is needed
+ // to be completely explicit about types (for static analyzers)
+ return (uint16_t)((pResult[0] << 8) + pResult[1]);
+
+#endif
+}
+
+
+static inline uint32_t UsefulInputBuf_GetUint32(UsefulInputBuf *pMe)
+{
+ const uint8_t *pResult = (const uint8_t *)UsefulInputBuf_GetBytes(pMe, sizeof(uint32_t));
+
+ if(!pResult) {
+ return 0;
+ }
+
+ // See UsefulInputBuf_GetUint64() for comments on this code
+#if defined(USEFULBUF_CONFIG_BIG_ENDIAN) || defined(USEFULBUF_CONFIG_HTON) || defined(USEFULBUF_CONFIG_BSWAP)
+ uint32_t uTmp;
+ memcpy(&uTmp, pResult, sizeof(uint32_t));
+
+#if defined(USEFULBUF_CONFIG_BIG_ENDIAN)
+ return uTmp;
+
+#elif defined(USEFULBUF_CONFIG_HTON)
+ return ntohl(uTmp);
+
+#else
+ return __builtin_bswap32(uTmp);
+
+#endif
+
+#else
+ return ((uint32_t)pResult[0]<<24) +
+ ((uint32_t)pResult[1]<<16) +
+ ((uint32_t)pResult[2]<<8) +
+ (uint32_t)pResult[3];
+#endif
+}
+
+
+static inline uint64_t UsefulInputBuf_GetUint64(UsefulInputBuf *pMe)
+{
+ const uint8_t *pResult = (const uint8_t *)UsefulInputBuf_GetBytes(pMe, sizeof(uint64_t));
+
+ if(!pResult) {
+ return 0;
+ }
+
+#if defined(USEFULBUF_CONFIG_BIG_ENDIAN) || defined(USEFULBUF_CONFIG_HTON) || defined(USEFULBUF_CONFIG_BSWAP)
+ // pResult will probably not be aligned. This memcpy() moves the
+ // bytes into a temp variable safely for CPUs that can or can't do
+ // unaligned memory access. Many compilers will optimize the
+ // memcpy() into a simple move instruction.
+ uint64_t uTmp;
+ memcpy(&uTmp, pResult, sizeof(uint64_t));
+
+#if defined(USEFULBUF_CONFIG_BIG_ENDIAN)
+ // We have been told expliclity this is a big-endian CPU. Since
+ // network byte order is big-endian, there is nothing to do.
+
+ return uTmp;
+
+#elif defined(USEFULBUF_CONFIG_HTON)
+ // We have been told to use ntoh(), the system function to handle
+ // big- and little-endian. This works on both big- and
+ // little-endian machines, but ntoh() is not always available or in
+ // a standard place so it is not used by default. On some CPUs the
+ // code for this is very compact through use of a special swap
+ // instruction.
+
+ return ntohll(uTmp);
+
+#else
+ // Little-endian (since it is not USEFULBUF_CONFIG_BIG_ENDIAN) and
+ // USEFULBUF_CONFIG_BSWAP (since it is not USEFULBUF_CONFIG_HTON).
+ // __builtin_bswap64() and friends are not conditional on CPU
+ // endianness so this must only be used on little-endian machines.
+
+ return __builtin_bswap64(uTmp);
+
+
+#endif
+
+#else
+ // This is the default code that works on every CPU and every
+ // endianness with no dependency on ntoh(). This works on CPUs
+ // that either allow or do not allow unaligned access. It will
+ // always work, but usually is a little less efficient than ntoh().
+
+ return ((uint64_t)pResult[0]<<56) +
+ ((uint64_t)pResult[1]<<48) +
+ ((uint64_t)pResult[2]<<40) +
+ ((uint64_t)pResult[3]<<32) +
+ ((uint64_t)pResult[4]<<24) +
+ ((uint64_t)pResult[5]<<16) +
+ ((uint64_t)pResult[6]<<8) +
+ (uint64_t)pResult[7];
+#endif
+}
+
+
+static inline float UsefulInputBuf_GetFloat(UsefulInputBuf *pMe)
+{
+ uint32_t uResult = UsefulInputBuf_GetUint32(pMe);
+
+ return uResult ? UsefulBufUtil_CopyUint32ToFloat(uResult) : 0;
+}
+
+
+static inline double UsefulInputBuf_GetDouble(UsefulInputBuf *pMe)
+{
+ uint64_t uResult = UsefulInputBuf_GetUint64(pMe);
+
+ return uResult ? UsefulBufUtil_CopyUint64ToDouble(uResult) : 0;
+}
+
+
+static inline int UsefulInputBuf_GetError(UsefulInputBuf *pMe)
+{
+ return pMe->err;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _UsefulBuf_h
+
+
diff --git a/inc/qcbor/qcbor.h b/inc/qcbor/qcbor.h
new file mode 100644
index 0000000..40b08e8
--- /dev/null
+++ b/inc/qcbor/qcbor.h
@@ -0,0 +1,3586 @@
+/*==============================================================================
+ Copyright (c) 2016-2018, The Linux Foundation.
+ Copyright (c) 2018-2020, Laurence Lundblade.
+ All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors, nor the name "Laurence Lundblade" may be used to
+ endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ =============================================================================*/
+
+
+/*=============================================================================
+ FILE: qcbor.h
+
+ DESCRIPTION: This is the full public API and data structures for QCBOR
+
+ EDIT HISTORY FOR FILE:
+
+ This section contains comments describing changes made to the module.
+ Notice that changes are listed in reverse chronological order.
+
+ when who what, where, why
+ -------- ---- ---------------------------------------------------
+ 02/07/2020 llundblade QCBOREncode_EncodeHead() and other for bstr hashing.
+ 01/25/2020 llundblade Cleaner handling of too-long encoded string input.
+ 01/08/2020 llundblade Documentation corrections & improved code formatting.
+ 12/30/19 llundblade Add support for decimal fractions and bigfloats.
+ 08/7/19 llundblade Better handling of not well-formed encode and decode.
+ 07/31/19 llundblade New error code for better end of data handling.
+ 7/25/19 janjongboom Add indefinite length encoding for maps and arrays.
+ 05/26/19 llundblade Add QCBOREncode_GetErrorState() and _IsBufferNULL().
+ 04/26/19 llundblade Big documentation & style update. No interface change.
+ 02/16/19 llundblade Redesign MemPool to fix memory access alignment bug.
+ 12/18/18 llundblade Move decode malloc optional code to separate repo.
+ 12/13/18 llundblade Documentatation improvements.
+ 11/29/18 llundblade Rework to simpler handling of tags and labels.
+ 11/9/18 llundblade Error codes are now enums.
+ 11/1/18 llundblade Floating support.
+ 10/31/18 llundblade Switch to one license that is almost BSD-3.
+ 10/15/18 llundblade indefinite-length maps and arrays supported
+ 10/8/18 llundblade indefinite-length strings supported
+ 09/28/18 llundblade Added bstr wrapping feature for COSE implementation.
+ 07/05/17 llundbla Add bstr wrapping of maps/arrays for COSE.
+ 03/01/17 llundbla More data types; decoding improvements and fixes.
+ 11/13/16 llundbla Integrate most TZ changes back into github version.
+ 09/30/16 gkanike Porting to TZ.
+ 03/15/16 llundbla Initial Version.
+
+ =============================================================================*/
+
+#ifndef __QCBOR__qcbor__
+#define __QCBOR__qcbor__
+
+
+/* ===========================================================================
+ BEGINNING OF PRIVATE PART OF THIS FILE
+
+ Caller of QCBOR should not reference any of the details below up until
+ the start of the public part.
+ ========================================================================== */
+
+/*
+ Standard integer types are used in the interface to be precise about
+ sizes to be better at preventing underflow/overflow errors.
+ */
+#include <stdint.h>
+#include <stdbool.h>
+#include "UsefulBuf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#ifdef 0
+} // Keep editor indention formatting happy
+#endif
+#endif
+
+/*
+ The maxium nesting of arrays and maps when encoding or decoding.
+ (Further down in the file there is a definition that refers to this
+ that is public. This is done this way so there can be a nice
+ separation of public and private parts in this file.
+*/
+#define QCBOR_MAX_ARRAY_NESTING1 15 // Do not increase this over 255
+
+
+/* The largest offset to the start of an array or map. It is slightly
+ less than UINT32_MAX so the error condition can be tests on 32-bit machines.
+ UINT32_MAX comes from uStart in QCBORTrackNesting being a uin32_t.
+
+ This will cause trouble on a machine where size_t is less than 32-bits.
+ */
+#define QCBOR_MAX_ARRAY_OFFSET (UINT32_MAX - 100)
+
+/*
+ PRIVATE DATA STRUCTURE
+
+ Holds the data for tracking array and map nesting during encoding. Pairs up
+ with the Nesting_xxx functions to make an "object" to handle nesting encoding.
+
+ uStart is a uint32_t instead of a size_t to keep the size of this
+ struct down so it can be on the stack without any concern. It would be about
+ double if size_t was used instead.
+
+ Size approximation (varies with CPU/compiler):
+ 64-bit machine: (15 + 1) * (4 + 2 + 1 + 1 pad) + 8 = 136 bytes
+ 32-bit machine: (15 + 1) * (4 + 2 + 1 + 1 pad) + 4 = 132 bytes
+*/
+typedef struct __QCBORTrackNesting {
+ // PRIVATE DATA STRUCTURE
+ struct {
+ // See function QCBOREncode_OpenMapOrArray() for details on how this works
+ uint32_t uStart; // uStart is the byte position where the array starts
+ uint16_t uCount; // Number of items in the arrary or map; counts items
+ // in a map, not pairs of items
+ uint8_t uMajorType; // Indicates if item is a map or an array
+ } pArrays[QCBOR_MAX_ARRAY_NESTING1+1], // stored state for the nesting levels
+ *pCurrentNesting; // the current nesting level
+} QCBORTrackNesting;
+
+
+/*
+ PRIVATE DATA STRUCTURE
+
+ Context / data object for encoding some CBOR. Used by all encode functions to
+ form a public "object" that does the job of encdoing.
+
+ Size approximation (varies with CPU/compiler):
+ 64-bit machine: 27 + 1 (+ 4 padding) + 136 = 32 + 136 = 168 bytes
+ 32-bit machine: 15 + 1 + 132 = 148 bytes
+*/
+struct _QCBOREncodeContext {
+ // PRIVATE DATA STRUCTURE
+ UsefulOutBuf OutBuf; // Pointer to output buffer, its length and
+ // position in it
+ uint8_t uError; // Error state, always from QCBORError enum
+ QCBORTrackNesting nesting; // Keep track of array and map nesting
+};
+
+
+/*
+ PRIVATE DATA STRUCTURE
+
+ Holds the data for array and map nesting for decoding work. This structure
+ and the DecodeNesting_xxx functions form an "object" that does the work
+ for arrays and maps.
+
+ Size approximation (varies with CPU/compiler):
+ 64-bit machine: 4 * 16 + 8 = 72
+ 32-bit machine: 4 * 16 + 4 = 68
+ */
+typedef struct __QCBORDecodeNesting {
+ // PRIVATE DATA STRUCTURE
+ struct {
+ uint16_t uCount;
+ uint8_t uMajorType;
+ } pMapsAndArrays[QCBOR_MAX_ARRAY_NESTING1+1],
+ *pCurrent;
+} QCBORDecodeNesting;
+
+
+typedef struct {
+ // PRIVATE DATA STRUCTURE
+ void *pAllocateCxt;
+ UsefulBuf (* pfAllocator)(void *pAllocateCxt, void *pOldMem, size_t uNewSize);
+} QCORInternalAllocator;
+
+
+/*
+ PRIVATE DATA STRUCTURE
+
+ The decode context. This data structure plus the public QCBORDecode_xxx
+ functions form an "object" that does CBOR decoding.
+
+ Size approximation (varies with CPU/compiler):
+ 64-bit machine: 32 + 1 + 1 + 6 bytes padding + 72 + 16 + 8 + 8 = 144 bytes
+ 32-bit machine: 16 + 1 + 1 + 2 bytes padding + 68 + 8 + 8 + 4 = 108 bytes
+ */
+struct _QCBORDecodeContext {
+ // PRIVATE DATA STRUCTURE
+ UsefulInputBuf InBuf;
+
+ uint8_t uDecodeMode;
+ uint8_t bStringAllocateAll;
+
+ QCBORDecodeNesting nesting;
+
+ // If a string allocator is configured for indefinite-length
+ // strings, it is configured here.
+ QCORInternalAllocator StringAllocator;
+
+ // These are special for the internal MemPool allocator.
+ // They are not used otherwise. We tried packing these
+ // in the MemPool itself, but there are issues
+ // with memory alignment.
+ uint32_t uMemPoolSize;
+ uint32_t uMemPoolFreeOffset;
+
+ // This is NULL or points to QCBORTagList.
+ // It is type void for the same reason as above.
+ const void *pCallerConfiguredTagList;
+};
+
+// Used internally in the impementation here
+// Must not conflict with any of the official CBOR types
+#define CBOR_MAJOR_NONE_TYPE_RAW 9
+#define CBOR_MAJOR_NONE_TAG_LABEL_REORDER 10
+#define CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY 11
+#define CBOR_MAJOR_NONE_TYPE_ARRAY_INDEFINITE_LEN 12
+#define CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN 13
+
+
+/* ==========================================================================
+ END OF PRIVATE PART OF THIS FILE
+
+ BEGINNING OF PUBLIC PART OF THIS FILE
+ ========================================================================== */
+
+
+
+/* ==========================================================================
+ BEGINNING OF CONSTANTS THAT COME FROM THE CBOR STANDARD, RFC 7049
+
+ It is not necessary to use these directly when encoding or decoding
+ CBOR with this implementation.
+ ========================================================================== */
+
+/* Standard CBOR Major type for positive integers of various lengths */
+#define CBOR_MAJOR_TYPE_POSITIVE_INT 0
+
+/* Standard CBOR Major type for negative integer of various lengths */
+#define CBOR_MAJOR_TYPE_NEGATIVE_INT 1
+
+/* Standard CBOR Major type for an array of arbitrary 8-bit bytes. */
+#define CBOR_MAJOR_TYPE_BYTE_STRING 2
+
+/* Standard CBOR Major type for a UTF-8 string. Note this is true 8-bit UTF8
+ with no encoding and no NULL termination */
+#define CBOR_MAJOR_TYPE_TEXT_STRING 3
+
+/* Standard CBOR Major type for an ordered array of other CBOR data items */
+#define CBOR_MAJOR_TYPE_ARRAY 4
+
+/* Standard CBOR Major type for CBOR MAP. Maps an array of pairs. The
+ first item in the pair is the "label" (key, name or identfier) and the second
+ item is the value. */
+#define CBOR_MAJOR_TYPE_MAP 5
+
+/* Standard CBOR optional tagging. This tags things like dates and URLs */
+#define CBOR_MAJOR_TYPE_OPTIONAL 6
+
+/* Standard CBOR extra simple types like floats and the values true and false */
+#define CBOR_MAJOR_TYPE_SIMPLE 7
+
+
+/*
+ These are special values for the AdditionalInfo bits that are part of
+ the first byte. Mostly they encode the length of the data item.
+ */
+#define LEN_IS_ONE_BYTE 24
+#define LEN_IS_TWO_BYTES 25
+#define LEN_IS_FOUR_BYTES 26
+#define LEN_IS_EIGHT_BYTES 27
+#define ADDINFO_RESERVED1 28
+#define ADDINFO_RESERVED2 29
+#define ADDINFO_RESERVED3 30
+#define LEN_IS_INDEFINITE 31
+
+
+/*
+ 24 is a special number for CBOR. Integers and lengths
+ less than it are encoded in the same byte as the major type.
+ */
+#define CBOR_TWENTY_FOUR 24
+
+
+/*
+ Tags that are used with CBOR_MAJOR_TYPE_OPTIONAL. These
+ are types defined in RFC 7049 and some additional ones
+ in the IANA CBOR tags registry.
+ */
+/** See QCBOREncode_AddDateString(). */
+#define CBOR_TAG_DATE_STRING 0
+/** See QCBOREncode_AddDateEpoch(). */
+#define CBOR_TAG_DATE_EPOCH 1
+/** See QCBOREncode_AddPositiveBignum(). */
+#define CBOR_TAG_POS_BIGNUM 2
+/** See QCBOREncode_AddNegativeBignum(). */
+#define CBOR_TAG_NEG_BIGNUM 3
+/** CBOR tag for a two-element array representing a fraction with a
+ mantissa and base-10 scaling factor. See QCBOREncode_AddDecimalFraction()
+ and @ref expAndMantissa.
+ */
+#define CBOR_TAG_DECIMAL_FRACTION 4
+/** CBOR tag for a two-element array representing a fraction with a
+ mantissa and base-2 scaling factor. See QCBOREncode_AddBigFloat()
+ and @ref expAndMantissa. */
+#define CBOR_TAG_BIGFLOAT 5
+/** Tag for COSE format encryption with no recipient
+ identification. See [RFC 8152, COSE]
+ (https://tools.ietf.org/html/rfc8152). No API is provided for this
+ tag. */
+#define CBOR_TAG_COSE_ENCRYPTO 16
+/** Tag for COSE format MAC'd data with no recipient
+ identification. See [RFC 8152, COSE]
+ (https://tools.ietf.org/html/rfc8152). No API is provided for this
+ tag.*/
+#define CBOR_TAG_COSE_MAC0 17
+/** Tag for COSE format single signature signing. No API is provided
+ for this tag. See [RFC 8152, COSE]
+ (https://tools.ietf.org/html/rfc8152). */
+#define CBOR_TAG_COSE_SIGN1 18
+/** A hint that the following byte string should be encoded in
+ Base64URL when converting to JSON or similar text-based
+ representations. Call @c
+ QCBOREncode_AddTag(pCtx,CBOR_TAG_ENC_AS_B64URL) before the call to
+ QCBOREncode_AddBytes(). */
+#define CBOR_TAG_ENC_AS_B64URL 21
+/** A hint that the following byte string should be encoded in Base64
+ when converting to JSON or similar text-based
+ representations. Call @c
+ QCBOREncode_AddTag(pCtx,CBOR_TAG_ENC_AS_B64) before the call to
+ QCBOREncode_AddBytes(). */
+#define CBOR_TAG_ENC_AS_B64 22
+/** A hint that the following byte string should be encoded in base-16
+ format per [RFC 4648] (https://tools.ietf.org/html/rfc4648) when
+ converting to JSON or similar text-based
+ representations. Essentially, Base-16 encoding is the standard
+ case- insensitive hex encoding and may be referred to as
+ "hex". Call @c QCBOREncode_AddTag(pCtx,CBOR_TAG_ENC_AS_B16) before
+ the call to QCBOREncode_AddBytes(). */
+#define CBOR_TAG_ENC_AS_B16 23
+/** Tag to indicate a byte string contains encoded CBOR. No API is
+ provided for this tag. */
+#define CBOR_TAG_CBOR 24
+/** See QCBOREncode_AddURI(). */
+#define CBOR_TAG_URI 32
+/** See QCBOREncode_AddB64URLText(). */
+#define CBOR_TAG_B64URL 33
+/** See QCBOREncode_AddB64Text(). */
+#define CBOR_TAG_B64 34
+/** See QCBOREncode_AddRegex(). */
+#define CBOR_TAG_REGEX 35
+/** See QCBOREncode_AddMIMEData(). */
+#define CBOR_TAG_MIME 36
+/** See QCBOREncode_AddBinaryUUID(). */
+#define CBOR_TAG_BIN_UUID 37
+/** The data is a CBOR Web Token per [RFC 8392]
+ (https://tools.ietf.org/html/rfc8932). No API is provided for this
+ tag. */
+#define CBOR_TAG_CWT 61
+/** Tag for COSE format encryption. See [RFC 8152, COSE]
+ (https://tools.ietf.org/html/rfc8152). No API is provided for this
+ tag. */
+#define CBOR_TAG_ENCRYPT 96
+/** Tag for COSE format MAC. See [RFC 8152, COSE]
+ (https://tools.ietf.org/html/rfc8152). No API is provided for this
+ tag. */
+#define CBOR_TAG_MAC 97
+/** Tag for COSE format signed data. See [RFC 8152, COSE]
+ (https://tools.ietf.org/html/rfc8152). No API is provided for this
+ tag. */
+#define CBOR_TAG_SIGN 98
+/** World geographic coordinates. See ISO 6709, [RFC 5870]
+ (https://tools.ietf.org/html/rfc5870) and WGS-84. No API is
+ provided for this tag. */
+#define CBOR_TAG_GEO_COORD 103
+/** The magic number, self-described CBOR. No API is provided for this
+ tag. */
+#define CBOR_TAG_CBOR_MAGIC 55799
+
+#define CBOR_TAG_NONE UINT64_MAX
+
+
+/*
+ Values for the 5 bits for items of major type 7
+ */
+#define CBOR_SIMPLEV_FALSE 20
+#define CBOR_SIMPLEV_TRUE 21
+#define CBOR_SIMPLEV_NULL 22
+#define CBOR_SIMPLEV_UNDEF 23
+#define CBOR_SIMPLEV_ONEBYTE 24
+#define HALF_PREC_FLOAT 25
+#define SINGLE_PREC_FLOAT 26
+#define DOUBLE_PREC_FLOAT 27
+#define CBOR_SIMPLE_BREAK 31
+#define CBOR_SIMPLEV_RESERVED_START CBOR_SIMPLEV_ONEBYTE
+#define CBOR_SIMPLEV_RESERVED_END CBOR_SIMPLE_BREAK
+
+
+
+/* ===========================================================================
+
+ END OF CONSTANTS THAT COME FROM THE CBOR STANDARD, RFC 7049
+
+ BEGINNING OF PUBLIC INTERFACE FOR QCBOR ENCODER / DECODER
+
+ =========================================================================== */
+
+/**
+
+ @file qcbor.h
+
+ Q C B O R E n c o d e / D e c o d e
+
+ This implements CBOR -- Concise Binary Object Representation as
+ defined in [RFC 7049] (https://tools.ietf.org/html/rfc7049). More
+ info is at http://cbor.io. This is a near-complete implementation of
+ the specification. Limitations are listed further down.
+
+ CBOR is intentionally designed to be translatable to JSON, but not
+ all CBOR can convert to JSON. See RFC 7049 for more info on how to
+ construct CBOR that is the most JSON friendly.
+
+ The memory model for encoding and decoding is that encoded CBOR must
+ be in a contiguous buffer in memory. During encoding the caller must
+ supply an output buffer and if the encoding would go off the end of
+ the buffer an error is returned. During decoding the caller supplies
+ the encoded CBOR in a contiguous buffer and the decoder returns
+ pointers and lengths into that buffer for strings.
+
+ This implementation does not require malloc. All data structures
+ passed in/out of the APIs can fit on the stack.
+
+ Decoding of indefinite-length strings is a special case that requires
+ a "string allocator" to allocate memory into which the segments of
+ the string are coalesced. Without this, decoding will error out if an
+ indefinite-length string is encountered (indefinite-length maps and
+ arrays do not require the string allocator). A simple string
+ allocator called MemPool is built-in and will work if supplied with a
+ block of memory to allocate. The string allocator can optionally use
+ malloc() or some other custom scheme.
+
+ Here are some terms and definitions:
+
+ - "Item", "Data Item": An integer or string or such. The basic "thing" that
+ CBOR is about. An array is an item itself that contains some items.
+
+ - "Array": An ordered sequence of items, the same as JSON.
+
+ - "Map": A collection of label/value pairs. Each pair is a data
+ item. A JSON "object" is the same as a CBOR "map".
+
+ - "Label": The data item in a pair in a map that names or identifies
+ the pair, not the value. This implementation refers to it as a
+ "label". JSON refers to it as the "name". The CBOR RFC refers to it
+ this as a "key". This implementation chooses label instead because
+ key is too easily confused with a cryptographic key. The COSE
+ standard, which uses CBOR, has also chosen to use the term "label"
+ rather than "key" for this same reason.
+
+ - "Key": See "Label" above.
+
+ - "Tag": Optional integer that can be added before each data item
+ usually to indicate it is new or more specific data type. For
+ example, a tag can indicate an integer is a date, or that a map is to
+ be considered a type (analogous to a typedef in C).
+
+ - "Initial Byte": The first byte of an encoded item. Encoding and
+ decoding of this byte is taken care of by the implementation.
+
+ - "Additional Info": In addition to the major type, all data items
+ have some other info. This is usually the length of the data but can
+ be several other things. Encoding and decoding of this is taken care
+ of by the implementation.
+
+ CBOR has two mechanisms for tagging and labeling the data values like
+ integers and strings. For example, an integer that represents
+ someone's birthday in epoch seconds since Jan 1, 1970 could be
+ encoded like this:
+
+ - First it is CBOR_MAJOR_TYPE_POSITIVE_INT (@ref QCBOR_TYPE_INT64),
+ the primitive positive integer.
+
+ - Next it has a "tag" @ref CBOR_TAG_DATE_EPOCH indicating the integer
+ represents a date in the form of the number of seconds since Jan 1,
+ 1970.
+
+ - Last it has a string "label" like "BirthDate" indicating the
+ meaning of the data.
+
+ The encoded binary looks like this:
+
+ a1 # Map of 1 item
+ 69 # Indicates text string of 9 bytes
+ 426972746844617465 # The text "BirthDate"
+ c1 # Tags next integer as epoch date
+ 1a # Indicates a 4-byte integer
+ 580d4172 # unsigned integer date 1477263730
+
+ Implementors using this API will primarily work with
+ labels. Generally, tags are only needed for making up new data
+ types. This implementation covers most of the data types defined in
+ the RFC using tags. It also, allows for the use of custom tags if
+ necessary.
+
+ This implementation explicitly supports labels that are text strings
+ and integers. Text strings translate nicely into JSON objects and are
+ very readable. Integer labels are much less readable but can be very
+ compact. If they are in the range of 0 to 23, they take up only one
+ byte.
+
+ CBOR allows a label to be any type of data including an array or a
+ map. It is possible to use this API to construct and parse such
+ labels, but it is not explicitly supported.
+
+ A common encoding usage mode is to invoke the encoding twice. First
+ with no output buffer to compute the length of the needed output
+ buffer. Then the correct sized output buffer is allocated. Last the
+ encoder is invoked again, this time with the output buffer.
+
+ The double invocation is not required if the maximum output buffer
+ size can be predicted. This is usually possible for simple CBOR
+ structures. If the double invocation is implemented, it can be in a
+ loop or function as in the example code so that the code doesn't have
+ to actually be written twice, saving code size.
+
+ If a buffer too small to hold the encoded output is given, the error
+ @ref QCBOR_ERR_BUFFER_TOO_SMALL will be returned. Data will never be
+ written off the end of the output buffer no matter which functions
+ here are called or what parameters are passed to them.
+
+ The encoding error handling is simple. The only possible errors are
+ trying to encode structures that are too large or too complex. There
+ are no internal malloc calls so there will be no failures for out of
+ memory. The error state is tracked internally, so there is no need
+ to check for errors when encoding. Only the return code from
+ QCBOREncode_Finish() need be checked as once an error happens, the
+ encoder goes into an error state and calls to it to add more data
+ will do nothing. An error check is not needed after every data item
+ is added.
+
+ Encoding generally proceeds by calling QCBOREncode_Init(), calling
+ lots of @c QCBOREncode_AddXxx() functions and calling
+ QCBOREncode_Finish(). There are many @c QCBOREncode_AddXxx()
+ functions for various data types. The input buffers need only to be
+ valid during the @c QCBOREncode_AddXxx() calls as the data is copied
+ into the output buffer.
+
+ There are three `Add` functions for each data type. The first / main
+ one for the type is for adding the data item to an array. The second
+ one's name ends in `ToMap`, is used for adding data items to maps and
+ takes a string argument that is its label in the map. The third one
+ ends in `ToMapN`, is also used for adding data items to maps, and
+ takes an integer argument that is its label in the map.
+
+ The simplest aggregate type is an array, which is a simple ordered
+ set of items without labels the same as JSON arrays. Call
+ QCBOREncode_OpenArray() to open a new array, then various @c
+ QCBOREncode_AddXxx() functions to put items in the array and then
+ QCBOREncode_CloseArray(). Nesting to the limit @ref
+ QCBOR_MAX_ARRAY_NESTING is allowed. All opens must be matched by
+ closes or an encoding error will be returned.
+
+ The other aggregate type is a map which does use labels. The `Add`
+ functions that end in `ToMap` and `ToMapN` are convenient ways to add
+ labeled data items to a map. You can also call any type of `Add`
+ function once to add a label of any time and then call any type of
+ `Add` again to add its value.
+
+ Note that when you nest arrays or maps in a map, the nested array or
+ map has a label.
+
+ @anchor Tags-Overview
+ Any CBOR data item can be tagged to add semantics, define a new data
+ type or such. Some tags are fully standardized and some are just
+ registered. Others are not registered and used in a proprietary way.
+
+ Encoding and decoding of many of the registered tags is fully
+ implemented by QCBOR. It is also possible to encode and decode tags
+ that are not directly supported. For many use cases the built-in tag
+ support should be adequate.
+
+ For example, the registered epoch date tag is supported in encoding
+ by QCBOREncode_AddDateEpoch() and in decoding by @ref
+ QCBOR_TYPE_DATE_EPOCH and the @c epochDate member of @ref
+ QCBORItem. This is typical of the built-in tag support. There is an
+ API to encode data for it and a @c QCBOR_TYPE_XXX when it is decoded.
+
+ Tags are registered in the [IANA CBOR Tags Registry]
+ (https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml). There
+ are roughly three options to create a new tag. First, a public
+ specification can be created and the new tag registered with IANA.
+ This is the most formal. Second, the new tag can be registered with
+ IANA with just a short description rather than a full specification.
+ These tags must be greater than 256. Third, a tag can be used without
+ any IANA registration, though the registry should be checked to see
+ that the new value doesn't collide with one that is registered. The
+ value of these tags must be 256 or larger.
+
+ The encoding side of tags not built-in is handled by
+ QCBOREncode_AddTag() and is relatively simple. Tag decoding is more
+ complex and mainly handled by QCBORDecode_GetNext(). Decoding of the
+ structure of tagged data not built-in (if there is any) has to be
+ implemented by the caller.
+
+ Summary Limits of this implementation:
+ - The entire encoded CBOR must fit into contiguous memory.
+ - Max size of encoded / decoded CBOR data is @c UINT32_MAX (4GB).
+ - Max array / map nesting level when encoding / decoding is
+ @ref QCBOR_MAX_ARRAY_NESTING (this is typically 15).
+ - Max items in an array or map when encoding / decoding is
+ @ref QCBOR_MAX_ITEMS_IN_ARRAY (typically 65,536).
+ - Does not directly support labels in maps other than text strings & integers.
+ - Does not directly support integer labels greater than @c INT64_MAX.
+ - Epoch dates limited to @c INT64_MAX (+/- 292 billion years).
+ - Exponents for bigfloats and decimal integers are limited to @c INT64_MAX.
+ - Tags on labels are ignored during decoding.
+ - There is no duplicate detection of map labels (but duplicates are passed on).
+ - Works only on 32- and 64-bit CPUs (modifications could make it work
+ on 16-bit CPUs).
+
+ The public interface uses @c size_t for all lengths. Internally the
+ implementation uses 32-bit lengths by design to use less memory and
+ fit structures on the stack. This limits the encoded CBOR it can work
+ with to size @c UINT32_MAX (4GB) which should be enough.
+
+ This implementation assumes two's compliment integer machines. @c
+ <stdint.h> also requires this. It is possible to modify this
+ implementation for another integer representation, but all modern
+ machines seem to be two's compliment.
+
+ */
+
+
+/**
+ The maximum number of items in a single array or map when encoding of
+ decoding.
+*/
+// -1 is because the value UINT16_MAX is used to track indefinite-length arrays
+#define QCBOR_MAX_ITEMS_IN_ARRAY (UINT16_MAX-1)
+
+/**
+ The maximum nesting of arrays and maps when encoding or decoding. The
+ error @ref QCBOR_ERR_ARRAY_NESTING_TOO_DEEP will be returned on
+ encoding of decoding if it is exceeded.
+*/
+#define QCBOR_MAX_ARRAY_NESTING QCBOR_MAX_ARRAY_NESTING1
+
+/**
+ The maximum number of tags that can be in @ref QCBORTagListIn and passed to
+ QCBORDecode_SetCallerConfiguredTagList()
+ */
+#define QCBOR_MAX_CUSTOM_TAGS 16
+
+/*
+ The size of the buffer to be passed to QCBOREncode_EncodeHead(). It is one
+ byte larger than sizeof(uint64_t) + 1, the actual maximum size of the
+ head of a CBOR data item. because QCBOREncode_EncodeHead() needs
+ one extra byte to work.
+ */
+#define QCBOR_HEAD_BUFFER_SIZE (sizeof(uint64_t) + 2)
+
+/**
+ Error codes returned by QCBOR Encoder and Decoder.
+ */
+typedef enum {
+ /** The encode or decode completely correctly. */
+ QCBOR_SUCCESS = 0,
+
+ /** The buffer provided for the encoded output when doing encoding
+ was too small and the encoded output will not fit. Also, when
+ the buffer given to QCBORDecode_SetMemPool() is too small. */
+ QCBOR_ERR_BUFFER_TOO_SMALL = 1,
+
+ /** During encoding or decoding, the array or map nesting was
+ deeper than this implementation can handle. Note that in the
+ interest of code size and memory use, this implementation has a
+ hard limit on array nesting. The limit is defined as the
+ constant @ref QCBOR_MAX_ARRAY_NESTING. */
+ QCBOR_ERR_ARRAY_NESTING_TOO_DEEP = 2,
+
+ /** During decoding or encoding, the array or map had too many
+ items in it. This limit @ref QCBOR_MAX_ITEMS_IN_ARRAY,
+ typically 65,535. */
+ QCBOR_ERR_ARRAY_TOO_LONG = 3,
+
+ /** During encoding, more arrays or maps were closed than
+ opened. This is a coding error on the part of the caller of the
+ encoder. */
+ QCBOR_ERR_TOO_MANY_CLOSES = 4,
+
+ /** During decoding, some CBOR construct was encountered that this
+ decoder doesn't support, primarily this is the reserved
+ additional info values, 28 through 30. During encoding,
+ an attempt to create simple value between 24 and 31. */
+ QCBOR_ERR_UNSUPPORTED = 5,
+
+ /** During decoding, hit the end of the given data to decode. For
+ example, a byte string of 100 bytes was expected, but the end
+ of the input was hit before finding those 100 bytes. Corrupted
+ CBOR input will often result in this error. See also @ref
+ QCBOR_ERR_NO_MORE_ITEMS.
+ */
+ QCBOR_ERR_HIT_END = 6,
+
+ /** During encoding, the length of the encoded CBOR exceeded @c
+ UINT32_MAX. */
+ QCBOR_ERR_BUFFER_TOO_LARGE = 7,
+
+ /** During decoding, an integer smaller than INT64_MIN was received
+ (CBOR can represent integers smaller than INT64_MIN, but C
+ cannot). */
+ QCBOR_ERR_INT_OVERFLOW = 8,
+
+ /** During decoding, the label for a map entry is bad. What causes
+ this error depends on the decoding mode. */
+ QCBOR_ERR_MAP_LABEL_TYPE = 9,
+
+ /** During encoding or decoding, the number of array or map opens
+ was not matched by the number of closes. */
+ QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN = 10,
+
+ /** During decoding, a date greater than +- 292 billion years from
+ Jan 1 1970 encountered during parsing. */
+ QCBOR_ERR_DATE_OVERFLOW = 11,
+
+ /** During decoding, the CBOR is not valid, primarily a simple type
+ is encoded in a prohibited way. */
+ QCBOR_ERR_BAD_TYPE_7 = 12,
+
+ /** Optional tagging that doesn't make sense (an integer is tagged
+ as a date string) or can't be handled. */
+ QCBOR_ERR_BAD_OPT_TAG = 13,
+
+ /** Returned by QCBORDecode_Finish() if all the inputs bytes have
+ not been consumed. */
+ QCBOR_ERR_EXTRA_BYTES = 14,
+
+ /** During encoding, @c QCBOREncode_CloseXxx() called with a
+ different type than is currently open. */
+ QCBOR_ERR_CLOSE_MISMATCH = 15,
+
+ /** Unable to decode an indefinite-length string because no string
+ allocator was configured. See QCBORDecode_SetMemPool() or
+ QCBORDecode_SetUpAllocator(). */
+ QCBOR_ERR_NO_STRING_ALLOCATOR = 16,
+
+ /** One of the chunks in an indefinite-length string is not of the
+ type of the start of the string. */
+ QCBOR_ERR_INDEFINITE_STRING_CHUNK = 17,
+
+ /** Error allocating space for a string, usually for an
+ indefinite-length string. */
+ QCBOR_ERR_STRING_ALLOCATE = 18,
+
+ /** During decoding, a break occurred outside an indefinite-length
+ item. */
+ QCBOR_ERR_BAD_BREAK = 19,
+
+ /** During decoding, too many tags in the caller-configured tag
+ list, or not enough space in @ref QCBORTagListOut. */
+ QCBOR_ERR_TOO_MANY_TAGS = 20,
+
+ /** An integer type is encoded with a bad length (an indefinite length) */
+ QCBOR_ERR_BAD_INT = 21,
+
+ /** All well-formed data items have been consumed and there are no
+ more. If parsing a CBOR stream this indicates the non-error
+ end of the stream. If parsing a CBOR stream / sequence, this
+ probably indicates that some data items expected are not present.
+ See also @ref QCBOR_ERR_HIT_END. */
+ QCBOR_ERR_NO_MORE_ITEMS = 22,
+
+ /** Something is wrong with a decimal fraction or bigfloat such as
+ it not consisting of an array with two integers */
+ QCBOR_ERR_BAD_EXP_AND_MANTISSA = 23,
+
+ /** When decoding, a string's size is greater than size_t. In all but some
+ very strange situations this is because of corrupt input CBOR and
+ should be treated as such. The strange situation is a CPU with a very
+ small size_t (e.g., a 16-bit CPU) and a large string (e.g., > 65KB).
+ */
+ QCBOR_ERR_STRING_TOO_LONG = 24
+
+} QCBORError;
+
+
+/**
+ The decode mode options.
+ */
+typedef enum {
+ /** See QCBORDecode_Init() */
+ QCBOR_DECODE_MODE_NORMAL = 0,
+ /** See QCBORDecode_Init() */
+ QCBOR_DECODE_MODE_MAP_STRINGS_ONLY = 1,
+ /** See QCBORDecode_Init() */
+ QCBOR_DECODE_MODE_MAP_AS_ARRAY = 2
+} QCBORDecodeMode;
+
+
+
+
+
+/* Do not renumber these. Code depends on some of these values. */
+/** The data type is unknown, unset or invalid. */
+#define QCBOR_TYPE_NONE 0
+/** Type for an integer that decoded either between @c INT64_MIN and
+ @c INT32_MIN or @c INT32_MAX and @c INT64_MAX. Data is in member
+ @c val.int64. */
+#define QCBOR_TYPE_INT64 2
+/** Type for an integer that decoded to a more than @c INT64_MAX and
+ @c UINT64_MAX. Data is in member @c val.uint64. */
+#define QCBOR_TYPE_UINT64 3
+/** Type for an array. The number of items in the array is in @c
+ val.uCount. */
+#define QCBOR_TYPE_ARRAY 4
+/** Type for a map; number of items in map is in @c val.uCount. */
+#define QCBOR_TYPE_MAP 5
+/** Type for a buffer full of bytes. Data is in @c val.string. */
+#define QCBOR_TYPE_BYTE_STRING 6
+/** Type for a UTF-8 string. It is not NULL-terminated. Data is in @c
+ val.string. */
+#define QCBOR_TYPE_TEXT_STRING 7
+/** Type for a positive big number. Data is in @c val.bignum, a
+ pointer and a length. */
+#define QCBOR_TYPE_POSBIGNUM 9
+/** Type for a negative big number. Data is in @c val.bignum, a
+ pointer and a length. */
+#define QCBOR_TYPE_NEGBIGNUM 10
+/** Type for [RFC 3339] (https://tools.ietf.org/html/rfc3339) date
+ string, possibly with time zone. Data is in @c val.dateString */
+#define QCBOR_TYPE_DATE_STRING 11
+/** Type for integer seconds since Jan 1970 + floating-point
+ fraction. Data is in @c val.epochDate */
+#define QCBOR_TYPE_DATE_EPOCH 12
+/** A simple type that this CBOR implementation doesn't know about;
+ Type is in @c val.uSimple. */
+#define QCBOR_TYPE_UKNOWN_SIMPLE 13
+
+/** A decimal fraction made of decimal exponent and integer mantissa.
+ See @ref expAndMantissa and QCBOREncode_AddDecimalFraction(). */
+#define QCBOR_TYPE_DECIMAL_FRACTION 14
+
+/** A decimal fraction made of decimal exponent and positive big
+ number mantissa. See @ref expAndMantissa and
+ QCBOREncode_AddDecimalFractionBigNum(). */
+#define QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM 15
+
+/** A decimal fraction made of decimal exponent and negative big
+ number mantissa. See @ref expAndMantissa and
+ QCBOREncode_AddDecimalFractionBigNum(). */
+#define QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM 16
+
+/** A floating-point number made of base-2 exponent and integer
+ mantissa. See @ref expAndMantissa and
+ QCBOREncode_AddBigFloat(). */
+#define QCBOR_TYPE_BIGFLOAT 17
+
+/** A floating-point number made of base-2 exponent and positive big
+ number mantissa. See @ref expAndMantissa and
+ QCBOREncode_AddBigFloatBigNum(). */
+#define QCBOR_TYPE_BIGFLOAT_POS_BIGNUM 18
+
+/** A floating-point number made of base-2 exponent and negative big
+ number mantissa. See @ref expAndMantissa and
+ QCBOREncode_AddBigFloatBigNum(). */
+#define QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM 19
+
+/** Type for the value false. */
+#define QCBOR_TYPE_FALSE 20
+/** Type for the value true. */
+#define QCBOR_TYPE_TRUE 21
+/** Type for the value null. */
+#define QCBOR_TYPE_NULL 22
+/** Type for the value undef. */
+#define QCBOR_TYPE_UNDEF 23
+/** Type for a floating-point number. Data is in @c val.float. */
+#define QCBOR_TYPE_FLOAT 26
+/** Type for a double floating-point number. Data is in @c val.double. */
+#define QCBOR_TYPE_DOUBLE 27
+/** For @ref QCBOR_DECODE_MODE_MAP_AS_ARRAY decode mode, a map that is
+ being traversed as an array. See QCBORDecode_Init() */
+#define QCBOR_TYPE_MAP_AS_ARRAY 32
+
+#define QCBOR_TYPE_BREAK 31 // Used internally; never returned
+
+#define QCBOR_TYPE_OPTTAG 254 // Used internally; never returned
+
+
+
+/*
+ Approx Size of this:
+ 8 + 8 + 1 + 1 + 1 + (1 padding) + (4 padding) = 24 for first part
+ (20 on a 32-bit machine)
+ 16 bytes for the val union
+ 16 bytes for label union
+ total = 56 bytes (52 bytes on 32-bit machine)
+ */
+
+/**
+ The main data structure that holds the type, value and other info for
+ a decoded item returned by QCBORDecode_GetNext() and
+ QCBORDecode_GetNextWithTags().
+ */
+typedef struct _QCBORItem {
+ /** Tells what element of the @c val union to use. One of @c
+ QCBOR_TYPE_XXXX */
+ uint8_t uDataType;
+ /** How deep the nesting from arrays and maps are. 0 is the top
+ level with no arrays or maps entered. */
+ uint8_t uNestingLevel;
+ /** Tells what element of the label union to use. */
+ uint8_t uLabelType;
+ /** 1 if allocated with string allocator, 0 if not. See
+ QCBORDecode_SetMemPool() or QCBORDecode_SetUpAllocator() */
+ uint8_t uDataAlloc;
+ /** Like @c uDataAlloc, but for label. */
+ uint8_t uLabelAlloc;
+ /** If not equal to @c uNestingLevel, this item closed out at least
+ one map/array */
+ uint8_t uNextNestLevel;
+
+ /** The union holding the item's value. Select union member based
+ on @c uDataType */
+ union {
+ /** The value for @c uDataType @ref QCBOR_TYPE_INT64. */
+ int64_t int64;
+ /** The value for uDataType @ref QCBOR_TYPE_UINT64. */
+ uint64_t uint64;
+ /** The value for @c uDataType @ref QCBOR_TYPE_BYTE_STRING and
+ @ref QCBOR_TYPE_TEXT_STRING. */
+ UsefulBufC string;
+ /** The "value" for @c uDataType @ref QCBOR_TYPE_ARRAY or @ref
+ QCBOR_TYPE_MAP -- the number of items in the array or map.
+ It is @c UINT16_MAX when decoding indefinite-lengths maps
+ and arrays. */
+ uint16_t uCount;
+ /** The value for @c uDataType @ref QCBOR_TYPE_DOUBLE. */
+ double dfnum;
+ /** The value for @c uDataType @ref QCBOR_TYPE_DATE_EPOCH. */
+ struct {
+ int64_t nSeconds;
+ double fSecondsFraction;
+ } epochDate;
+ /** The value for @c uDataType @ref QCBOR_TYPE_DATE_STRING. */
+ UsefulBufC dateString;
+ /** The value for @c uDataType @ref QCBOR_TYPE_POSBIGNUM and
+ @ref QCBOR_TYPE_NEGBIGNUM. */
+ UsefulBufC bigNum;
+ /** The integer value for unknown simple types. */
+ uint8_t uSimple;
+#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+ /** @anchor expAndMantissa
+
+ The value for bigfloats and decimal fractions. The use of the
+ fields in this structure depend on @c uDataType.
+
+ When @c uDataType is a @c DECIMAL_FRACTION, the exponent is
+ base-10. When it is a @c BIG_FLOAT it is base-2.
+
+ When @c uDataType is a @c POS_BIGNUM or a @c NEG_BIGNUM then the
+ @c bigNum part of @c Mantissa is valid. Otherwise the
+ @c nInt part of @c Mantissa is valid.
+
+ See @ref QCBOR_TYPE_DECIMAL_FRACTION,
+ @ref QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
+ @ref QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM,
+ @ref QCBOR_TYPE_BIGFLOAT, @ref QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
+ and @ref QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM.
+
+ Also see QCBOREncode_AddDecimalFraction(), QCBOREncode_AddBigFloat(),
+ QCBOREncode_AddDecimalFractionBigNum() and
+ QCBOREncode_AddBigFloatBigNum().
+ */
+ struct {
+ int64_t nExponent;
+ union {
+ int64_t nInt;
+ UsefulBufC bigNum;
+ } Mantissa;
+ } expAndMantissa;
+#endif
+ uint64_t uTagV; // Used internally during decoding
+ } val;
+
+ /** Union holding the different label types selected based on @c
+ uLabelType */
+ union {
+ /** The label for @c uLabelType @ref QCBOR_TYPE_BYTE_STRING and
+ @ref QCBOR_TYPE_TEXT_STRING */
+ UsefulBufC string;
+ /** The label for @c uLabelType for @ref QCBOR_TYPE_INT64 */
+ int64_t int64;
+ /** The label for @c uLabelType for @ref QCBOR_TYPE_UINT64 */
+ uint64_t uint64;
+ } label;
+
+ /** Bit indicating which tags (major type 6) on this item. See
+ QCBORDecode_IsTagged(). */
+ uint64_t uTagBits;
+
+} QCBORItem;
+
+
+
+/**
+ @brief The type defining what a string allocator function must do.
+
+ @param[in] pAllocateCxt Pointer to context for the particular
+ allocator implementation What is in the
+ context is dependent on how a particular
+ string allocator works. Typically, it
+ will contain a pointer to the memory pool
+ and some booking keeping data.
+ @param[in] pOldMem Points to some memory allocated by the
+ allocator that is either to be freed or
+ to be reallocated to be larger. It is
+ @c NULL for new allocations and when called as
+ a destructor to clean up the whole
+ allocation.
+ @param[in] uNewSize Size of memory to be allocated or new
+ size of chunk to be reallocated. Zero for
+ a new allocation or when called as a
+ destructor.
+
+ @return Either the allocated buffer is returned, or @ref
+ NULLUsefulBufC. @ref NULLUsefulBufC is returned on a failed
+ allocation and in the two cases where there is nothing to
+ return.
+
+ This is called in one of four modes:
+
+ Allocate -- @c uNewSize is the amount to allocate. @c pOldMem is @c
+ NULL.
+
+ Free -- @c uNewSize is 0. @c pOldMem points to the memory to be
+ freed. When the decoder calls this, it will always be the most
+ recent block that was either allocated or reallocated.
+
+ Reallocate -- @c pOldMem is the block to reallocate. @c uNewSize is
+ its new size. When the decoder calls this, it will always be the
+ most recent block that was either allocated or reallocated.
+
+ Destruct -- @c pOldMem is @c NULL and @c uNewSize is 0. This is called
+ when the decoding is complete by QCBORDecode_Finish(). Usually the
+ strings allocated by a string allocator are in use after the decoding
+ is completed so this usually will not free those strings. Many string
+ allocators will not need to do anything in this mode.
+
+ The strings allocated by this will have @c uDataAlloc set to true in
+ the @ref QCBORItem when they are returned. The user of the strings
+ will have to free them. How they free them, depends on the string
+ allocator.
+
+ If QCBORDecode_SetMemPool() is called, the internal MemPool will be
+ used. It has its own internal implementation of this function, so
+ one does not need to be implemented.
+ */
+typedef UsefulBuf (* QCBORStringAllocate)(void *pAllocateCxt, void *pOldMem, size_t uNewSize);
+
+
+/**
+ This only matters if you use the built-in string allocator by setting
+ it up with QCBORDecode_SetMemPool(). This is the size of the overhead
+ needed by QCBORDecode_SetMemPool(). The amount of memory available
+ for decoded strings will be the size of the buffer given to
+ QCBORDecode_SetMemPool() less this amount.
+
+ If you write your own string allocator or use the separately
+ available malloc based string allocator, this size will not apply.
+ */
+#define QCBOR_DECODE_MIN_MEM_POOL_SIZE 8
+
+
+/**
+ This is used by QCBORDecode_SetCallerConfiguredTagList() to set a
+ list of tags beyond the built-in ones.
+
+ See also QCBORDecode_GetNext() for general description of tag
+ decoding.
+ */
+typedef struct {
+ /** The number of tags in the @c puTags. The maximum size is @ref
+ QCBOR_MAX_CUSTOM_TAGS. */
+ uint8_t uNumTags;
+ /** An array of tags to add to recognize in addition to the
+ built-in ones. */
+ const uint64_t *puTags;
+} QCBORTagListIn;
+
+
+/**
+ This is for QCBORDecode_GetNextWithTags() to be able to return the
+ full list of tags on an item. It is not needed for most CBOR protocol
+ implementations. Its primary use is for pretty-printing CBOR or
+ protocol conversion to another format.
+
+ On input, @c puTags points to a buffer to be filled in and
+ uNumAllocated is the number of @c uint64_t values in the buffer.
+
+ On output the buffer contains the tags for the item. @c uNumUsed
+ tells how many there are.
+ */
+typedef struct {
+ uint8_t uNumUsed;
+ uint8_t uNumAllocated;
+ uint64_t *puTags;
+} QCBORTagListOut;
+
+
+/**
+ QCBOREncodeContext is the data type that holds context for all the
+ encoding functions. It is less than 200 bytes, so it can go on the
+ stack. The contents are opaque, and the caller should not access
+ internal members. A context may be re used serially as long as it is
+ re initialized.
+ */
+typedef struct _QCBOREncodeContext QCBOREncodeContext;
+
+
+/**
+ Initialize the encoder to prepare to encode some CBOR.
+
+ @param[in,out] pCtx The encoder context to initialize.
+ @param[in] Storage The buffer into which this encoded result
+ will be placed.
+
+ Call this once at the start of an encoding of a CBOR structure. Then
+ call the various @c QCBOREncode_AddXxx() functions to add the data
+ items. Then call QCBOREncode_Finish().
+
+ The maximum output buffer is @c UINT32_MAX (4GB). This is not a
+ practical limit in any way and reduces the memory needed by the
+ implementation. The error @ref QCBOR_ERR_BUFFER_TOO_LARGE will be
+ returned by QCBOREncode_Finish() if a larger buffer length is passed
+ in.
+
+ If this is called with @c Storage.ptr as @c NULL and @c Storage.len a
+ large value like @c UINT32_MAX, all the QCBOREncode_AddXxx()
+ functions and QCBOREncode_Finish() can still be called. No data will
+ be encoded, but the length of what would be encoded will be
+ calculated. The length of the encoded structure will be handed back
+ in the call to QCBOREncode_Finish(). You can then allocate a buffer
+ of that size and call all the encoding again, this time to fill in
+ the buffer.
+
+ A @ref QCBOREncodeContext can be reused over and over as long as
+ QCBOREncode_Init() is called.
+ */
+void QCBOREncode_Init(QCBOREncodeContext *pCtx, UsefulBuf Storage);
+
+
+/**
+ @brief Add a signed 64-bit integer to the encoded output.
+
+ @param[in] pCtx The encoding context to add the integer to.
+ @param[in] nNum The integer to add.
+
+ The integer will be encoded and added to the CBOR output.
+
+ This function figures out the size and the sign and encodes in the
+ correct minimal CBOR. Specifically, it will select CBOR major type 0
+ or 1 based on sign and will encode to 1, 2, 4 or 8 bytes depending on
+ the value of the integer. Values less than 24 effectively encode to
+ one byte because they are encoded in with the CBOR major type. This
+ is a neat and efficient characteristic of CBOR that can be taken
+ advantage of when designing CBOR-based protocols. If integers like
+ tags can be kept between -23 and 23 they will be encoded in one byte
+ including the major type.
+
+ If you pass a smaller int, say an @c int16_t or a small value, say
+ 100, the encoding will still be CBOR's most compact that can
+ represent the value. For example, CBOR always encodes the value 0 as
+ one byte, 0x00. The representation as 0x00 includes identification of
+ the type as an integer too as the major type for an integer is 0. See
+ [RFC 7049] (https://tools.ietf.org/html/rfc7049) Appendix A for more
+ examples of CBOR encoding. This compact encoding is also canonical
+ CBOR as per section 3.9 in RFC 7049.
+
+ There are no functions to add @c int16_t or @c int32_t because they
+ are not necessary because this always encodes to the smallest number
+ of bytes based on the value (If this code is running on a 32-bit
+ machine having a way to add 32-bit integers would reduce code size
+ some).
+
+ If the encoding context is in an error state, this will do
+ nothing. If an error occurs when adding this integer, the internal
+ error flag will be set, and the error will be returned when
+ QCBOREncode_Finish() is called.
+
+ See also QCBOREncode_AddUInt64().
+ */
+void QCBOREncode_AddInt64(QCBOREncodeContext *pCtx, int64_t nNum);
+
+static void QCBOREncode_AddInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, int64_t uNum);
+
+static void QCBOREncode_AddInt64ToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, int64_t uNum);
+
+
+/**
+ @brief Add an unsigned 64-bit integer to the encoded output.
+
+ @param[in] pCtx The encoding context to add the integer to.
+ @param[in] uNum The integer to add.
+
+ The integer will be encoded and added to the CBOR output.
+
+ The only reason so use this function is for integers larger than @c
+ INT64_MAX and smaller than @c UINT64_MAX. Otherwise
+ QCBOREncode_AddInt64() will work fine.
+
+ Error handling is the same as for QCBOREncode_AddInt64().
+ */
+void QCBOREncode_AddUInt64(QCBOREncodeContext *pCtx, uint64_t uNum);
+
+static void QCBOREncode_AddUInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, uint64_t uNum);
+
+static void QCBOREncode_AddUInt64ToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, uint64_t uNum);
+
+
+/**
+ @brief Add a UTF-8 text string to the encoded output.
+
+ @param[in] pCtx The encoding context to add the text to.
+ @param[in] Text Pointer and length of text to add.
+
+ The text passed in must be unencoded UTF-8 according to [RFC 3629]
+ (https://tools.ietf.org/html/rfc3629). There is no NULL
+ termination. The text is added as CBOR major type 3.
+
+ If called with @c nBytesLen equal to 0, an empty string will be
+ added. When @c nBytesLen is 0, @c pBytes may be @c NULL.
+
+ Note that the restriction of the buffer length to a @c uint32_t is
+ entirely intentional as this encoder is not capable of encoding
+ lengths greater. This limit to 4GB for a text string should not be a
+ problem.
+
+ Error handling is the same as QCBOREncode_AddInt64().
+ */
+static void QCBOREncode_AddText(QCBOREncodeContext *pCtx, UsefulBufC Text);
+
+static void QCBOREncode_AddTextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Text);
+
+static void QCBOREncode_AddTextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Text);
+
+
+/**
+ @brief Add a UTF-8 text string to the encoded output.
+
+ @param[in] pCtx The encoding context to add the text to.
+ @param[in] szString Null-terminated text to add.
+
+ This works the same as QCBOREncode_AddText().
+ */
+static void QCBOREncode_AddSZString(QCBOREncodeContext *pCtx, const char *szString);
+
+static void QCBOREncode_AddSZStringToMap(QCBOREncodeContext *pCtx, const char *szLabel, const char *szString);
+
+static void QCBOREncode_AddSZStringToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, const char *szString);
+
+
+/**
+ @brief Add a floating-point number to the encoded output.
+
+ @param[in] pCtx The encoding context to add the double to.
+ @param[in] dNum The double-precision number to add.
+
+ This outputs a floating-point number with CBOR major type 7.
+
+ This will selectively encode the double-precision floating-point
+ number as either double-precision, single-precision or
+ half-precision. It will always encode infinity, NaN and 0 has half
+ precision. If no precision will be lost in the conversion to
+ half-precision, then it will be converted and encoded. If not and no
+ precision will be lost in conversion to single-precision, then it
+ will be converted and encoded. If not, then no conversion is
+ performed, and it encoded as a double.
+
+ Half-precision floating-point numbers take up 2 bytes, half that of
+ single-precision, one quarter of double-precision
+
+ This automatically reduces the size of encoded messages a lot, maybe
+ even by four if most of values are 0, infinity or NaN.
+
+ On decode, these will always be returned as a double.
+
+ Error handling is the same as QCBOREncode_AddInt64().
+ */
+void QCBOREncode_AddDouble(QCBOREncodeContext *pCtx, double dNum);
+
+static void QCBOREncode_AddDoubleToMap(QCBOREncodeContext *pCtx, const char *szLabel, double dNum);
+
+static void QCBOREncode_AddDoubleToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, double dNum);
+
+
+/**
+ @brief Add an optional tag.
+
+ @param[in] pCtx The encoding context to add the tag to.
+ @param[in] uTag The tag to add
+
+ This outputs a CBOR major type 6 item that tags the next data item
+ that is output usually to indicate it is some new data type.
+
+ For many of the common standard tags, a function to encode data using
+ it is provided and this is not needed. For example,
+ QCBOREncode_AddDateEpoch() already exists to output integers
+ representing dates with the right tag.
+
+ The tag is applied to the next data item added to the encoded
+ output. That data item that is to be tagged can be of any major CBOR
+ type. Any number of tags can be added to a data item by calling this
+ multiple times before the data item is added.
+
+ See @ref Tags-Overview for discussion of creating new non-standard
+ tags. See QCBORDecode_GetNext() for discussion of decoding custom
+ tags.
+*/
+void QCBOREncode_AddTag(QCBOREncodeContext *pCtx,uint64_t uTag);
+
+
+/**
+ @brief Add an epoch-based date.
+
+ @param[in] pCtx The encoding context to add the date to.
+ @param[in] date Number of seconds since 1970-01-01T00:00Z in UTC time.
+
+ As per RFC 7049 this is similar to UNIX/Linux/POSIX dates. This is
+ the most compact way to specify a date and time in CBOR. Note that
+ this is always UTC and does not include the time zone. Use
+ QCBOREncode_AddDateString() if you want to include the time zone.
+
+ The integer encoding rules apply here so the date will be encoded in
+ a minimal number of bytes. Until about the year 2106 these dates will
+ encode in 6 bytes -- one byte for the tag, one byte for the type and
+ 4 bytes for the integer. After that it will encode to 10 bytes.
+
+ Negative values are supported for dates before 1970.
+
+ If you care about leap-seconds and that level of accuracy, make sure
+ the system you are running this code on does it correctly. This code
+ just takes the value passed in.
+
+ This implementation cannot encode fractional seconds using float or
+ double even though that is allowed by CBOR, but you can encode them
+ if you want to by calling QCBOREncode_AddDouble() and
+ QCBOREncode_AddTag().
+
+ Error handling is the same as QCBOREncode_AddInt64().
+ */
+static void QCBOREncode_AddDateEpoch(QCBOREncodeContext *pCtx, int64_t date);
+
+static void QCBOREncode_AddDateEpochToMap(QCBOREncodeContext *pCtx, const char *szLabel, int64_t date);
+
+static void QCBOREncode_AddDateEpochToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, int64_t date);
+
+
+/**
+ @brief Add a byte string to the encoded output.
+
+ @param[in] pCtx The encoding context to add the bytes to.
+ @param[in] Bytes Pointer and length of the input data.
+
+ Simply adds the bytes to the encoded output as CBOR major type 2.
+
+ If called with @c Bytes.len equal to 0, an empty string will be
+ added. When @c Bytes.len is 0, @c Bytes.ptr may be @c NULL.
+
+ Error handling is the same as QCBOREncode_AddInt64().
+ */
+static void QCBOREncode_AddBytes(QCBOREncodeContext *pCtx, UsefulBufC Bytes);
+
+static void QCBOREncode_AddBytesToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes);
+
+static void QCBOREncode_AddBytesToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes);
+
+
+
+/**
+ @brief Add a binary UUID to the encoded output.
+
+ @param[in] pCtx The encoding context to add the UUID to.
+ @param[in] Bytes Pointer and length of the binary UUID.
+
+ A binary UUID as defined in [RFC 4122]
+ (https://tools.ietf.org/html/rfc4122) is added to the output.
+
+ It is output as CBOR major type 2, a binary string, with tag @ref
+ CBOR_TAG_BIN_UUID indicating the binary string is a UUID.
+ */
+static void QCBOREncode_AddBinaryUUID(QCBOREncodeContext *pCtx, UsefulBufC Bytes);
+
+static void QCBOREncode_AddBinaryUUIDToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes);
+
+static void QCBOREncode_AddBinaryUUIDToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes);
+
+
+/**
+ @brief Add a positive big number to the encoded output.
+
+ @param[in] pCtx The encoding context to add the big number to.
+ @param[in] Bytes Pointer and length of the big number.
+
+ Big numbers are integers larger than 64-bits. Their format is
+ described in [RFC 7049] (https://tools.ietf.org/html/rfc7049).
+
+ It is output as CBOR major type 2, a binary string, with tag @ref
+ CBOR_TAG_POS_BIGNUM indicating the binary string is a positive big
+ number.
+
+ Often big numbers are used to represent cryptographic keys, however,
+ COSE which defines representations for keys chose not to use this
+ particular type.
+ */
+static void QCBOREncode_AddPositiveBignum(QCBOREncodeContext *pCtx, UsefulBufC Bytes);
+
+static void QCBOREncode_AddPositiveBignumToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes);
+
+static void QCBOREncode_AddPositiveBignumToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes);
+
+
+/**
+ @brief Add a negative big number to the encoded output.
+
+ @param[in] pCtx The encoding context to add the big number to.
+ @param[in] Bytes Pointer and length of the big number.
+
+ Big numbers are integers larger than 64-bits. Their format is
+ described in [RFC 7049] (https://tools.ietf.org/html/rfc7049).
+
+ It is output as CBOR major type 2, a binary string, with tag @ref
+ CBOR_TAG_NEG_BIGNUM indicating the binary string is a negative big
+ number.
+
+ Often big numbers are used to represent cryptographic keys, however,
+ COSE which defines representations for keys chose not to use this
+ particular type.
+ */
+static void QCBOREncode_AddNegativeBignum(QCBOREncodeContext *pCtx, UsefulBufC Bytes);
+
+static void QCBOREncode_AddNegativeBignumToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes);
+
+static void QCBOREncode_AddNegativeBignumToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes);
+
+
+#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+/**
+ @brief Add a decimal fraction to the encoded output.
+
+ @param[in] pCtx The encoding context to add the decimal fraction to.
+ @param[in] nMantissa The mantissa.
+ @param[in] nBase10Exponent The exponent.
+
+ The value is nMantissa * 10 ^ nBase10Exponent.
+
+ A decimal fraction is good for exact representation of some values
+ that can't be represented exactly with standard C (IEEE 754)
+ floating-point numbers. Much larger and much smaller numbers can
+ also be represented than floating-point because of the larger number
+ of bits in the exponent.
+
+ The decimal fraction is conveyed as two integers, a mantissa and a
+ base-10 scaling factor.
+
+ For example, 273.15 is represented by the two integers 27315 and -2.
+
+ The exponent and mantissa have the range from @c INT64_MIN to
+ @c INT64_MAX for both encoding and decoding (CBOR allows @c -UINT64_MAX
+ to @c UINT64_MAX, but this implementation doesn't support this range to
+ reduce code size and interface complexity a little).
+
+ CBOR Preferred encoding of the integers is used, thus they will be encoded
+ in the smallest number of bytes possible.
+
+ See also QCBOREncode_AddDecimalFractionBigNum() for a decimal
+ fraction with arbitrarily large precision and QCBOREncode_AddBigFloat().
+
+ There is no representation of positive or negative infinity or NaN
+ (Not a Number). Use QCBOREncode_AddDouble() to encode them.
+
+ See @ref expAndMantissa for decoded representation.
+ */
+static void QCBOREncode_AddDecimalFraction(QCBOREncodeContext *pCtx,
+ int64_t nMantissa,
+ int64_t nBase10Exponent);
+
+static void QCBOREncode_AddDecimalFractionToMap(QCBOREncodeContext *pCtx,
+ const char *szLabel,
+ int64_t nMantissa,
+ int64_t nBase10Exponent);
+
+static void QCBOREncode_AddDecimalFractionToMapN(QCBOREncodeContext *pCtx,
+ int64_t nLabel,
+ int64_t nMantissa,
+ int64_t nBase10Exponent);
+
+/**
+ @brief Add a decimal fraction with a big number mantissa to the encoded output.
+
+ @param[in] pCtx The encoding context to add the decimal fraction to.
+ @param[in] Mantissa The mantissa.
+ @param[in] bIsNegative false if mantissa is positive, true if negative.
+ @param[in] nBase10Exponent The exponent.
+
+ This is the same as QCBOREncode_AddDecimalFraction() except the
+ mantissa is a big number (See QCBOREncode_AddPositiveBignum())
+ allowing for arbitrarily large precision.
+
+ See @ref expAndMantissa for decoded representation.
+ */
+static void QCBOREncode_AddDecimalFractionBigNum(QCBOREncodeContext *pCtx,
+ UsefulBufC Mantissa,
+ bool bIsNegative,
+ int64_t nBase10Exponent);
+
+static void QCBOREncode_AddDecimalFractionBigNumToMap(QCBOREncodeContext *pCtx,
+ const char *szLabel,
+ UsefulBufC Mantissa,
+ bool bIsNegative,
+ int64_t nBase10Exponent);
+
+static void QCBOREncode_AddDecimalFractionBigNumToMapN(QCBOREncodeContext *pCtx,
+ int64_t nLabel,
+ UsefulBufC Mantissa,
+ bool bIsNegative,
+ int64_t nBase10Exponent);
+
+/**
+ @brief Add a big floating-point number to the encoded output.
+
+ @param[in] pCtx The encoding context to add the bigfloat to.
+ @param[in] nMantissa The mantissa.
+ @param[in] nBase2Exponent The exponent.
+
+ The value is nMantissa * 2 ^ nBase2Exponent.
+
+ "Bigfloats", as CBOR terms them, are similar to IEEE floating-point
+ numbers in having a mantissa and base-2 exponent, but they are not
+ supported by hardware or encoded the same. They explicitly use two
+ CBOR-encoded integers to convey the mantissa and exponent, each of which
+ can be 8, 16, 32 or 64 bits. With both the mantissa and exponent
+ 64 bits they can express more precision and a larger range than an
+ IEEE double floating-point number. See
+ QCBOREncode_AddBigFloatBigNum() for even more precision.
+
+ For example, 1.5 would be represented by a mantissa of 3 and an
+ exponent of -1.
+
+ The exponent and mantissa have the range from @c INT64_MIN to
+ @c INT64_MAX for both encoding and decoding (CBOR allows @c -UINT64_MAX
+ to @c UINT64_MAX, but this implementation doesn't support this range to
+ reduce code size and interface complexity a little).
+
+ CBOR Preferred encoding of the integers is used, thus they will be encoded
+ in the smallest number of bytes possible.
+
+ This can also be used to represent floating-point numbers in
+ environments that don't support IEEE 754.
+
+ See @ref expAndMantissa for decoded representation.
+ */
+static void QCBOREncode_AddBigFloat(QCBOREncodeContext *pCtx,
+ int64_t nMantissa,
+ int64_t nBase2Exponent);
+
+static void QCBOREncode_AddBigFloatToMap(QCBOREncodeContext *pCtx,
+ const char *szLabel,
+ int64_t nMantissa,
+ int64_t nBase2Exponent);
+
+static void QCBOREncode_AddBigFloatToMapN(QCBOREncodeContext *pCtx,
+ int64_t nLabel,
+ int64_t nMantissa,
+ int64_t nBase2Exponent);
+
+
+/**
+ @brief Add a big floating-point number with a big number mantissa to
+ the encoded output.
+
+ @param[in] pCtx The encoding context to add the bigfloat to.
+ @param[in] Mantissa The mantissa.
+ @param[in] bIsNegative false if mantissa is positive, true if negative.
+ @param[in] nBase2Exponent The exponent.
+
+ This is the same as QCBOREncode_AddBigFloat() except the mantissa is
+ a big number (See QCBOREncode_AddPositiveBignum()) allowing for
+ arbitrary precision.
+
+ See @ref expAndMantissa for decoded representation.
+ */
+static void QCBOREncode_AddBigFloatBigNum(QCBOREncodeContext *pCtx,
+ UsefulBufC Mantissa,
+ bool bIsNegative,
+ int64_t nBase2Exponent);
+
+static void QCBOREncode_AddBigFloatBigNumToMap(QCBOREncodeContext *pCtx,
+ const char *szLabel,
+ UsefulBufC Mantissa,
+ bool bIsNegative,
+ int64_t nBase2Exponent);
+
+static void QCBOREncode_AddBigFloatBigNumToMapN(QCBOREncodeContext *pCtx,
+ int64_t nLabel,
+ UsefulBufC Mantissa,
+ bool bIsNegative,
+ int64_t nBase2Exponent);
+#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+
+
+/**
+ @brief Add a text URI to the encoded output.
+
+ @param[in] pCtx The encoding context to add the URI to.
+ @param[in] URI Pointer and length of the URI.
+
+ The format of URI must be per [RFC 3986]
+ (https://tools.ietf.org/html/rfc3986).
+
+ It is output as CBOR major type 3, a text string, with tag @ref
+ CBOR_TAG_URI indicating the text string is a URI.
+
+ A URI in a NULL-terminated string, @c szURI, can be easily added with
+ this code:
+
+ QCBOREncode_AddURI(pCtx, UsefulBuf_FromSZ(szURI));
+ */
+static void QCBOREncode_AddURI(QCBOREncodeContext *pCtx, UsefulBufC URI);
+
+static void QCBOREncode_AddURIToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC URI);
+
+static void QCBOREncode_AddURIToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC URI);
+
+
+/**
+ @brief Add Base64-encoded text to encoded output.
+
+ @param[in] pCtx The encoding context to add the base-64 text to.
+ @param[in] B64Text Pointer and length of the base-64 encoded text.
+
+ The text content is Base64 encoded data per [RFC 4648]
+ (https://tools.ietf.org/html/rfc4648).
+
+ It is output as CBOR major type 3, a text string, with tag @ref
+ CBOR_TAG_B64 indicating the text string is Base64 encoded.
+ */
+static void QCBOREncode_AddB64Text(QCBOREncodeContext *pCtx, UsefulBufC B64Text);
+
+static void QCBOREncode_AddB64TextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC B64Text);
+
+static void QCBOREncode_AddB64TextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC B64Text);
+
+
+/**
+ @brief Add base64url encoded data to encoded output.
+
+ @param[in] pCtx The encoding context to add the base64url to.
+ @param[in] B64Text Pointer and length of the base64url encoded text.
+
+ The text content is base64URL encoded text as per [RFC 4648]
+ (https://tools.ietf.org/html/rfc4648).
+
+ It is output as CBOR major type 3, a text string, with tag @ref
+ CBOR_TAG_B64URL indicating the text string is a Base64url encoded.
+ */
+static void QCBOREncode_AddB64URLText(QCBOREncodeContext *pCtx, UsefulBufC B64Text);
+
+static void QCBOREncode_AddB64URLTextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC B64Text);
+
+static void QCBOREncode_AddB64URLTextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC B64Text);
+
+
+/**
+ @brief Add Perl Compatible Regular Expression.
+
+ @param[in] pCtx The encoding context to add the regular expression to.
+ @param[in] Regex Pointer and length of the regular expression.
+
+ The text content is Perl Compatible Regular
+ Expressions (PCRE) / JavaScript syntax [ECMA262].
+
+ It is output as CBOR major type 3, a text string, with tag @ref
+ CBOR_TAG_REGEX indicating the text string is a regular expression.
+ */
+static void QCBOREncode_AddRegex(QCBOREncodeContext *pCtx, UsefulBufC Regex);
+
+static void QCBOREncode_AddRegexToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Regex);
+
+static void QCBOREncode_AddRegexToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Regex);
+
+
+/**
+ @brief MIME encoded text to the encoded output.
+
+ @param[in] pCtx The encoding context to add the MIME data to.
+ @param[in] MIMEData Pointer and length of the regular expression.
+
+ The text content is in MIME format per [RFC 2045]
+ (https://tools.ietf.org/html/rfc2045) including the headers. Note
+ that this only supports text-format MIME. Binary MIME is not
+ supported.
+
+ It is output as CBOR major type 3, a text string, with tag
+ @ref CBOR_TAG_MIME indicating the text string is MIME data.
+ */
+static void QCBOREncode_AddMIMEData(QCBOREncodeContext *pCtx, UsefulBufC MIMEData);
+
+static void QCBOREncode_AddMIMEDataToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC MIMEData);
+
+static void QCBOREncode_AddMIMEDataToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC MIMEData);
+
+
+/**
+ @brief Add an RFC 3339 date string
+
+ @param[in] pCtx The encoding context to add the date to.
+ @param[in] szDate Null-terminated string with date to add.
+
+ The string szDate should be in the form of [RFC 3339]
+ (https://tools.ietf.org/html/rfc3339) as defined by section 3.3 in
+ [RFC 4287] (https://tools.ietf.org/html/rfc4287). This is as
+ described in section 2.4.1 in [RFC 7049]
+ (https://tools.ietf.org/html/rfc7049).
+
+ Note that this function doesn't validate the format of the date string
+ at all. If you add an incorrect format date string, the generated
+ CBOR will be incorrect and the receiver may not be able to handle it.
+
+ Error handling is the same as QCBOREncode_AddInt64().
+ */
+static void QCBOREncode_AddDateString(QCBOREncodeContext *pCtx, const char *szDate);
+
+static void QCBOREncode_AddDateStringToMap(QCBOREncodeContext *pCtx, const char *szLabel, const char *szDate);
+
+static void QCBOREncode_AddDateStringToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, const char *szDate);
+
+
+/**
+ @brief Add a standard Boolean.
+
+ @param[in] pCtx The encoding context to add the Boolean to.
+ @param[in] b true or false from @c <stdbool.h>.
+
+ Adds a Boolean value as CBOR major type 7.
+
+ Error handling is the same as QCBOREncode_AddInt64().
+ */
+static void QCBOREncode_AddBool(QCBOREncodeContext *pCtx, bool b);
+
+static void QCBOREncode_AddBoolToMap(QCBOREncodeContext *pCtx, const char *szLabel, bool b);
+
+static void QCBOREncode_AddBoolToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, bool b);
+
+
+
+/**
+ @brief Add a NULL to the encoded output.
+
+ @param[in] pCtx The encoding context to add the NULL to.
+
+ Adds the NULL value as CBOR major type 7.
+
+ This NULL doesn't have any special meaning in CBOR such as a
+ terminating value for a string or an empty value.
+
+ Error handling is the same as QCBOREncode_AddInt64().
+ */
+static void QCBOREncode_AddNULL(QCBOREncodeContext *pCtx);
+
+static void QCBOREncode_AddNULLToMap(QCBOREncodeContext *pCtx, const char *szLabel);
+
+static void QCBOREncode_AddNULLToMapN(QCBOREncodeContext *pCtx, int64_t nLabel);
+
+
+/**
+ @brief Add an "undef" to the encoded output.
+
+ @param[in] pCtx The encoding context to add the "undef" to.
+
+ Adds the undef value as CBOR major type 7.
+
+ Note that this value will not translate to JSON.
+
+ This Undef doesn't have any special meaning in CBOR such as a
+ terminating value for a string or an empty value.
+
+ Error handling is the same as QCBOREncode_AddInt64().
+ */
+static void QCBOREncode_AddUndef(QCBOREncodeContext *pCtx);
+
+static void QCBOREncode_AddUndefToMap(QCBOREncodeContext *pCtx, const char *szLabel);
+
+static void QCBOREncode_AddUndefToMapN(QCBOREncodeContext *pCtx, int64_t nLabel);
+
+
+/**
+ @brief Indicates that the next items added are in an array.
+
+ @param[in] pCtx The encoding context to open the array in.
+
+ Arrays are the basic CBOR aggregate or structure type. Call this
+ function to start or open an array. Then call the various @c
+ QCBOREncode_AddXxx() functions to add the items that go into the
+ array. Then call QCBOREncode_CloseArray() when all items have been
+ added. The data items in the array can be of any type and can be of
+ mixed types.
+
+ Nesting of arrays and maps is allowed and supported just by calling
+ QCBOREncode_OpenArray() again before calling
+ QCBOREncode_CloseArray(). While CBOR has no limit on nesting, this
+ implementation does in order to keep it smaller and simpler. The
+ limit is @ref QCBOR_MAX_ARRAY_NESTING. This is the max number of
+ times this can be called without calling
+ QCBOREncode_CloseArray(). QCBOREncode_Finish() will return @ref
+ QCBOR_ERR_ARRAY_NESTING_TOO_DEEP when it is called as this function
+ just sets an error state and returns no value when this occurs.
+
+ If you try to add more than @ref QCBOR_MAX_ITEMS_IN_ARRAY items to a
+ single array or map, @ref QCBOR_ERR_ARRAY_TOO_LONG will be returned
+ when QCBOREncode_Finish() is called.
+
+ An array itself must have a label if it is being added to a map.
+ Note that array elements do not have labels (but map elements do).
+
+ An array itself may be tagged by calling QCBOREncode_AddTag() before this call.
+ */
+static void QCBOREncode_OpenArray(QCBOREncodeContext *pCtx);
+
+static void QCBOREncode_OpenArrayInMap(QCBOREncodeContext *pCtx, const char *szLabel);
+
+static void QCBOREncode_OpenArrayInMapN(QCBOREncodeContext *pCtx, int64_t nLabel);
+
+
+/**
+ @brief Close an open array.
+
+ @param[in] pCtx The encoding context to close the array in.
+
+ The closes an array opened by QCBOREncode_OpenArray(). It reduces
+ nesting level by one. All arrays (and maps) must be closed before
+ calling QCBOREncode_Finish().
+
+ When an error occurs as a result of this call, the encoder records
+ the error and enters the error state. The error will be returned when
+ QCBOREncode_Finish() is called.
+
+ If this has been called more times than QCBOREncode_OpenArray(), then
+ @ref QCBOR_ERR_TOO_MANY_CLOSES will be returned when QCBOREncode_Finish()
+ is called.
+
+ If this is called and it is not an array that is currently open, @ref
+ QCBOR_ERR_CLOSE_MISMATCH will be returned when QCBOREncode_Finish()
+ is called.
+ */
+static void QCBOREncode_CloseArray(QCBOREncodeContext *pCtx);
+
+
+/**
+ @brief Indicates that the next items added are in a map.
+
+ @param[in] pCtx The encoding context to open the map in.
+
+ See QCBOREncode_OpenArray() for more information, particularly error
+ handling.
+
+ CBOR maps are an aggregate type where each item in the map consists
+ of a label and a value. They are similar to JSON objects.
+
+ The value can be any CBOR type including another map.
+
+ The label can also be any CBOR type, but in practice they are
+ typically, integers as this gives the most compact output. They might
+ also be text strings which gives readability and translation to JSON.
+
+ Every @c QCBOREncode_AddXxx() call has one version that ends with @c
+ InMap for adding items to maps with string labels and one that ends
+ with @c InMapN that is for adding with integer labels.
+
+ RFC 7049 uses the term "key" instead of "label".
+
+ If you wish to use map labels that are neither integer labels nor
+ text strings, then just call the QCBOREncode_AddXxx() function
+ explicitly to add the label. Then call it again to add the value.
+
+ See the [RFC 7049] (https://tools.ietf.org/html/rfc7049) for a lot
+ more information on creating maps.
+ */
+static void QCBOREncode_OpenMap(QCBOREncodeContext *pCtx);
+
+static void QCBOREncode_OpenMapInMap(QCBOREncodeContext *pCtx, const char *szLabel);
+
+static void QCBOREncode_OpenMapInMapN(QCBOREncodeContext *pCtx, int64_t nLabel);
+
+
+
+/**
+ @brief Close an open map.
+
+ @param[in] pCtx The encoding context to close the map in .
+
+ This closes a map opened by QCBOREncode_OpenMap(). It reduces nesting
+ level by one.
+
+ When an error occurs as a result of this call, the encoder records
+ the error and enters the error state. The error will be returned when
+ QCBOREncode_Finish() is called.
+
+ If this has been called more times than QCBOREncode_OpenMap(),
+ then @ref QCBOR_ERR_TOO_MANY_CLOSES will be returned when
+ QCBOREncode_Finish() is called.
+
+ If this is called and it is not a map that is currently open, @ref
+ QCBOR_ERR_CLOSE_MISMATCH will be returned when QCBOREncode_Finish()
+ is called.
+ */
+static void QCBOREncode_CloseMap(QCBOREncodeContext *pCtx);
+
+
+/**
+ @brief Indicate start of encoded CBOR to be wrapped in a bstr.
+
+ @param[in] pCtx The encoding context to open the bstr-wrapped CBOR in.
+
+ All added encoded items between this call and a call to
+ QCBOREncode_CloseBstrWrap2() will be wrapped in a bstr. They will
+ appear in the final output as a byte string. That byte string will
+ contain encoded CBOR. This increases nesting level by one.
+
+ The typical use case is for encoded CBOR that is to be
+ cryptographically hashed, as part of a [RFC 8152, COSE]
+ (https://tools.ietf.org/html/rfc8152) implementation.
+
+ Using QCBOREncode_BstrWrap() and QCBOREncode_CloseBstrWrap2() avoids
+ having to encode the items first in one buffer (e.g., the COSE
+ payload) and then add that buffer as a bstr to another encoding
+ (e.g. the COSE to-be-signed bytes, the @c Sig_structure) potentially
+ halving the memory needed.
+
+ RFC 7049 states the purpose of this wrapping is to prevent code
+ relaying the signed data but not verifying it from tampering with the
+ signed data thus making the signature unverifiable. It is also quite
+ beneficial for the signature verification code. Standard CBOR
+ decoders usually do not give access to partially decoded CBOR as
+ would be needed to check the signature of some CBOR. With this
+ wrapping, standard CBOR decoders can be used to get to all the data
+ needed for a signature verification.
+ */
+static void QCBOREncode_BstrWrap(QCBOREncodeContext *pCtx);
+
+static void QCBOREncode_BstrWrapInMap(QCBOREncodeContext *pCtx, const char *szLabel);
+
+static void QCBOREncode_BstrWrapInMapN(QCBOREncodeContext *pCtx, int64_t nLabel);
+
+
+/**
+ @brief Close a wrapping bstr.
+
+ @param[in] pCtx The encoding context to close of bstr wrapping in.
+ @param[in] bIncludeCBORHead Include the encoded CBOR head of the bstr
+ as well as the bytes in @c pWrappedCBOR.
+ @param[out] pWrappedCBOR A @ref UsefulBufC containing wrapped bytes.
+
+ The closes a wrapping bstr opened by QCBOREncode_BstrWrap(). It reduces
+ nesting level by one.
+
+ A pointer and length of the enclosed encoded CBOR is returned in @c
+ *pWrappedCBOR if it is not @c NULL. The main purpose of this is so
+ this data can be hashed (e.g., with SHA-256) as part of a [RFC 8152,
+ COSE] (https://tools.ietf.org/html/rfc8152)
+ implementation. **WARNING**, this pointer and length should be used
+ right away before any other calls to @c QCBOREncode_CloseXxx() as
+ they will move data around and the pointer and length will no longer
+ be to the correct encoded CBOR.
+
+ When an error occurs as a result of this call, the encoder records
+ the error and enters the error state. The error will be returned when
+ QCBOREncode_Finish() is called.
+
+ If this has been called more times than QCBOREncode_BstrWrap(), then
+ @ref QCBOR_ERR_TOO_MANY_CLOSES will be returned when
+ QCBOREncode_Finish() is called.
+
+ If this is called and it is not a wrapping bstr that is currently
+ open, @ref QCBOR_ERR_CLOSE_MISMATCH will be returned when
+ QCBOREncode_Finish() is called.
+
+ QCBOREncode_CloseBstrWrap() is a deprecated version of this function
+ that is equivalent to the call with @c bIncludeCBORHead @c true.
+ */
+void QCBOREncode_CloseBstrWrap2(QCBOREncodeContext *pCtx, bool bIncludeCBORHead, UsefulBufC *pWrappedCBOR);
+
+static void QCBOREncode_CloseBstrWrap(QCBOREncodeContext *pCtx, UsefulBufC *pWrappedCBOR);
+
+
+/**
+ @brief Add some already-encoded CBOR bytes.
+
+ @param[in] pCtx The encoding context to add the already-encode CBOR to.
+ @param[in] Encoded The already-encoded CBOR to add to the context.
+
+ The encoded CBOR being added must be fully conforming CBOR. It must
+ be complete with no arrays or maps that are incomplete. While this
+ encoder doesn't ever produce indefinite lengths, it is OK for the
+ raw CBOR added here to have indefinite lengths.
+
+ The raw CBOR added here is not checked in anyway. If it is not
+ conforming or has open arrays or such, the final encoded CBOR
+ will probably be wrong or not what was intended.
+
+ If the encoded CBOR being added here contains multiple items, they
+ must be enclosed in a map or array. At the top level the raw
+ CBOR must be a single data item.
+ */
+static void QCBOREncode_AddEncoded(QCBOREncodeContext *pCtx, UsefulBufC Encoded);
+
+static void QCBOREncode_AddEncodedToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Encoded);
+
+static void QCBOREncode_AddEncodedToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Encoded);
+
+
+/**
+ @brief Get the encoded result.
+
+ @param[in] pCtx The context to finish encoding with.
+ @param[out] pEncodedCBOR Pointer and length of encoded CBOR.
+
+ @retval QCBOR_ERR_TOO_MANY_CLOSES Nesting error
+
+ @retval QCBOR_ERR_CLOSE_MISMATCH Nesting error
+
+ @retval QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN Nesting error
+
+ @retval QCBOR_ERR_BUFFER_TOO_LARGE Encoded output buffer size
+
+ @retval QCBOR_ERR_BUFFER_TOO_SMALL Encoded output buffer size
+
+ @retval QCBOR_ERR_ARRAY_NESTING_TOO_DEEP Implementation limit
+
+ @retval QCBOR_ERR_ARRAY_TOO_LONG Implementation limit
+
+ If this returns success @ref QCBOR_SUCCESS the encoding was a success
+ and the return length is correct and complete.
+
+ If no buffer was passed to QCBOREncode_Init(), then only the length
+ was computed. If a buffer was passed, then the encoded CBOR is in the
+ buffer.
+
+ Encoding errors primarily manifest here as most other encoding function
+ do no return an error. They just set the error state in the encode
+ context after which no encoding function does anything.
+
+ Three types of errors manifest here. The first type are nesting
+ errors where the number of @c QCBOREncode_OpenXxx() calls do not
+ match the number @c QCBOREncode_CloseXxx() calls. The solution is to
+ fix the calling code.
+
+ The second type of error is because the buffer given is either too
+ small or too large. The remedy is to give a correctly sized buffer.
+
+ The third type are due to limits in this implementation. @ref
+ QCBOR_ERR_ARRAY_NESTING_TOO_DEEP can be worked around by encoding the
+ CBOR in two (or more) phases and adding the CBOR from the first phase
+ to the second with @c QCBOREncode_AddEncoded().
+
+ If an error is returned, the buffer may have partially encoded
+ incorrect CBOR in it and it should not be used. Likewise, the length
+ may be incorrect and should not be used.
+
+ Note that the error could have occurred in one of the many @c
+ QCBOREncode_AddXxx() calls long before QCBOREncode_Finish() was
+ called. This error handling reduces the CBOR implementation size but
+ makes debugging harder.
+
+ This may be called multiple times. It will always return the same. It
+ can also be interleaved with calls to QCBOREncode_FinishGetSize().
+
+ QCBOREncode_GetErrorState() can be called to get the current
+ error state and abort encoding early as an optimization, but is
+ is never required.
+ */
+QCBORError QCBOREncode_Finish(QCBOREncodeContext *pCtx, UsefulBufC *pEncodedCBOR);
+
+
+/**
+ @brief Get the encoded CBOR and error status.
+
+ @param[in] pCtx The context to finish encoding with.
+ @param[out] uEncodedLen The length of the encoded or potentially
+ encoded CBOR in bytes.
+
+ @return The same errors as QCBOREncode_Finish().
+
+ This functions the same as QCBOREncode_Finish(), but only returns the
+ size of the encoded output.
+ */
+QCBORError QCBOREncode_FinishGetSize(QCBOREncodeContext *pCtx, size_t *uEncodedLen);
+
+
+/**
+ @brief Indicate whether output buffer is NULL or not.
+
+ @param[in] pCtx The encoding context.
+
+ @return 1 if the output buffer is @c NULL.
+
+ Sometimes a @c NULL input buffer is given to QCBOREncode_Init() so
+ that the size of the generated CBOR can be calculated without
+ allocating a buffer for it. This returns 1 when the output buffer is
+ NULL and 0 when it is not.
+*/
+static int QCBOREncode_IsBufferNULL(QCBOREncodeContext *pCtx);
+
+ /**
+ @brief Get the encoding error state.
+
+ @param[in] pCtx The encoding context.
+
+ @return One of \ref QCBORError. See return values from
+ QCBOREncode_Finish()
+
+ Normally encoding errors need only be handled at the end of encoding
+ when QCBOREncode_Finish() is called. This can be called to get the
+ error result before finish should there be a need to halt encoding
+ before QCBOREncode_Finish() is called.
+*/
+static QCBORError QCBOREncode_GetErrorState(QCBOREncodeContext *pCtx);
+
+
+/**
+ Encode the "head" of a CBOR data item.
+
+ @param buffer Buffer to output the encoded head to; must be
+ @ref QCBOR_HEAD_BUFFER_SIZE bytes in size.
+ @param uMajorType One of CBOR_MAJOR_TYPE_XX.
+ @param uMinLen The minimum number of bytes to encode uNumber. Almost always
+ this is 0 to use preferred minimal encoding. If this is 4,
+ then even the values 0xffff and smaller will be encoded
+ as in 4 bytes. This is used primarily when encoding a
+ float or double put into uNumber as the leading zero bytes
+ for them must be encoded.
+ @param uNumber The numeric argument part of the CBOR head.
+ @return Pointer and length of the encoded head or
+ @NULLUsefulBufC if the output buffer is too small.
+
+ Callers to need to call this for normal CBOR encoding. Note that it doesn't even
+ take a @ref QCBOREncodeContext argument.
+
+ This encodes the major type and argument part of a data item. The
+ argument is an integer that is usually either the value or the length
+ of the data item.
+
+ This is exposed in the public interface to allow hashing of some CBOR
+ data types, bstr in particular, a chunk at a time so the full CBOR
+ doesn't have to be encoded in a contiguous buffer.
+
+ For example, if you have a 100,000 byte binary blob in a buffer that
+ needs to be a bstr encoded and then hashed. You could allocate a
+ 100,010 byte buffer and encode it normally. Alternatively, you can
+ encode the head in a 10 byte buffer with this function, hash that and
+ then hash the 100,000 bytes using the same hash context.
+
+ See also QCBOREncode_AddBytesLenOnly();
+ */
+UsefulBufC QCBOREncode_EncodeHead(UsefulBuf buffer,
+ uint8_t uMajorType,
+ uint8_t uMinLen,
+ uint64_t uNumber);
+
+
+/**
+ QCBORDecodeContext is the data type that holds context decoding the
+ data items for some received CBOR. It is about 100 bytes, so it can
+ go on the stack. The contents are opaque, and the caller should not
+ access any internal items. A context may be re used serially as long
+ as it is re initialized.
+ */
+typedef struct _QCBORDecodeContext QCBORDecodeContext;
+
+
+/**
+ Initialize the CBOR decoder context.
+
+ @param[in] pCtx The context to initialize.
+ @param[in] EncodedCBOR The buffer with CBOR encoded bytes to be decoded.
+ @param[in] nMode See below and @ref QCBORDecodeMode.
+
+ Initialize context for a pre-order traversal of the encoded CBOR
+ tree.
+
+ Most CBOR decoding can be completed by calling this function to start
+ and QCBORDecode_GetNext() in a loop.
+
+ If indefinite-length strings are to be decoded, then
+ QCBORDecode_SetMemPool() or QCBORDecode_SetUpAllocator() must be
+ called to set up a string allocator.
+
+ If tags other than built-in tags are to be recognized and recorded in
+ @c uTagBits, then QCBORDecode_SetCallerConfiguredTagList() must be
+ called. The built-in tags are those for which a macro of the form @c
+ CBOR_TAG_XXX is defined.
+
+ Three decoding modes are supported. In normal mode, @ref
+ QCBOR_DECODE_MODE_NORMAL, maps are decoded and strings and integers
+ are accepted as map labels. If a label is other than these, the error
+ @ref QCBOR_ERR_MAP_LABEL_TYPE is returned by QCBORDecode_GetNext().
+
+ In strings-only mode, @ref QCBOR_DECODE_MODE_MAP_STRINGS_ONLY, only
+ text strings are accepted for map labels. This lines up with CBOR
+ that converts to JSON. The error @ref QCBOR_ERR_MAP_LABEL_TYPE is
+ returned by QCBORDecode_GetNext() if anything but a text string label
+ is encountered.
+
+ In @ref QCBOR_DECODE_MODE_MAP_AS_ARRAY maps are treated as special
+ arrays. They will be return with special @c uDataType @ref
+ QCBOR_TYPE_MAP_AS_ARRAY and @c uCount, the number of items, will be
+ double what it would be for a normal map because the labels are also
+ counted. This mode is useful for decoding CBOR that has labels that
+ are not integers or text strings, but the caller must manage much of
+ the map decoding.
+ */
+void QCBORDecode_Init(QCBORDecodeContext *pCtx, UsefulBufC EncodedCBOR, QCBORDecodeMode nMode);
+
+
+/**
+ @brief Set up the MemPool string allocator for indefinite-length strings.
+
+ @param[in] pCtx The decode context.
+ @param[in] MemPool The pointer and length of the memory pool.
+ @param[in] bAllStrings If true, all strings, even of definite
+ length, will be allocated with the string
+ allocator.
+
+ @return Error if the MemPool was less than @ref QCBOR_DECODE_MIN_MEM_POOL_SIZE.
+
+ indefinite-length strings (text and byte) cannot be decoded unless
+ there is a string allocator configured. MemPool is a simple built-in
+ string allocator that allocates bytes from a memory pool handed to it
+ by calling this function. The memory pool is just a pointer and
+ length for some block of memory that is to be used for string
+ allocation. It can come from the stack, heap or other.
+
+ The memory pool must be @ref QCBOR_DECODE_MIN_MEM_POOL_SIZE plus
+ space for all the strings allocated. There is no overhead per string
+ allocated. A conservative way to size this buffer is to make it the
+ same size as the CBOR being decoded plus @ref
+ QCBOR_DECODE_MIN_MEM_POOL_SIZE.
+
+ This memory pool is used for all indefinite-length strings that are
+ text strings or byte strings, including strings used as labels.
+
+ The pointers to strings in @ref QCBORItem will point into the memory
+ pool set here. They do not need to be individually freed. Just
+ discard the buffer when they are no longer needed.
+
+ If @c bAllStrings is set, then the size will be the overhead plus the
+ space to hold **all** strings, definite and indefinite-length, value
+ or label. The advantage of this is that after the decode is complete,
+ the original memory holding the encoded CBOR does not need to remain
+ valid.
+
+ If this function is never called because there is no need to support
+ indefinite-length strings, the internal MemPool implementation should
+ be dead-stripped by the loader and not add to code size.
+ */
+QCBORError QCBORDecode_SetMemPool(QCBORDecodeContext *pCtx, UsefulBuf MemPool, bool bAllStrings);
+
+
+/**
+ @brief Sets up a custom string allocator for indefinite-length strings
+
+ @param[in] pCtx The decoder context to set up an
+ allocator for.
+ @param[in] pfAllocateFunction Pointer to function that will be
+ called by QCBOR for allocations and
+ frees.
+ @param[in] pAllocateContext Context passed to @c
+ pfAllocateFunction.
+ @param[in] bAllStrings If true, all strings, even of definite
+ length, will be allocated with the
+ string allocator.
+
+ indefinite-length strings (text and byte) cannot be decoded unless
+ there a string allocator is configured. QCBORDecode_SetUpAllocator()
+ allows the caller to configure an external string allocator
+ implementation if the internal string allocator is not suitable. See
+ QCBORDecode_SetMemPool() to configure the internal allocator. Note
+ that the internal allocator is not automatically set up.
+
+ The string allocator configured here can be a custom one designed and
+ implemented by the caller. See @ref QCBORStringAllocate for the
+ requirements for a string allocator implementation.
+
+ A malloc-based string external allocator can be obtained by calling
+ @c QCBORDecode_MakeMallocStringAllocator(). It will return a function
+ and pointer that can be given here as @c pAllocatorFunction and @c
+ pAllocatorContext. It uses standard @c malloc() so @c free() must be
+ called on all strings marked by @c uDataAlloc @c == @c 1 or @c
+ uLabelAlloc @c == @c 1 in @ref QCBORItem.
+
+ Note that an older version of this function took an allocator
+ structure, rather than single function and pointer. The older
+ version @c QCBORDecode_MakeMallocStringAllocator() also implemented
+ the older interface.
+ */
+void QCBORDecode_SetUpAllocator(QCBORDecodeContext *pCtx,
+ QCBORStringAllocate pfAllocateFunction,
+ void *pAllocateContext,
+ bool bAllStrings);
+
+/**
+ @brief Configure list of caller-selected tags to be recognized.
+
+ @param[in] pCtx The decode context.
+ @param[out] pTagList Structure holding the list of tags to configure.
+
+ This is used to tell the decoder about tags beyond those that are
+ built-in that should be recognized. The built-in tags are those with
+ macros of the form @c CBOR_TAG_XXX.
+
+ The list pointed to by @c pTagList must persist during decoding. No
+ copy of it is made.
+
+ The maximum number of tags that can be added is @ref
+ QCBOR_MAX_CUSTOM_TAGS. If a list larger than this is given, the
+ error will be returned when QCBORDecode_GetNext() is called, not
+ here.
+
+ See description of @ref QCBORTagListIn.
+ */
+void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pCtx, const QCBORTagListIn *pTagList);
+
+
+/**
+ @brief Gets the next item (integer, byte string, array...) in
+ preorder traversal of CBOR tree.
+
+ @param[in] pCtx The decoder context.
+ @param[out] pDecodedItem Holds the CBOR item just decoded.
+
+ @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Not well-formed, one of the
+ chunks in indefinite-length
+ string is wrong type.
+
+ @retval QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN Not well-formed, array or map
+ not closed.
+
+ @retval QCBOR_ERR_UNSUPPORTED Not well-formed, input contains
+ unsupported CBOR.
+
+ @retval QCBOR_ERR_HIT_END Not well-formed, unexpectedly ran out
+ of bytes.
+
+ @retval QCBOR_ERR_BAD_TYPE_7 Not well-formed, bad simple type value.
+
+ @retval QCBOR_ERR_BAD_BREAK Not well-formed, break occurs where
+ not allowed.
+
+ @retval QCBOR_ERR_EXTRA_BYTES Not well-formed, unprocessed bytes at
+ the end.
+
+ @retval QCBOR_ERR_BAD_INT Not well-formed, length of integer is
+ bad.
+
+ @retval QCBOR_ERR_BAD_OPT_TAG Invalid CBOR, tag on wrong type.
+
+ @retval QCBOR_ERR_ARRAY_TOO_LONG Implementation limit, array or map
+ too long.
+
+ @retval QCBOR_ERR_INT_OVERFLOW Implementation limit, negative
+ integer too large.
+
+ @retval QCBOR_ERR_DATE_OVERFLOW Implementation limit, date larger
+ than can be handled.
+
+ @retval QCBOR_ERR_ARRAY_NESTING_TOO_DEEP Implementation limit, nesting
+ too deep.
+
+ @retval QCBOR_ERR_STRING_ALLOCATE Resource exhaustion, string allocator
+ failed.
+
+ @retval QCBOR_ERR_MAP_LABEL_TYPE Configuration error / Implementation
+ limit encountered a map label this is
+ not a string on an integer.
+
+ @retval QCBOR_ERR_NO_STRING_ALLOCATOR Configuration error, encountered
+ indefinite-length string with no
+ allocator configured.
+ @retval QCBOR_ERR_NO_MORE_ITEMS No more bytes to decode. The previous
+ item was successfully decoded. This
+ is usually how the non-error end of
+ a CBOR stream / sequence is detected.
+
+ @c pDecodedItem is filled in with the value parsed. Generally, the
+ following data is returned in the structure:
+
+ - @c uDataType which indicates which member of the @c val union the
+ data is in. This decoder figures out the type based on the CBOR
+ major type, the CBOR "additionalInfo", the CBOR optional tags and
+ the value of the integer.
+
+ - The value of the item, which might be an integer, a pointer and a
+ length, the count of items in an array, a floating-point number or
+ other.
+
+ - The nesting level for maps and arrays.
+
+ - The label for an item in a map, which may be a text or byte string
+ or an integer.
+
+ - The CBOR optional tag or tags.
+
+ See documentation on in the data type @ref _QCBORItem for all the
+ details on what is returned.
+
+ This function handles arrays and maps. When first encountered a @ref
+ QCBORItem will be returned with major type @ref QCBOR_TYPE_ARRAY or
+ @ref QCBOR_TYPE_MAP. @c QCBORItem.val.uCount will indicate the number
+ of Items in the array or map. Typically, an implementation will call
+ QCBORDecode_GetNext() in a for loop to fetch them all. When decoding
+ indefinite-length maps and arrays, @c QCBORItem.val.uCount is @c
+ UINT16_MAX and @c uNextNestLevel must be used to know when the end of
+ a map or array is reached.
+
+ Nesting level 0 is the outside top-most nesting level. For example,
+ in a CBOR structure with two items, an integer and a byte string
+ only, both would be at nesting level 0. A CBOR structure with an
+ array open, an integer and a byte string, would have the integer and
+ byte string as nesting level 1.
+
+ Here is an example of how the nesting level is reported with no arrays
+ or maps at all.
+
+ @verbatim
+ CBOR Structure Nesting Level
+ Integer 0
+ Byte String 0
+ @endverbatim
+
+ Here is an example of how the nesting level is reported with a simple
+ array and some top-level items.
+
+ @verbatim
+ Integer 0
+ Array (with 2 items) 0
+ Byte String 1
+ Byte string 1
+ Integer 0
+ @endverbatim
+
+
+ Here's a more complex example
+ @verbatim
+
+ Map with 2 items 0
+ Text string 1
+ Array with 3 integers 1
+ integer 2
+ integer 2
+ integer 2
+ text string 1
+ byte string 1
+ @endverbatim
+
+ In @ref _QCBORItem, @c uNextNestLevel is the nesting level for the
+ next call to QCBORDecode_GetNext(). It indicates if any maps or
+ arrays were closed out during the processing of the just-fetched @ref
+ QCBORItem. This processing includes a look-ahead for any breaks that
+ close out indefinite-length arrays or maps. This value is needed to
+ be able to understand the hierarchical structure. If @c
+ uNextNestLevel is not equal to @c uNestLevel the end of the current
+ map or array has been encountered. This works the same for both
+ definite and indefinite-length arrays.
+
+ This decoder support CBOR type 6 tagging. The decoding of particular
+ given tag value may be supported in one of three different ways.
+
+ First, some common tags are fully and transparently supported by
+ automatically decoding them and returning them in a @ref QCBORItem.
+ These tags have a @c QCBOR_TYPE_XXX associated with them and manifest
+ pretty much the same as a standard CBOR type. @ref
+ QCBOR_TYPE_DATE_EPOCH and the @c epochDate member of @ref QCBORItem
+ is an example.
+
+ Second are tags that are automatically recognized, but not decoded.
+ These are tags that have a @c \#define of the form @c CBOR_TAG_XXX.
+ These are recorded in the @c uTagBits member of @ref QCBORItem. There
+ is an internal table that maps each bit to a particular tag value
+ allowing up to 64 tags on an individual item to be reported (it is
+ rare to have more than one or two). To find out if a particular tag
+ value is set call QCBORDecode_IsTagged() on the @ref QCBORItem. See
+ also QCBORDecode_GetNextWithTags().
+
+ Third are tags that are not automatically recognized, because they
+ are proprietary, custom or more recently registered with [IANA]
+ (https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml). The
+ internal mapping table has to be configured to recognize these. Call
+ QCBORDecode_SetCallerConfiguredTagList() to do that. Then
+ QCBORDecode_IsTagged() will work with them.
+
+ The actual decoding of tags supported in the second and third way
+ must be handled by the caller. Often this is simply verifying that
+ the expected tag is present on a map, byte string or such. In other
+ cases, there might a complicated map structure to decode.
+
+ See @ref Tags-Overview for a description of how to go about creating
+ custom tags.
+
+ This tag decoding design is to be open-ended and flexible to be able
+ to handle newly defined tags, while using very little memory, in
+ particular keeping @ref QCBORItem as small as possible.
+
+ If any error occurs, \c uDataType and \c uLabelType will be set
+ to \ref QCBOR_TYPE_NONE. If there is no need to know the specific
+ error, \ref QCBOR_TYPE_NONE can be checked for and the return value
+ ignored.
+
+ Errors fall in several categories as noted in list above:
+
+ - Not well-formed errors are those where there is something
+ syntactically and fundamentally wrong with the CBOR being
+ decoded. Encoding should stop completely.
+
+ - Invalid CBOR is well-formed, but still not correct. It is probably
+ best to stop decoding, but not necessary.
+
+ - This implementation has some size limits. They should rarely be
+ encountered. If they are it may because something is wrong with the
+ CBOR, for example an array size is incorrect.
+
+ - Resource exhaustion. This only occurs when a string allocator is
+ configured to handle indefinite-length strings as other than that,
+ this implementation does no dynamic memory allocation.
+
+ - There are a few CBOR constructs that are not handled without some
+ extra configuration. These are indefinite length strings and maps
+ with labels that are not strings or integers. See QCBORDecode_Init().
+
+ */
+QCBORError QCBORDecode_GetNext(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem);
+
+
+/**
+ @brief Gets the next item including full list of tags for item.
+
+ @param[in] pCtx The decoder context.
+ @param[out] pDecodedItem Holds the CBOR item just decoded.
+ @param[in,out] pTagList On input array to put tags in; on output
+ the tags on this item. See
+ @ref QCBORTagListOut.
+
+ @return See return values for QCBORDecode_GetNext().
+
+ @retval QCBOR_ERR_TOO_MANY_TAGS The size of @c pTagList is too small.
+
+ This works the same as QCBORDecode_GetNext() except that it also
+ returns the full list of tags for the data item. This function should
+ only be needed when parsing CBOR to print it out or convert it to
+ some other format. It should not be needed to implement a CBOR-based
+ protocol. See QCBORDecode_GetNext() for the main description of tag
+ decoding.
+
+ Tags will be returned here whether or not they are in the built-in or
+ caller-configured tag lists.
+
+ CBOR has no upper bound of limit on the number of tags that can be
+ associated with a data item though in practice the number of tags on
+ an item will usually be small, perhaps less than five. This will
+ return @ref QCBOR_ERR_TOO_MANY_TAGS if the array in @c pTagList is
+ too small to hold all the tags for the item.
+
+ (This function is separate from QCBORDecode_GetNext() so as to not
+ have to make @ref QCBORItem large enough to be able to hold a full
+ list of tags. Even a list of five tags would nearly double its size
+ because tags can be a @c uint64_t ).
+ */
+QCBORError QCBORDecode_GetNextWithTags(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem, QCBORTagListOut *pTagList);
+
+
+/**
+ @brief Determine if a CBOR item was tagged with a particular tag
+
+ @param[in] pCtx The decoder context.
+ @param[in] pItem The CBOR item to check.
+ @param[in] uTag The tag to check, one of @c CBOR_TAG_XXX.
+
+ @return 1 if it was tagged, 0 if not
+
+ See QCBORDecode_GetNext() for the main description of tag
+ handling. For tags that are not fully decoded a bit corresponding to
+ the tag is set in in @c uTagBits in the @ref QCBORItem. The
+ particular bit depends on an internal mapping table. This function
+ checks for set bits against the mapping table.
+
+ Typically, a protocol implementation just wants to know if a
+ particular tag is present. That is what this provides. To get the
+ full list of tags on a data item, see QCBORDecode_GetNextWithTags().
+
+ Also see QCBORDecode_SetCallerConfiguredTagList() for the means to
+ add new tags to the internal list so they can be checked for with
+ this function.
+ */
+int QCBORDecode_IsTagged(QCBORDecodeContext *pCtx, const QCBORItem *pItem, uint64_t uTag);
+
+
+/**
+ Check whether all the bytes have been decoded and maps and arrays closed.
+
+ @param[in] pCtx The context to check.
+
+ @return An error or @ref QCBOR_SUCCESS.
+
+ This tells you if all the bytes given to QCBORDecode_Init() have been
+ consumed and whether all maps and arrays were closed. The decode is
+ considered to be incorrect or incomplete if not and an error will be
+ returned.
+ */
+QCBORError QCBORDecode_Finish(QCBORDecodeContext *pCtx);
+
+
+
+
+/**
+ @brief Convert int64_t to smaller integers safely.
+
+ @param [in] src An @c int64_t.
+ @param [out] dest A smaller sized integer to convert to.
+
+ @return 0 on success -1 if not
+
+ When decoding an integer, the CBOR decoder will return the value as
+ an int64_t unless the integer is in the range of @c INT64_MAX and @c
+ UINT64_MAX. That is, unless the value is so large that it can only be
+ represented as a @c uint64_t, it will be an @c int64_t.
+
+ CBOR itself doesn't size the individual integers it carries at
+ all. The only limits it puts on the major integer types is that they
+ are 8 bytes or less in length. Then encoders like this one use the
+ smallest number of 1, 2, 4 or 8 bytes to represent the integer based
+ on its value. There is thus no notion that one data item in CBOR is
+ a 1-byte integer and another is a 4-byte integer.
+
+ The interface to this CBOR encoder only uses 64-bit integers. Some
+ CBOR protocols or implementations of CBOR protocols may not want to
+ work with something smaller than a 64-bit integer. Perhaps an array
+ of 1000 integers needs to be sent and none has a value larger than
+ 50,000 and are represented as @c uint16_t.
+
+ The sending / encoding side is easy. Integers are temporarily widened
+ to 64-bits as a parameter passing through QCBOREncode_AddInt64() and
+ encoded in the smallest way possible for their value, possibly in
+ less than an @c uint16_t.
+
+ On the decoding side the integers will be returned at @c int64_t even if
+ they are small and were represented by only 1 or 2 bytes in the
+ encoded CBOR. The functions here will convert integers to a small
+ representation with an overflow check.
+
+ (The decoder could have support 8 different integer types and
+ represented the integer with the smallest type automatically, but
+ this would have made the decoder more complex and code calling the
+ decoder more complex in most use cases. In most use cases on 64-bit
+ machines it is no burden to carry around even small integers as
+ 64-bit values).
+ */
+static inline int QCBOR_Int64ToInt32(int64_t src, int32_t *dest)
+{
+ if(src > INT32_MAX || src < INT32_MIN) {
+ return -1;
+ } else {
+ *dest = (int32_t) src;
+ }
+ return 0;
+}
+
+static inline int QCBOR_Int64ToInt16(int64_t src, int16_t *dest)
+{
+ if(src > INT16_MAX || src < INT16_MIN) {
+ return -1;
+ } else {
+ *dest = (int16_t) src;
+ }
+ return 0;
+}
+
+static inline int QCBOR_Int64ToInt8(int64_t src, int8_t *dest)
+{
+ if(src > INT8_MAX || src < INT8_MIN) {
+ return -1;
+ } else {
+ *dest = (int8_t) src;
+ }
+ return 0;
+}
+
+static inline int QCBOR_Int64ToUInt32(int64_t src, uint32_t *dest)
+{
+ if(src > UINT32_MAX || src < 0) {
+ return -1;
+ } else {
+ *dest = (uint32_t) src;
+ }
+ return 0;
+}
+
+static inline int QCBOR_Int64UToInt16(int64_t src, uint16_t *dest)
+{
+ if(src > UINT16_MAX || src < 0) {
+ return -1;
+ } else {
+ *dest = (uint16_t) src;
+ }
+ return 0;
+}
+
+static inline int QCBOR_Int64ToUInt8(int64_t src, uint8_t *dest)
+{
+ if(src > UINT8_MAX || src < 0) {
+ return -1;
+ } else {
+ *dest = (uint8_t) src;
+ }
+ return 0;
+}
+
+static inline int QCBOR_Int64ToUInt64(int64_t src, uint64_t *dest)
+{
+ if(src > 0) {
+ return -1;
+ } else {
+ *dest = (uint64_t) src;
+ }
+ return 0;
+}
+
+
+
+
+
+/* ===========================================================================
+ BEGINNING OF PRIVATE INLINE IMPLEMENTATION
+
+ =========================================================================== */
+
+/**
+ @brief Semi-private method to add a buffer full of bytes to encoded output
+
+ @param[in] pCtx The encoding context to add the integer to.
+ @param[in] uMajorType The CBOR major type of the bytes.
+ @param[in] Bytes The bytes to add.
+
+ Use QCBOREncode_AddText() or QCBOREncode_AddBytes() or
+ QCBOREncode_AddEncoded() instead. They are inline functions that call
+ this and supply the correct major type. This function is public to
+ make the inline functions work to keep the overall code size down and
+ because the C language has no way to make it private.
+
+ If this is called the major type should be @c
+ CBOR_MAJOR_TYPE_TEXT_STRING, @c CBOR_MAJOR_TYPE_BYTE_STRING or @c
+ CBOR_MAJOR_NONE_TYPE_RAW. The last one is special for adding
+ already-encoded CBOR.
+ */
+void QCBOREncode_AddBuffer(QCBOREncodeContext *pCtx, uint8_t uMajorType, UsefulBufC Bytes);
+
+
+/**
+ @brief Semi-private method to open a map, array or bstr-wrapped CBOR
+
+ @param[in] pCtx The context to add to.
+ @param[in] uMajorType The major CBOR type to close
+
+ Call QCBOREncode_OpenArray(), QCBOREncode_OpenMap() or
+ QCBOREncode_BstrWrap() instead of this.
+ */
+void QCBOREncode_OpenMapOrArray(QCBOREncodeContext *pCtx, uint8_t uMajorType);
+
+
+/**
+ @brief Semi-private method to open a map, array with indefinite length
+
+ @param[in] pCtx The context to add to.
+ @param[in] uMajorType The major CBOR type to close
+
+ Call QCBOREncode_OpenArrayIndefiniteLength() or
+ QCBOREncode_OpenMapIndefiniteLength() instead of this.
+ */
+void QCBOREncode_OpenMapOrArrayIndefiniteLength(QCBOREncodeContext *pCtx, uint8_t uMajorType);
+
+
+/**
+ @brief Semi-private method to close a map, array or bstr wrapped CBOR
+
+ @param[in] pCtx The context to add to.
+ @param[in] uMajorType The major CBOR type to close.
+
+ Call QCBOREncode_CloseArray() or QCBOREncode_CloseMap() instead of this.
+ */
+void QCBOREncode_CloseMapOrArray(QCBOREncodeContext *pCtx, uint8_t uMajorType);
+
+
+/**
+ @brief Semi-private method to close a map, array with indefinite length
+
+ @param[in] pCtx The context to add to.
+ @param[in] uMajorType The major CBOR type to close.
+
+ Call QCBOREncode_CloseArrayIndefiniteLength() or
+ QCBOREncode_CloseMapIndefiniteLength() instead of this.
+ */
+void QCBOREncode_CloseMapOrArrayIndefiniteLength(QCBOREncodeContext *pCtx,
+ uint8_t uMajorType);
+
+
+/**
+ @brief Semi-private method to add simple types.
+
+ @param[in] pCtx The encoding context to add the simple value to.
+ @param[in] uMinLen Minimum encoding size for uNum. Usually 0.
+ @param[in] uNum One of CBOR_SIMPLEV_FALSE through _UNDEF or other.
+
+ This is used to add simple types like true and false.
+
+ Call QCBOREncode_AddBool(), QCBOREncode_AddNULL(),
+ QCBOREncode_AddUndef() instead of this.
+
+ This function can add simple values that are not defined by CBOR
+ yet. This expansion point in CBOR should not be used unless they are
+ standardized.
+
+ Error handling is the same as QCBOREncode_AddInt64().
+ */
+void QCBOREncode_AddType7(QCBOREncodeContext *pCtx, uint8_t uMinLen, uint64_t uNum);
+
+
+/**
+ @brief Semi-private method to add bigfloats and decimal fractions.
+
+ @param[in] pCtx The encoding context to add the value to.
+ @param[in] uTag The type 6 tag indicating what this is to be
+ @param[in] BigNumMantissa Is @ref NULLUsefulBufC if mantissa is an
+ @c int64_t or the actual big number mantissa
+ if not.
+ @param[in] nMantissa The @c int64_t mantissa if it is not a big number.
+ @param[in] nExponent The exponent.
+
+ This adds a tagged array with two members, the mantissa and exponent. The
+ mantissa can be either a big number or an @c int64_t.
+
+ Typically, QCBOREncode_AddDecimalFraction(), QCBOREncode_AddBigFloat(),
+ QCBOREncode_AddDecimalFractionBigNum() or QCBOREncode_AddBigFloatBigNum()
+ is called instead of this.
+ */
+void QCBOREncode_AddExponentAndMantissa(QCBOREncodeContext *pCtx,
+ uint64_t uTag,
+ UsefulBufC BigNumMantissa,
+ bool bBigNumIsNegative,
+ int64_t nMantissa,
+ int64_t nExponent);
+
+/**
+ @brief Semi-private method to add only the type and length of a byte string.
+
+ @param[in] pCtx The context to initialize.
+ @param[in] Bytes Pointer and length of the input data.
+
+ This is the same as QCBOREncode_AddBytes() except it only adds the
+ CBOR encoding for the type and the length. It doesn't actually add
+ the bytes. You can't actually produce correct CBOR with this and the
+ rest of this API. It is only used for a special case where
+ the valid CBOR is created manually by putting this type and length in
+ and then adding the actual bytes. In particular, when only a hash of
+ the encoded CBOR is needed, where the type and header are hashed
+ separately and then the bytes is hashed. This makes it possible to
+ implement COSE Sign1 with only one copy of the payload in the output
+ buffer, rather than two, roughly cutting memory use in half.
+
+ This is only used for this odd case, but this is a supported
+ tested function.
+
+ See also QCBOREncode_EncodeHead().
+*/
+static inline void QCBOREncode_AddBytesLenOnly(QCBOREncodeContext *pCtx, UsefulBufC Bytes);
+
+static inline void QCBOREncode_AddBytesLenOnlyToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes);
+
+static inline void QCBOREncode_AddBytesLenOnlyToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes);
+
+
+
+
+
+static inline void QCBOREncode_AddInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, int64_t uNum)
+{
+ // Use _AddBuffer() because _AddSZString() is defined below, not above
+ QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_TYPE_TEXT_STRING, UsefulBuf_FromSZ(szLabel));
+ QCBOREncode_AddInt64(pCtx, uNum);
+}
+
+static inline void QCBOREncode_AddInt64ToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, int64_t uNum)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddInt64(pCtx, uNum);
+}
+
+
+static inline void QCBOREncode_AddUInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, uint64_t uNum)
+{
+ // Use _AddBuffer() because _AddSZString() is defined below, not above
+ QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_TYPE_TEXT_STRING, UsefulBuf_FromSZ(szLabel));
+ QCBOREncode_AddUInt64(pCtx, uNum);
+}
+
+static inline void QCBOREncode_AddUInt64ToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, uint64_t uNum)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddUInt64(pCtx, uNum);
+}
+
+
+static inline void QCBOREncode_AddText(QCBOREncodeContext *pCtx, UsefulBufC Text)
+{
+ QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_TYPE_TEXT_STRING, Text);
+}
+
+static inline void QCBOREncode_AddTextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Text)
+{
+ // Use _AddBuffer() because _AddSZString() is defined below, not above
+ QCBOREncode_AddText(pCtx, UsefulBuf_FromSZ(szLabel));
+ QCBOREncode_AddText(pCtx, Text);
+}
+
+static inline void QCBOREncode_AddTextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Text)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddText(pCtx, Text);
+}
+
+
+inline static void QCBOREncode_AddSZString(QCBOREncodeContext *pCtx, const char *szString)
+{
+ QCBOREncode_AddText(pCtx, UsefulBuf_FromSZ(szString));
+}
+
+static inline void QCBOREncode_AddSZStringToMap(QCBOREncodeContext *pCtx, const char *szLabel, const char *szString)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddSZString(pCtx, szString);
+}
+
+static inline void QCBOREncode_AddSZStringToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, const char *szString)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddSZString(pCtx, szString);
+}
+
+
+static inline void QCBOREncode_AddDoubleToMap(QCBOREncodeContext *pCtx, const char *szLabel, double dNum)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddDouble(pCtx, dNum);
+}
+
+static inline void QCBOREncode_AddDoubleToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, double dNum)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddDouble(pCtx, dNum);
+}
+
+
+static inline void QCBOREncode_AddDateEpoch(QCBOREncodeContext *pCtx, int64_t date)
+{
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_EPOCH);
+ QCBOREncode_AddInt64(pCtx, date);
+}
+
+static inline void QCBOREncode_AddDateEpochToMap(QCBOREncodeContext *pCtx, const char *szLabel, int64_t date)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_EPOCH);
+ QCBOREncode_AddInt64(pCtx, date);
+}
+
+static inline void QCBOREncode_AddDateEpochToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, int64_t date)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_EPOCH);
+ QCBOREncode_AddInt64(pCtx, date);
+}
+
+
+static inline void QCBOREncode_AddBytes(QCBOREncodeContext *pCtx, UsefulBufC Bytes)
+{
+ QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_TYPE_BYTE_STRING, Bytes);
+}
+
+static inline void QCBOREncode_AddBytesToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddBytes(pCtx, Bytes);
+}
+
+static inline void QCBOREncode_AddBytesToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddBytes(pCtx, Bytes);
+}
+
+static inline void QCBOREncode_AddBytesLenOnly(QCBOREncodeContext *pCtx, UsefulBufC Bytes)
+{
+ QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY, Bytes);
+}
+
+static inline void QCBOREncode_AddBytesLenOnlyToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddBytesLenOnly(pCtx, Bytes);
+}
+
+static inline void QCBOREncode_AddBytesLenOnlyToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddBytesLenOnly(pCtx, Bytes);
+}
+
+static inline void QCBOREncode_AddBinaryUUID(QCBOREncodeContext *pCtx, UsefulBufC Bytes)
+{
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_BIN_UUID);
+ QCBOREncode_AddBytes(pCtx, Bytes);
+}
+
+static inline void QCBOREncode_AddBinaryUUIDToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_BIN_UUID);
+ QCBOREncode_AddBytes(pCtx, Bytes);
+}
+
+static inline void QCBOREncode_AddBinaryUUIDToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_BIN_UUID);
+ QCBOREncode_AddBytes(pCtx, Bytes);
+}
+
+
+static inline void QCBOREncode_AddPositiveBignum(QCBOREncodeContext *pCtx, UsefulBufC Bytes)
+{
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_POS_BIGNUM);
+ QCBOREncode_AddBytes(pCtx, Bytes);
+}
+
+static inline void QCBOREncode_AddPositiveBignumToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_POS_BIGNUM);
+ QCBOREncode_AddBytes(pCtx, Bytes);
+}
+
+static inline void QCBOREncode_AddPositiveBignumToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_POS_BIGNUM);
+ QCBOREncode_AddBytes(pCtx, Bytes);
+}
+
+
+static inline void QCBOREncode_AddNegativeBignum(QCBOREncodeContext *pCtx, UsefulBufC Bytes)
+{
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_NEG_BIGNUM);
+ QCBOREncode_AddBytes(pCtx, Bytes);
+}
+
+static inline void QCBOREncode_AddNegativeBignumToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_NEG_BIGNUM);
+ QCBOREncode_AddBytes(pCtx, Bytes);
+}
+
+static inline void QCBOREncode_AddNegativeBignumToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_NEG_BIGNUM);
+ QCBOREncode_AddBytes(pCtx, Bytes);
+}
+
+
+#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+
+static inline void QCBOREncode_AddDecimalFraction(QCBOREncodeContext *pCtx,
+ int64_t nMantissa,
+ int64_t nBase10Exponent)
+{
+ QCBOREncode_AddExponentAndMantissa(pCtx,
+ CBOR_TAG_DECIMAL_FRACTION,
+ NULLUsefulBufC,
+ false,
+ nMantissa,
+ nBase10Exponent);
+}
+
+static inline void QCBOREncode_AddDecimalFractionToMap(QCBOREncodeContext *pCtx,
+ const char *szLabel,
+ int64_t nMantissa,
+ int64_t nBase10Exponent)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddDecimalFraction(pCtx, nMantissa, nBase10Exponent);
+}
+
+static inline void QCBOREncode_AddDecimalFractionToMapN(QCBOREncodeContext *pCtx,
+ int64_t nLabel,
+ int64_t nMantissa,
+ int64_t nBase10Exponent)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddDecimalFraction(pCtx, nMantissa, nBase10Exponent);
+}
+
+static inline void QCBOREncode_AddDecimalFractionBigNum(QCBOREncodeContext *pCtx,
+ UsefulBufC Mantissa,
+ bool bIsNegative,
+ int64_t nBase10Exponent)
+{
+ QCBOREncode_AddExponentAndMantissa(pCtx,
+ CBOR_TAG_DECIMAL_FRACTION,
+ Mantissa, bIsNegative,
+ 0,
+ nBase10Exponent);
+}
+
+static inline void QCBOREncode_AddDecimalFractionBigNumToMap(QCBOREncodeContext *pCtx,
+ const char *szLabel,
+ UsefulBufC Mantissa,
+ bool bIsNegative,
+ int64_t nBase10Exponent)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddDecimalFractionBigNum(pCtx, Mantissa, bIsNegative, nBase10Exponent);
+}
+
+static inline void QCBOREncode_AddDecimalFractionBigNumToMapN(QCBOREncodeContext *pCtx,
+ int64_t nLabel,
+ UsefulBufC Mantissa,
+ bool bIsNegative,
+ int64_t nBase2Exponent)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddDecimalFractionBigNum(pCtx, Mantissa, bIsNegative, nBase2Exponent);
+}
+
+static inline void QCBOREncode_AddBigFloat(QCBOREncodeContext *pCtx,
+ int64_t nMantissa,
+ int64_t nBase2Exponent)
+{
+ QCBOREncode_AddExponentAndMantissa(pCtx, CBOR_TAG_BIGFLOAT, NULLUsefulBufC, false, nMantissa, nBase2Exponent);
+}
+
+static inline void QCBOREncode_AddBigFloatToMap(QCBOREncodeContext *pCtx,
+ const char *szLabel,
+ int64_t nMantissa,
+ int64_t nBase2Exponent)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddBigFloat(pCtx, nMantissa, nBase2Exponent);
+}
+
+static inline void QCBOREncode_AddBigFloatToMapN(QCBOREncodeContext *pCtx,
+ int64_t nLabel,
+ int64_t nMantissa,
+ int64_t nBase2Exponent)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddBigFloat(pCtx, nMantissa, nBase2Exponent);
+}
+
+static inline void QCBOREncode_AddBigFloatBigNum(QCBOREncodeContext *pCtx,
+ UsefulBufC Mantissa,
+ bool bIsNegative,
+ int64_t nBase2Exponent)
+{
+ QCBOREncode_AddExponentAndMantissa(pCtx, CBOR_TAG_BIGFLOAT, Mantissa, bIsNegative, 0, nBase2Exponent);
+}
+
+static inline void QCBOREncode_AddBigFloatBigNumToMap(QCBOREncodeContext *pCtx,
+ const char *szLabel,
+ UsefulBufC Mantissa,
+ bool bIsNegative,
+ int64_t nBase2Exponent)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddBigFloatBigNum(pCtx, Mantissa, bIsNegative, nBase2Exponent);
+}
+
+static inline void QCBOREncode_AddBigFloatBigNumToMapN(QCBOREncodeContext *pCtx,
+ int64_t nLabel,
+ UsefulBufC Mantissa,
+ bool bIsNegative,
+ int64_t nBase2Exponent)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddBigFloatBigNum(pCtx, Mantissa, bIsNegative, nBase2Exponent);
+}
+#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+
+
+static inline void QCBOREncode_AddURI(QCBOREncodeContext *pCtx, UsefulBufC URI)
+{
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_URI);
+ QCBOREncode_AddText(pCtx, URI);
+}
+
+static inline void QCBOREncode_AddURIToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC URI)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_URI);
+ QCBOREncode_AddText(pCtx, URI);
+}
+
+static inline void QCBOREncode_AddURIToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC URI)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_URI);
+ QCBOREncode_AddText(pCtx, URI);
+}
+
+
+
+static inline void QCBOREncode_AddB64Text(QCBOREncodeContext *pCtx, UsefulBufC B64Text)
+{
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_B64);
+ QCBOREncode_AddText(pCtx, B64Text);
+}
+
+static inline void QCBOREncode_AddB64TextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC B64Text)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_B64);
+ QCBOREncode_AddText(pCtx, B64Text);
+}
+
+static inline void QCBOREncode_AddB64TextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC B64Text)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_B64);
+ QCBOREncode_AddText(pCtx, B64Text);
+}
+
+
+static inline void QCBOREncode_AddB64URLText(QCBOREncodeContext *pCtx, UsefulBufC B64Text)
+{
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_B64URL);
+ QCBOREncode_AddText(pCtx, B64Text);
+}
+
+static inline void QCBOREncode_AddB64URLTextToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC B64Text)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_B64URL);
+ QCBOREncode_AddText(pCtx, B64Text);
+}
+
+static inline void QCBOREncode_AddB64URLTextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC B64Text)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_B64URL);
+ QCBOREncode_AddText(pCtx, B64Text);
+}
+
+
+static inline void QCBOREncode_AddRegex(QCBOREncodeContext *pCtx, UsefulBufC Bytes)
+{
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_REGEX);
+ QCBOREncode_AddText(pCtx, Bytes);
+}
+
+static inline void QCBOREncode_AddRegexToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Bytes)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_REGEX);
+ QCBOREncode_AddText(pCtx, Bytes);
+}
+
+static inline void QCBOREncode_AddRegexToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Bytes)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_REGEX);
+ QCBOREncode_AddText(pCtx, Bytes);
+}
+
+
+static inline void QCBOREncode_AddMIMEData(QCBOREncodeContext *pCtx, UsefulBufC MIMEData)
+{
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_MIME);
+ QCBOREncode_AddText(pCtx, MIMEData);
+}
+
+static inline void QCBOREncode_AddMIMEDataToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC MIMEData)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_MIME);
+ QCBOREncode_AddText(pCtx, MIMEData);
+}
+
+static inline void QCBOREncode_AddMIMEDataToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC MIMEData)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_MIME);
+ QCBOREncode_AddText(pCtx, MIMEData);
+}
+
+
+static inline void QCBOREncode_AddDateString(QCBOREncodeContext *pCtx, const char *szDate)
+{
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_STRING);
+ QCBOREncode_AddSZString(pCtx, szDate);
+}
+
+static inline void QCBOREncode_AddDateStringToMap(QCBOREncodeContext *pCtx, const char *szLabel, const char *szDate)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_STRING);
+ QCBOREncode_AddSZString(pCtx, szDate);
+}
+
+static inline void QCBOREncode_AddDateStringToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, const char *szDate)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddTag(pCtx, CBOR_TAG_DATE_STRING);
+ QCBOREncode_AddSZString(pCtx, szDate);
+}
+
+
+static inline void QCBOREncode_AddSimple(QCBOREncodeContext *pCtx, uint64_t uNum)
+{
+ QCBOREncode_AddType7(pCtx, 0, uNum);
+}
+
+static inline void QCBOREncode_AddSimpleToMap(QCBOREncodeContext *pCtx, const char *szLabel, uint8_t uSimple)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddSimple(pCtx, uSimple);
+}
+
+static inline void QCBOREncode_AddSimpleToMapN(QCBOREncodeContext *pCtx, int nLabel, uint8_t uSimple)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddSimple(pCtx, uSimple);
+}
+
+
+static inline void QCBOREncode_AddBool(QCBOREncodeContext *pCtx, bool b)
+{
+ uint8_t uSimple = CBOR_SIMPLEV_FALSE;
+ if(b) {
+ uSimple = CBOR_SIMPLEV_TRUE;
+ }
+ QCBOREncode_AddSimple(pCtx, uSimple);
+}
+
+static inline void QCBOREncode_AddBoolToMap(QCBOREncodeContext *pCtx, const char *szLabel, bool b)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddBool(pCtx, b);
+}
+
+static inline void QCBOREncode_AddBoolToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, bool b)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddBool(pCtx, b);
+}
+
+
+static inline void QCBOREncode_AddNULL(QCBOREncodeContext *pCtx)
+{
+ QCBOREncode_AddSimple(pCtx, CBOR_SIMPLEV_NULL);
+}
+
+static inline void QCBOREncode_AddNULLToMap(QCBOREncodeContext *pCtx, const char *szLabel)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddNULL(pCtx);
+}
+
+static inline void QCBOREncode_AddNULLToMapN(QCBOREncodeContext *pCtx, int64_t nLabel)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddNULL(pCtx);
+}
+
+
+static inline void QCBOREncode_AddUndef(QCBOREncodeContext *pCtx)
+{
+ QCBOREncode_AddSimple(pCtx, CBOR_SIMPLEV_UNDEF);
+}
+
+static inline void QCBOREncode_AddUndefToMap(QCBOREncodeContext *pCtx, const char *szLabel)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddUndef(pCtx);
+}
+
+static inline void QCBOREncode_AddUndefToMapN(QCBOREncodeContext *pCtx, int64_t nLabel)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddUndef(pCtx);
+}
+
+
+static inline void QCBOREncode_OpenArray(QCBOREncodeContext *pCtx)
+{
+ QCBOREncode_OpenMapOrArray(pCtx, CBOR_MAJOR_TYPE_ARRAY);
+}
+
+static inline void QCBOREncode_OpenArrayInMap(QCBOREncodeContext *pCtx, const char *szLabel)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_OpenArray(pCtx);
+}
+
+static inline void QCBOREncode_OpenArrayInMapN(QCBOREncodeContext *pCtx, int64_t nLabel)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_OpenArray(pCtx);
+}
+
+static inline void QCBOREncode_CloseArray(QCBOREncodeContext *pCtx)
+{
+ QCBOREncode_CloseMapOrArray(pCtx, CBOR_MAJOR_TYPE_ARRAY);
+}
+
+
+static inline void QCBOREncode_OpenMap(QCBOREncodeContext *pCtx)
+{
+ QCBOREncode_OpenMapOrArray(pCtx, CBOR_MAJOR_TYPE_MAP);
+}
+
+static inline void QCBOREncode_OpenMapInMap(QCBOREncodeContext *pCtx, const char *szLabel)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_OpenMap(pCtx);
+}
+
+static inline void QCBOREncode_OpenMapInMapN(QCBOREncodeContext *pCtx, int64_t nLabel)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_OpenMap(pCtx);
+}
+
+static inline void QCBOREncode_CloseMap(QCBOREncodeContext *pCtx)
+{
+ QCBOREncode_CloseMapOrArray(pCtx, CBOR_MAJOR_TYPE_MAP);
+}
+
+static inline void QCBOREncode_OpenArrayIndefiniteLength(QCBOREncodeContext *pCtx)
+{
+ QCBOREncode_OpenMapOrArrayIndefiniteLength(pCtx, CBOR_MAJOR_NONE_TYPE_ARRAY_INDEFINITE_LEN);
+}
+
+static inline void QCBOREncode_OpenArrayIndefiniteLengthInMap(QCBOREncodeContext *pCtx, const char *szLabel)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_OpenArrayIndefiniteLength(pCtx);
+}
+
+static inline void QCBOREncode_OpenArrayIndefiniteLengthInMapN(QCBOREncodeContext *pCtx, int64_t nLabel)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_OpenArrayIndefiniteLength(pCtx);
+}
+
+static inline void QCBOREncode_CloseArrayIndefiniteLength(QCBOREncodeContext *pCtx)
+{
+ QCBOREncode_CloseMapOrArrayIndefiniteLength(pCtx, CBOR_MAJOR_NONE_TYPE_ARRAY_INDEFINITE_LEN);
+}
+
+
+static inline void QCBOREncode_OpenMapIndefiniteLength(QCBOREncodeContext *pCtx)
+{
+ QCBOREncode_OpenMapOrArrayIndefiniteLength(pCtx, CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN);
+}
+
+static inline void QCBOREncode_OpenMapIndefiniteLengthInMap(QCBOREncodeContext *pCtx, const char *szLabel)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_OpenMapIndefiniteLength(pCtx);
+}
+
+static inline void QCBOREncode_OpenMapIndefiniteLengthInMapN(QCBOREncodeContext *pCtx, int64_t nLabel)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_OpenMapIndefiniteLength(pCtx);
+}
+
+static inline void QCBOREncode_CloseMapIndefiniteLength(QCBOREncodeContext *pCtx)
+{
+ QCBOREncode_CloseMapOrArrayIndefiniteLength(pCtx, CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN);
+}
+
+
+static inline void QCBOREncode_BstrWrap(QCBOREncodeContext *pCtx)
+{
+ QCBOREncode_OpenMapOrArray(pCtx, CBOR_MAJOR_TYPE_BYTE_STRING);
+}
+
+static inline void QCBOREncode_BstrWrapInMap(QCBOREncodeContext *pCtx, const char *szLabel)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_BstrWrap(pCtx);
+}
+
+static inline void QCBOREncode_BstrWrapInMapN(QCBOREncodeContext *pCtx, int64_t nLabel)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_BstrWrap(pCtx);
+}
+
+static inline void QCBOREncode_CloseBstrWrap(QCBOREncodeContext *pCtx, UsefulBufC *pWrappedCBOR)
+{
+ QCBOREncode_CloseBstrWrap2(pCtx, true, pWrappedCBOR);
+}
+
+
+static inline void QCBOREncode_AddEncoded(QCBOREncodeContext *pCtx, UsefulBufC Encoded)
+{
+ QCBOREncode_AddBuffer(pCtx, CBOR_MAJOR_NONE_TYPE_RAW, Encoded);
+}
+
+static inline void QCBOREncode_AddEncodedToMap(QCBOREncodeContext *pCtx, const char *szLabel, UsefulBufC Encoded)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_AddEncoded(pCtx, Encoded);
+}
+
+static inline void QCBOREncode_AddEncodedToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBufC Encoded)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_AddEncoded(pCtx, Encoded);
+}
+
+
+static inline int QCBOREncode_IsBufferNULL(QCBOREncodeContext *pCtx)
+{
+ return UsefulOutBuf_IsBufferNULL(&(pCtx->OutBuf));
+}
+
+static inline QCBORError QCBOREncode_GetErrorState(QCBOREncodeContext *pCtx)
+{
+ if(UsefulOutBuf_GetError(&(pCtx->OutBuf))) {
+ // Items didn't fit in the buffer.
+ // This check catches this condition for all the appends and inserts
+ // so checks aren't needed when the appends and inserts are performed.
+ // And of course UsefulBuf will never overrun the input buffer given
+ // to it. No complex analysis of the error handling in this file is
+ // needed to know that is true. Just read the UsefulBuf code.
+ pCtx->uError = QCBOR_ERR_BUFFER_TOO_SMALL;
+ // QCBOR_ERR_BUFFER_TOO_SMALL masks other errors, but that is
+ // OK. Once the caller fixes this, they'll be unmasked.
+ }
+
+ return (QCBORError)pCtx->uError;
+}
+
+
+/* ===========================================================================
+ END OF PRIVATE INLINE IMPLEMENTATION
+
+ =========================================================================== */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* defined(__QCBOR__qcbor__) */