Merge branch 'master' into dev
diff --git a/QCBOR.xcodeproj/project.pbxproj b/QCBOR.xcodeproj/project.pbxproj
index 6e69fbd..d869aa6 100644
--- a/QCBOR.xcodeproj/project.pbxproj
+++ b/QCBOR.xcodeproj/project.pbxproj
@@ -274,8 +274,8 @@
E776E08C214AE07400E67947 /* qcbor_encode.c */,
E776E08E214AE07500E67947 /* qcbor_decode.c */,
E776E08D214AE07500E67947 /* UsefulBuf.c */,
- E73B57582161CA690080D658 /* ieee754.c */,
E73B57572161CA680080D658 /* ieee754.h */,
+ E73B57582161CA690080D658 /* ieee754.c */,
E7864765252CE63100A0C11B /* qcbor_err_to_str.c */,
);
name = src;
diff --git a/README.md b/README.md
index 673e940..635211b 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,18 @@
+This is the QCBOR 2.0 branch. It is under development and not ready for use.
+
+The plan for QCBOR 2 is a few larger features:
+ - Map sorting
+ - Full canonical encoding support (CDE)
+ - Improved support for tag handling
+ - Perhaps other features like OID support
+ - Perhaps dCBOR support
+ - Improved test and verification
+ - Improved documentation
+ - Better presence in GitHub
+
+The improved tag handling is one of the largest work items and may change
+backwards compatibility.
+

