Merge recent changes from master
diff --git a/src/UsefulBuf.c b/src/UsefulBuf.c
index dae4eb1..91ffda1 100644
--- a/src/UsefulBuf.c
+++ b/src/UsefulBuf.c
@@ -1,33 +1,36 @@
/*==============================================================================
- Copyright (c) 2016-2018, The Linux Foundation.
- Copyright (c) 2018-2024, Laurence Lundblade.
+ * Copyright (c) 2016-2018, The Linux Foundation.
+ * Copyright (c) 2018-2024, 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.
+ * ========================================================================= */
-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.c
@@ -41,6 +44,7 @@
when who what, where, why
-------- ---- ---------------------------------------------------
+ 21/05/2024 llundblade Comment formatting and some code tidiness.
28/02/2022 llundblade Rearrange UsefulOutBuf_Compare().
19/11/2023 llundblade Add UsefulOutBuf_GetOutput().
19/11/2023 llundblade Add UsefulOutBuf_Swap().
@@ -65,18 +69,20 @@
#include "UsefulBuf.h"
-// used to catch use of uninitialized or corrupted UsefulOutBuf
+/* used to catch use of uninitialized or corrupted UsefulOutBuf */
#define USEFUL_OUT_BUF_MAGIC (0x0B0F)
/*
- Public function -- see UsefulBuf.h
+ * Public function -- see UsefulBuf.h
*/
UsefulBufC UsefulBuf_CopyOffset(UsefulBuf Dest, size_t uOffset, const UsefulBufC Src)
{
- // Do this with subtraction so it doesn't give erroneous
- // result if uOffset + Src.len overflows
- if(uOffset > Dest.len || Src.len > Dest.len - uOffset) { // uOffset + Src.len > Dest.len
+ /* Do this with subtraction so it doesn't give an erroneous
+ * result if uOffset + Src.len overflows. Right side is equivalent to
+ * uOffset + Src.len > Dest.len
+ */
+ if(uOffset > Dest.len || Src.len > Dest.len - uOffset) {
return NULLUsefulBufC;
}
@@ -87,24 +93,25 @@
/*
- Public function -- see UsefulBuf.h
+ * Public function -- see UsefulBuf.h
*/
int UsefulBuf_Compare(const UsefulBufC UB1, const UsefulBufC UB2)
{
- // use the comparisons rather than subtracting lengths to
- // return an int instead of a size_t
+ /* Use comparisons rather than subtracting lengths to
+ * return an int instead of a size_t
+ */
if(UB1.len < UB2.len) {
return -1;
} else if (UB1.len > UB2.len) {
return 1;
- } // else UB1.len == UB2.len
+ } /* else UB1.len == UB2.len */
return memcmp(UB1.ptr, UB2.ptr, UB1.len);
}
/*
- Public function -- see UsefulBuf.h
+ * Public function -- see UsefulBuf.h
*/
size_t UsefulBuf_IsValue(const UsefulBufC UB, uint8_t uValue)
{
@@ -117,7 +124,7 @@
for(const uint8_t *p = UB.ptr; p < pEnd; p++) {
if(*p != uValue) {
/* Byte didn't match */
- /* Cast from signed to unsigned . Safe because the loop increments.*/
+ /* Cast from signed to unsigned. Safe because the loop increments.*/
return (size_t)(p - (const uint8_t *)UB.ptr);
}
}
@@ -128,7 +135,7 @@
/*
- Public function -- see UsefulBuf.h
+ * Public function -- see UsefulBuf.h
*/
size_t UsefulBuf_FindBytes(UsefulBufC BytesToSearch, UsefulBufC BytesToFind)
{
@@ -137,7 +144,11 @@
}
for(size_t uPos = 0; uPos <= BytesToSearch.len - BytesToFind.len; uPos++) {
- if(!UsefulBuf_Compare((UsefulBufC){((const uint8_t *)BytesToSearch.ptr) + uPos, BytesToFind.len}, BytesToFind)) {
+ UsefulBufC SearchNext;
+
+ SearchNext.ptr = ((const uint8_t *)BytesToSearch.ptr) + uPos;
+ SearchNext.len = BytesToFind.len;
+ if(!UsefulBuf_Compare(SearchNext, BytesToFind)) {
return uPos;
}
}
@@ -147,9 +158,9 @@
/*
- Public function -- see UsefulBuf.h
-
- Code Reviewers: THIS FUNCTION DOES POINTER MATH
+ * Public function -- see UsefulBuf.h
+ *
+ * Code Reviewers: THIS FUNCTION DOES POINTER MATH
*/
void UsefulOutBuf_Init(UsefulOutBuf *pMe, UsefulBuf Storage)
{
@@ -158,17 +169,18 @@
pMe->UB = Storage;
#if 0
- // This check is off by default.
-
- // The following check fails on ThreadX
-
- // Sanity check on the pointer and size to be sure we are not
- // passed a buffer that goes off the end of the address space.
- // Given this test, we know that all unsigned lengths less than
- // me->size are valid and won't wrap in any pointer additions
- // based off of pStorage in the rest of this code.
+ /* This check is off by default.
+ *
+ * The following check fails on ThreadX
+ *
+ * Sanity check on the pointer and size to be sure we are not
+ * passed a buffer that goes off the end of the address space.
+ * Given this test, we know that all unsigned lengths less than
+ * me->size are valid and won't wrap in any pointer additions
+ * based off of pStorage in the rest of this code.
+ */
const uintptr_t ptrM = UINTPTR_MAX - Storage.len;
- if(Storage.ptr && (uintptr_t)Storage.ptr > ptrM) // Check #0
+ if(Storage.ptr && (uintptr_t)Storage.ptr > ptrM) /* Check #0 */
me->err = 1;
#endif
}
@@ -176,101 +188,107 @@
/*
- Public function -- see UsefulBuf.h
-
- The core of UsefulOutBuf -- put some bytes in the buffer without writing off
- the end of it.
-
- Code Reviewers: THIS FUNCTION DOES POINTER MATH
-
- This function inserts the source buffer, NewData, into the destination
- buffer, me->UB.ptr.
-
- Destination is represented as:
- me->UB.ptr -- start of the buffer
- me->UB.len -- size of the buffer UB.ptr
- me->data_len -- length of value data in UB
-
- Source is data:
- NewData.ptr -- start of source buffer
- NewData.len -- length of source buffer
-
- Insertion point:
- uInsertionPos.
-
- Steps:
-
- 0. Corruption checks on UsefulOutBuf
-
- 1. Figure out if the new data will fit or not
-
- 2. Is insertion position in the range of valid data?
-
- 3. If insertion point is not at the end, slide data to the right of the
- insertion point to the right
-
- 4. Put the new data in at the insertion position.
-
+ * Public function -- see UsefulBuf.h
+ *
+ * The core of UsefulOutBuf -- put some bytes in the buffer without writing off
+ * the end of it.
+ *
+ * Code Reviewers: THIS FUNCTION DOES POINTER MATH
+ *
+ * This function inserts the source buffer, NewData, into the destination
+ * buffer, me->UB.ptr.
+ *
+ * Destination is represented as:
+ * me->UB.ptr -- start of the buffer
+ * me->UB.len -- size of the buffer UB.ptr
+ * me->data_len -- length of value data in UB
+ *
+ * Source is data:
+ * NewData.ptr -- start of source buffer
+ * NewData.len -- length of source buffer
+ *
+ * Insertion point:
+ * uInsertionPos.
+ *
+ * Steps:
+ *
+ * 0. Corruption checks on UsefulOutBuf
+ *
+ * 1. Figure out if the new data will fit or not
+ *
+ * 2. Is insertion position in the range of valid data?
+ *
+ * 3. If insertion point is not at the end, slide data to the right of the
+ * insertion point to the right
+ *
+ * 4. Put the new data in at the insertion position.
+ *
*/
void UsefulOutBuf_InsertUsefulBuf(UsefulOutBuf *pMe, UsefulBufC NewData, size_t uInsertionPos)
{
if(pMe->err) {
- // Already in error state.
+ /* Already in error state. */
return;
}
- /* 0. Sanity check the UsefulOutBuf structure */
- // A "counter measure". If magic number is not the right number it
- // probably means me was not initialized or it was corrupted. Attackers
- // can defeat this, but it is a hurdle and does good with very
- // little code.
+ /* 0. Sanity check the UsefulOutBuf structure
+ * A "counter measure". If magic number is not the right number it
+ * probably means pMe was not initialized or it was corrupted. Attackers
+ * can defeat this, but it is a hurdle and does good with very
+ * little code.
+ */
if(pMe->magic != USEFUL_OUT_BUF_MAGIC) {
pMe->err = 1;
- return; // Magic number is wrong due to uninitalization or corrption
+ return; /* Magic number is wrong due to uninitalization or corrption */
}
- // Make sure valid data is less than buffer size. This would only occur
- // if there was corruption of me, but it is also part of the checks to
- // be sure there is no pointer arithmatic under/overflow.
- if(pMe->data_len > pMe->UB.len) { // Check #1
+ /* Make sure valid data is less than buffer size. This would only occur
+ * if there was corruption of me, but it is also part of the checks to
+ * be sure there is no pointer arithmatic under/overflow.
+ */
+ if(pMe->data_len > pMe->UB.len) { /* Check #1 */
pMe->err = 1;
- // Offset of valid data is off the end of the UsefulOutBuf due to
- // uninitialization or corruption
+ /* Offset of valid data is off the end of the UsefulOutBuf due to
+ * uninitialization or corruption
+ */
return;
}
- /* 1. Will it fit? */
- // WillItFit() is the same as: NewData.len <= (me->UB.len - me->data_len)
- // Check #1 makes sure subtraction in RoomLeft will not wrap around
- if(! UsefulOutBuf_WillItFit(pMe, NewData.len)) { // Check #2
- // The new data will not fit into the the buffer.
+ /* 1. Will it fit?
+ * WillItFit() is the same as: NewData.len <= (me->UB.len - me->data_len)
+ * Check #1 makes sure subtraction in RoomLeft will not wrap around
+ */
+ if(! UsefulOutBuf_WillItFit(pMe, NewData.len)) { /* Check #2 */
+ /* The new data will not fit into the the buffer. */
pMe->err = 1;
return;
}
- /* 2. Check the Insertion Position */
- // This, with Check #1, also confirms that uInsertionPos <= me->data_len and
- // that uInsertionPos + pMe->UB.ptr will not wrap around the end of the
- // address space.
- if(uInsertionPos > pMe->data_len) { // Check #3
- // Off the end of the valid data in the buffer.
+ /* 2. Check the Insertion Position
+ * This, with Check #1, also confirms that uInsertionPos <= me->data_len and
+ * that uInsertionPos + pMe->UB.ptr will not wrap around the end of the
+ * address space.
+ */
+ if(uInsertionPos > pMe->data_len) { /* Check #3 */
+ /* Off the end of the valid data in the buffer. */
pMe->err = 1;
return;
}
/* 3. Slide existing data to the right */
if (!UsefulOutBuf_IsBufferNULL(pMe)) {
- uint8_t *pSourceOfMove = ((uint8_t *)pMe->UB.ptr) + uInsertionPos; // PtrMath #1
- size_t uNumBytesToMove = pMe->data_len - uInsertionPos; // PtrMath #2
- uint8_t *pDestinationOfMove = pSourceOfMove + NewData.len; // PtrMath #3
+ uint8_t *pSourceOfMove = ((uint8_t *)pMe->UB.ptr) + uInsertionPos; /* PtrMath #1 */
+ size_t uNumBytesToMove = pMe->data_len - uInsertionPos; /* PtrMath #2 */
+ uint8_t *pDestinationOfMove = pSourceOfMove + NewData.len; /* PtrMath #3*/
- // To know memmove won't go off end of destination, see PtrMath #4
- // Use memove because it handles overlapping buffers
+ /* To know memmove won't go off end of destination, see PtrMath #4.
+ * Use memove because it handles overlapping buffers
+ */
memmove(pDestinationOfMove, pSourceOfMove, uNumBytesToMove);
/* 4. Put the new data in */
uint8_t *pInsertionPoint = pSourceOfMove;
- // To know memmove won't go off end of destination, see PtrMath #5
+ /* To know memmove won't go off end of destination, see PtrMath #5 */
if(NewData.ptr != NULL) {
memmove(pInsertionPoint, NewData.ptr, NewData.len);
}
@@ -281,30 +299,30 @@
/*
- Rationale that describes why the above pointer math is safe
-
- PtrMath #1 will never wrap around over because
- Check #0 in UsefulOutBuf_Init makes sure me->UB.ptr + me->UB.len doesn't wrap
- Check #1 makes sure me->data_len is less than me->UB.len
- Check #3 makes sure uInsertionPos is less than me->data_len
-
- PtrMath #2 will never wrap around under because
- Check #3 makes sure uInsertionPos is less than me->data_len
-
- PtrMath #3 will never wrap around over because
- PtrMath #1 is checked resulting in pSourceOfMove being between me->UB.ptr and me->UB.ptr + me->data_len
- Check #2 that NewData.len will fit in the unused space left in me->UB
-
- PtrMath #4 will never wrap under because
- Calculation for extent or memmove is uRoomInDestination = me->UB.len - (uInsertionPos + NewData.len)
- Check #3 makes sure uInsertionPos is less than me->data_len
- Check #3 allows Check #2 to be refactored as NewData.Len > (me->size - uInsertionPos)
- This algebraically rearranges to me->size > uInsertionPos + NewData.len
-
- PtrMath #5 will never wrap under because
- Calculation for extent of memove is uRoomInDestination = me->UB.len - uInsertionPos;
- Check #1 makes sure me->data_len is less than me->size
- Check #3 makes sure uInsertionPos is less than me->data_len
+ * Rationale that describes why the above pointer math is safe
+ *
+ * PtrMath #1 will never wrap around over because
+ * Check #0 in UsefulOutBuf_Init that me->UB.ptr + me->UB.len doesn't wrap
+ * Check #1 makes sure me->data_len is less than me->UB.len
+ * Check #3 makes sure uInsertionPos is less than me->data_len
+ *
+ * PtrMath #2 will never wrap around under because
+ * Check #3 makes sure uInsertionPos is less than me->data_len
+ *
+ * PtrMath #3 will never wrap around over because
+ * PtrMath #1 is checked resulting in pSourceOfMove being between me->UB.ptr and me->UB.ptr + me->data_len
+ * Check #2 that NewData.len will fit in the unused space left in me->UB
+ *
+ * PtrMath #4 will never wrap under because
+ * Calculation for extent or memmove is uRoomInDestination = me->UB.len - (uInsertionPos + NewData.len)
+ * Check #3 makes sure uInsertionPos is less than me->data_len
+ * Check #3 allows Check #2 to be refactored as NewData.Len > (me->size - uInsertionPos)
+ * This algebraically rearranges to me->size > uInsertionPos + NewData.len
+ *
+ * PtrMath #5 will never wrap under because
+ * Calculation for extent of memove is uRoomInDestination = me->UB.len - uInsertionPos;
+ * Check #1 makes sure me->data_len is less than me->size
+ * Check #3 makes sure uInsertionPos is less than me->data_len
*/
@@ -342,7 +360,7 @@
* checks to be sure there is no pointer arithmatic
* under/overflow.
*/
- if(pMe->data_len > pMe->UB.len) { // Check #1
+ if(pMe->data_len > pMe->UB.len) { /* Check #1 */
pMe->err = 1;
/* Offset of valid data is off the end of the UsefulOutBuf due
* to uninitialization or corruption.
@@ -367,7 +385,7 @@
/*
- Public function -- see UsefulBuf.h
+ * Public function -- see UsefulBuf.h
*/
UsefulBufC UsefulOutBuf_OutUBuf(UsefulOutBuf *pMe)
{
@@ -385,9 +403,9 @@
/*
- Public function -- see UsefulBuf.h
-
- Copy out the data accumulated in to the output buffer.
+ * Public function -- see UsefulBuf.h
+ *
+ * Copy out the data accumulated in to the output buffer.
*/
UsefulBufC UsefulOutBuf_CopyOut(UsefulOutBuf *pMe, UsefulBuf pDest)
{
@@ -402,28 +420,28 @@
/*
- Public function -- see UsefulBuf.h
-
- The core of UsefulInputBuf -- consume bytes without going off end of buffer.
-
- Code Reviewers: THIS FUNCTION DOES POINTER MATH
+ * Public function -- see UsefulBuf.h
+ *
+ * The core of UsefulInputBuf -- consume bytes without going off end of buffer.
+ *
+ * Code Reviewers: THIS FUNCTION DOES POINTER MATH
*/
const void * UsefulInputBuf_GetBytes(UsefulInputBuf *pMe, size_t uAmount)
{
- // Already in error state. Do nothing.
+ /* Already in error state. Do nothing. */
if(pMe->err) {
return NULL;
}
if(!UsefulInputBuf_BytesAvailable(pMe, uAmount)) {
- // Number of bytes asked for at current position are more than available
+ /* Number of bytes asked for is more than available */
pMe->err = 1;
return NULL;
}
- // This is going to succeed
+ /* This is going to succeed */
const void * const result = ((const uint8_t *)pMe->UB.ptr) + pMe->cursor;
- // Will not overflow because of check using UsefulInputBuf_BytesAvailable()
+ /* Won't overflow because of check using UsefulInputBuf_BytesAvailable() */
pMe->cursor += uAmount;
return result;
}
diff --git a/src/qcbor_decode.c b/src/qcbor_decode.c
index d37aa24..645f6a8 100644
--- a/src/qcbor_decode.c
+++ b/src/qcbor_decode.c
@@ -372,7 +372,12 @@
return false;
}
- if(pNesting->pCurrentBounded->uLevelType != uType) {
+ uint8_t uItemDataType = pNesting->pCurrentBounded->uLevelType;
+ if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) {
+ uItemDataType = QCBOR_TYPE_ARRAY;
+ }
+
+ if(uItemDataType != uType) {
return false;
}
@@ -1743,15 +1748,18 @@
* strings.
*/
if(pDecodedItem->uDataType == QCBOR_TYPE_MAP) {
- if(pDecodedItem->val.uCount > QCBOR_MAX_ITEMS_IN_ARRAY/2) {
- uReturn = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
- goto Done;
- }
pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY;
- /* Cast is safe because of check against QCBOR_MAX_ITEMS_IN_ARRAY/2.
- * Cast is needed because of integer promotion.
- */
- pDecodedItem->val.uCount = (uint16_t)(pDecodedItem->val.uCount * 2);
+ if(pDecodedItem->val.uCount != UINT16_MAX) {
+ /* Adjust definite-length map item count */
+ if(pDecodedItem->val.uCount > QCBOR_MAX_ITEMS_IN_ARRAY/2) {
+ uReturn = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
+ goto Done;
+ }
+ /* Cast is safe because of check against QCBOR_MAX_ITEMS_IN_ARRAY/2.
+ * Cast is needed because of integer promotion.
+ */
+ pDecodedItem->val.uCount = (uint16_t)(pDecodedItem->val.uCount * 2);
+ }
}
}
@@ -3569,7 +3577,12 @@
return;
}
- if(pItem->uDataType != uType) {
+ uint8_t uItemDataType = pItem->uDataType;
+ if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) {
+ uItemDataType = QCBOR_TYPE_ARRAY;
+ }
+
+ if(uItemDataType != uType) {
pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
return;
}
@@ -4054,7 +4067,12 @@
if(uErr != QCBOR_SUCCESS) {
goto Done;
}
- if(Item.uDataType != uType) {
+
+ uint8_t uItemDataType = Item.uDataType;
+ if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY ) {
+ uItemDataType = QCBOR_TYPE_ARRAY;
+ }
+ if(uItemDataType != uType) {
uErr = QCBOR_ERR_UNEXPECTED_TYPE;
goto Done;
}
diff --git a/src/qcbor_encode.c b/src/qcbor_encode.c
index a614eb1..d196149 100644
--- a/src/qcbor_encode.c
+++ b/src/qcbor_encode.c
@@ -118,7 +118,7 @@
if(1 >= QCBOR_MAX_ITEMS_IN_ARRAY - pNesting->pCurrentNesting->uCount) {
return QCBOR_ERR_ARRAY_TOO_LONG;
}
-#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
+#endif /* !QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
pNesting->pCurrentNesting->uCount++;
@@ -436,6 +436,7 @@
/* The 5 bits in the initial byte that are not the major type */
int nAdditionalInfo;
+#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
if(uMajorType > QCBOR_INDEFINITE_LEN_TYPE_MODIFIER) {
/* Special case for start & end of indefinite length */
uMajorType = uMajorType - QCBOR_INDEFINITE_LEN_TYPE_MODIFIER;
@@ -448,7 +449,9 @@
#endif
nAdditionalInfo = CBOR_SIMPLE_BREAK;
- } else if (uArgument < CBOR_TWENTY_FOUR && uMinLen == 0) {
+ } else
+#endif /* !QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
+ if (uArgument < CBOR_TWENTY_FOUR && uMinLen == 0) {
/* Simple case where argument is < 24 */
nAdditionalInfo = (int)uArgument;
@@ -510,16 +513,39 @@
/**
+ * @brief Increment item counter for maps and arrays.
+ *
+ * @param pMe QCBOR encoding context.
+ *
+ * This is mostly a separate function to make code more readable and
+ * to have fewer occurrences of #ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
+ */
+static void
+QCBOREncode_Private_IncrementMapOrArrayCount(QCBOREncodeContext *pMe)
+{
+#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
+ if(pMe->uError == QCBOR_SUCCESS) {
+ pMe->uError = Nesting_Increment(&(pMe->nesting));
+ }
+#else
+ (void)Nesting_Increment(&(pMe->nesting));
+#endif /* !QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
+}
+
+
+/**
* @brief Append the CBOR head, the major type and argument
*
- * @param pMe Encoder context.
+ * @param pMe Encoder context.
* @param uMajorType Major type to insert.
* @param uArgument The argument (an integer value or a length).
* @param uMinLen Minimum number of bytes for encoding the CBOR argument.
*
* This formats the CBOR "head" and appends it to the output.
+ *
+ * This also increments the array/map item counter in most cases.
*/
-static void
+void
QCBOREncode_Private_AppendCBORHead(QCBOREncodeContext *pMe,
const uint8_t uMajorType,
const uint64_t uArgument,
@@ -541,136 +567,15 @@
*/
UsefulOutBuf_AppendUsefulBuf(&(pMe->OutBuf), EncodedHead);
-}
-
-/**
- * @brief Check for errors when decreasing nesting.
- *
- * @param pMe QCBOR encoding context.
- * @param uMajorType The major type of the nesting.
- *
- * Check that there is no previous error, that there is actually some
- * nesting and that the major type of the opening of the nesting
- * matches the major type of the nesting being closed.
- *
- * This is called when closing maps, arrays, byte string wrapping and
- * open/close of byte strings.
- */
-static bool
-QCBOREncode_Private_CheckDecreaseNesting(QCBOREncodeContext *pMe,
- const uint8_t uMajorType)
-{
-#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
- if(pMe->uError != QCBOR_SUCCESS) {
- return true;
+ if(!(uMajorType & QCBOR_INDEFINITE_LEN_TYPE_MODIFIER || uMajorType == CBOR_MAJOR_TYPE_TAG)) {
+ /* Don't increment the map count for tag or break because that is
+ * not needed. Don't do it for indefinite-length arrays and maps
+ * because it is done elsewhere. This is never called for definite-length
+ * arrays and maps.
+ */
+ QCBOREncode_Private_IncrementMapOrArrayCount(pMe);
}
-
- if(!Nesting_IsInNest(&(pMe->nesting))) {
- pMe->uError = QCBOR_ERR_TOO_MANY_CLOSES;
- return true;
- }
-
- if(Nesting_GetMajorType(&(pMe->nesting)) != uMajorType) {
- pMe->uError = QCBOR_ERR_CLOSE_MISMATCH;
- return true;
- }
-
-#else
- /* None of these checks are performed if the encode guards are
- * turned off as they all relate to correct calling.
- *
- * Turning off all these checks does not turn off any checking for
- * buffer overflows or pointer issues.
- */
-
- (void)uMajorType;
- (void)pMe;
-#endif
-
- return false;
-}
-
-
-/**
- * @brief Insert the CBOR head for a map, array or wrapped bstr
- *
- * @param pMe QCBOR encoding context.
- * @param uMajorType One of CBOR_MAJOR_TYPE_XXXX.
- * @param uLen The length of the data item.
- *
- * When an array, map or bstr was opened, nothing was done but note
- * the position. This function goes back to that position and inserts
- * the CBOR Head with the major type and length.
- */
-static void
-QCBOREncode_Private_InsertCBORHead(QCBOREncodeContext *pMe,
- uint8_t uMajorType,
- size_t uLen)
-{
- if(QCBOREncode_Private_CheckDecreaseNesting(pMe, uMajorType)) {
- return;
- }
-
- if(uMajorType == CBOR_MAJOR_NONE_TYPE_OPEN_BSTR) {
- uMajorType = CBOR_MAJOR_TYPE_BYTE_STRING;
- }
-
- /* A stack buffer large enough for a CBOR head (9 bytes) */
- UsefulBuf_MAKE_STACK_UB(pBufferForEncodedHead, QCBOR_HEAD_BUFFER_SIZE);
-
- UsefulBufC EncodedHead = QCBOREncode_EncodeHead(pBufferForEncodedHead,
- uMajorType,
- 0,
- uLen);
-
- /* No check for EncodedHead == NULLUsefulBufC is performed here to
- * save object code. It is very clear that pBufferForEncodedHead is
- * the correct size. If EncodedHead == NULLUsefulBufC then
- * UsefulOutBuf_InsertUsefulBuf() will do nothing so there is no
- * security hole introduced.
- */
- UsefulOutBuf_InsertUsefulBuf(&(pMe->OutBuf),
- EncodedHead,
- Nesting_GetStartPos(&(pMe->nesting)));
-
- Nesting_Decrease(&(pMe->nesting));
-}
-
-
-/**
- * @brief Increment item counter for maps and arrays.
- *
- * @param pMe QCBOR encoding context.
- *
- * This is mostly a separate function to make code more readable and
- * to have fewer occurrences of #ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
- */
-static void
-QCBOREncode_Private_IncrementMapOrArrayCount(QCBOREncodeContext *pMe)
-{
-#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
- if(pMe->uError == QCBOR_SUCCESS) {
- pMe->uError = Nesting_Increment(&(pMe->nesting));
- }
-#else
- (void)Nesting_Increment(&(pMe->nesting));
-#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
-}
-
-
-/*
- * Public functions for adding unsigned integers. See qcbor/qcbor_encode.h
- */
-void
-QCBOREncode_AddUInt64(QCBOREncodeContext *pMe, const uint64_t uValue)
-{
- QCBOREncode_Private_AppendCBORHead(pMe,
- CBOR_MAJOR_TYPE_POSITIVE_INT,
- uValue,
- 0);
-
- QCBOREncode_Private_IncrementMapOrArrayCount(pMe);
}
@@ -694,8 +599,6 @@
#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_TYPE_NEGATIVE_INT, uValue, 0);
-
- QCBOREncode_Private_IncrementMapOrArrayCount(pMe);
}
@@ -722,140 +625,57 @@
uMajorType = CBOR_MAJOR_TYPE_POSITIVE_INT;
}
QCBOREncode_Private_AppendCBORHead(pMe, uMajorType, uValue, 0);
-
- QCBOREncode_Private_IncrementMapOrArrayCount(pMe);
}
/**
* @brief Semi-private method to add a buffer full of bytes to encoded output.
*
- * @param[in] pMe The encoding context to add the integer to.
+ * @param[in] pMe The encoding context to add the string 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.
+ * Called by inline functions to add text and byte strings.
*
- * 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.
- *
- * This does the work of adding actual strings bytes to the CBOR
- * output (as opposed to adding numbers and opening / closing
- * aggregate types).
-
- * There are four use cases:
- * CBOR_MAJOR_TYPE_BYTE_STRING -- Byte strings
- * CBOR_MAJOR_TYPE_TEXT_STRING -- Text strings
- * CBOR_MAJOR_NONE_TYPE_RAW -- Already-encoded CBOR
- *
- * The first two add the head plus the actual bytes. The third just
- * adds the bytes as the heas is presumed to be in the bytes. The
- * fourth just adds the head for the very special case of
- * QCBOREncode_AddBytesLenOnly().
+ * (This used to support QCBOREncode_AddEncoded() and
+ * QCBOREncode_AddBytesLenOnly(), but that was pulled out to make this
+ * smaller. This is one of the most used methods and they are some of
+ * the least used).
*/
void
QCBOREncode_Private_AddBuffer(QCBOREncodeContext *pMe,
const uint8_t uMajorType,
const UsefulBufC Bytes)
{
- /* If it is not Raw CBOR, add the type and the length */
- if(uMajorType != CBOR_MAJOR_NONE_TYPE_RAW) {
- uint8_t uRealMajorType = uMajorType;
- QCBOREncode_Private_AppendCBORHead(pMe, uRealMajorType, Bytes.len, 0);
- }
-
- /* Actually add the bytes */
+ QCBOREncode_Private_AppendCBORHead(pMe, uMajorType, Bytes.len, 0);
UsefulOutBuf_AppendUsefulBuf(&(pMe->OutBuf), Bytes);
+}
+
+/*
+ * Public functions for adding raw encoded CBOR. See qcbor/qcbor_encode.h
+ */
+void
+QCBOREncode_AddEncoded(QCBOREncodeContext *pMe, const UsefulBufC Encoded)
+{
+ UsefulOutBuf_AppendUsefulBuf(&(pMe->OutBuf), Encoded);
QCBOREncode_Private_IncrementMapOrArrayCount(pMe);
}
-/*
- * Public functions for adding a tag. See qcbor/qcbor_encode.h
- */
-void
-QCBOREncode_AddTag(QCBOREncodeContext *pMe, const uint64_t uTag)
-{
- QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_TYPE_TAG, uTag, 0);
-}
-
-
-/**
- * @brief Semi-private method to add simple types.
- *
- * @param[in] pMe 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_Private_AddType7(QCBOREncodeContext *pMe,
- const uint8_t uMinLen,
- const uint64_t uNum)
-{
-#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
- if(pMe->uError == QCBOR_SUCCESS) {
- if(uNum >= CBOR_SIMPLEV_RESERVED_START && uNum <= CBOR_SIMPLEV_RESERVED_END) {
- pMe->uError = QCBOR_ERR_ENCODE_UNSUPPORTED;
- return;
- }
- }
-#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
-
- /* AppendCBORHead() does endian swapping for the float / double */
- QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_TYPE_SIMPLE, uNum, uMinLen);
-
- QCBOREncode_Private_IncrementMapOrArrayCount(pMe);
-}
-
-
-#ifndef USEFULBUF_DISABLE_ALL_FLOAT
-/*
- * Public functions for adding a double. See qcbor/qcbor_encode.h
- */
-void
-QCBOREncode_AddDoubleNoPreferred(QCBOREncodeContext *pMe, const double dNum)
-{
-#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
- if(pMe->uMode >= QCBOR_ENCODE_MODE_PREFERRED) {
- pMe->uError = QCBOR_ERR_NOT_PREFERRED;
- return;
- }
- if(IEEE754_IsNotStandardDoubleNaN(dNum) && !(pMe->uAllow & QCBOR_ENCODE_ALLOW_NAN_PAYLOAD)) {
- pMe->uError = QCBOR_ERR_NOT_ALLOWED;
- return;
- }
-#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
-
- QCBOREncode_Private_AddType7(pMe,
- sizeof(uint64_t),
- UsefulBufUtil_CopyDoubleToUint64(dNum));
-}
-
-
-/*
- * Public functions for adding a double. See qcbor/qcbor_encode.h
- */
-void
-QCBOREncode_AddDouble(QCBOREncodeContext *pMe, double dNum)
-{
#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
+/**
+ * @brief Semi-private method to add a double using preferred encoding.
+ *
+ * @param[in] pMe The encode context.
+ * @param[in] dNum The double to add.
+ *
+ * This converts the double to a float or half-precision if it can be done
+ * without a loss of precision. See QCBOREncode_AddDouble().
+ */
+void
+QCBOREncode_Private_AddPreferredDouble(QCBOREncodeContext *pMe, double dNum)
+{
IEEE754_union FloatResult;
bool bNoNaNPayload;
struct IEEE754_ToInt IntResult;
@@ -890,44 +710,21 @@
FloatResult = IEEE754_DoubleToSmaller(dNum, true, bNoNaNPayload);
QCBOREncode_Private_AddType7(pMe, (uint8_t)FloatResult.uSize, FloatResult.uValue);
-
-#else /* QCBOR_DISABLE_PREFERRED_FLOAT */
- QCBOREncode_AddDoubleNoPreferred(pMe, dNum);
-#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
}
-
-
-/*
- * Public functions for adding a float. See qcbor/qcbor_encode.h
+/**
+ * @brief Semi-private method to add a float using preferred encoding.
+ *
+ * @param[in] pMe The encode context.
+ * @param[in] fNum The float to add.
+ *
+ * This converts the float to a half-precision if it can be done
+ * without a loss of precision. See QCBOREncode_AddFloat().
*/
void
-QCBOREncode_AddFloatNoPreferred(QCBOREncodeContext *pMe, const float fNum)
+QCBOREncode_Private_AddPreferredFloat(QCBOREncodeContext *pMe, float fNum)
{
-#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
- if(pMe->uMode >= QCBOR_ENCODE_MODE_PREFERRED) {
- pMe->uError = QCBOR_ERR_NOT_PREFERRED;
- return;
- }
- if(IEEE754_IsNotStandardSingleNaN(fNum) && !(pMe->uAllow & QCBOR_ENCODE_ALLOW_NAN_PAYLOAD)) {
- pMe->uError = QCBOR_ERR_NOT_ALLOWED;
- return;
- }
-#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
- QCBOREncode_Private_AddType7(pMe,
- sizeof(uint32_t),
- UsefulBufUtil_CopyFloatToUint32(fNum));
-}
-
-
-/*
- * Public functions for adding a float. See qcbor/qcbor_encode.h
- */
-void
-QCBOREncode_AddFloat(QCBOREncodeContext *pMe, float fNum)
-{
-#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
IEEE754_union FloatResult;
bool bNoNaNPayload;
struct IEEE754_ToInt IntResult;
@@ -939,7 +736,6 @@
}
#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
-
if(pMe->uMode == QCBOR_ENCODE_MODE_DCBOR) {
IntResult = IEEE754_SingleToInt(fNum);
switch(IntResult.type) {
@@ -963,12 +759,9 @@
FloatResult = IEEE754_SingleToHalf(fNum, bNoNaNPayload);
QCBOREncode_Private_AddType7(pMe, (uint8_t)FloatResult.uSize, FloatResult.uValue);
-
-#else /* QCBOR_DISABLE_PREFERRED_FLOAT */
- QCBOREncode_AddFloatNoPreferred(pMe, fNum);
-#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
}
-#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
+#endif /* !QCBOR_DISABLE_PREFERRED_FLOAT */
+
#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
@@ -1079,6 +872,7 @@
}
+#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
/**
* @brief Semi-private method to open a map, array with indefinite length
*
@@ -1107,6 +901,101 @@
*/
QCBOREncode_Private_OpenMapOrArray(pMe, uMajorType);
}
+#endif
+
+
+/**
+ * @brief Check for errors when decreasing nesting.
+ *
+ * @param pMe QCBOR encoding context.
+ * @param uMajorType The major type of the nesting.
+ *
+ * Check that there is no previous error, that there is actually some
+ * nesting and that the major type of the opening of the nesting
+ * matches the major type of the nesting being closed.
+ *
+ * This is called when closing maps, arrays, byte string wrapping and
+ * open/close of byte strings.
+ */
+static bool
+QCBOREncode_Private_CheckDecreaseNesting(QCBOREncodeContext *pMe,
+ const uint8_t uMajorType)
+{
+#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
+ if(pMe->uError != QCBOR_SUCCESS) {
+ return true;
+ }
+
+ if(!Nesting_IsInNest(&(pMe->nesting))) {
+ pMe->uError = QCBOR_ERR_TOO_MANY_CLOSES;
+ return true;
+ }
+
+ if(Nesting_GetMajorType(&(pMe->nesting)) != uMajorType) {
+ pMe->uError = QCBOR_ERR_CLOSE_MISMATCH;
+ return true;
+ }
+
+#else /* !QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
+ /* None of these checks are performed if the encode guards are
+ * turned off as they all relate to correct calling.
+ *
+ * Turning off all these checks does not turn off any checking for
+ * buffer overflows or pointer issues.
+ */
+
+ (void)uMajorType;
+ (void)pMe;
+#endif /* !QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
+
+ return false;
+}
+
+
+/**
+ * @brief Insert the CBOR head for a map, array or wrapped bstr
+ *
+ * @param pMe QCBOR encoding context.
+ * @param uMajorType One of CBOR_MAJOR_TYPE_XXXX.
+ * @param uLen The length of the data item.
+ *
+ * When an array, map or bstr was opened, nothing was done but note
+ * the position. This function goes back to that position and inserts
+ * the CBOR Head with the major type and length.
+ */
+static void
+QCBOREncode_Private_CloseAggregate(QCBOREncodeContext *pMe,
+ uint8_t uMajorType,
+ size_t uLen)
+{
+ if(QCBOREncode_Private_CheckDecreaseNesting(pMe, uMajorType)) {
+ return;
+ }
+
+ if(uMajorType == CBOR_MAJOR_NONE_TYPE_OPEN_BSTR) {
+ uMajorType = CBOR_MAJOR_TYPE_BYTE_STRING;
+ }
+
+ /* A stack buffer large enough for a CBOR head (9 bytes) */
+ UsefulBuf_MAKE_STACK_UB(pBufferForEncodedHead, QCBOR_HEAD_BUFFER_SIZE);
+
+ UsefulBufC EncodedHead = QCBOREncode_EncodeHead(pBufferForEncodedHead,
+ uMajorType,
+ 0,
+ uLen);
+
+ /* No check for EncodedHead == NULLUsefulBufC is performed here to
+ * save object code. It is very clear that pBufferForEncodedHead is
+ * the correct size. If EncodedHead == NULLUsefulBufC then
+ * UsefulOutBuf_InsertUsefulBuf() will do nothing so there is no
+ * security hole introduced.
+ */
+ UsefulOutBuf_InsertUsefulBuf(&(pMe->OutBuf),
+ EncodedHead,
+ Nesting_GetStartPos(&(pMe->nesting)));
+
+ Nesting_Decrease(&(pMe->nesting));
+}
/**
@@ -1119,7 +1008,7 @@
QCBOREncode_Private_CloseMapOrArray(QCBOREncodeContext *pMe,
const uint8_t uMajorType)
{
- QCBOREncode_Private_InsertCBORHead(pMe, uMajorType, Nesting_GetCount(&(pMe->nesting)));
+ QCBOREncode_Private_CloseAggregate(pMe, uMajorType, Nesting_GetCount(&(pMe->nesting)));
}
@@ -1437,7 +1326,7 @@
uStart = Nesting_GetStartPos(&(pMe->nesting));
QCBOREncode_Private_SortMap(pMe, uStart);
- QCBOREncode_Private_InsertCBORHead(pMe, CBOR_MAJOR_TYPE_MAP, Nesting_GetCount(&(pMe->nesting)));
+ QCBOREncode_Private_CloseAggregate(pMe, CBOR_MAJOR_TYPE_MAP, Nesting_GetCount(&(pMe->nesting)));
}
@@ -1475,7 +1364,7 @@
const size_t uBstrLen = uEndPosition - uInsertPosition;
/* Actually insert */
- QCBOREncode_Private_InsertCBORHead(pMe, CBOR_MAJOR_TYPE_BYTE_STRING, uBstrLen);
+ QCBOREncode_Private_CloseAggregate(pMe, CBOR_MAJOR_TYPE_BYTE_STRING, uBstrLen);
if(pWrappedCBOR) {
/* Return pointer and length to the enclosed encoded CBOR. The
@@ -1561,10 +1450,12 @@
return;
}
- QCBOREncode_Private_InsertCBORHead(pMe, CBOR_MAJOR_NONE_TYPE_OPEN_BSTR, uAmount);
+ QCBOREncode_Private_CloseAggregate(pMe, CBOR_MAJOR_NONE_TYPE_OPEN_BSTR, uAmount);
}
+#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
+
/**
* @brief Semi-private method to close a map, array with indefinite length
*
@@ -1586,6 +1477,7 @@
QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_NONE_TYPE_SIMPLE_BREAK, CBOR_SIMPLE_BREAK, 0);
Nesting_Decrease(&(pMe->nesting));
}
+#endif
/*