**QCBOR** is a powerful, commercial-quality CBOR encoder/decoder that
diff --git a/inc/qcbor/UsefulBuf.h b/inc/qcbor/UsefulBuf.h
index 5f53044..eb0a691 100644
--- a/inc/qcbor/UsefulBuf.h
+++ b/inc/qcbor/UsefulBuf.h
@@ -43,6 +43,9 @@
when who what, where, why
-------- ---- --------------------------------------------------
+ 19/11/2023 llundblade Add UsefulOutBuf_GetOutput().
+ 19/11/2023 llundblade Add UsefulOutBuf_Swap().
+ 19/11/2023 llundblade Add UsefulOutBuf_Compare().
19/12/2022 llundblade Document that adding empty data is allowed.
4/11/2022 llundblade Add GetOutPlace and Advance to UsefulOutBuf.
9/21/2021 llundbla Clarify UsefulOutBuf size calculation mode
@@ -854,7 +857,7 @@
/**
- * @brief Initialize and supply the actual output buffer.
+ * @brief Initialize and supply the output buffer.
*
* @param[out] pUOutBuf The @ref UsefulOutBuf to initialize.
* @param[in] Storage Buffer to output into.
@@ -1336,7 +1339,7 @@
/**
- * @brief Returns the resulting valid data in a UsefulOutBuf
+ * @brief Returns the data put into a UsefulOutBuf.
*
* @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
*
@@ -1354,7 +1357,7 @@
/**
- * @brief Copies the valid data into a supplied buffer
+ * @brief Copy out the data put into a UsefulOutBuf.
*
* @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
* @param[out] Dest The destination buffer to copy into.
@@ -1364,11 +1367,98 @@
* state was entered.
*
* This is the same as UsefulOutBuf_OutUBuf() except it copies the
- * data to @c Dest.
+ * data to @c Dest rather than returning a pointer.
*/
UsefulBufC UsefulOutBuf_CopyOut(UsefulOutBuf *pUOutBuf, UsefulBuf Dest);
+/**
+ * @brief Returns data starting at an offset that was put into a UsefulOutBuf.
+ *
+ * @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+ * @param[in] uOffset Offset to bytes to return.
+ *
+ * @return NULLUsefulBufC or the bytes at the offset.
+ *
+ * This is the same as UsefulOutBuf_OutUBuf() except a starting offset
+ * maybe specified. It returns the bytes starting at @c uOffset to the
+ * end of what was encoded so far. Calling this with @c uOffset 0 is
+ * equivalent to UsefulOutBuf_OutUBuf().
+ *
+ * If there's nothing at @c uOffset or it is past the in the output
+ * buffer, a \ref NULLUsefulBufC is returned.
+ *
+ * This is typically not needed in typical use. It is used by QCBOR
+ * along with UsefulOutBuf_Compare() and UsefulOutBuf_Swap() for
+ * sorting CBOR maps.
+ */
+UsefulBufC
+UsefulOutBuf_OutUBufOffset(UsefulOutBuf *pUOutBuf, size_t uOffset);
+
+
+/**
+ * @brief Compare bytes at offsets.
+ *
+ * @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+ * @param[in] uStart1 Offset of first bytes to compare.
+ * @param[in] uStart2 Offset of second bytes to compare.
+ *
+ * @return 0 for equality, positive if uStart1 is lexographically larger,
+ * negative if uStart2 is lexographically larger.
+ *
+ * This looks into bytes that have been output at the offsets @c start1
+ * and @c start2. It compares bytes at those two starting points until
+ * they are not equal or the end of the output data is reached from
+ * one of the starting points.
+ *
+ * This returns positive when @c uStart1 lexographically sorts ahead
+ * of @c uStart2 and vice versa. Zero is returned if the strings
+ * compare equally. This only happens when the end of the valid data
+ * is reached from one of the starting points and the comparison up to
+ * that point is equality.
+ *
+ * If either start is past the end of data in the output buffer, 0
+ * will be returned. It is the caller's responsibility to make sure
+ * the offsets are not off the end such that a comparison is actually
+ * being made. No data will ever be read off the end of the buffer so
+ * this safe no matter what offsets are passed.
+ *
+ * This is a relatively odd function in that it works on data in the
+ * output buffer. It is employed by QCBOR to sort CBOR-encoded maps that
+ * are in the output buffer.
+ */
+int UsefulOutBuf_Compare(UsefulOutBuf *pUOutBuf, size_t uStart1, size_t uStart2);
+
+
+/**
+ * @brief Swap two regions of output bytes.
+ *
+ * @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
+ * @param[in] uStartOffset Offset to start of bytes to be swapped.
+ * @param[in] uPivotOffset Offset to pivot around which bytes are swapped.
+ * @param[in] uEndOffset Offset to end of region to be swappe.
+ *
+ * This reaches into bytes that have been output and swaps two
+ * adjacent regions.
+ *
+ * If any of the offsets are outside the range of valid data, no
+ * swapping will be performed. If the start is not the smallest and
+ * the pivot is not in the middle no swapping will be performed.
+ *
+ * The byte at @c uStartOffset will participate in the swapping. The
+ * byte at @c uEndOffset will not participate in the swapping, only
+ * the byte before it.
+ *
+ * This is a relatively odd function in that it works on data in the
+ * output buffer. It is employed by QCBOR to bubble sort encoded CBOR
+ * maps.
+ */
+void UsefulOutBuf_Swap(UsefulOutBuf *pUOutBuf,
+ size_t uStartOffset,
+ size_t uPivotOffset,
+ size_t uEndOffset);
+
+
/**
diff --git a/inc/qcbor/qcbor_common.h b/inc/qcbor/qcbor_common.h
index 0575fd5..07de6c7 100644
--- a/inc/qcbor/qcbor_common.h
+++ b/inc/qcbor/qcbor_common.h
@@ -60,8 +60,8 @@
* - QCBOR 1.1 is indicated by the #define QCBOR_1_1
* - QCBOR 1.0 is indicated by the absence of all the above
*/
-#define QCBOR_VERSION_MAJOR 1
-#define QCBOR_VERSION_MINOR 3
+#define QCBOR_VERSION_MAJOR 2
+#define QCBOR_VERSION_MINOR 0
#define QCBOR_VERSION_PATCH 0
diff --git a/inc/qcbor/qcbor_decode.h b/inc/qcbor/qcbor_decode.h
index bf4a042..e9c40fc 100644
--- a/inc/qcbor/qcbor_decode.h
+++ b/inc/qcbor/qcbor_decode.h
@@ -291,6 +291,16 @@
/** Type for a double floating-point number. Data is in @c val.double. */
#define QCBOR_TYPE_DOUBLE 27
+/** Special type for integers between -2^63 - 1 to -2^64 that
+ * can't be returned as @ref QCBOR_TYPE_INT64 because they don't fit
+ * in an int64_t. The value is returned in @c val.uint64, but this
+ * isn't the number transmitted. Do this arithmatic (carefully to
+ * avoid over/underflow) to get the value transmitted: - val.uint64 - 1.
+ * See QCBOREncode_AddNegativeUInt64() for a longer explanation
+ * and warning. */
+#define QCBOR_TYPE_65BIT_NEG_INT 28
+
+
#define QCBOR_TYPE_BREAK 31 /* Used internally; never returned */
/** For @ref QCBOR_DECODE_MODE_MAP_AS_ARRAY decode mode, a map that is
diff --git a/inc/qcbor/qcbor_encode.h b/inc/qcbor/qcbor_encode.h
index 49d2394..435d5e0 100644
--- a/inc/qcbor/qcbor_encode.h
+++ b/inc/qcbor/qcbor_encode.h
@@ -544,6 +544,51 @@
/**
+ * @brief Add a negative 64-bit integer to encoded output
+ *
+ * @param[in] pCtx The encoding context to add the integer to.
+ * @param[in] uNum The integer to add.
+ *
+ * QCBOREncode_AddInt64() is much better to encode negative integers
+ * than this. What this can do is add integers with one more
+ * significant bit than an int64_t (a "65-bit" integer if you count
+ * the sign as a bit) which is possible because CBOR happens to
+ * support such integers.
+ *
+ * The actual value encoded is -uNum - 1. That is, give 0 for uNum to
+ * transmit -1, give 1 to transmit -2 and give UINT64_MAX to transmit
+ * -UINT64_MAX-1 (18446744073709551616). The interface is odd like
+ * this so all negative values CBOR can represent can be encoded by
+ * QCBOR (making this a complete CBOR implementation).
+ *
+ * The most negative value QCBOREncode_AddInt64() can encode is
+ * -9223372036854775808 which is -2^63 or negative
+ * 0x800000000000. This can encode from -9223372036854775809 to
+ * -18446744073709551616 or -2^63 - 1 to -2^64. Note that
+ * it is not possible to represent plus or minus 18446744073709551616
+ * in any standard C data type.
+ *
+ * Negative integers are normally decoded in QCBOR with type
+ * @ref QCBOR_TYPE_INT64. Integers in the range of -9223372036854775809
+ * to -18446744073709551616 are returned as @ref QCBOR_TYPE_65BIT_NEG_INT.
+ *
+ * WARNING: some CBOR decoders will be unable to decode -2^63 - 1 to
+ * -2^64. Also, most CPUs do not have registers that can represent
+ * this range. If you need 65-bit negative integers, you likely need
+ * negative 66, 67 and 68-bit negative integers so it is likely better
+ * to use CBOR big numbers where you can have any number of bits. See
+ * QCBOREncode_AddTNegativeBignum() and TODO: also xxxx
+ */
+void
+QCBOREncode_AddNegativeUInt64(QCBOREncodeContext *pCtx, uint64_t uNum);
+
+static void
+QCBOREncode_AddNegativeUInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, uint64_t uNum);
+
+static void
+QCBOREncode_AddNegativeUInt64ToMapN(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.
@@ -1996,6 +2041,27 @@
QCBOREncode_CloseMapIndefiniteLength(QCBOREncodeContext *pCtx);
+/**
+ * @brief Close and sort an open map.
+ *
+ * @param[in] pCtx The encoding context to close the map in .
+ *
+ * This is the same as QCBOREncode_CloseMap() except it sorts the map
+ * per RFC 8949 Section 4.2.1. This sort is lexicographic of the CBOR-
+ * encoded map labels.
+ *
+ * This is more expensive than most things in the encoder. It uses
+ * bubble sort which runs in n-squared time where n is the number of
+ * map items. Sorting large maps on slow CPUs might be slow. This is
+ * also increases the object code size of the encoder by about 30%.
+ *
+ * Bubble sort was selected so as to not need an extra buffer to track
+ * map item offsets. Bubble sort works well even though map items are
+ * not all the same size because it always swaps adjacent items.
+ */
+void QCBOREncode_CloseAndSortMap(QCBOREncodeContext *pCtx);
+
+void QCBOREncode_CloseAndSortMapIndef(QCBOREncodeContext *pCtx);
/**
@@ -2285,8 +2351,6 @@
* 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,
@@ -2348,47 +2412,6 @@
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 will be removed in QCBOR 2.0. It was never a public function.
- *
- * 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().
- *
- * TODO: remove this in QCBOR 2.0
- */
-static void
-QCBOREncode_AddBytesLenOnly(QCBOREncodeContext *pCtx,
- UsefulBufC Bytes);
-
-static void
-QCBOREncode_AddBytesLenOnlyToMap(QCBOREncodeContext *pCtx,
- const char *szLabel,
- UsefulBufC Bytes);
-
-static void
-QCBOREncode_AddBytesLenOnlyToMapN(QCBOREncodeContext *pCtx,
- int64_t nLabel,
- UsefulBufC Bytes);
-
-
@@ -2437,6 +2460,24 @@
static inline void
+QCBOREncode_AddNegativeUInt64ToMap(QCBOREncodeContext *pMe, const char *szLabel, uint64_t uNum)
+{
+ /* Use _AddBuffer() because _AddSZString() is defined below, not above */
+ QCBOREncode_Private_AddBuffer(pMe,
+ CBOR_MAJOR_TYPE_TEXT_STRING,
+ UsefulBuf_FromSZ(szLabel));
+ QCBOREncode_AddNegativeUInt64(pMe, uNum);
+}
+
+static inline void
+QCBOREncode_AddNegativeUInt64ToMapN(QCBOREncodeContext *pMe, int64_t nLabel, uint64_t uNum)
+{
+ QCBOREncode_AddInt64(pMe, nLabel);
+ QCBOREncode_AddNegativeUInt64(pMe, uNum);
+}
+
+
+static inline void
QCBOREncode_AddText(QCBOREncodeContext *pMe, const UsefulBufC Text)
{
QCBOREncode_Private_AddBuffer(pMe, CBOR_MAJOR_TYPE_TEXT_STRING, Text);
@@ -2694,30 +2735,6 @@
QCBOREncode_OpenBytes(pMe, pPlace);
}
-static inline void
-QCBOREncode_AddBytesLenOnly(QCBOREncodeContext *pMe, const UsefulBufC Bytes)
-{
- QCBOREncode_Private_AddBuffer(pMe, CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY, Bytes);
-}
-
-static inline void
-QCBOREncode_AddBytesLenOnlyToMap(QCBOREncodeContext *pMe,
- const char *szLabel,
- const UsefulBufC Bytes)
-{
- QCBOREncode_AddSZString(pMe, szLabel);
- QCBOREncode_AddBytesLenOnly(pMe, Bytes);
-}
-
-static inline void
-QCBOREncode_AddBytesLenOnlyToMapN(QCBOREncodeContext *pMe,
- const int64_t nLabel,
- const UsefulBufC Bytes)
-{
- QCBOREncode_AddInt64(pMe, nLabel);
- QCBOREncode_AddBytesLenOnly(pMe, Bytes);
-}
-
static inline void
QCBOREncode_AddTBinaryUUID(QCBOREncodeContext *pMe,
diff --git a/src/UsefulBuf.c b/src/UsefulBuf.c
index b36e5d0..847395c 100644
--- a/src/UsefulBuf.c
+++ b/src/UsefulBuf.c
@@ -1,6 +1,6 @@
/*==============================================================================
Copyright (c) 2016-2018, The Linux Foundation.
- Copyright (c) 2018-2022, Laurence Lundblade.
+ Copyright (c) 2018-2023, Laurence Lundblade.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
@@ -41,9 +41,12 @@
when who what, where, why
-------- ---- ---------------------------------------------------
+ 19/11/2023 llundblade Add UsefulOutBuf_GetOutput().
+ 19/11/2023 llundblade Add UsefulOutBuf_Swap().
+ 19/11/2023 llundblade Add UsefulOutBuf_Compare().
19/12/2022 llundblade Don't pass NULL to memmove when adding empty data.
4/11/2022 llundblade Add GetOutPlace and Advance to UsefulOutBuf
- 3/6/2021 mcr/llundblade Fix warnings related to --Wcast-qual
+ 3/6/2021 mcr/llundblade Fix warnings related to --Wcast-qual
01/28/2020 llundblade Refine integer signedness to quiet static analysis.
01/08/2020 llundblade Documentation corrections & improved code formatting.
11/08/2019 llundblade Re check pointer math and update comments
@@ -424,3 +427,105 @@
return result;
}
+
+/*
+ * Public function -- see UsefulBuf.h
+ *
+ * Code Reviewers: THIS FUNCTION DOES POINTER MATH
+ */
+int UsefulOutBuf_Compare(UsefulOutBuf *me, size_t uStart1, size_t uStart2)
+{
+ const uint8_t *pBase;
+ const uint8_t *pEnd;
+ const uint8_t *p1;
+ const uint8_t *p2;
+ int uComparison;
+
+ pBase = me->UB.ptr;
+ pEnd = (const uint8_t *)pBase + me->data_len;
+ p1 = pBase + uStart1;
+ p2 = pBase + uStart2;
+
+ uComparison = 0;
+ while(p1 < pEnd && p2 < pEnd) {
+ uComparison = *p2 - *p1;
+ if(uComparison != 0) {
+ break;;
+ }
+ p1++;
+ p2++;
+ }
+
+ return uComparison;
+}
+
+
+/**
+ * @brief Reverse order of bytes in a buffer.
+ *
+ * This reverses bytes starting at pStart, up to, but not including
+ * the byte at pEnd
+ */
+static void
+UsefulOutBuf_Private_ReverseBytes(uint8_t *pStart, uint8_t *pEnd)
+{
+ uint8_t uTmp;
+
+ while(pStart < pEnd) {
+ pEnd--;
+ uTmp = *pStart;
+ *pStart = *pEnd;
+ *pEnd = uTmp;
+ pStart++;
+ }
+}
+
+
+/*
+ * Public function -- see UsefulBuf.h
+ *
+ * Code Reviewers: THIS FUNCTION DOES POINTER MATH
+ */
+void UsefulOutBuf_Swap(UsefulOutBuf *pMe, size_t uStartOffset, size_t uPivotOffset, size_t uEndOffset)
+{
+ uint8_t *pBase;
+
+ if(uStartOffset > pMe->data_len || uPivotOffset > pMe->data_len || uEndOffset > pMe->data_len) {
+ return;
+ }
+
+ if(uStartOffset > uPivotOffset || uStartOffset > uEndOffset || uPivotOffset > uEndOffset) {
+ return;
+ }
+
+ /* This is the "reverse" algorithm to swap two memory regions */
+ pBase = pMe->UB.ptr;
+ UsefulOutBuf_Private_ReverseBytes(pBase + uStartOffset, pBase + uPivotOffset);
+ UsefulOutBuf_Private_ReverseBytes(pBase + uPivotOffset, pBase + uEndOffset);
+ UsefulOutBuf_Private_ReverseBytes(pBase + uStartOffset, pBase + uEndOffset);
+}
+
+
+/*
+ * Public function -- see UsefulBuf.h
+ */
+UsefulBufC
+UsefulOutBuf_OutUBufOffset(UsefulOutBuf *pMe, size_t uOffset)
+{
+ UsefulBufC ReturnValue;
+
+ ReturnValue = UsefulOutBuf_OutUBuf(pMe);
+
+ if(UsefulBuf_IsNULLC(ReturnValue)) {
+ return NULLUsefulBufC;
+ }
+
+ if(uOffset >= ReturnValue.len) {
+ return NULLUsefulBufC;
+ }
+
+ ReturnValue.ptr = (const uint8_t *)ReturnValue.ptr + uOffset;
+ ReturnValue.len -= uOffset;
+
+ return ReturnValue;
+}
diff --git a/src/qcbor_decode.c b/src/qcbor_decode.c
index 49a6a76..a0bec4e 100644
--- a/src/qcbor_decode.c
+++ b/src/qcbor_decode.c
@@ -884,10 +884,8 @@
pDecodedItem->uDataType = QCBOR_TYPE_INT64;
} else {
- /* C can't represent a negative integer in this range so it
- * is an error.
- */
- uReturn = QCBOR_ERR_INT_OVERFLOW;
+ pDecodedItem->val.uint64 = uArgument;
+ pDecodedItem->uDataType = QCBOR_TYPE_65BIT_NEG_INT;
}
}
@@ -5148,6 +5146,12 @@
}
break;
+ case QCBOR_TYPE_65BIT_NEG_INT:
+ /* This type occurs if the value won't fit into int64_t
+ * so this is always an error. */
+ return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
+ break;
+
default:
return QCBOR_ERR_UNEXPECTED_TYPE;
}
@@ -5556,12 +5560,15 @@
case QCBOR_TYPE_UINT64:
if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
- *puValue = pItem->val.uint64;
+ *puValue = pItem->val.uint64;
} else {
return QCBOR_ERR_UNEXPECTED_TYPE;
}
break;
+ case QCBOR_TYPE_65BIT_NEG_INT:
+ return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
+
default:
return QCBOR_ERR_UNEXPECTED_TYPE;
}
@@ -5956,6 +5963,10 @@
return QCBOR_ERR_HW_FLOAT_DISABLED;
#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
+ case QCBOR_TYPE_65BIT_NEG_INT:
+ *pdValue = -(double)pItem->val.uint64 - 1;
+ break;
+
default:
return QCBOR_ERR_UNEXPECTED_TYPE;
}
diff --git a/src/qcbor_encode.c b/src/qcbor_encode.c
index 9117a7d..a2a944a 100644
--- a/src/qcbor_encode.c
+++ b/src/qcbor_encode.c
@@ -665,6 +665,18 @@
/*
+ * Public functions for adding negative integers. See qcbor/qcbor_encode.h
+ */
+void QCBOREncode_AddNegativeUInt64(QCBOREncodeContext *pMe, const uint64_t uValue)
+{
+ // TODO: Error out in dCBOR mode
+ QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_TYPE_NEGATIVE_INT, uValue, 0);
+
+ QCBOREncode_Private_IncrementMapOrArrayCount(pMe);
+}
+
+
+/*
* Public functions for adding signed integers. See qcbor/qcbor_encode.h
*/
void
@@ -676,9 +688,9 @@
if(nNum < 0) {
/* In CBOR -1 encodes as 0x00 with major type negative int.
* First add one as a signed integer because that will not
- * overflow. Then change the sign as needed for encoding. (The
+ * overflow. Then change the sign as needed for encoding (the
* opposite order, changing the sign and subtracting, can cause
- * an overflow when encoding INT64_MIN. */
+ * an overflow when encoding INT64_MIN). */
int64_t nTmp = nNum + 1;
uValue = (uint64_t)-nTmp;
uMajorType = CBOR_MAJOR_TYPE_NEGATIVE_INT;
@@ -826,6 +838,32 @@
/*
+ * Public functions for adding a double. See qcbor/qcbor_encode.h
+ */
+void QCBOREncode_AddDoubleDeterministic(QCBOREncodeContext *me, double dNum)
+{
+ if(dNum <= (double)UINT64_MAX && dNum >= 0) {
+ uint64_t uNum = (uint64_t)dNum;
+ if((double)uNum == dNum) {
+ QCBOREncode_AddUInt64(me, uNum);
+ return;
+ }
+ /* Fall through */
+ } else if(dNum >= (double)INT64_MIN && dNum < 0) {
+ int64_t nNum = (int64_t)dNum;
+ if((double)nNum == dNum) {
+ QCBOREncode_AddInt64(me, nNum);
+ return;
+ }
+ /* Fall through */
+ }
+ //const IEEE754_union uNum = IEEE754_DoubleToSmallest(dNum);
+
+ //QCBOREncode_AddType7(me, uNum.uSize, uNum.uValue);
+}
+
+
+/*
* Public functions for adding a float. See qcbor/qcbor_encode.h
*/
void
@@ -1002,6 +1040,299 @@
}
+
+/**
+ * @brief Decode a CBOR item head.
+ *
+ * @param[in] pUInBuf UsefulInputBuf to read from.
+ * @param[out] pnMajorType Major type of decoded head.
+ * @param[out] puArgument Argument of decoded head.
+ * @param[out] pnAdditionalInfo Additional info from decoded head.
+ *
+ * @return SUCCESS if a head was decoded
+ * HIT_END if there were not enough bytes to decode a head
+ * UNSUPPORTED if the decoded item is not one that is supported
+ *
+ * This is copied from qcbor_decode.c rather than referenced. This
+ * makes the core decoder 60 bytes smaller because it gets inlined.
+ * It would not get inlined if it was referenced. It is important to
+ * make the core decoder as small as possible. The copy here does make
+ * map sorting 200 bytes bigger, but map sorting is rarely used in
+ * environments that need small object code. It would also make
+ * qcbor_encode.c depend on qcbor_decode.c
+ *
+ * This is also super stable and tested. It implements the very
+ * well-defined part of CBOR that will never change. So this won't
+ * change.
+ */
+static QCBORError
+QCBOREncodePriv_DecodeHead(UsefulInputBuf *pUInBuf,
+ int *pnMajorType,
+ uint64_t *puArgument,
+ int *pnAdditionalInfo)
+{
+ QCBORError uReturn;
+
+ /* Get the initial byte that every CBOR data item has and break it
+ * down. */
+ const int nInitialByte = (int)UsefulInputBuf_GetByte(pUInBuf);
+ const int nTmpMajorType = nInitialByte >> 5;
+ const int nAdditionalInfo = nInitialByte & 0x1f;
+
+ /* Where the argument accumulates */
+ uint64_t uArgument;
+
+ if(nAdditionalInfo >= LEN_IS_ONE_BYTE && nAdditionalInfo <= LEN_IS_EIGHT_BYTES) {
+ /* Need to get 1,2,4 or 8 additional argument bytes. Map
+ * LEN_IS_ONE_BYTE..LEN_IS_EIGHT_BYTES to actual length.
+ */
+ static const uint8_t aIterate[] = {1,2,4,8};
+
+ /* Loop getting all the bytes in the argument */
+ uArgument = 0;
+ for(int i = aIterate[nAdditionalInfo - LEN_IS_ONE_BYTE]; i; i--) {
+ /* This shift and add gives the endian conversion. */
+ uArgument = (uArgument << 8) + UsefulInputBuf_GetByte(pUInBuf);
+ }
+ } else if(nAdditionalInfo >= ADDINFO_RESERVED1 && nAdditionalInfo <= ADDINFO_RESERVED3) {
+ /* The reserved and thus-far unused additional info values */
+ uReturn = QCBOR_ERR_UNSUPPORTED;
+ goto Done;
+ } else {
+ /* Less than 24, additional info is argument or 31, an
+ * indefinite-length. No more bytes to get.
+ */
+ uArgument = (uint64_t)nAdditionalInfo;
+ }
+
+ if(UsefulInputBuf_GetError(pUInBuf)) {
+ uReturn = QCBOR_ERR_HIT_END;
+ goto Done;
+ }
+
+ /* All successful if arrived here. */
+ uReturn = QCBOR_SUCCESS;
+ *pnMajorType = nTmpMajorType;
+ *puArgument = uArgument;
+ *pnAdditionalInfo = nAdditionalInfo;
+
+Done:
+ return uReturn;
+}
+
+
+/**
+ * @brief Consume the next item from a UsefulInputBuf.
+ *
+ * @param[in] pInBuf UsefulInputBuf from which to consume item.
+ *
+ * Recursive, but stack usage is light and encoding depth limit
+ */
+static QCBORError
+QCBOR_Private_ConsumeNext(UsefulInputBuf *pInBuf)
+{
+ int nMajor;
+ uint64_t uArgument;
+ int nAdditional;
+ uint16_t uItemCount;
+ uint16_t uMul;
+ uint16_t i;
+ QCBORError uCBORError;
+
+ uCBORError = QCBOREncodePriv_DecodeHead(pInBuf, &nMajor, &uArgument, &nAdditional);
+ if(uCBORError != QCBOR_SUCCESS) {
+ return uCBORError;
+ }
+
+ uMul = 1;
+
+ switch(nMajor) {
+ case CBOR_MAJOR_TYPE_POSITIVE_INT: /* Major type 0 */
+ case CBOR_MAJOR_TYPE_NEGATIVE_INT: /* Major type 1 */
+ break;
+
+ case CBOR_MAJOR_TYPE_SIMPLE:
+ return uArgument == CBOR_SIMPLE_BREAK ? 1 : 0;
+ break;
+
+ case CBOR_MAJOR_TYPE_BYTE_STRING:
+ case CBOR_MAJOR_TYPE_TEXT_STRING:
+ if(nAdditional == LEN_IS_INDEFINITE) {
+ /* Segments of indefinite length */
+ while(QCBOR_Private_ConsumeNext(pInBuf) == 0);
+ }
+ (void)UsefulInputBuf_GetBytes(pInBuf, uArgument);
+ break;
+
+ case CBOR_MAJOR_TYPE_TAG:
+ QCBOR_Private_ConsumeNext(pInBuf);
+ break;
+
+ case CBOR_MAJOR_TYPE_MAP:
+ uMul = 2;
+ /* Fallthrough */
+ case CBOR_MAJOR_TYPE_ARRAY:
+ uItemCount = (uint16_t)uArgument * uMul;
+ if(nAdditional == LEN_IS_INDEFINITE) {
+ uItemCount = UINT16_MAX;
+ }
+ for(i = uItemCount; i > 0; i--) {
+ if(QCBOR_Private_ConsumeNext(pInBuf)) {
+ /* End of indefinite length */
+ break;
+ }
+ }
+ break;
+ }
+
+ return QCBOR_SUCCESS;
+}
+
+
+/**
+ * @brief Decoded next item to get its length.
+ *
+ * Decode the next item in map no matter what type it is. It works
+ * recursively when an item is a map or array It returns offset just
+ * past the item decoded or zero there are no more items in the output
+ * buffer.
+ *
+ * This doesn't distinguish between end of the input and an error
+ * because it is used to decode stuff we encoded into a buffer, not
+ * stuff that came in from outside. We still want a check for safety
+ * in case of bugs here, but it is OK to report end of input on error.
+ */
+static uint32_t
+QCBOREncode_Private_DecodeNextInMap(QCBOREncodeContext *pMe, uint32_t uStart)
+{
+ UsefulInputBuf InBuf;
+ UsefulBufC EncodedMapBytes;
+ QCBORError uCBORError;
+
+ EncodedMapBytes = UsefulOutBuf_OutUBufOffset(&(pMe->OutBuf), uStart);
+ if(UsefulBuf_IsNULLC(EncodedMapBytes)) {
+ return 0;
+ }
+
+ UsefulInputBuf_Init(&InBuf, EncodedMapBytes);
+
+ /* This is always used on maps, so consume two, the label and the value */
+ uCBORError = QCBOR_Private_ConsumeNext(&InBuf);
+ if(uCBORError) {
+ return 0;
+ }
+ uCBORError = QCBOR_Private_ConsumeNext(&InBuf);
+ if(uCBORError) {
+ return 0;
+ }
+
+ /* Cast is safe because this is QCBOR which limits sizes to UINT32_MAX */
+ return (uint32_t)UsefulInputBuf_Tell(&InBuf);
+}
+
+
+/**
+ * @brief Sort items lexographically by encoded labels.
+ *
+ * @param[in] pMe Encoding context.
+ * @param[in] uStart Offset in outbuf of first item for sorting.
+ *
+ * This reaches into the UsefulOutBuf in the encoding context and
+ * sorts encoded CBOR items. The byte offset start of the items is at
+ * @c uStart and it goes to the end of valid bytes in the
+ * UsefulOutBuf.
+ */
+static void
+QCBOREncode_Private_SortMap(QCBOREncodeContext *pMe, uint32_t uStart)
+{
+ bool bSwapped;
+ int nComparison;
+ uint32_t uLen2;
+ uint32_t uLen1;
+ uint32_t uStart1;
+ uint32_t uStart2;
+
+ if(pMe->uError != QCBOR_SUCCESS) {
+ return;
+ }
+
+ /* Bubble sort because the sizes of all the items are not the
+ * same. It works with adjacent pairs so the swap is not too
+ * difficult even though sizes are different.
+ *
+ * While bubble sort is n-squared, it seems OK here because n will
+ * usually be small and the comparison and swap functions aren't
+ * too CPU intensive.
+ *
+ * Another approach would be to have an array of offsets to the
+ * items. However this requires memory allocation and the swap
+ * operation for quick sort or such is complicated because the item
+ * sizes are not the same and overlap may occur in the bytes being
+ * swapped.
+ */
+ do {
+ uLen1 = QCBOREncode_Private_DecodeNextInMap(pMe, uStart);
+ if(uLen1 == 0) {
+ /* It's an empty map. Nothing to do. */
+ break;
+ }
+ uStart1 = uStart;
+ uStart2 = uStart1 + uLen1;
+ bSwapped = false;
+
+ while(1) {
+ uLen2 = QCBOREncode_Private_DecodeNextInMap(pMe, uStart2);
+ if(uLen2 == 0) {
+ break;
+ }
+
+ nComparison = UsefulOutBuf_Compare(&(pMe->OutBuf), uStart1, uStart2);
+ if(nComparison < 0) {
+ UsefulOutBuf_Swap(&(pMe->OutBuf), uStart1, uStart2, uStart2 + uLen2);
+ uStart1 = uStart1 + uLen2;
+ bSwapped = true;
+ } else {
+ uStart1 = uStart2;
+ }
+ uStart2 = uStart2 + uLen2;
+ }
+ } while(bSwapped);
+}
+
+
+/*
+ * Public functions for closing sorted maps. See qcbor/qcbor_encode.h
+ */
+void QCBOREncode_CloseAndSortMap(QCBOREncodeContext *pMe)
+{
+ uint32_t uStart;
+
+ /* The Header for the map we are about to sort hasn't been
+ * inserted yet, so uStart is the position of the first item
+ * and the end out the UsefulOutBuf data is the end of the
+ * items we are about to sort.
+ */
+ uStart = Nesting_GetStartPos(&(pMe->nesting));
+ QCBOREncode_Private_SortMap(pMe, uStart);
+
+ QCBOREncode_Private_InsertCBORHead(pMe, CBOR_MAJOR_TYPE_MAP, Nesting_GetCount(&(pMe->nesting)));
+}
+
+
+/*
+ * Public functions for closing sorted maps. See qcbor/qcbor_encode.h
+ */
+void QCBOREncode_CloseAndSortMapIndef(QCBOREncodeContext *pMe)
+{
+ uint32_t uStart;
+
+ uStart = Nesting_GetStartPos(&(pMe->nesting));
+ QCBOREncode_Private_SortMap(pMe, uStart);
+
+ QCBOREncode_Private_CloseMapOrArrayIndefiniteLength(pMe, CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN);
+}
+
+
/*
* Public functions for closing bstr wrapping. See qcbor/qcbor_encode.h
*/
diff --git a/test/UsefulBuf_Tests.c b/test/UsefulBuf_Tests.c
index e93a011..e6be249 100644
--- a/test/UsefulBuf_Tests.c
+++ b/test/UsefulBuf_Tests.c
@@ -1,6 +1,6 @@
/*==============================================================================
Copyright (c) 2016-2018, The Linux Foundation.
- Copyright (c) 2018-2022, Laurence Lundblade.
+ Copyright (c) 2018-2023, Laurence Lundblade.
Copyright (c) 2021, Arm Limited.
All rights reserved.
@@ -873,3 +873,185 @@
return NULL;
}
+
+
+const char * UOBExtraTests(void)
+{
+ #define COMPARE_TEST_SIZE 10
+ UsefulOutBuf_MakeOnStack( UOB, COMPARE_TEST_SIZE);
+ int nCompare;
+ UsefulBufC Out;
+
+ /* Test UsefulOutBuf_Compare() */
+ UsefulOutBuf_AppendString(&UOB, "abcabdefab");
+
+ nCompare = UsefulOutBuf_Compare(&UOB, 0, 8);
+ if(nCompare != 0) {
+ return "ab should compare equal";
+ }
+
+ nCompare = UsefulOutBuf_Compare(&UOB, 0, 3);
+ if(nCompare != 'd' - 'c') {
+ return "abc should not equal abd";
+ }
+
+ nCompare = UsefulOutBuf_Compare(&UOB, 3, 8);
+ if(nCompare != 0) {
+ return "ab should compare equal";
+ }
+
+ nCompare = UsefulOutBuf_Compare(&UOB, 2, 5);
+ if(nCompare != 'd' - 'c') {
+ return "ca should not equal de";
+ }
+
+ nCompare = UsefulOutBuf_Compare(&UOB, 5, 2);
+ if(nCompare != 'c' - 'd') {
+ return "de should not equal ca";
+ }
+
+ nCompare = UsefulOutBuf_Compare(&UOB, 7, 8);
+ if(nCompare != 'a' - 'f') {
+ return "fa should not equal ab";
+ }
+
+ nCompare = UsefulOutBuf_Compare(&UOB, 0, 0);
+ if(nCompare != 0) {
+ return "comparison to self failed";
+ }
+
+ nCompare = UsefulOutBuf_Compare(&UOB, 9, 9);
+ if(nCompare != 0) {
+ return "b should compare equal to b";
+ }
+
+ nCompare = UsefulOutBuf_Compare(&UOB, 10, 10);
+ if(nCompare != 0) {
+ return "Comparison off the end is equal";
+ }
+
+ nCompare = UsefulOutBuf_Compare(&UOB, 0, 100);
+ if(nCompare != 0) {
+ return "Comparison off the end is equal";
+ }
+
+ nCompare = UsefulOutBuf_Compare(&UOB, 100, 0);
+ if(nCompare != 0) {
+ return "Comparison off the end is equal";
+ }
+
+ /* Test UsefulOutBuf_Swap() */
+
+ UsefulOutBuf_Reset(&UOB);
+ UsefulOutBuf_AppendString(&UOB, "abcdefgh");
+ UsefulOutBuf_Swap(&UOB, 0, 4, 8);
+ Out = UsefulOutBuf_OutUBuf(&UOB);
+ if(UsefulBuf_Compare(Out, UsefulBuf_FROM_SZ_LITERAL("efghabcd"))) {
+ return "swap fail 1";
+ }
+
+ UsefulOutBuf_Reset(&UOB);
+ UsefulOutBuf_AppendString(&UOB, "abcdefgh");
+ UsefulOutBuf_Swap(&UOB, 0, 1, 2);
+ Out = UsefulOutBuf_OutUBuf(&UOB);
+ if(UsefulBuf_Compare(Out, UsefulBuf_FROM_SZ_LITERAL("bacdefgh"))) {
+ return "swap fail 2";
+ }
+
+ UsefulOutBuf_Reset(&UOB);
+ UsefulOutBuf_AppendString(&UOB, "abcdefgh");
+ UsefulOutBuf_Swap(&UOB, 0, 1, 8);
+ Out = UsefulOutBuf_OutUBuf(&UOB);
+ if(UsefulBuf_Compare(Out, UsefulBuf_FROM_SZ_LITERAL("bcdefgha"))) {
+ return "swap fail 3";
+ }
+
+ UsefulOutBuf_Reset(&UOB);
+ UsefulOutBuf_AppendString(&UOB, "abcdefgh");
+ UsefulOutBuf_Swap(&UOB, 0, 3, 4);
+ Out = UsefulOutBuf_OutUBuf(&UOB);
+ if(UsefulBuf_Compare(Out, UsefulBuf_FROM_SZ_LITERAL("dabcefgh"))) {
+ return "swap fail 4";
+ }
+
+ UsefulOutBuf_Reset(&UOB);
+ UsefulOutBuf_AppendString(&UOB, "abcdefgh");
+ UsefulOutBuf_Swap(&UOB, 9, 10, 11);
+ Out = UsefulOutBuf_OutUBuf(&UOB);
+ if(UsefulBuf_Compare(Out, UsefulBuf_FROM_SZ_LITERAL("abcdefgh"))) {
+ return "swap fail 5";
+ }
+
+ UsefulOutBuf_Reset(&UOB);
+ UsefulOutBuf_AppendString(&UOB, "abcdefgh");
+ UsefulOutBuf_Swap(&UOB, 0, 4, 11);
+ Out = UsefulOutBuf_OutUBuf(&UOB);
+ if(UsefulBuf_Compare(Out, UsefulBuf_FROM_SZ_LITERAL("abcdefgh"))) {
+ return "swap fail 6";
+ }
+
+ UsefulOutBuf_Reset(&UOB);
+ UsefulOutBuf_AppendString(&UOB, "abcdefgh");
+ UsefulOutBuf_Swap(&UOB, 9, 0, 0);
+ Out = UsefulOutBuf_OutUBuf(&UOB);
+ if(UsefulBuf_Compare(Out, UsefulBuf_FROM_SZ_LITERAL("abcdefgh"))) {
+ return "swap fail 7";
+ }
+
+ UsefulOutBuf_Reset(&UOB);
+ UsefulOutBuf_AppendString(&UOB, "abcdefgh");
+ UsefulOutBuf_Swap(&UOB, 0, 0, 0);
+ Out = UsefulOutBuf_OutUBuf(&UOB);
+ if(UsefulBuf_Compare(Out, UsefulBuf_FROM_SZ_LITERAL("abcdefgh"))) {
+ return "swap fail 8";
+ }
+
+ UsefulOutBuf_Reset(&UOB);
+ UsefulOutBuf_AppendString(&UOB, "abcdefgh");
+ UsefulOutBuf_Swap(&UOB, 8, 4, 0);
+ Out = UsefulOutBuf_OutUBuf(&UOB);
+ if(UsefulBuf_Compare(Out, UsefulBuf_FROM_SZ_LITERAL("abcdefgh"))) {
+ return "swap fail 9";
+ }
+
+ UsefulOutBuf_Reset(&UOB);
+ UsefulOutBuf_AppendString(&UOB, "abcdefgh");
+ UsefulOutBuf_Swap(&UOB, 0, 8, 4);
+ Out = UsefulOutBuf_OutUBuf(&UOB);
+ if(UsefulBuf_Compare(Out, UsefulBuf_FROM_SZ_LITERAL("abcdefgh"))) {
+ return "swap fail 10";
+ }
+
+
+ /* Test for UsefulOutBuf_GetOutput() */
+ UsefulOutBuf_Reset(&UOB);
+ UsefulOutBuf_AppendString(&UOB, "abc");
+ UsefulOutBuf_AppendString(&UOB, "xyz");
+
+ Out = UsefulOutBuf_OutUBufOffset(&UOB, 0);
+ if(UsefulBuf_Compare(Out, UsefulBuf_FROM_SZ_LITERAL("abcxyz"))) {
+ return "GetOutput fail 1";
+ }
+
+ Out = UsefulOutBuf_OutUBufOffset(&UOB, 5);
+ if(UsefulBuf_Compare(Out, UsefulBuf_FROM_SZ_LITERAL("z"))) {
+ return "GetOutput fail 2";
+ }
+
+ Out = UsefulOutBuf_OutUBufOffset(&UOB, 1);
+ if(UsefulBuf_Compare(Out, UsefulBuf_FROM_SZ_LITERAL("bcxyz"))) {
+ return "GetOutput fail 3";
+ }
+
+ Out = UsefulOutBuf_OutUBufOffset(&UOB, 6);
+ if(!UsefulBuf_IsNULLC(Out)) {
+ return "GetOutput fail 4";
+ }
+
+ Out = UsefulOutBuf_OutUBufOffset(&UOB, 7);
+ if(!UsefulBuf_IsNULLC(Out)) {
+ return "GetOutput fail 5";
+ }
+
+ return NULL;
+}
diff --git a/test/UsefulBuf_Tests.h b/test/UsefulBuf_Tests.h
index 235358e..e00aa37 100644
--- a/test/UsefulBuf_Tests.h
+++ b/test/UsefulBuf_Tests.h
@@ -1,6 +1,6 @@
/*==============================================================================
Copyright (c) 2016-2018, The Linux Foundation.
- Copyright (c) 2018, Laurence Lundblade.
+ Copyright (c) 2018-2023, Laurence Lundblade.
Copyright (c) 2021, Arm Limited.
All rights reserved.
@@ -52,4 +52,6 @@
const char * UBAdvanceTest(void);
+const char * UOBExtraTests(void);
+
#endif
diff --git a/test/qcbor_decode_tests.c b/test/qcbor_decode_tests.c
index 05d2466..b489657 100644
--- a/test/qcbor_decode_tests.c
+++ b/test/qcbor_decode_tests.c
@@ -116,7 +116,9 @@
*/
static const uint8_t spExpectedEncodedInts[] = {
- 0x98, 0x2f, 0x3b, 0x7f, 0xff, 0xff, 0xff, 0xff,
+ 0x98, 0x31, 0x3b, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x3b, 0xFf, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xfe, 0x3b, 0x7f, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x3b, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x3a, 0xff, 0xff, 0xff,
0xff, 0x3a, 0xff, 0xff, 0xff, 0xfe, 0x3a, 0xff,
@@ -156,6 +158,18 @@
if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return (int32_t)nCBORError;
+ if(Item.uDataType != QCBOR_TYPE_65BIT_NEG_INT ||
+ Item.val.uint64 != 18446744073709551615ULL)
+ return -1;
+
+ if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+ return (int32_t)nCBORError;
+ if(Item.uDataType != QCBOR_TYPE_65BIT_NEG_INT ||
+ Item.val.uint64 != 18446744073709551614ULL)
+ return -1;
+
+ if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+ return (int32_t)nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != -9223372036854775807LL - 1)
return -1;
@@ -471,14 +485,6 @@
}
-/* One less than the smallest negative integer allowed in C. Decoding
- this should fail.
- -9223372036854775809
- */
-static const uint8_t spTooSmallNegative[] = {
- 0x3b, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
-
/*
Tests the decoding of lots of different integers sizes
@@ -499,16 +505,6 @@
return nReturn;
}
- // The one large negative integer that can be parsed
- QCBORDecode_Init(&DCtx,
- UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTooSmallNegative),
- QCBOR_DECODE_MODE_NORMAL);
-
- QCBORItem item;
- if(QCBORDecode_GetNext(&DCtx, &item) != QCBOR_ERR_INT_OVERFLOW) {
- nReturn = -4000;
- }
-
return(nReturn);
}
@@ -5655,13 +5651,12 @@
*/
static const uint8_t spRecoverableMapErrors[] = {
#ifndef QCBOR_DISABLE_TAGS
- 0xa6,
+ 0xa5,
0x04, 0xc1, 0xfb, 0x7e, 0x37, 0xe4, 0x3c, 0x88, 0x00, 0x75, 0x9c,
0x01, 0xd8, 0xe0, 0xd8, 0xe1, 0xd8, 0xe2, 0xd8, 0xe3, 0xd8, 0x04, 0x00,
#else
0xa4,
#endif
- 0x03, 0x3b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x05, 0x00,
0x05, 0x00,
0x08, 0x08,
@@ -6050,12 +6045,6 @@
#endif
- QCBORDecode_GetInt64InMapN(&DCtx, 0x03, &nInt);
- uErr = QCBORDecode_GetAndResetError(&DCtx);
- if(uErr != QCBOR_ERR_INT_OVERFLOW) {
- return 2023;
- }
-
#ifndef QCBOR_DISABLE_TAGS
QCBORDecode_GetEpochDateInMapN(&DCtx, 0x04, QCBOR_TAG_REQUIREMENT_TAG, &nInt);
uErr = QCBORDecode_GetAndResetError(&DCtx);
@@ -6561,8 +6550,8 @@
FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)
},
{
- "Negative integer -18446744073709551616",
- {(uint8_t[]){0x3b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, 9},
+ "Negative integer -9223372036854775808",
+ {(uint8_t[]){0x3b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, 9},
-9223372036854775807-1, // INT64_MIN
QCBOR_SUCCESS,
0ULL,
@@ -6571,6 +6560,16 @@
FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)
},
{
+ "Negative integer -18446744073709551616",
+ {(uint8_t[]){0x3b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, 9},
+ 0ULL,
+ QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW,
+ 0ULL,
+ QCBOR_ERR_NUMBER_SIGN_CONVERSION,
+ -18446744073709551616.0,
+ FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)
+ },
+ {
"Double Floating point value 100.3",
{(uint8_t[]){0xfb, 0x40, 0x59, 0x13, 0x33, 0x33, 0x33, 0x33, 0x33}, 9},
100L,
diff --git a/test/qcbor_encode_tests.c b/test/qcbor_encode_tests.c
index 267b439..c639a84 100644
--- a/test/qcbor_encode_tests.c
+++ b/test/qcbor_encode_tests.c
@@ -96,13 +96,9 @@
#endif
-#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
/*
Returns 0 if UsefulBufs are equal
Returns 1000000 + offeset if they are not equal.
-
-
-
*/
struct UBCompareDiagnostic {
uint8_t uActual;
@@ -130,7 +126,6 @@
return 0;
}
-#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
// One big buffer that is used by all the tests to encode into
@@ -281,10 +276,10 @@
static const uint8_t spExpectedEncodedAll[] = {
- 0x98, 0x23, 0x66, 0x55, 0x49, 0x4e, 0x54, 0x36, 0x32, 0xd8,
+ 0x98, 0x24, 0x66, 0x55, 0x49, 0x4e, 0x54, 0x36, 0x32, 0xd8,
0x64, 0x1a, 0x05, 0x5d, 0x23, 0x15, 0x65, 0x49, 0x4e, 0x54,
0x36, 0x34, 0xd8, 0x4c, 0x1b, 0x00, 0x00, 0x00, 0x12, 0x16,
- 0xaf, 0x2b, 0x15, 0x00, 0x38, 0x2b, 0xa4, 0x63, 0x4c, 0x42,
+ 0xaf, 0x2b, 0x15, 0x00, 0x38, 0x2b, 0x20, 0xa4, 0x63, 0x4c, 0x42,
0x4c, 0x18, 0x4d, 0x23, 0x18, 0x58, 0x78, 0x1a, 0x4e, 0x45,
0x47, 0x4c, 0x42, 0x4c, 0x54, 0x48, 0x41, 0x54, 0x20, 0x49,
0x53, 0x20, 0x4b, 0x49, 0x4e, 0x44, 0x20, 0x4f, 0x46, 0x20,
@@ -526,8 +521,9 @@
QCBOREncode_AddSZString(pECtx, "INT64");
QCBOREncode_AddTag(pECtx, 76);
QCBOREncode_AddInt64(pECtx, 77689989909);
- QCBOREncode_AddUInt64(pECtx,0);
+ QCBOREncode_AddUInt64(pECtx, 0);
QCBOREncode_AddInt64(pECtx, -44);
+ QCBOREncode_AddNegativeUInt64(pECtx, 0);
/* ints that go in maps */
QCBOREncode_OpenMap(pECtx);
@@ -700,7 +696,7 @@
QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
- AddAll (&ECtx);
+ AddAll(&ECtx);
UsefulBufC Enc;
if(QCBOREncode_Finish(&ECtx, &Enc)) {
@@ -1766,12 +1762,6 @@
*/
static const uint8_t spExpectedBstrWrap[] = {0x82, 0x19, 0x01, 0xC3, 0x43, 0x19, 0x01, 0xD2};
-/*
- 81 #array(1)
- 0x58 0x25 # string of length 37 (length of "This is longer than twenty four bytes")
- */
-static const uint8_t spExpectedTypeAndLen[] = {0x81, 0x58, 0x25};
-
static const uint8_t spExpectedForBstrWrapCancel[] = {0x82, 0x19, 0x01, 0xC3, 0x18, 0x2A};
/*
@@ -1821,19 +1811,6 @@
return -5;
}
- // Third, test QCBOREncode_AddBytesLenOnly() here as it is part of the
- // bstr wrapping use cases.
- UsefulBuf_MAKE_STACK_UB(StuffBuf, 50);
- QCBOREncode_Init(&EC, StuffBuf);
- QCBOREncode_OpenArray(&EC);
- QCBOREncode_AddBytesLenOnly(&EC, UsefulBuf_FROM_SZ_LITERAL("This is longer than twenty four bytes"));
- QCBOREncode_CloseArray(&EC);
- if(QCBOREncode_Finish(&EC, &Encoded)) {
- return -6;
- }
- if(CheckResults(Encoded, spExpectedTypeAndLen)) {
- return -7;
- }
// Fourth test, cancelling a byte string
QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
@@ -3080,3 +3057,309 @@
return 0;
}
+
+
+
+int32_t
+SortMapTest(void)
+{
+ UsefulBuf_MAKE_STACK_UB( TestBuf, 200);
+ QCBOREncodeContext EC;
+ UsefulBufC EncodedAndSorted;
+ QCBORError uErr;
+ struct UBCompareDiagnostic CompareDiagnostics;
+
+
+ /* --- Basic sort test case --- */
+ QCBOREncode_Init(&EC, TestBuf);
+ QCBOREncode_OpenMap(&EC);
+ QCBOREncode_AddInt64ToMapN(&EC, 3, 3);
+ QCBOREncode_AddInt64ToMapN(&EC, 1, 1);
+ QCBOREncode_AddInt64ToMapN(&EC, 4, 4);
+ QCBOREncode_AddInt64ToMapN(&EC, 2, 2);
+ QCBOREncode_CloseAndSortMap(&EC);
+ uErr = QCBOREncode_Finish(&EC, &EncodedAndSorted);
+ if(uErr) {
+ return 11;
+ }
+
+ static const uint8_t spBasic[] = {
+ 0xA4, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04};
+
+ if(UsefulBuf_Compare(EncodedAndSorted, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBasic))) {
+ return 12;
+ }
+
+ /* --- Empty map sort test case --- */
+ QCBOREncode_Init(&EC, TestBuf);
+ QCBOREncode_OpenMap(&EC);
+ QCBOREncode_CloseAndSortMap(&EC);
+ uErr = QCBOREncode_Finish(&EC, &EncodedAndSorted);
+ if(uErr) {
+ return 21;
+ }
+
+ static const uint8_t spEmpty[] = {0xA0};
+ if(UsefulBuf_CompareWithDiagnostic(EncodedAndSorted,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spEmpty),
+ &CompareDiagnostics)) {
+ return 22;
+ }
+
+ /* --- Several levels of nested sorted maps --- */
+ QCBOREncode_Init(&EC, TestBuf);
+ QCBOREncode_OpenMap(&EC);
+ QCBOREncode_AddInt64ToMap(&EC, "three", 3);
+ QCBOREncode_OpenMapInMapN(&EC, 428);
+ QCBOREncode_AddNULLToMap(&EC, "null");
+ QCBOREncode_OpenArrayInMap(&EC, "array");
+ QCBOREncode_AddSZString(&EC, "hi");
+ QCBOREncode_AddSZString(&EC, "there");
+ QCBOREncode_CloseArray(&EC);
+ QCBOREncode_OpenMapInMap(&EC, "empty2");
+ QCBOREncode_CloseAndSortMap(&EC);
+ QCBOREncode_OpenMapInMap(&EC, "empty1");
+ QCBOREncode_CloseAndSortMap(&EC);
+ QCBOREncode_CloseAndSortMap(&EC);
+ QCBOREncode_AddDateEpochToMapN(&EC, 88, 888888);
+ QCBOREncode_AddBoolToMap(&EC, "boo", true);
+ QCBOREncode_CloseAndSortMap(&EC);
+ uErr = QCBOREncode_Finish(&EC, &EncodedAndSorted);
+ if(uErr) {
+ return 31;
+ }
+ static const uint8_t spNested[] = {
+ 0xA4, 0x18, 0x58, 0xC1, 0x1A, 0x00, 0x0D, 0x90,
+ 0x38, 0x19, 0x01, 0xAC, 0xA4, 0x64, 0x6E, 0x75,
+ 0x6C, 0x6C, 0xF6, 0x65, 0x61, 0x72, 0x72, 0x61,
+ 0x79, 0x82, 0x62, 0x68, 0x69, 0x65, 0x74, 0x68,
+ 0x65, 0x72, 0x65, 0x66, 0x65, 0x6D, 0x70, 0x74,
+ 0x79, 0x31, 0xA0, 0x66, 0x65, 0x6D, 0x70, 0x74,
+ 0x79, 0x32, 0xA0, 0x63, 0x62, 0x6F, 0x6F, 0xF5,
+ 0x65, 0x74, 0x68, 0x72, 0x65, 0x65, 0x03};
+
+ if(UsefulBuf_CompareWithDiagnostic(EncodedAndSorted,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spNested),
+ &CompareDiagnostics)) {
+ return 32;
+ }
+
+ /* --- Degenerate case of everything in order --- */
+ QCBOREncode_Init(&EC, TestBuf);
+ QCBOREncode_OpenMap(&EC);
+ QCBOREncode_AddInt64ToMapN(&EC, 0, 0);
+ QCBOREncode_AddInt64ToMapN(&EC, 1, 1);
+ QCBOREncode_AddInt64ToMapN(&EC, 2, 2);
+ QCBOREncode_AddInt64ToMap(&EC, "a", 3);
+ QCBOREncode_AddInt64ToMap(&EC, "b", 4);
+ QCBOREncode_AddInt64ToMap(&EC, "aa", 5);
+ QCBOREncode_AddInt64ToMap(&EC, "aaa", 6);
+ QCBOREncode_CloseAndSortMap(&EC);
+ uErr = QCBOREncode_Finish(&EC, &EncodedAndSorted);
+ if(uErr) {
+ return 41;
+ }
+
+ static const uint8_t sp6Items[] = {
+ 0xA7, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x61,
+ 0x61, 0x03, 0x61, 0x62, 0x04, 0x62, 0x61, 0x61,
+ 0x05, 0x63, 0x61, 0x61, 0x61, 0x06};
+ if(UsefulBuf_CompareWithDiagnostic(EncodedAndSorted,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(sp6Items),
+ &CompareDiagnostics)) {
+ return 42;
+ }
+
+ /* --- Degenerate case -- reverse order --- */
+ QCBOREncode_Init(&EC, TestBuf);
+ QCBOREncode_OpenMap(&EC);
+ QCBOREncode_AddInt64ToMap(&EC, "aaa", 6);
+ QCBOREncode_AddInt64ToMap(&EC, "aa", 5);
+ QCBOREncode_AddInt64ToMap(&EC, "b", 4);
+ QCBOREncode_AddInt64ToMap(&EC, "a", 3);
+ QCBOREncode_AddInt64ToMapN(&EC, 2, 2);
+ QCBOREncode_AddInt64ToMapN(&EC, 0, 0);
+ QCBOREncode_AddInt64ToMapN(&EC, 1, 1);
+ QCBOREncode_CloseAndSortMap(&EC);
+ uErr = QCBOREncode_Finish(&EC, &EncodedAndSorted);
+ if(uErr) {
+ return 51;
+ }
+
+ if(UsefulBuf_CompareWithDiagnostic(EncodedAndSorted,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(sp6Items),
+ &CompareDiagnostics)) {
+ return 52;
+ }
+
+ /* --- Same items, randomly out of order --- */
+ QCBOREncode_Init(&EC, TestBuf);
+ QCBOREncode_OpenMap(&EC);
+ QCBOREncode_AddInt64ToMap(&EC, "aa", 5);
+ QCBOREncode_AddInt64ToMapN(&EC, 2, 2);
+ QCBOREncode_AddInt64ToMapN(&EC, 0, 0);
+ QCBOREncode_AddInt64ToMap(&EC, "b", 4);
+ QCBOREncode_AddInt64ToMap(&EC, "aaa", 6);
+ QCBOREncode_AddInt64ToMap(&EC, "a", 3);
+ QCBOREncode_AddInt64ToMapN(&EC, 1, 1);
+ QCBOREncode_CloseAndSortMap(&EC);
+ uErr = QCBOREncode_Finish(&EC, &EncodedAndSorted);
+ if(uErr) {
+ return 61;
+ }
+
+ if(UsefulBuf_CompareWithDiagnostic(EncodedAndSorted,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(sp6Items),
+ &CompareDiagnostics)) {
+ return 62;
+ }
+
+ /* --- Stuff in front of and after array to sort --- */
+ QCBOREncode_Init(&EC, TestBuf);
+ QCBOREncode_OpenArray(&EC);
+ QCBOREncode_AddInt64(&EC, 111);
+ QCBOREncode_AddInt64(&EC, 222);
+ QCBOREncode_OpenMap(&EC);
+ QCBOREncode_AddInt64ToMapN(&EC, 0, 0);
+ QCBOREncode_AddInt64ToMapN(&EC, 1, 1);
+ QCBOREncode_AddInt64ToMapN(&EC, 2, 2);
+ QCBOREncode_CloseAndSortMap(&EC);
+ QCBOREncode_AddInt64(&EC, 888);
+ QCBOREncode_AddInt64(&EC, 999);
+ QCBOREncode_CloseArray(&EC);
+ uErr = QCBOREncode_Finish(&EC, &EncodedAndSorted);
+ if(uErr) {
+ return 71;
+ }
+
+ static const uint8_t spPreItems[] = {
+ 0x85, 0x18, 0x6F, 0x18, 0xDE, 0xA3, 0x00, 0x00,
+ 0x01, 0x01, 0x02, 0x02, 0x19, 0x03, 0x78, 0x19,
+ 0x03, 0xE7};
+ if(UsefulBuf_CompareWithDiagnostic(EncodedAndSorted,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spPreItems),
+ &CompareDiagnostics)) {
+ return 72;
+ }
+
+ /* --- map with labels of all CBOR major types and in reverse order --- */
+ QCBOREncode_Init(&EC, TestBuf);
+ QCBOREncode_OpenMap(&EC);
+
+ /* Adding labels directly rather than AddToMap functions */
+
+#ifndef USEFULBUF_DISABLE_ALL_FLOAT
+ QCBOREncode_AddDouble(&EC, 8.77);
+ QCBOREncode_AddInt64(&EC, 7);
+#endif /* QCBOR_DISABLE_ALL_FLOAT */
+
+ QCBOREncode_AddBool(&EC, true);
+ QCBOREncode_AddInt64(&EC, 6);
+
+ QCBOREncode_AddDateEpoch(&EC, 88);
+ QCBOREncode_AddInt64(&EC, 5);
+
+ QCBOREncode_AddEncoded(&EC, UsefulBuf_FromSZ("\xa0"));
+ QCBOREncode_AddInt64(&EC, 4);
+
+ QCBOREncode_AddEncoded(&EC, UsefulBuf_FromSZ("\x80"));
+ QCBOREncode_AddInt64(&EC, 7);
+
+ QCBOREncode_AddInt64ToMap(&EC, "text", 3);
+
+ QCBOREncode_AddBytes(&EC, UsefulBuf_FromSZ("xx"));
+ QCBOREncode_AddInt64(&EC, 2);
+
+ QCBOREncode_AddInt64ToMapN(&EC, 1, 1); /* Integer */
+ QCBOREncode_CloseAndSortMap(&EC);
+
+ uErr = QCBOREncode_Finish(&EC, &EncodedAndSorted);
+ if(uErr) {
+ return 81;
+ }
+
+#ifndef USEFULBUF_DISABLE_ALL_FLOAT
+ static const uint8_t spLabelTypes[] = {
+ 0xA8, 0x01, 0x01, 0x42, 0x78, 0x78, 0x02, 0x64,
+ 0x74, 0x65, 0x78, 0x74, 0x03, 0x80, 0x07, 0xA0,
+ 0x04, 0xC1, 0x18, 0x58, 0x05, 0xF5, 0x06, 0xFB,
+ 0x40, 0x21, 0x8A, 0x3D, 0x70, 0xA3, 0xD7, 0x0A,
+ 0x07};
+#else
+ static const uint8_t spLabelTypes[] = {
+ 0xA7, 0x01, 0x01, 0x42, 0x78, 0x78, 0x02, 0x64,
+ 0x74, 0x65, 0x78, 0x74, 0x03, 0x80, 0x07, 0xA0,
+ 0x04, 0xC1, 0x18, 0x58, 0x05, 0xF5, 0x06};
+#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
+
+ if(UsefulBuf_CompareWithDiagnostic(EncodedAndSorted,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spLabelTypes),
+ &CompareDiagnostics)) {
+ return 82;
+ }
+
+ /* --- labels are indefinitely encoded --- */
+ QCBOREncode_Init(&EC, TestBuf);
+ QCBOREncode_OpenMap(&EC);
+
+ QCBOREncode_AddInt64ToMap(&EC, "aaaa", 1);
+
+ QCBOREncode_AddInt64ToMap(&EC, "bb", 2);
+
+ QCBOREncode_AddEncoded(&EC, UsefulBuf_FromSZ("\x7f\x61" "a" "\x61" "a" "\xff"));
+ QCBOREncode_AddInt64(&EC, 3);
+
+ QCBOREncode_AddEncoded(&EC, UsefulBuf_FromSZ("\x7f" "\x61" "c" "\xff"));
+ QCBOREncode_AddInt64(&EC, 4);
+
+ QCBOREncode_CloseAndSortMap(&EC);
+
+ uErr = QCBOREncode_Finish(&EC, &EncodedAndSorted);
+ if(uErr) {
+ return 91;
+ }
+
+ static const uint8_t spIndefItems[] = {
+ 0xA4, 0x62, 0x62, 0x62, 0x02, 0x64, 0x61, 0x61,
+ 0x61, 0x61, 0x01, 0x7F, 0x61, 0x61, 0x61, 0x61,
+ 0xFF, 0x03, 0x7F, 0x61, 0x63, 0xFF, 0x04};
+ if(UsefulBuf_CompareWithDiagnostic(EncodedAndSorted,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefItems),
+ &CompareDiagnostics)) {
+ return 92;
+ }
+
+ /* --- Indefinitely encoded maps --- */
+ QCBOREncode_Init(&EC, TestBuf);
+ QCBOREncode_OpenMapIndefiniteLength(&EC);
+
+ QCBOREncode_OpenMapIndefiniteLengthInMap(&EC, "aa");
+ QCBOREncode_CloseMapIndefiniteLength(&EC);
+
+ QCBOREncode_OpenArrayIndefiniteLengthInMap(&EC, "ff");
+ QCBOREncode_CloseArrayIndefiniteLength(&EC);
+
+ QCBOREncode_OpenMapIndefiniteLengthInMap(&EC, "zz");
+ QCBOREncode_CloseMapIndefiniteLength(&EC);
+
+ QCBOREncode_OpenMapIndefiniteLengthInMap(&EC, "bb");
+ QCBOREncode_CloseMapIndefiniteLength(&EC);
+
+ QCBOREncode_CloseAndSortMapIndef(&EC);
+ uErr = QCBOREncode_Finish(&EC, &EncodedAndSorted);
+ if(uErr) {
+ return 101;
+ }
+
+ static const uint8_t spIndeMaps[] = {
+ 0xBF, 0x62, 0x61, 0x61, 0xBF, 0xFF, 0x62, 0x62,
+ 0x62, 0xBF, 0xFF, 0x62, 0x66, 0x66, 0x9F, 0xFF,
+ 0x62, 0x7A, 0x7A, 0xBF, 0xFF, 0xFF, 0x06, 0xFB};
+ if(UsefulBuf_CompareWithDiagnostic(EncodedAndSorted,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndeMaps),
+ &CompareDiagnostics)) {
+ return 102;
+ }
+
+ return 0;
+}
diff --git a/test/qcbor_encode_tests.h b/test/qcbor_encode_tests.h
index bac1085..5271fd4 100644
--- a/test/qcbor_encode_tests.h
+++ b/test/qcbor_encode_tests.h
@@ -1,6 +1,6 @@
/*==============================================================================
Copyright (c) 2016-2018, The Linux Foundation.
- Copyright (c) 2018-2022, Laurence Lundblade.
+ Copyright (c) 2018-2023, Laurence Lundblade.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -192,5 +192,8 @@
int32_t OpenCloseBytesTest(void);
+/* Test map sorting */
+int32_t SortMapTest(void);
+
#endif /* defined(__QCBOR__qcbor_encode_tests__) */
diff --git a/test/run_tests.c b/test/run_tests.c
index 9e747a6..30e942e 100644
--- a/test/run_tests.c
+++ b/test/run_tests.c
@@ -1,7 +1,7 @@
/*==============================================================================
run_tests.c -- test aggregator and results reporting
- Copyright (c) 2018-2021, Laurence Lundblade. All rights reserved.
+ Copyright (c) 2018-2023, Laurence Lundblade. All rights reserved.
Copyright (c) 2021, Arm Limited. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause
@@ -61,7 +61,8 @@
TEST_ENTRY(UBMacroConversionsTest),
TEST_ENTRY(UBUtilTests),
TEST_ENTRY(UIBTest_IntegerFormat),
- TEST_ENTRY(UBAdvanceTest)
+ TEST_ENTRY(UBAdvanceTest),
+ TEST_ENTRY(UOBExtraTests)
};
@@ -147,7 +148,8 @@
TEST_ENTRY(ExponentAndMantissaEncodeTests),
#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
TEST_ENTRY(ParseEmptyMapInMapTest),
- TEST_ENTRY(BoolTest)
+ TEST_ENTRY(BoolTest),
+ TEST_ENTRY(SortMapTest)
};