aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurence Lundblade <lgl@securitytheory.com>2020-01-30 10:44:06 -0800
committerTamas Ban <tamas.ban@arm.com>2020-02-05 13:29:37 +0000
commitac515e5a4410e1ae79d5e22fbec45af1fe3591b6 (patch)
tree7e72a162488a58d9be2aad5aec296d776a518fe9
parentd5b6817608cfc1340ad1c169df423aff4dbe4cd3 (diff)
downloadtrusted-firmware-m-ac515e5a4410e1ae79d5e22fbec45af1fe3591b6.tar.gz
QCBOR: Quiet static analyzers; add bigfloat support; documentation improvements
Refined use of types, particular integer types and their signedness so there are fewer warnings from static analyzers. Added casts to make implicit type conversions explicit and more clear for code reader. No actual bugs or vulnerabilities where found by the static analyzer but a lot of lines were changed. Cleaner handling of too-long bstr and tstr error condition when decoding. Add support for bigfloats and decimal fractions -- all of RFC 7049 is now supported except duplicate detection when decoding maps and some of strict mode. Dead-stripping and/or linking through a .a file will automatically leave out the added code on the encoder side. bytes or so of code on the decode side Documentation corrections and improved code formatting, fewer long lines, spelling... A lot of lines where change for this. Repair a few tests that weren't testing what they were supposed to be testing. Change-Id: I4c9c56c1ee16812eac7a5c2f2ba0d896f3f1b5ae Signed-off-by: Laurence Lundblade <lgl@securitytheory.com>
-rw-r--r--lib/ext/qcbor/README.md48
-rw-r--r--lib/ext/qcbor/inc/UsefulBuf.h43
-rw-r--r--lib/ext/qcbor/inc/qcbor.h560
-rw-r--r--lib/ext/qcbor/src/UsefulBuf.c65
-rw-r--r--lib/ext/qcbor/src/ieee754.c187
-rw-r--r--lib/ext/qcbor/src/ieee754.h111
-rw-r--r--lib/ext/qcbor/src/qcbor_decode.c903
-rw-r--r--lib/ext/qcbor/src/qcbor_encode.c433
-rw-r--r--lib/ext/qcbor/test/UsefulBuf_Tests.c23
-rw-r--r--lib/ext/qcbor/test/float_tests.c77
-rw-r--r--lib/ext/qcbor/test/float_tests.h12
-rw-r--r--lib/ext/qcbor/test/half_to_double_from_rfc7049.c2
-rw-r--r--lib/ext/qcbor/test/half_to_double_from_rfc7049.h4
-rw-r--r--lib/ext/qcbor/test/not_well_formed_cbor.h22
-rw-r--r--lib/ext/qcbor/test/qcbor_decode_tests.c747
-rw-r--r--lib/ext/qcbor/test/qcbor_decode_tests.h74
-rw-r--r--lib/ext/qcbor/test/qcbor_encode_tests.c367
-rw-r--r--lib/ext/qcbor/test/qcbor_encode_tests.h85
-rw-r--r--lib/ext/qcbor/test/run_tests.c49
-rw-r--r--lib/ext/qcbor/test/run_tests.h11
-rw-r--r--test/suites/qcbor/non_secure/qcbor_ns_testsuite.c4
21 files changed, 2702 insertions, 1125 deletions
diff --git a/lib/ext/qcbor/README.md b/lib/ext/qcbor/README.md
index 780d255985..e3953aa400 100644
--- a/lib/ext/qcbor/README.md
+++ b/lib/ext/qcbor/README.md
@@ -4,9 +4,10 @@ QCBOR encodes and decodes [RFC 7049](https://tools.ietf.org/html/rfc7049) CBOR.
## Characteristics
-**Implemented in C with minimal dependency** – Only dependencies are
- C99, <stdint.h>, <stddef.h>, <stdbool.h> and <string.h> making it
- highly portable. There are no #ifdefs to be configured at all.
+**Implemented in C with minimal dependency** – The only dependencies
+ are C99, <stdint.h>, <stddef.h>, <stdbool.h> and <string.h> making it
+ highly portable. No #ifdefs or compiler options need to be set for it
+ to run correctly.
**Focused on C / native data representation** – Simpler code because
there is no support for encoding/decoding to/from JSON, pretty
@@ -21,18 +22,18 @@ QCBOR encodes and decodes [RFC 7049](https://tools.ietf.org/html/rfc7049) CBOR.
of memory usage making it good for embedded implementations that
have to run in small fixed memory.
-**Supports nearly all of RFC 7049** – Only minor, corner-case parts of
- RFC 7049 are not directly supported (canonicalization, decimal
- fractions, big floats). Decoding indefinite length strings is supported,
- but requires a string allocator (see documentation). Encoding indefinite
- length strings is not supported, but is also not necessary or
- preferred.
+**Supports all of RFC 7049 except strict mode** – With some size
+ limits, all data types and formats specified are supported.
+ Decoding indefinite length strings requires a string allocator (see
+ documentation). The most notable part of RFC 7049 not supported is
+ detection of duplicate keys in maps, however, the duplicates are
+ passed up to the caller so it can do duplicate detection.
**Extensible and general** – Provides a way to handle data types that
are not directly supported.
**Secure coding style** – Uses a construct called UsefulBuf as a
- discipline for very safe coding the handling of binary data.
+ discipline for very safe coding and handling of binary data.
**Small code size** – When optimized for size using the compiler -Os
option, x86 code is about 4KB (~1.1KB encode, ~2.5KB decode,
@@ -47,7 +48,7 @@ QCBOR encodes and decodes [RFC 7049](https://tools.ietf.org/html/rfc7049) CBOR.
**Comprehensive test suite** – Easy to verify on a new platform
or OS with the test suite. The test suite dependencies are also
- minimal, only additionally requiring <math.h> for floating point
+ minimal, only additionally requiring <math.h> for floating-point
tests.
## Code Status
@@ -58,7 +59,8 @@ permissive Linux license, September 2018 (thanks Qualcomm!).
This code in [Laurence's
GitHub](https://github.com/laurencelundblade/QCBOR) has diverged from
-the CAF source with some small simplifications and tidying up.
+the CAF source with some simplifications, tidying up and feature
+additions.
From Nov 3, 2018, the interface and code are fairly stable. Large
changes are not planned or expected, particularly in the
@@ -91,8 +93,8 @@ project. Hopefully the easy portability of this implementation makes
this work straight away, whatever your development environment is.
The files ieee754.c and ieee754.h are support for half-precision
-floating point. The encoding side of the floating point functionality
-is about 500 bytes. If it is never called because no floating point
+floating-point. The encoding side of the floating-point functionality
+is about 500 bytes. If it is never called because no floating-point
numbers are ever encoded, all 500 bytes will be dead stripped and not
impact code size. The decoding side is about 150 bytes of object
code. It is never dead stripped because it directly referenced by the
@@ -104,6 +106,24 @@ support UNIX style command line and make, you should be able to make a
simple project and add the test files to it. Then just call
RunTests() to invoke them all.
+While this code will run fine without configuration, there are several
+C pre processor macros that can be #defined in order to:
+
+* use a more efficient implementation
+ * to reduce code size
+ * to improve performance (a little)
+* remove features to reduce code size
+
+See the comment sections on "Configuration" in inc/UsefulBuf.h.
+
+## Other Software Using QCBOR
+
+* [t_cose](https://github.com/laurencelundblade/t_cose) implements enough of
+[COSE, RFC 8152](https://tools.ietf.org/html/rfc8152) to support
+[CBOR Web Token (CWT)](https://tools.ietf.org/html/rfc8392) and
+[Entity Attestation Token (EAT)](https://tools.ietf.org/html/draft-ietf-rats-eat-01).
+Specifically it supports signing and verification of the COSE_Sign1 message.
+
## Changes from CAF Version
* Float support is restored
diff --git a/lib/ext/qcbor/inc/UsefulBuf.h b/lib/ext/qcbor/inc/UsefulBuf.h
index 89ed64367f..a8da83b643 100644
--- a/lib/ext/qcbor/inc/UsefulBuf.h
+++ b/lib/ext/qcbor/inc/UsefulBuf.h
@@ -1,6 +1,6 @@
/*============================================================================
Copyright (c) 2016-2018, The Linux Foundation.
- Copyright (c) 2018-2019, Laurence Lundblade.
+ 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
@@ -41,6 +41,7 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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
@@ -1692,8 +1693,8 @@ static inline void UsefulOutBuf_InsertUint16(UsefulOutBuf *me,
#else
uint8_t aTmp[2];
- aTmp[0] = (uInteger16 & 0xff00) >> 8;
- aTmp[1] = (uInteger16 & 0xff);
+ aTmp[0] = (uint8_t)((uInteger16 & 0xff00) >> 8);
+ aTmp[1] = (uint8_t)(uInteger16 & 0xff);
pBytes = aTmp;
#endif
@@ -1725,10 +1726,10 @@ static inline void UsefulOutBuf_InsertUint32(UsefulOutBuf *pMe,
#else
uint8_t aTmp[4];
- aTmp[0] = (uInteger32 & 0xff000000) >> 24;
- aTmp[1] = (uInteger32 & 0xff0000) >> 16;
- aTmp[2] = (uInteger32 & 0xff00) >> 8;
- aTmp[3] = (uInteger32 & 0xff);
+ 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
@@ -1775,14 +1776,14 @@ static inline void UsefulOutBuf_InsertUint64(UsefulOutBuf *pMe,
// it is usually a little larger and slower than hton().
uint8_t aTmp[8];
- aTmp[0] = (uInteger64 & 0xff00000000000000) >> 56;
- aTmp[1] = (uInteger64 & 0xff000000000000) >> 48;
- aTmp[2] = (uInteger64 & 0xff0000000000) >> 40;
- aTmp[3] = (uInteger64 & 0xff00000000) >> 32;
- aTmp[4] = (uInteger64 & 0xff000000) >> 24;
- aTmp[5] = (uInteger64 & 0xff0000) >> 16;
- aTmp[6] = (uInteger64 & 0xff00) >> 8;
- aTmp[7] = (uInteger64 & 0xff);
+ 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
@@ -1967,7 +1968,10 @@ static inline uint8_t UsefulInputBuf_GetByte(UsefulInputBuf *pMe)
{
const void *pResult = UsefulInputBuf_GetBytes(pMe, sizeof(uint8_t));
- return pResult ? *(uint8_t *)pResult : 0;
+ // 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)
@@ -1995,7 +1999,12 @@ static inline uint16_t UsefulInputBuf_GetUint16(UsefulInputBuf *pMe)
#endif
#else
- return ((uint16_t)pResult[0] << 8) + (uint16_t)pResult[1];
+
+ // 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
}
diff --git a/lib/ext/qcbor/inc/qcbor.h b/lib/ext/qcbor/inc/qcbor.h
index d541a10647..00e3656d5f 100644
--- a/lib/ext/qcbor/inc/qcbor.h
+++ b/lib/ext/qcbor/inc/qcbor.h
@@ -1,6 +1,6 @@
/*==============================================================================
Copyright (c) 2016-2018, The Linux Foundation.
- Copyright (c) 2018-2019, Laurence Lundblade.
+ Copyright (c) 2018-2020, Laurence Lundblade.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -28,10 +28,10 @@ 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
@@ -41,30 +41,33 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This section contains comments describing changes made to the module.
Notice that changes are listed in reverse chronological order.
- when who what, where, why
- -------- ---- ---------------------------------------------------
- 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 repository.
- 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.
-
- =====================================================================================*/
+ when who what, where, why
+ -------- ---- ---------------------------------------------------
+ 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__
@@ -75,7 +78,7 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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
@@ -109,8 +112,8 @@ extern "C" {
/*
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.
+ 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
@@ -123,10 +126,10 @@ extern "C" {
typedef struct __QCBORTrackNesting {
// PRIVATE DATA STRUCTURE
struct {
- // See function OpenArrayInternal() for detailed comments 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
+ // 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
@@ -224,20 +227,20 @@ struct _QCBORDecodeContext {
#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
@@ -302,12 +305,13 @@ struct _QCBORDecodeContext {
/** 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. No API is provided for this
- tag. */
-#define CBOR_TAG_FRACTION 4
+ 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. No API is provided for this
- tag. */
+ 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]
@@ -614,11 +618,12 @@ struct _QCBORDecodeContext {
@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 some tagged types: decimal fractions, big floats
- - Does not directly support labels in maps other than text strings and integers.
+ - 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).
@@ -765,7 +770,18 @@ typedef enum {
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
+ 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;
@@ -815,12 +831,42 @@ typedef enum {
/** 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
+/** 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. */
@@ -904,8 +950,38 @@ typedef struct _QCBORItem {
UsefulBufC bigNum;
/** The integer value for unknown simple types. */
uint8_t uSimple;
- uint64_t uTagV; // Used internally during decoding
+#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
@@ -1146,7 +1222,7 @@ static void QCBOREncode_AddUInt64ToMapN(QCBOREncodeContext *pCtx, int64_t nLabel
/**
@brief Add a UTF-8 text string to the encoded output.
- @param[in] pCtx The context to initialize.
+ @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]
@@ -1173,7 +1249,7 @@ static void QCBOREncode_AddTextToMapN(QCBOREncodeContext *pCtx, int64_t nLabel,
/**
@brief Add a UTF-8 text string to the encoded output.
- @param[in] pCtx The context to initialize.
+ @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().
@@ -1188,8 +1264,8 @@ static void QCBOREncode_AddSZStringToMapN(QCBOREncodeContext *pCtx, int64_t nLab
/**
@brief Add a floating-point number to the encoded output.
- @param[in] pCtx The encoding context to add the float to.
- @param[in] dNum The double precision number to add.
+ @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.
@@ -1222,7 +1298,7 @@ static void QCBOREncode_AddDoubleToMapN(QCBOREncodeContext *pCtx, int64_t nLabel
/**
@brief Add an optional tag.
- @param[in] pCtx The encoding context to add the integer to.
+ @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
@@ -1248,7 +1324,7 @@ void QCBOREncode_AddTag(QCBOREncodeContext *pCtx,uint64_t uTag);
/**
@brief Add an epoch-based date.
- @param[in] pCtx The encoding context to add the simple value to.
+ @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
@@ -1284,7 +1360,7 @@ static void QCBOREncode_AddDateEpochToMapN(QCBOREncodeContext *pCtx, int64_t nL
/**
@brief Add a byte string to the encoded output.
- @param[in] pCtx The context to initialize.
+ @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.
@@ -1305,7 +1381,7 @@ static void QCBOREncode_AddBytesToMapN(QCBOREncodeContext *pCtx, int64_t nLabel,
/**
@brief Add a binary UUID to the encoded output.
- @param[in] pCtx The context to initialize.
+ @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]
@@ -1324,7 +1400,7 @@ static void QCBOREncode_AddBinaryUUIDToMapN(QCBOREncodeContext *pCtx, int64_t nL
/**
@brief Add a positive big number to the encoded output.
- @param[in] pCtx The context to initialize.
+ @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
@@ -1348,7 +1424,7 @@ static void QCBOREncode_AddPositiveBignumToMapN(QCBOREncodeContext *pCtx, int64_
/**
@brief Add a negative big number to the encoded output.
- @param[in] pCtx The context to initialize.
+ @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
@@ -1369,10 +1445,175 @@ static void QCBOREncode_AddNegativeBignumToMap(QCBOREncodeContext *pCtx, const c
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 context to initialize.
+ @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]
@@ -1396,7 +1637,7 @@ static void QCBOREncode_AddURIToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, U
/**
@brief Add Base64-encoded text to encoded output.
- @param[in] pCtx The context to initialize.
+ @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]
@@ -1415,7 +1656,7 @@ static void QCBOREncode_AddB64TextToMapN(QCBOREncodeContext *pCtx, int64_t nLabe
/**
@brief Add base64url encoded data to encoded output.
- @param[in] pCtx The context to initialize.
+ @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]
@@ -1434,7 +1675,7 @@ static void QCBOREncode_AddB64URLTextToMapN(QCBOREncodeContext *pCtx, int64_t nL
/**
@brief Add Perl Compatible Regular Expression.
- @param[in] pCtx The context to initialize.
+ @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
@@ -1453,7 +1694,7 @@ static void QCBOREncode_AddRegexToMapN(QCBOREncodeContext *pCtx, int64_t nLabel,
/**
@brief MIME encoded text to the encoded output.
- @param[in] pCtx The context to initialize.
+ @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]
@@ -1474,7 +1715,7 @@ static void QCBOREncode_AddMIMEDataToMapN(QCBOREncodeContext *pCtx, int64_t nLab
/**
@brief Add an RFC 3339 date string
- @param[in] pCtx The encoding context to add the simple value to.
+ @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]
@@ -1499,8 +1740,8 @@ static void QCBOREncode_AddDateStringToMapN(QCBOREncodeContext *pCtx, int64_t nL
/**
@brief Add a standard Boolean.
- @param[in] pCtx The encoding context to add the simple value to.
- @param[in] b true or false from @c <stdbool.h>. Anything will result in an error.
+ @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.
@@ -1517,7 +1758,7 @@ static void QCBOREncode_AddBoolToMapN(QCBOREncodeContext *pCtx, int64_t nLabel,
/**
@brief Add a NULL to the encoded output.
- @param[in] pCtx The encoding context to add the simple value to.
+ @param[in] pCtx The encoding context to add the NULL to.
Adds the NULL value as CBOR major type 7.
@@ -1536,7 +1777,7 @@ 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 simple value to.
+ @param[in] pCtx The encoding context to add the "undef" to.
Adds the undef value as CBOR major type 7.
@@ -1595,7 +1836,7 @@ static void QCBOREncode_OpenArrayInMapN(QCBOREncodeContext *pCtx, int64_t nLabe
/**
@brief Close an open array.
- @param[in] pCtx The context to add to.
+ @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
@@ -1619,7 +1860,7 @@ static void QCBOREncode_CloseArray(QCBOREncodeContext *pCtx);
/**
@brief Indicates that the next items added are in a map.
- @param[in] pCtx The context to add to.
+ @param[in] pCtx The encoding context to open the map in.
See QCBOREncode_OpenArray() for more information, particularly error
handling.
@@ -1657,7 +1898,7 @@ static void QCBOREncode_OpenMapInMapN(QCBOREncodeContext *pCtx, int64_t nLabel);
/**
@brief Close an open map.
- @param[in] pCtx The context to add to.
+ @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.
@@ -1680,7 +1921,7 @@ static void QCBOREncode_CloseMap(QCBOREncodeContext *pCtx);
/**
@brief Indicate start of encoded CBOR to be wrapped in a bstr.
- @param[in] pCtx The context to add to.
+ @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_CloseBstrWrap() will be wrapped in a bstr. They will
@@ -1719,7 +1960,7 @@ static void QCBOREncode_BstrWrapInMapN(QCBOREncodeContext *pCtx, int64_t nLabel)
/**
@brief Close a wrapping bstr.
- @param[in] pCtx The context to add to.
+ @param[in] pCtx The encoding context to close of bstr wrapping in.
@param[out] pWrappedCBOR A @ref UsefulBufC containing wrapped bytes.
The closes a wrapping bstr opened by QCBOREncode_CloseBstrWrap(). It reduces
@@ -1752,7 +1993,7 @@ static void QCBOREncode_CloseBstrWrap(QCBOREncodeContext *pCtx, UsefulBufC *pWra
/**
@brief Add some already-encoded CBOR bytes.
- @param[in] pCtx The context to add to.
+ @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
@@ -1856,7 +2097,7 @@ QCBORError QCBOREncode_FinishGetSize(QCBOREncodeContext *pCtx, size_t *uEncodedL
/**
@brief Indicate whether output buffer is NULL or not.
- @param[in] pCtx The encoding ontext.
+ @param[in] pCtx The encoding context.
@return 1 if the output buffer is @c NULL.
@@ -1870,7 +2111,7 @@ static int QCBOREncode_IsBufferNULL(QCBOREncodeContext *pCtx);
/**
@brief Get the encoding error state.
- @param[in] pCtx The encoding ontext.
+ @param[in] pCtx The encoding context.
@return One of \ref QCBORError. See return values from
QCBOREncode_Finish()
@@ -2480,7 +2721,7 @@ void QCBOREncode_AddBuffer(QCBOREncodeContext *pCtx, uint8_t uMajorType, UsefulB
/**
- @brief Semi-private method to open a map, array or bstr wrapped CBOR
+ @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
@@ -2492,13 +2733,13 @@ void QCBOREncode_OpenMapOrArray(QCBOREncodeContext *pCtx, uint8_t uMajorType);
/**
- @brief Semi-private method to open a map, array or bstr wrapped CBOR with indefinite length
+ @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.
+ Call QCBOREncode_OpenArrayIndefiniteLength() or
+ QCBOREncode_OpenMapIndefiniteLength() instead of this.
*/
void QCBOREncode_OpenMapOrArrayIndefiniteLength(QCBOREncodeContext *pCtx, uint8_t uMajorType);
@@ -2513,19 +2754,23 @@ void QCBOREncode_OpenMapOrArrayIndefiniteLength(QCBOREncodeContext *pCtx, uint8_
Call QCBOREncode_CloseArray(), QCBOREncode_CloseMap() or
QCBOREncode_CloseBstrWrap() instead of this.
*/
-void QCBOREncode_CloseMapOrArray(QCBOREncodeContext *pCtx, uint8_t uMajorType, UsefulBufC *pWrappedCBOR);
+void QCBOREncode_CloseMapOrArray(QCBOREncodeContext *pCtx,
+ uint8_t uMajorType,
+ UsefulBufC *pWrappedCBOR);
/**
- @brief Semi-private method to close a map, array or bstr wrapped CBOR with indefinite length
+ @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.
@param[out] pWrappedCBOR Pointer to @ref UsefulBufC containing wrapped bytes.
- Call QCBOREncode_CloseArrayIndefiniteLength() or QCBOREncode_CloseMapIndefiniteLength()
- instead of this.
+ Call QCBOREncode_CloseArrayIndefiniteLength() or
+ QCBOREncode_CloseMapIndefiniteLength() instead of this.
*/
-void QCBOREncode_CloseMapOrArrayIndefiniteLength(QCBOREncodeContext *pCtx, uint8_t uMajorType, UsefulBufC *pWrappedCBOR);
+void QCBOREncode_CloseMapOrArrayIndefiniteLength(QCBOREncodeContext *pCtx,
+ uint8_t uMajorType,
+ UsefulBufC *pWrappedCBOR);
/**
@brief Semi-private method to add simple types.
@@ -2549,6 +2794,31 @@ void QCBOREncode_AddType7(QCBOREncodeContext *pCtx, size_t uSize, 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.
@@ -2577,6 +2847,7 @@ static inline void QCBOREncode_AddBytesLenOnlyToMapN(QCBOREncodeContext *pCtx, i
+
static inline void QCBOREncode_AddInt64ToMap(QCBOREncodeContext *pCtx, const char *szLabel, int64_t uNum)
{
// Use _AddBuffer() because _AddSZString() is defined below, not above
@@ -2773,6 +3044,125 @@ static inline void QCBOREncode_AddNegativeBignumToMapN(QCBOREncodeContext *pCtx,
}
+#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);
diff --git a/lib/ext/qcbor/src/UsefulBuf.c b/lib/ext/qcbor/src/UsefulBuf.c
index 0c336b8e7e..a96f74eb26 100644
--- a/lib/ext/qcbor/src/UsefulBuf.c
+++ b/lib/ext/qcbor/src/UsefulBuf.c
@@ -1,6 +1,6 @@
/*==============================================================================
Copyright (c) 2016-2018, The Linux Foundation.
- Copyright (c) 2018-2019, Laurence Lundblade.
+ 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
@@ -27,9 +27,9 @@ 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
DESCRIPTION: General purpose input and output buffers
@@ -39,24 +39,27 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This section contains comments describing changes made to the module.
Notice that changes are listed in reverse chronological order.
- when who what, where, why
- -------- ---- ---------------------------------------------------
- 11/08/2019 llundblade Re check pointer math and update comments
- 3/6/2019 llundblade Add UsefulBuf_IsValue()
- 09/07/17 llundbla Fix critical bug in UsefulBuf_Find() -- a read off
- the end of memory when the bytes to find is longer
- than the bytes to search.
- 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.
-
- =====================================================================================*/
+ when who what, where, why
+ -------- ---- ---------------------------------------------------
+ 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
+ 3/6/2019 llundblade Add UsefulBuf_IsValue()
+ 09/07/17 llundbla Fix critical bug in UsefulBuf_Find() -- a read off
+ the end of memory when the bytes to find is longer
+ than the bytes to search.
+ 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.
+
+ ============================================================================*/
#include "UsefulBuf.h"
-#define USEFUL_OUT_BUF_MAGIC (0x0B0F) // used to catch use of uninitialized or corrupted UOBs
+// used to catch use of uninitialized or corrupted UsefulOutBuf
+#define USEFUL_OUT_BUF_MAGIC (0x0B0F)
/*
@@ -64,7 +67,8 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
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
+ // 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
return NULLUsefulBufC;
}
@@ -106,7 +110,8 @@ size_t UsefulBuf_IsValue(const UsefulBufC UB, uint8_t uValue)
for(const uint8_t *p = UB.ptr; p < pEnd; p++) {
if(*p != uValue) {
/* Byte didn't match */
- return p - (uint8_t *)UB.ptr;
+ /* Cast from signed to unsigned . Safe because the loop increments.*/
+ return (size_t)(p - (uint8_t *)UB.ptr);
}
}
@@ -166,11 +171,13 @@ void UsefulOutBuf_Init(UsefulOutBuf *pMe, UsefulBuf Storage)
/*
Public function -- see UsefulBuf.h
- The core of UsefulOutBuf -- put some bytes in the buffer without writing off the end of it.
+ 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.
+ 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
@@ -192,7 +199,8 @@ void UsefulOutBuf_Init(UsefulOutBuf *pMe, UsefulBuf Storage)
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
+ 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.
@@ -219,7 +227,9 @@ void UsefulOutBuf_InsertUsefulBuf(UsefulOutBuf *pMe, UsefulBufC NewData, size_t
// be sure there is no pointer arithmatic under/overflow.
if(pMe->data_len > pMe->UB.len) { // Check #1
pMe->err = 1;
- return; // 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? */
@@ -330,7 +340,7 @@ UsefulBufC UsefulOutBuf_CopyOut(UsefulOutBuf *pMe, UsefulBuf pDest)
/*
Public function -- see UsefulBuf.h
- The core of UsefulInputBuf -- consume some bytes without going off the end of the buffer.
+ The core of UsefulInputBuf -- consume bytes without going off end of buffer.
Code Reviewers: THIS FUNCTION DOES POINTER MATH
*/
@@ -342,14 +352,15 @@ const void * UsefulInputBuf_GetBytes(UsefulInputBuf *pMe, size_t uAmount)
}
if(!UsefulInputBuf_BytesAvailable(pMe, uAmount)) {
- // The number of bytes asked for at current position are more than available
+ // Number of bytes asked for at current position are more than available
pMe->err = 1;
return NULL;
}
// This is going to succeed
const void * const result = ((uint8_t *)pMe->UB.ptr) + pMe->cursor;
- pMe->cursor += uAmount; // this will not overflow because of check using UsefulInputBuf_BytesAvailable()
+ // Will not overflow because of check using UsefulInputBuf_BytesAvailable()
+ pMe->cursor += uAmount;
return result;
}
diff --git a/lib/ext/qcbor/src/ieee754.c b/lib/ext/qcbor/src/ieee754.c
index 6fdfda8f4b..41f60cf808 100644
--- a/lib/ext/qcbor/src/ieee754.c
+++ b/lib/ext/qcbor/src/ieee754.c
@@ -1,35 +1,44 @@
/*==============================================================================
- ieee754.c -- floating point conversion between half, double and single precision
+ ieee754.c -- floating-point conversion between half, double & single-precision
- Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved.
+ Copyright (c) 2018-2020, Laurence Lundblade. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause
See BSD-3-Clause license in README.md
Created on 7/23/18
- ==============================================================================*/
+ =============================================================================*/
#include "ieee754.h"
#include <string.h> // For memcpy()
/*
- This code is written for clarity and verifiability, not for size, on the assumption
- that the optimizer will do a good job. The LLVM optimizer, -Os, does seem to do the
- job and the resulting object code is smaller from combining code for the many different
- cases (normal, subnormal, infinity, zero...) for the conversions.
-
- Dead stripping is also really helpful to get code size down when floating point
- encoding is not needed.
-
- This code works solely using shifts and masks and thus has no dependency on
- any math libraries. It can even work if the CPU doesn't have any floating
- point support, though that isn't the most useful thing to do.
-
- The memcpy() dependency is only for CopyFloatToUint32() and friends which only
- is needed to avoid type punning when converting the actual float bits to
- an unsigned value so the bit shifts and masks can work.
+ This code is written for clarity and verifiability, not for size, on
+ the assumption that the optimizer will do a good job. The LLVM
+ optimizer, -Os, does seem to do the job and the resulting object code
+ is smaller from combining code for the many different cases (normal,
+ subnormal, infinity, zero...) for the conversions. GCC is no where near
+ as good.
+
+ This code has really long lines and is much easier to read because of
+ them. Some coding guidelines prefer 80 column lines (can they not afford
+ big displays?). It would make this code much worse even to wrap at 120
+ columns.
+
+ Dead stripping is also really helpful to get code size down when
+ floating-point encoding is not needed. (If this is put in a library
+ and linking is against the library, then dead stripping is automatic).
+
+ This code works solely using shifts and masks and thus has no
+ dependency on any math libraries. It can even work if the CPU doesn't
+ have any floating-point support, though that isn't the most useful
+ thing to do.
+
+ The memcpy() dependency is only for CopyFloatToUint32() and friends
+ which only is needed to avoid type punning when converting the actual
+ float bits to an unsigned value so the bit shifts and masks can work.
*/
/*
@@ -40,6 +49,10 @@
- https://en.wikipedia.org/wiki/IEEE_754 and subordinate pages
- https://stackoverflow.com/questions/19800415/why-does-ieee-754-reserve-so-many-nan-values
+
+ - https://stackoverflow.com/questions/46073295/implicit-type-promotion-rules
+
+ - https://stackoverflow.com/questions/589575/what-does-the-c-standard-state-the-size-of-int-long-type-to-be
*/
@@ -52,10 +65,10 @@
#define HALF_EXPONENT_SHIFT (HALF_NUM_SIGNIFICAND_BITS)
#define HALF_SIGN_SHIFT (HALF_NUM_SIGNIFICAND_BITS + HALF_NUM_EXPONENT_BITS)
-#define HALF_SIGNIFICAND_MASK (0x3ff) // The lower 10 bits // 0x03ff
-#define HALF_EXPONENT_MASK (0x1f << HALF_EXPONENT_SHIFT) // 0x7c00 5 bits of exponent
-#define HALF_SIGN_MASK (0x01 << HALF_SIGN_SHIFT) // // 0x80001 bit of sign
-#define HALF_QUIET_NAN_BIT (0x01 << (HALF_NUM_SIGNIFICAND_BITS-1)) // 0x0200
+#define HALF_SIGNIFICAND_MASK (0x3ffU) // The lower 10 bits // 0x03ff
+#define HALF_EXPONENT_MASK (0x1fU << HALF_EXPONENT_SHIFT) // 0x7c00 5 bits of exponent
+#define HALF_SIGN_MASK (0x01U << HALF_SIGN_SHIFT) // // 0x8000 1 bit of sign
+#define HALF_QUIET_NAN_BIT (0x01U << (HALF_NUM_SIGNIFICAND_BITS-1)) // 0x0200
/* Biased Biased Unbiased Use
0x00 0 -15 0 and subnormal
@@ -69,7 +82,7 @@
#define HALF_EXPONENT_INF_OR_NAN (HALF_EXPONENT_BIAS+1) // 16 Unbiased
-// ------ Single Precision --------
+// ------ Single-Precision --------
#define SINGLE_NUM_SIGNIFICAND_BITS (23)
#define SINGLE_NUM_EXPONENT_BITS (8)
#define SINGLE_NUM_SIGN_BITS (1)
@@ -78,10 +91,10 @@
#define SINGLE_EXPONENT_SHIFT (SINGLE_NUM_SIGNIFICAND_BITS)
#define SINGLE_SIGN_SHIFT (SINGLE_NUM_SIGNIFICAND_BITS + SINGLE_NUM_EXPONENT_BITS)
-#define SINGLE_SIGNIFICAND_MASK (0x7fffffUL) // The lower 23 bits
-#define SINGLE_EXPONENT_MASK (0xffUL << SINGLE_EXPONENT_SHIFT) // 8 bits of exponent
-#define SINGLE_SIGN_MASK (0x01UL << SINGLE_SIGN_SHIFT) // 1 bit of sign
-#define SINGLE_QUIET_NAN_BIT (0x01UL << (SINGLE_NUM_SIGNIFICAND_BITS-1))
+#define SINGLE_SIGNIFICAND_MASK (0x7fffffU) // The lower 23 bits
+#define SINGLE_EXPONENT_MASK (0xffU << SINGLE_EXPONENT_SHIFT) // 8 bits of exponent
+#define SINGLE_SIGN_MASK (0x01U << SINGLE_SIGN_SHIFT) // 1 bit of sign
+#define SINGLE_QUIET_NAN_BIT (0x01U << (SINGLE_NUM_SIGNIFICAND_BITS-1))
/* Biased Biased Unbiased Use
0x0000 0 -127 0 and subnormal
@@ -90,13 +103,13 @@
0xfe 254 127 Largest normal exponent
0xff 255 128 NaN and Infinity */
#define SINGLE_EXPONENT_BIAS (127)
-#define SINGLE_EXPONENT_MAX (SINGLE_EXPONENT_BIAS) // 127 unbiased
+#define SINGLE_EXPONENT_MAX (SINGLE_EXPONENT_BIAS) // 127 unbiased
#define SINGLE_EXPONENT_MIN (-SINGLE_EXPONENT_BIAS+1) // -126 unbiased
#define SINGLE_EXPONENT_ZERO (-SINGLE_EXPONENT_BIAS) // -127 unbiased
-#define SINGLE_EXPONENT_INF_OR_NAN (SINGLE_EXPONENT_BIAS+1) // 128 unbiased
+#define SINGLE_EXPONENT_INF_OR_NAN (SINGLE_EXPONENT_BIAS+1) // 128 unbiased
-// --------- Double Precision ----------
+// --------- Double-Precision ----------
#define DOUBLE_NUM_SIGNIFICAND_BITS (52)
#define DOUBLE_NUM_EXPONENT_BITS (11)
#define DOUBLE_NUM_SIGN_BITS (1)
@@ -125,14 +138,13 @@
/*
- Convenient functions to avoid type punning, compiler warnings and such
- The optimizer reduces them to a simple assignment.
- This is a crusty corner of C. It shouldn't be this hard.
+ Convenient functions to avoid type punning, compiler warnings and
+ such. The optimizer reduces them to a simple assignment. This is a
+ crusty corner of C. It shouldn't be this hard.
These are also in UsefulBuf.h under a different name. They are copied
- here to avoid a dependency on UsefulBuf.h. There is no
- object code size impact because these always optimze down to a
- simple assignment.
+ here to avoid a dependency on UsefulBuf.h. There is no object code
+ size impact because these always optimze down to a simple assignment.
*/
static inline uint32_t CopyFloatToUint32(float f)
{
@@ -168,13 +180,18 @@ uint16_t IEEE754_FloatToHalf(float f)
{
// Pull the three parts out of the single-precision float
const uint32_t uSingle = CopyFloatToUint32(f);
- const int32_t nSingleUnbiasedExponent = ((uSingle & SINGLE_EXPONENT_MASK) >> SINGLE_EXPONENT_SHIFT) - SINGLE_EXPONENT_BIAS;
- const uint32_t uSingleSign = (uSingle & SINGLE_SIGN_MASK) >> SINGLE_SIGN_SHIFT;
- const uint32_t uSingleSignificand = uSingle & SINGLE_SIGNIFICAND_MASK;
+ const int32_t nSingleUnbiasedExponent = (int32_t)((uSingle & SINGLE_EXPONENT_MASK) >> SINGLE_EXPONENT_SHIFT) - SINGLE_EXPONENT_BIAS;
+ const uint32_t uSingleSign = (uSingle & SINGLE_SIGN_MASK) >> SINGLE_SIGN_SHIFT;
+ const uint32_t uSingleSignificand = uSingle & SINGLE_SIGNIFICAND_MASK;
// Now convert the three parts to half-precision.
- uint16_t uHalfSign, uHalfSignificand, uHalfBiasedExponent;
+
+ // All works is done on uint32_t with conversion to uint16_t at the end.
+ // This avoids integer promotions that static analyzers complain about and
+ // reduces code size.
+ uint32_t uHalfSign, uHalfSignificand, uHalfBiasedExponent;
+
if(nSingleUnbiasedExponent == SINGLE_EXPONENT_INF_OR_NAN) {
// +/- Infinity and NaNs -- single biased exponent is 0xff
uHalfBiasedExponent = HALF_EXPONENT_INF_OR_NAN + HALF_EXPONENT_BIAS;
@@ -182,13 +199,13 @@ uint16_t IEEE754_FloatToHalf(float f)
// Infinity
uHalfSignificand = 0;
} else {
- // Copy the LBSs of the NaN payload that will fit from the single to the half
+ // Copy the LSBs of the NaN payload that will fit from the single to the half
uHalfSignificand = uSingleSignificand & (HALF_SIGNIFICAND_MASK & ~HALF_QUIET_NAN_BIT);
if(uSingleSignificand & SINGLE_QUIET_NAN_BIT) {
// It's a qNaN; copy the qNaN bit
uHalfSignificand |= HALF_QUIET_NAN_BIT;
} else {
- // It's a sNaN; make sure the significand is not zero so it stays a NaN
+ // It's an sNaN; make sure the significand is not zero so it stays a NaN
// This is needed because not all significand bits are copied from single
if(!uHalfSignificand) {
// Set the LSB. This is what wikipedia shows for sNAN.
@@ -206,26 +223,28 @@ uint16_t IEEE754_FloatToHalf(float f)
uHalfSignificand = 0;
} else if(nSingleUnbiasedExponent < HALF_EXPONENT_MIN) {
// Exponent is too small to express in half-precision normal; make it a half-precision subnormal
- uHalfBiasedExponent = (uint16_t)(HALF_EXPONENT_ZERO + HALF_EXPONENT_BIAS);
+ uHalfBiasedExponent = HALF_EXPONENT_ZERO + HALF_EXPONENT_BIAS;
// Difference between single normal exponent and the base exponent of a half subnormal
- const uint32_t nExpDiff = -(nSingleUnbiasedExponent - HALF_EXPONENT_MIN);
+ const uint32_t uExpDiff = (uint32_t)-(nSingleUnbiasedExponent - HALF_EXPONENT_MIN);
// Also have to shift the significand by the difference in number of bits between a single and a half significand
- const int32_t nSignificandBitsDiff = SINGLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS;
+ const uint32_t uSignificandBitsDiff = SINGLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS;
// Add in the 1 that is implied in the significand of a normal number; it needs to be present in a subnormal
- const uint32_t uSingleSignificandSubnormal = uSingleSignificand + (0x01L << SINGLE_NUM_SIGNIFICAND_BITS);
- uHalfSignificand = uSingleSignificandSubnormal >> (nExpDiff + nSignificandBitsDiff);
+ const uint32_t uSingleSignificandSubnormal = uSingleSignificand + (0x01U << SINGLE_NUM_SIGNIFICAND_BITS);
+ uHalfSignificand = uSingleSignificandSubnormal >> (uExpDiff + uSignificandBitsDiff);
} else {
- // The normal case
- uHalfBiasedExponent = nSingleUnbiasedExponent + HALF_EXPONENT_BIAS;
+ // The normal case, exponent is in range for half-precision
+ uHalfBiasedExponent = (uint32_t)(nSingleUnbiasedExponent + HALF_EXPONENT_BIAS);
uHalfSignificand = uSingleSignificand >> (SINGLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS);
}
uHalfSign = uSingleSign;
// Put the 3 values in the right place for a half precision
- const uint16_t uHalfPrecision = uHalfSignificand |
+ const uint32_t uHalfPrecision = uHalfSignificand |
(uHalfBiasedExponent << HALF_EXPONENT_SHIFT) |
(uHalfSign << HALF_SIGN_SHIFT);
- return uHalfPrecision;
+ // Cast is safe because all the masks and shifts above work to make
+ // a half precision value which is only 16 bits.
+ return (uint16_t)uHalfPrecision;
}
@@ -234,13 +253,19 @@ uint16_t IEEE754_DoubleToHalf(double d)
{
// Pull the three parts out of the double-precision float
const uint64_t uDouble = CopyDoubleToUint64(d);
- const int64_t nDoubleUnbiasedExponent = ((uDouble & DOUBLE_EXPONENT_MASK) >> DOUBLE_EXPONENT_SHIFT) - DOUBLE_EXPONENT_BIAS;
- const uint64_t uDoubleSign = (uDouble & DOUBLE_SIGN_MASK) >> DOUBLE_SIGN_SHIFT;
- const uint64_t uDoubleSignificand = uDouble & DOUBLE_SIGNIFICAND_MASK;
-
+ const int64_t nDoubleUnbiasedExponent = (int64_t)((uDouble & DOUBLE_EXPONENT_MASK) >> DOUBLE_EXPONENT_SHIFT) - DOUBLE_EXPONENT_BIAS;
+ const uint64_t uDoubleSign = (uDouble & DOUBLE_SIGN_MASK) >> DOUBLE_SIGN_SHIFT;
+ const uint64_t uDoubleSignificand = uDouble & DOUBLE_SIGNIFICAND_MASK;
// Now convert the three parts to half-precision.
- uint16_t uHalfSign, uHalfSignificand, uHalfBiasedExponent;
+
+ // All works is done on uint64_t with conversion to uint16_t at the end.
+ // This avoids integer promotions that static analyzers complain about.
+ // Other options are for these to be unsigned int or fast_int16_t. Code
+ // size doesn't vary much between all these options for 64-bit LLVM,
+ // 64-bit GCC and 32-bit Armv7 LLVM.
+ uint64_t uHalfSign, uHalfSignificand, uHalfBiasedExponent;
+
if(nDoubleUnbiasedExponent == DOUBLE_EXPONENT_INF_OR_NAN) {
// +/- Infinity and NaNs -- single biased exponent is 0xff
uHalfBiasedExponent = HALF_EXPONENT_INF_OR_NAN + HALF_EXPONENT_BIAS;
@@ -248,7 +273,7 @@ uint16_t IEEE754_DoubleToHalf(double d)
// Infinity
uHalfSignificand = 0;
} else {
- // Copy the LBSs of the NaN payload that will fit from the double to the half
+ // Copy the LSBs of the NaN payload that will fit from the double to the half
uHalfSignificand = uDoubleSignificand & (HALF_SIGNIFICAND_MASK & ~HALF_QUIET_NAN_BIT);
if(uDoubleSignificand & DOUBLE_QUIET_NAN_BIT) {
// It's a qNaN; copy the qNaN bit
@@ -272,37 +297,42 @@ uint16_t IEEE754_DoubleToHalf(double d)
uHalfSignificand = 0;
} else if(nDoubleUnbiasedExponent < HALF_EXPONENT_MIN) {
// Exponent is too small to express in half-precision; round down to zero
- uHalfBiasedExponent = (uint16_t)(HALF_EXPONENT_ZERO + HALF_EXPONENT_BIAS);
+ uHalfBiasedExponent = HALF_EXPONENT_ZERO + HALF_EXPONENT_BIAS;
// Difference between double normal exponent and the base exponent of a half subnormal
- const uint64_t nExpDiff = -(nDoubleUnbiasedExponent - HALF_EXPONENT_MIN);
+ const uint64_t uExpDiff = (uint64_t)-(nDoubleUnbiasedExponent - HALF_EXPONENT_MIN);
// Also have to shift the significand by the difference in number of bits between a double and a half significand
- const int64_t nSignificandBitsDiff = DOUBLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS;
+ const uint64_t uSignificandBitsDiff = DOUBLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS;
// Add in the 1 that is implied in the significand of a normal number; it needs to be present in a subnormal
const uint64_t uDoubleSignificandSubnormal = uDoubleSignificand + (0x01ULL << DOUBLE_NUM_SIGNIFICAND_BITS);
- uHalfSignificand = uDoubleSignificandSubnormal >> (nExpDiff + nSignificandBitsDiff);
+ uHalfSignificand = uDoubleSignificandSubnormal >> (uExpDiff + uSignificandBitsDiff);
} else {
- // The normal case
- uHalfBiasedExponent = nDoubleUnbiasedExponent + HALF_EXPONENT_BIAS;
+ // The normal case, exponent is in range for half-precision
+ uHalfBiasedExponent = (uint32_t)(nDoubleUnbiasedExponent + HALF_EXPONENT_BIAS);
uHalfSignificand = uDoubleSignificand >> (DOUBLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS);
}
uHalfSign = uDoubleSign;
// Put the 3 values in the right place for a half precision
- const uint16_t uHalfPrecision = uHalfSignificand |
+ const uint64_t uHalfPrecision = uHalfSignificand |
(uHalfBiasedExponent << HALF_EXPONENT_SHIFT) |
(uHalfSign << HALF_SIGN_SHIFT);
- return uHalfPrecision;
+ // Cast is safe because all the masks and shifts above work to make
+ // a half precision value which is only 16 bits.
+ return (uint16_t)uHalfPrecision;
}
+
// Public function; see ieee754.h
float IEEE754_HalfToFloat(uint16_t uHalfPrecision)
{
// Pull out the three parts of the half-precision float
- const uint16_t uHalfSignificand = uHalfPrecision & HALF_SIGNIFICAND_MASK;
- const int16_t nHalfUnBiasedExponent = ((uHalfPrecision & HALF_EXPONENT_MASK) >> HALF_EXPONENT_SHIFT) - HALF_EXPONENT_BIAS;
- const uint16_t uHalfSign = (uHalfPrecision & HALF_SIGN_MASK) >> HALF_SIGN_SHIFT;
+ // Do all the work in 32 bits because that is what the end result is
+ // may give smaller code size and will keep static analyzers happier.
+ const uint32_t uHalfSignificand = uHalfPrecision & HALF_SIGNIFICAND_MASK;
+ const int32_t nHalfUnBiasedExponent = (int32_t)((uHalfPrecision & HALF_EXPONENT_MASK) >> HALF_EXPONENT_SHIFT) - HALF_EXPONENT_BIAS;
+ const uint32_t uHalfSign = (uHalfPrecision & HALF_SIGN_MASK) >> HALF_SIGN_SHIFT;
// Make the three parts of the single-precision number
@@ -343,13 +373,12 @@ float IEEE754_HalfToFloat(uint16_t uHalfPrecision)
}
} else {
// Normal number
- uSingleBiasedExponent = nHalfUnBiasedExponent + SINGLE_EXPONENT_BIAS;
+ uSingleBiasedExponent = (uint32_t)(nHalfUnBiasedExponent + SINGLE_EXPONENT_BIAS);
uSingleSignificand = uHalfSignificand << (SINGLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS);
}
uSingleSign = uHalfSign;
-
- // Shift the three parts of the single precision into place
+ // Shift the three parts of the single-precision into place
const uint32_t uSinglePrecision = uSingleSignificand |
(uSingleBiasedExponent << SINGLE_EXPONENT_SHIFT) |
(uSingleSign << SINGLE_SIGN_SHIFT);
@@ -362,9 +391,11 @@ float IEEE754_HalfToFloat(uint16_t uHalfPrecision)
double IEEE754_HalfToDouble(uint16_t uHalfPrecision)
{
// Pull out the three parts of the half-precision float
- const uint16_t uHalfSignificand = uHalfPrecision & HALF_SIGNIFICAND_MASK;
- const int16_t nHalfUnBiasedExponent = ((uHalfPrecision & HALF_EXPONENT_MASK) >> HALF_EXPONENT_SHIFT) - HALF_EXPONENT_BIAS;
- const uint16_t uHalfSign = (uHalfPrecision & HALF_SIGN_MASK) >> HALF_SIGN_SHIFT;
+ // Do all the work in 64 bits because that is what the end result is
+ // may give smaller code size and will keep static analyzers happier.
+ const uint64_t uHalfSignificand = uHalfPrecision & HALF_SIGNIFICAND_MASK;
+ const int64_t nHalfUnBiasedExponent = (int64_t)((uHalfPrecision & HALF_EXPONENT_MASK) >> HALF_EXPONENT_SHIFT) - HALF_EXPONENT_BIAS;
+ const uint64_t uHalfSign = (uHalfPrecision & HALF_SIGN_MASK) >> HALF_SIGN_SHIFT;
// Make the three parts of hte single-precision number
@@ -405,8 +436,8 @@ double IEEE754_HalfToDouble(uint16_t uHalfPrecision)
}
} else {
// Normal number
- uDoubleBiasedExponent = nHalfUnBiasedExponent + DOUBLE_EXPONENT_BIAS;
- uDoubleSignificand = (uint64_t)uHalfSignificand << (DOUBLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS);
+ uDoubleBiasedExponent = (uint64_t)(nHalfUnBiasedExponent + DOUBLE_EXPONENT_BIAS);
+ uDoubleSignificand = uHalfSignificand << (DOUBLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS);
}
uDoubleSign = uHalfSign;
@@ -426,7 +457,7 @@ IEEE754_union IEEE754_FloatToSmallest(float f)
// Pull the neeed two parts out of the single-precision float
const uint32_t uSingle = CopyFloatToUint32(f);
- const int32_t nSingleExponent = ((uSingle & SINGLE_EXPONENT_MASK) >> SINGLE_EXPONENT_SHIFT) - SINGLE_EXPONENT_BIAS;
+ const int32_t nSingleExponent = (int32_t)((uSingle & SINGLE_EXPONENT_MASK) >> SINGLE_EXPONENT_SHIFT) - SINGLE_EXPONENT_BIAS;
const uint32_t uSingleSignificand = uSingle & SINGLE_SIGNIFICAND_MASK;
// Bit mask that is the significand bits that would be lost when converting
@@ -462,7 +493,7 @@ IEEE754_union IEEE754_DoubleToSmallestInternal(double d, int bAllowHalfPrecision
// Pull the needed two parts out of the double-precision float
const uint64_t uDouble = CopyDoubleToUint64(d);
- const int64_t nDoubleExponent = ((uDouble & DOUBLE_EXPONENT_MASK) >> DOUBLE_EXPONENT_SHIFT) - DOUBLE_EXPONENT_BIAS;
+ const int64_t nDoubleExponent = (int64_t)((uDouble & DOUBLE_EXPONENT_MASK) >> DOUBLE_EXPONENT_SHIFT) - DOUBLE_EXPONENT_BIAS;
const uint64_t uDoubleSignificand = uDouble & DOUBLE_SIGNIFICAND_MASK;
// Masks to check whether dropped significand bits are zero or not
diff --git a/lib/ext/qcbor/src/ieee754.h b/lib/ext/qcbor/src/ieee754.h
index 2530f984e4..705ef62e73 100644
--- a/lib/ext/qcbor/src/ieee754.h
+++ b/lib/ext/qcbor/src/ieee754.h
@@ -1,14 +1,14 @@
/*==============================================================================
- ieee754.c -- floating point conversion between half, double and single precision
+ ieee754.c -- floating-point conversion between half, double & single-precision
- Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved.
+ Copyright (c) 2018-2020, Laurence Lundblade. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause
See BSD-3-Clause license in README.md
Created on 7/23/18
- ==============================================================================*/
+ =============================================================================*/
#ifndef ieee754_h
#define ieee754_h
@@ -20,94 +20,77 @@
/*
General comments
- This is a complete in that it handles all conversion cases
- including +/- infinity, +/- zero, subnormal numbers, qNaN, sNaN
- and NaN payloads.
+ This is a complete in that it handles all conversion cases including
+ +/- infinity, +/- zero, subnormal numbers, qNaN, sNaN and NaN
+ payloads.
- This confirms to IEEE 754-2008, but note that this doesn't
- specify conversions, just the encodings.
+ This conforms to IEEE 754-2008, but note that this doesn't specify
+ conversions, just the encodings.
- NaN payloads are preserved with alignment on the LSB. The
- qNaN bit is handled differently and explicity copied. It
- is always the MSB of the significand. The NaN payload MSBs
- (except the qNaN bit) are truncated when going from
- double or single to half.
+ NaN payloads are preserved with alignment on the LSB. The qNaN bit is
+ handled differently and explicity copied. It is always the MSB of the
+ significand. The NaN payload MSBs (except the qNaN bit) are truncated
+ when going from double or single to half.
TODO: what does the C cast do with NaN payloads from
- double to single?
-
-
+ double to single? It probably depends entirely on the
+ CPU.
*/
/*
- Most simply just explicilty encode the type you want, single or double.
- This works easily everywhere since standard C supports both
- these types and so does qcbor. This encoder also supports
- half precision and there's a few ways to use it to encode
- floating point numbers in less space.
+ Most simply just explicilty encode the type you want, single or
+ double. This works easily everywhere since standard C supports both
+ these types and so does qcbor. This encoder also supports half
+ precision and there's a few ways to use it to encode floating-point
+ numbers in less space.
- Without losing precision, you can encode a single or double
- such that the special values of 0, NaN and Infinity encode
- as half-precision. This CBOR decodoer and most others
- should handle this properly.
+ Without losing precision, you can encode a single or double such that
+ the special values of 0, NaN and Infinity encode as half-precision.
+ This CBOR decodoer and most others should handle this properly.
If you don't mind losing precision, then you can use half-precision.
One way to do this is to set up your environment to use
___fp_16. Some compilers and CPUs support it even though it is not
- standard C. What is nice about this is that your program
- will use less memory and floating point operations like
- multiplying, adding and such will be faster.
-
- Another way to make use of half-precision is to represent
- the values in your program as single or double, but encode
- them in CBOR as half-precision. This cuts the size
- of the encoded messages by 2 or 4, but doesn't reduce
- memory needs or speed because you are still using
+ standard C. What is nice about this is that your program will use
+ less memory and floating-point operations like multiplying, adding
+ and such will be faster.
+
+ Another way to make use of half-precision is to represent the values
+ in your program as single or double, but encode them in CBOR as
+ half-precision. This cuts the size of the encoded messages by 2 or 4,
+ but doesn't reduce memory needs or speed because you are still using
single or double in your code.
-
- encode:
- - float as float
- - double as double
- - half as half
- - float as half_precision, for environments that don't support a half-precision type
- - double as half_precision, for environments that don't support a half-precision type
- - float with NaN, Infinity and 0 as half
- - double with NaN, Infinity and 0 as half
-
-
-
-
*/
/*
- Convert single precision float to half-precision float.
- Precision and NaN payload bits will be lost. Too large
- values will round up to infinity and too small to zero.
+ Convert single-precision float to half-precision float. Precision
+ and NaN payload bits will be lost. Too-large values will round up to
+ infinity and too small to zero.
*/
uint16_t IEEE754_FloatToHalf(float f);
/*
- Convert half precision float to single precision float.
- This is a loss-less conversion.
+ Convert half-precision float to single-precision float. This is a
+ loss-less conversion.
*/
float IEEE754_HalfToFloat(uint16_t uHalfPrecision);
/*
- Convert double precision float to half-precision float.
- Precision and NaN payload bits will be lost. Too large
- values will round up to infinity and too small to zero.
+ Convert double-precision float to half-precision float. Precision
+ and NaN payload bits will be lost. Too-large values will round up to
+ infinity and too small to zero.
*/
uint16_t IEEE754_DoubleToHalf(double d);
/*
- Convert half precision float to double precision float.
+ Convert half-precision float to double-precision float.
This is a loss-less conversion.
*/
double IEEE754_HalfToDouble(uint16_t uHalfPrecision);
@@ -126,9 +109,10 @@ typedef struct {
/*
- Converts double-precision to single-precision or half-precision if possible without
- loss of precisions. If not, leaves it as a double. Only converts to single-precision
- unless bAllowHalfPrecision is set.
+ Converts double-precision to single-precision or half-precision if
+ possible without loss of precisions. If not, leaves it as a
+ double. Only converts to single-precision unless bAllowHalfPrecision
+ is set.
*/
IEEE754_union IEEE754_DoubleToSmallestInternal(double d, int bAllowHalfPrecision);
@@ -143,17 +127,18 @@ static inline IEEE754_union IEEE754_DoubleToSmall(double d)
/*
- Converts double-precision to single-precision or half-precision if possible without
- loss of precisions. If not, leaves it as a double.
+ Converts double-precision to single-precision or half-precision if
+ possible without loss of precisions. If not, leaves it as a double.
*/
static inline IEEE754_union IEEE754_DoubleToSmallest(double d)
{
return IEEE754_DoubleToSmallestInternal(d, 1);
}
+
/*
- Converts single-precision to half-precision if possible without
- loss of precision. If not leaves as single-precision.
+ Converts single-precision to half-precision if possible without loss
+ of precision. If not leaves as single-precision.
*/
IEEE754_union IEEE754_FloatToSmallest(float f);
diff --git a/lib/ext/qcbor/src/qcbor_decode.c b/lib/ext/qcbor/src/qcbor_decode.c
index 36a9d116e4..1b6ff3eaca 100644
--- a/lib/ext/qcbor/src/qcbor_decode.c
+++ b/lib/ext/qcbor/src/qcbor_decode.c
@@ -1,6 +1,6 @@
/*==============================================================================
Copyright (c) 2016-2018, The Linux Foundation.
- Copyright (c) 2018-2019, Laurence Lundblade.
+ Copyright (c) 2018-2020, Laurence Lundblade.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -28,9 +28,9 @@ 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_decode.c
DESCRIPTION: This file contains the implementation of QCBOR.
@@ -40,30 +40,36 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This section contains comments describing changes made to the module.
Notice that changes are listed in reverse chronological order.
- when who what, where, why
- -------- ---- ---------------------------------------------------
- 11/07/19 llundblade Fix long long conversion to double compiler warning
- 09/07/19 llundblade Fix bug decoding empty arrays and maps
- 07/31/19 llundblade Decode error fixes for some not-well-formed CBOR
- 07/31/19 llundblade New error code for better end of data handling
- 02/17/19 llundblade Fixed: QCBORItem.u{Data|Label}Alloc when bAllStrings set
- 02/16/19 llundblade Redesign MemPool to fix memory access alignment bug
- 01/10/19 llundblade Clever type and argument decoder is 250 bytes smaller
- 11/9/18 llundblade Error codes are now enums.
- 11/2/18 llundblade Simplify float decoding and align with preferred
- float encoding
- 10/31/18 llundblade Switch to one license that is almost BSD-3.
- 10/28/18 llundblade Reworked tag decoding
- 10/15/18 llundblade Indefinite length maps and arrays supported
- 10/8/18 llundblade Indefinite length strings supported
- 02/04/17 llundbla Work on CPUs that don's require pointer alignment
- by making use of changes in UsefulBuf
- 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.
-
- =====================================================================================*/
+ when who what, where, why
+ -------- ---- ---------------------------------------------------
+ 01/28/2020 llundblade Refine integer signedness to quiet static analysis.
+ 01/25/2020 llundblade Cleaner handling of too-long encoded string input.
+ 01/25/2020 llundblade Refine use of integer types to quiet static analysis
+ 01/08/2020 llundblade Documentation corrections & improved code formatting
+ 12/30/19 llundblade Add support for decimal fractions and bigfloats.
+ 11/07/19 llundblade Fix long long conversion to double compiler warning
+ 09/07/19 llundblade Fix bug decoding empty arrays and maps
+ 07/31/19 llundblade Decode error fixes for some not-well-formed CBOR
+ 07/31/19 llundblade New error code for better end of data handling
+ 02/17/19 llundblade Fixed: QCBORItem.u{Data|Label}Alloc when
+ bAllStrings set
+ 02/16/19 llundblade Redesign MemPool to fix memory access alignment bug
+ 01/10/19 llundblade Clever type and argument decoder; 250 bytes smaller
+ 11/9/18 llundblade Error codes are now enums.
+ 11/2/18 llundblade Simplify float decoding and align with preferred
+ float encoding
+ 10/31/18 llundblade Switch to one license that is almost BSD-3.
+ 10/28/18 llundblade Reworked tag decoding
+ 10/15/18 llundblade Indefinite length maps and arrays supported
+ 10/8/18 llundblade Indefinite length strings supported
+ 02/04/17 llundbla Work on CPUs that don's require pointer alignment
+ by making use of changes in UsefulBuf
+ 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.
+
+ =============================================================================*/
#include "qcbor.h"
#include "ieee754.h"
@@ -76,31 +82,41 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define UNCONST_POINTER(ptr) ((void *)(ptr))
-/*
- Collection of functions to track the map/array nesting for decoding
- */
-inline static int IsMapOrArray(uint8_t uDataType)
+/*===========================================================================
+ DecodeNesting -- Functions for tracking array/map nesting when decoding
+
+ See qcbor.h for definition of the object used here: QCBORDecodeNesting
+ ===========================================================================*/
+
+inline static int
+IsMapOrArray(uint8_t uDataType)
{
return uDataType == QCBOR_TYPE_MAP || uDataType == QCBOR_TYPE_ARRAY;
}
-inline static int DecodeNesting_IsNested(const QCBORDecodeNesting *pNesting)
+inline static int
+DecodeNesting_IsNested(const QCBORDecodeNesting *pNesting)
{
return pNesting->pCurrent != &(pNesting->pMapsAndArrays[0]);
}
-inline static int DecodeNesting_IsIndefiniteLength(const QCBORDecodeNesting *pNesting)
+inline static int
+DecodeNesting_IsIndefiniteLength(const QCBORDecodeNesting *pNesting)
{
return pNesting->pCurrent->uCount == UINT16_MAX;
}
-inline static uint8_t DecodeNesting_GetLevel(QCBORDecodeNesting *pNesting)
+inline static uint8_t
+DecodeNesting_GetLevel(QCBORDecodeNesting *pNesting)
{
- return pNesting->pCurrent - &(pNesting->pMapsAndArrays[0]);
+ // Check in DecodeNesting_Descend and never having
+ // QCBOR_MAX_ARRAY_NESTING > 255 gaurantee cast is safe
+ return (uint8_t)(pNesting->pCurrent - &(pNesting->pMapsAndArrays[0]));
}
-inline static int DecodeNesting_TypeIsMap(const QCBORDecodeNesting *pNesting)
+inline static int
+DecodeNesting_TypeIsMap(const QCBORDecodeNesting *pNesting)
{
if(!DecodeNesting_IsNested(pNesting)) {
return 0;
@@ -110,7 +126,8 @@ inline static int DecodeNesting_TypeIsMap(const QCBORDecodeNesting *pNesting)
}
// Process a break. This will either ascend the nesting or error out
-inline static QCBORError DecodeNesting_BreakAscend(QCBORDecodeNesting *pNesting)
+inline static QCBORError
+DecodeNesting_BreakAscend(QCBORDecodeNesting *pNesting)
{
// breaks must always occur when there is nesting
if(!DecodeNesting_IsNested(pNesting)) {
@@ -128,8 +145,9 @@ inline static QCBORError DecodeNesting_BreakAscend(QCBORDecodeNesting *pNesting)
return QCBOR_SUCCESS;
}
-// Called on every single item except breaks including the opening of a map/array
-inline static void DecodeNesting_DecrementCount(QCBORDecodeNesting *pNesting)
+// Called on every single item except breaks including open of a map/array
+inline static void
+DecodeNesting_DecrementCount(QCBORDecodeNesting *pNesting)
{
while(DecodeNesting_IsNested(pNesting)) {
// Not at the top level, so there is decrementing to be done.
@@ -151,9 +169,9 @@ inline static void DecodeNesting_DecrementCount(QCBORDecodeNesting *pNesting)
}
}
-
// Called on every map/array
-inline static QCBORError DecodeNesting_Descend(QCBORDecodeNesting *pNesting, QCBORItem *pItem)
+inline static QCBORError
+DecodeNesting_Descend(QCBORDecodeNesting *pNesting, QCBORItem *pItem)
{
QCBORError nReturn = QCBOR_SUCCESS;
@@ -187,7 +205,8 @@ Done:
return nReturn;;
}
-inline static void DecodeNesting_Init(QCBORDecodeNesting *pNesting)
+inline static void
+DecodeNesting_Init(QCBORDecodeNesting *pNesting)
{
pNesting->pCurrent = &(pNesting->pMapsAndArrays[0]);
}
@@ -201,12 +220,12 @@ inline static void DecodeNesting_Init(QCBORDecodeNesting *pNesting)
There are only 48 slots available forever.
*/
static const uint16_t spBuiltInTagMap[] = {
- CBOR_TAG_DATE_STRING, // See TAG_MAPPER_FIRST_FOUR
- CBOR_TAG_DATE_EPOCH, // See TAG_MAPPER_FIRST_FOUR
- CBOR_TAG_POS_BIGNUM, // See TAG_MAPPER_FIRST_FOUR
- CBOR_TAG_NEG_BIGNUM, // See TAG_MAPPER_FIRST_FOUR
- CBOR_TAG_FRACTION,
- CBOR_TAG_BIGFLOAT,
+ CBOR_TAG_DATE_STRING, // See TAG_MAPPER_FIRST_SIX
+ CBOR_TAG_DATE_EPOCH, // See TAG_MAPPER_FIRST_SIX
+ CBOR_TAG_POS_BIGNUM, // See TAG_MAPPER_FIRST_SIX
+ CBOR_TAG_NEG_BIGNUM, // See TAG_MAPPER_FIRST_SIX
+ CBOR_TAG_DECIMAL_FRACTION, // See TAG_MAPPER_FIRST_SIX
+ CBOR_TAG_BIGFLOAT, // See TAG_MAPPER_FIRST_SIX
CBOR_TAG_COSE_ENCRYPTO,
CBOR_TAG_COSE_MAC0,
CBOR_TAG_COSE_SIGN1,
@@ -230,17 +249,26 @@ static const uint16_t spBuiltInTagMap[] = {
// This is used in a bit of cleverness in GetNext_TaggedItem() to
// keep code size down and switch for the internal processing of
-// these types. This will break if the first four items in
-// spBuiltInTagMap don't have values 0,1,2,3. That is the
-// mapping is 0 to 0, 1 to 1, 2 to 2 and 3 to 3.
-#define QCBOR_TAGFLAG_DATE_STRING (0x01LL << CBOR_TAG_DATE_STRING)
-#define QCBOR_TAGFLAG_DATE_EPOCH (0x01LL << CBOR_TAG_DATE_EPOCH)
-#define QCBOR_TAGFLAG_POS_BIGNUM (0x01LL << CBOR_TAG_POS_BIGNUM)
-#define QCBOR_TAGFLAG_NEG_BIGNUM (0x01LL << CBOR_TAG_NEG_BIGNUM)
-
-#define TAG_MAPPER_FIRST_FOUR (QCBOR_TAGFLAG_DATE_STRING |\
- QCBOR_TAGFLAG_DATE_EPOCH |\
- QCBOR_TAGFLAG_POS_BIGNUM |\
+// these types. This will break if the first six items in
+// spBuiltInTagMap don't have values 0,1,2,3,4,5. That is the
+// mapping is 0 to 0, 1 to 1, 2 to 2 and 3 to 3....
+#define QCBOR_TAGFLAG_DATE_STRING (0x01LL << CBOR_TAG_DATE_STRING)
+#define QCBOR_TAGFLAG_DATE_EPOCH (0x01LL << CBOR_TAG_DATE_EPOCH)
+#define QCBOR_TAGFLAG_POS_BIGNUM (0x01LL << CBOR_TAG_POS_BIGNUM)
+#define QCBOR_TAGFLAG_NEG_BIGNUM (0x01LL << CBOR_TAG_NEG_BIGNUM)
+#define QCBOR_TAGFLAG_DECIMAL_FRACTION (0x01LL << CBOR_TAG_DECIMAL_FRACTION)
+#define QCBOR_TAGFLAG_BIGFLOAT (0x01LL << CBOR_TAG_BIGFLOAT)
+
+#define TAG_MAPPER_FIRST_SIX (QCBOR_TAGFLAG_DATE_STRING |\
+ QCBOR_TAGFLAG_DATE_EPOCH |\
+ QCBOR_TAGFLAG_POS_BIGNUM |\
+ QCBOR_TAGFLAG_NEG_BIGNUM |\
+ QCBOR_TAGFLAG_DECIMAL_FRACTION |\
+ QCBOR_TAGFLAG_BIGFLOAT)
+
+#define TAG_MAPPER_FIRST_FOUR (QCBOR_TAGFLAG_DATE_STRING |\
+ QCBOR_TAGFLAG_DATE_EPOCH |\
+ QCBOR_TAGFLAG_POS_BIGNUM |\
QCBOR_TAGFLAG_NEG_BIGNUM)
#define TAG_MAPPER_TOTAL_TAG_BITS 64 // Number of bits in a uint64_t
@@ -250,10 +278,12 @@ static const uint16_t spBuiltInTagMap[] = {
static inline int TagMapper_LookupBuiltIn(uint64_t uTag)
{
if(sizeof(spBuiltInTagMap)/sizeof(uint16_t) > TAG_MAPPER_MAX_SIZE_BUILT_IN_TAGS) {
- // This is a cross-check to make sure the above array doesn't
- // accidentally get made too big.
- // In normal conditions the above test should optimize out
- // as all the values are known at compile time.
+ /*
+ This is a cross-check to make sure the above array doesn't
+ accidentally get made too big. In normal conditions the above
+ test should optimize out as all the values are known at compile
+ time.
+ */
return -1;
}
@@ -287,7 +317,10 @@ static inline int TagMapper_LookupCallerConfigured(const QCBORTagListIn *pCaller
This and the above functions could probably be optimized and made
clearer and neater.
*/
-static QCBORError TagMapper_Lookup(const QCBORTagListIn *pCallerConfiguredTagMap, uint64_t uTag, uint8_t *puTagBitIndex)
+static QCBORError
+TagMapper_Lookup(const QCBORTagListIn *pCallerConfiguredTagMap,
+ uint64_t uTag,
+ uint8_t *puTagBitIndex)
{
int nTagBitIndex = TagMapper_LookupBuiltIn(uTag);
if(nTagBitIndex >= 0) {
@@ -314,31 +347,38 @@ static QCBORError TagMapper_Lookup(const QCBORTagListIn *pCallerConfiguredTagMap
-/* ===========================================================================
+/*===========================================================================
QCBORStringAllocate -- STRING ALLOCATOR INVOCATION
The following four functions are pretty wrappers for invocation of
the string allocator supplied by the caller.
- ==============================================================================*/
+ ===========================================================================*/
-static inline void StringAllocator_Free(const QCORInternalAllocator *pMe, void *pMem)
+static inline void
+StringAllocator_Free(const QCORInternalAllocator *pMe, void *pMem)
{
(pMe->pfAllocator)(pMe->pAllocateCxt, pMem, 0);
}
-// StringAllocator_Reallocate called with pMem NULL is equal to StringAllocator_Allocate()
-static inline UsefulBuf StringAllocator_Reallocate(const QCORInternalAllocator *pMe, void *pMem, size_t uSize)
+// StringAllocator_Reallocate called with pMem NULL is
+// equal to StringAllocator_Allocate()
+static inline UsefulBuf
+StringAllocator_Reallocate(const QCORInternalAllocator *pMe,
+ void *pMem,
+ size_t uSize)
{
return (pMe->pfAllocator)(pMe->pAllocateCxt, pMem, uSize);
}
-static inline UsefulBuf StringAllocator_Allocate(const QCORInternalAllocator *pMe, size_t uSize)
+static inline UsefulBuf
+StringAllocator_Allocate(const QCORInternalAllocator *pMe, size_t uSize)
{
return (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, uSize);
}
-static inline void StringAllocator_Destruct(const QCORInternalAllocator *pMe)
+static inline void
+StringAllocator_Destruct(const QCORInternalAllocator *pMe)
{
if(pMe->pfAllocator) {
(pMe->pfAllocator)(pMe->pAllocateCxt, NULL, 0);
@@ -347,16 +387,22 @@ static inline void StringAllocator_Destruct(const QCORInternalAllocator *pMe)
+/*===========================================================================
+ QCBORDecode -- The main implementation of CBOR decoding
+ See qcbor.h for definition of the object used here: QCBORDecodeContext
+ ===========================================================================*/
/*
Public function, see header file
*/
-void QCBORDecode_Init(QCBORDecodeContext *me, UsefulBufC EncodedCBOR, QCBORDecodeMode nDecodeMode)
+void QCBORDecode_Init(QCBORDecodeContext *me,
+ UsefulBufC EncodedCBOR,
+ QCBORDecodeMode nDecodeMode)
{
memset(me, 0, sizeof(QCBORDecodeContext));
UsefulInputBuf_Init(&(me->InBuf), EncodedCBOR);
- // Don't bother with error check on decode mode. If a bad value is passed it will just act as
- // if the default normal mode of 0 was set.
+ // Don't bother with error check on decode mode. If a bad value is
+ // passed it will just act as if the default normal mode of 0 was set.
me->uDecodeMode = nDecodeMode;
DecodeNesting_Init(&(me->nesting));
}
@@ -379,63 +425,72 @@ void QCBORDecode_SetUpAllocator(QCBORDecodeContext *pMe,
/*
Public function, see header file
*/
-void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *me, const QCBORTagListIn *pTagList)
+void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *me,
+ const QCBORTagListIn *pTagList)
{
me->pCallerConfiguredTagList = pTagList;
}
/*
- This decodes the fundamental part of a CBOR data item, the type and number
+ This decodes the fundamental part of a CBOR data item, the type and
+ number
This is the Counterpart to InsertEncodedTypeAndNumber().
- This does the network->host byte order conversion. The conversion here
- also results in the conversion for floats in addition to that for
- lengths, tags and integer values.
+ This does the network->host byte order conversion. The conversion
+ here also results in the conversion for floats in addition to that
+ for lengths, tags and integer values.
This returns:
pnMajorType -- the major type for the item
- puNumber -- the "number" which is used a the value for integers, tags and floats and length for strings and arrays
- puAdditionalInfo -- Pass this along to know what kind of float or if length is indefinite
+ puArgument -- the "number" which is used a the value for integers,
+ tags and floats and length for strings and arrays
+
+ pnAdditionalInfo -- Pass this along to know what kind of float or
+ if length is indefinite
+
+ The int type is preferred to uint8_t for some variables as this
+ avoids integer promotions, can reduce code size and makes
+ static analyzers happier.
*/
inline static QCBORError DecodeTypeAndNumber(UsefulInputBuf *pUInBuf,
int *pnMajorType,
uint64_t *puArgument,
- uint8_t *puAdditionalInfo)
+ int *pnAdditionalInfo)
{
QCBORError nReturn;
// Get the initial byte that every CBOR data item has
- const uint8_t uInitialByte = UsefulInputBuf_GetByte(pUInBuf);
+ const int nInitialByte = (int)UsefulInputBuf_GetByte(pUInBuf);
// Break down the initial byte
- const uint8_t uTmpMajorType = uInitialByte >> 5;
- const uint8_t uAdditionalInfo = uInitialByte & 0x1f;
+ const int nTmpMajorType = nInitialByte >> 5;
+ const int nAdditionalInfo = nInitialByte & 0x1f;
// Where the number or argument accumulates
uint64_t uArgument;
- if(uAdditionalInfo >= LEN_IS_ONE_BYTE && uAdditionalInfo <= 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
+ 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[uAdditionalInfo - LEN_IS_ONE_BYTE]; i; i--) {
+ 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(uAdditionalInfo >= ADDINFO_RESERVED1 && uAdditionalInfo <= ADDINFO_RESERVED3) {
+ } else if(nAdditionalInfo >= ADDINFO_RESERVED1 && nAdditionalInfo <= ADDINFO_RESERVED3) {
// The reserved and thus-far unused additional info values
nReturn = QCBOR_ERR_UNSUPPORTED;
goto Done;
} else {
// Less than 24, additional info is argument or 31, an indefinite length
// No more bytes to get
- uArgument = uAdditionalInfo;
+ uArgument = (uint64_t)nAdditionalInfo;
}
if(UsefulInputBuf_GetError(pUInBuf)) {
@@ -445,30 +500,36 @@ inline static QCBORError DecodeTypeAndNumber(UsefulInputBuf *pUInBuf,
// All successful if we got here.
nReturn = QCBOR_SUCCESS;
- *pnMajorType = uTmpMajorType;
+ *pnMajorType = nTmpMajorType;
*puArgument = uArgument;
- *puAdditionalInfo = uAdditionalInfo;
+ *pnAdditionalInfo = nAdditionalInfo;
Done:
return nReturn;
}
+
/*
- CBOR doesn't explicitly specify two's compliment for integers but all CPUs
- use it these days and the test vectors in the RFC are so. All integers in the CBOR
- structure are positive and the major type indicates positive or negative.
- CBOR can express positive integers up to 2^x - 1 where x is the number of bits
- and negative integers down to 2^x. Note that negative numbers can be one
- more away from zero than positive.
- Stdint, as far as I can tell, uses two's compliment to represent
- negative integers.
+ CBOR doesn't explicitly specify two's compliment for integers but all
+ CPUs use it these days and the test vectors in the RFC are so. All
+ integers in the CBOR structure are positive and the major type
+ indicates positive or negative. CBOR can express positive integers
+ up to 2^x - 1 where x is the number of bits and negative integers
+ down to 2^x. Note that negative numbers can be one more away from
+ zero than positive. Stdint, as far as I can tell, uses two's
+ compliment to represent negative integers.
See http://www.unix.org/whitepapers/64bit.html for reasons int isn't
- used here in any way including in the interface
+ used carefully here, and in particular why it isn't used in the interface.
+ Also see
+ https://stackoverflow.com/questions/17489857/why-is-int-typically-32-bit-on-64-bit-compilers
+
+ Int is used for values that need less than 16-bits and would be subject
+ to integer promotion and complaining by static analyzers.
*/
-inline static QCBORError DecodeInteger(int nMajorType, uint64_t uNumber, QCBORItem *pDecodedItem)
+inline static QCBORError
+DecodeInteger(int nMajorType, uint64_t uNumber, QCBORItem *pDecodedItem)
{
- // Stack usage: int/ptr 1 -- 8
QCBORError nReturn = QCBOR_SUCCESS;
if(nMajorType == CBOR_MAJOR_TYPE_POSITIVE_INT) {
@@ -483,7 +544,11 @@ inline static QCBORError DecodeInteger(int nMajorType, uint64_t uNumber, QCBORIt
}
} else {
if(uNumber <= INT64_MAX) {
- pDecodedItem->val.int64 = -uNumber-1;
+ // CBOR's representation of negative numbers lines up with the
+ // two-compliment representation. A negative integer has one
+ // more in range than a positive integer. INT64_MIN is
+ // equal to (-INT64_MAX) - 1.
+ pDecodedItem->val.int64 = (-(int64_t)uNumber) - 1;
pDecodedItem->uDataType = QCBOR_TYPE_INT64;
} else {
@@ -528,18 +593,19 @@ inline static QCBORError DecodeInteger(int nMajorType, uint64_t uNumber, QCBORIt
/*
Decode true, false, floats, break...
*/
-
-inline static QCBORError DecodeSimple(uint8_t uAdditionalInfo, uint64_t uNumber, QCBORItem *pDecodedItem)
+inline static QCBORError
+DecodeSimple(int nAdditionalInfo, uint64_t uNumber, QCBORItem *pDecodedItem)
{
- // Stack usage: 0
QCBORError nReturn = QCBOR_SUCCESS;
- // uAdditionalInfo is 5 bits from the initial byte
- // compile time checks above make sure uAdditionalInfo values line up with uDataType values
- pDecodedItem->uDataType = uAdditionalInfo;
+ // uAdditionalInfo is 5 bits from the initial byte compile time checks
+ // above make sure uAdditionalInfo values line up with uDataType values.
+ // DecodeTypeAndNumber never returns a major type > 1f so cast is safe
+ pDecodedItem->uDataType = (uint8_t)nAdditionalInfo;
- switch(uAdditionalInfo) {
- // No check for ADDINFO_RESERVED1 - ADDINFO_RESERVED3 as it is caught before this is called.
+ switch(nAdditionalInfo) {
+ // No check for ADDINFO_RESERVED1 - ADDINFO_RESERVED3 as they are
+ // caught before this is called.
case HALF_PREC_FLOAT:
pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uNumber);
@@ -572,8 +638,12 @@ inline static QCBORError DecodeSimple(uint8_t uAdditionalInfo, uint64_t uNumber,
default: // 0-19
pDecodedItem->uDataType = QCBOR_TYPE_UKNOWN_SIMPLE;
- // DecodeTypeAndNumber will make uNumber equal to uAdditionalInfo when uAdditionalInfo is < 24
- // This cast is safe because the 2, 4 and 8 byte lengths of uNumber are in the double/float cases above
+ /*
+ DecodeTypeAndNumber will make uNumber equal to
+ uAdditionalInfo when uAdditionalInfo is < 24 This cast is
+ safe because the 2, 4 and 8 byte lengths of uNumber are in
+ the double/float cases above
+ */
pDecodedItem->val.uSimple = (uint8_t)uNumber;
break;
}
@@ -583,7 +653,6 @@ Done:
}
-
/*
Decode text and byte strings. Call the string allocator if asked to.
*/
@@ -593,10 +662,20 @@ inline static QCBORError DecodeBytes(const QCORInternalAllocator *pAllocator,
UsefulInputBuf *pUInBuf,
QCBORItem *pDecodedItem)
{
- // Stack usage: UsefulBuf 2, int/ptr 1 40
QCBORError nReturn = QCBOR_SUCCESS;
- const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(pUInBuf, uStrLen);
+ // CBOR lengths can be 64 bits, but size_t is not 64 bits on all CPUs.
+ // This check makes the casts to size_t below safe.
+
+ // 4 bytes less than the largest sizeof() so this can be tested by
+ // putting a SIZE_MAX length in the CBOR test input (no one will
+ // care the limit on strings is 4 bytes shorter).
+ if(uStrLen > SIZE_MAX-4) {
+ nReturn = QCBOR_ERR_STRING_TOO_LONG;
+ goto Done;
+ }
+
+ const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(pUInBuf, (size_t)uStrLen);
if(UsefulBuf_IsNULLC(Bytes)) {
// Failed to get the bytes for this string item
nReturn = QCBOR_ERR_HIT_END;
@@ -605,7 +684,7 @@ inline static QCBORError DecodeBytes(const QCORInternalAllocator *pAllocator,
if(pAllocator) {
// We are asked to use string allocator to make a copy
- UsefulBuf NewMem = StringAllocator_Allocate(pAllocator, uStrLen);
+ UsefulBuf NewMem = StringAllocator_Allocate(pAllocator, (size_t)uStrLen);
if(UsefulBuf_IsNULL(NewMem)) {
nReturn = QCBOR_ERR_STRING_ALLOCATE;
goto Done;
@@ -616,116 +695,23 @@ inline static QCBORError DecodeBytes(const QCORInternalAllocator *pAllocator,
// Normal case with no string allocator
pDecodedItem->val.string = Bytes;
}
- pDecodedItem->uDataType = (nMajorType == CBOR_MAJOR_TYPE_BYTE_STRING) ? QCBOR_TYPE_BYTE_STRING : QCBOR_TYPE_TEXT_STRING;
+ const bool bIsBstr = (nMajorType == CBOR_MAJOR_TYPE_BYTE_STRING);
+ // Cast because ternary operator causes promotion to integer
+ pDecodedItem->uDataType = (uint8_t)(bIsBstr ? QCBOR_TYPE_BYTE_STRING
+ : QCBOR_TYPE_TEXT_STRING);
Done:
return nReturn;
}
-/*
- Mostly just assign the right data type for the date string.
- */
-inline static QCBORError DecodeDateString(QCBORItem *pDecodedItem)
-{
- // Stack Use: UsefulBuf 1 16
- if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
- return QCBOR_ERR_BAD_OPT_TAG;
- }
- const UsefulBufC Temp = pDecodedItem->val.string;
- pDecodedItem->val.dateString = Temp;
- pDecodedItem->uDataType = QCBOR_TYPE_DATE_STRING;
- return QCBOR_SUCCESS;
-}
-/*
- Mostly just assign the right data type for the bignum.
- */
-inline static QCBORError DecodeBigNum(QCBORItem *pDecodedItem)
-{
- // Stack Use: UsefulBuf 1 -- 16
- if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
- return QCBOR_ERR_BAD_OPT_TAG;
- }
- const UsefulBufC Temp = pDecodedItem->val.string;
- pDecodedItem->val.bigNum = Temp;
- pDecodedItem->uDataType = pDecodedItem->uTagBits & QCBOR_TAGFLAG_POS_BIGNUM ? QCBOR_TYPE_POSBIGNUM : QCBOR_TYPE_NEGBIGNUM;
- return QCBOR_SUCCESS;
-}
-
-/*
- The epoch formatted date. Turns lots of different forms of encoding date into uniform one
- */
-static int DecodeDateEpoch(QCBORItem *pDecodedItem)
-{
- // Stack usage: 1
- QCBORError nReturn = QCBOR_SUCCESS;
- pDecodedItem->val.epochDate.fSecondsFraction = 0;
-
- switch (pDecodedItem->uDataType) {
-
- case QCBOR_TYPE_INT64:
- pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.int64;
- break;
-
- case QCBOR_TYPE_UINT64:
- if(pDecodedItem->val.uint64 > INT64_MAX) {
- nReturn = QCBOR_ERR_DATE_OVERFLOW;
- goto Done;
- }
- pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.uint64;
- break;
-
- case QCBOR_TYPE_DOUBLE:
- {
- // This comparison needs to be done as a float before
- // conversion to an int64_t to be able to detect doubles
- // that are too large to fit into an int64_t. A double
- // has 52 bits of preceision. An int64_t has 63. Casting
- // INT64_MAX to a double actually causes a round up which
- // is bad and wrong for the comparison because it will
- // allow conversion of doubles that can't fit into a
- // uint64_t. To remedy this INT64_MAX - 0x7ff is used as
- // the cutoff point as if that rounds up in conversion to
- // double it will still be less than INT64_MAX. 0x7ff is
- // picked because it has 11 bits set.
- //
- // INT64_MAX seconds is on the order of 10 billion years,
- // and the earth is less than 5 billion years old, so for
- // most uses this conversion error won't occur even though
- // doubles can go much larger.
- //
- // Without the 0x7ff there is a ~30 minute range of time
- // values 10 billion years in the past and in the future
- // where this this code would go wrong.
- const double d = pDecodedItem->val.dfnum;
- if(d > (double)(INT64_MAX - 0x7ff)) {
- nReturn = QCBOR_ERR_DATE_OVERFLOW;
- goto Done;
- }
- pDecodedItem->val.epochDate.nSeconds = (int64_t)d;
- pDecodedItem->val.epochDate.fSecondsFraction = d - (double)pDecodedItem->val.epochDate.nSeconds;
- }
- break;
-
- default:
- nReturn = QCBOR_ERR_BAD_OPT_TAG;
- goto Done;
- }
- pDecodedItem->uDataType = QCBOR_TYPE_DATE_EPOCH;
-
-Done:
- return nReturn;
-}
-
-
-
-
-// Make sure the constants align as this is assumed by the GetAnItem() implementation
+// Make sure the constants align as this is assumed by
+// the GetAnItem() implementation
#if QCBOR_TYPE_ARRAY != CBOR_MAJOR_TYPE_ARRAY
#error QCBOR_TYPE_ARRAY value not lined up with major type
#endif
@@ -734,55 +720,61 @@ Done:
#endif
/*
- This gets a single data item and decodes it including preceding optional tagging. This does not
- deal with arrays and maps and nesting except to decode the data item introducing them. Arrays and
- maps are handled at the next level up in GetNext().
+ This gets a single data item and decodes it including preceding
+ optional tagging. This does not deal with arrays and maps and nesting
+ except to decode the data item introducing them. Arrays and maps are
+ handled at the next level up in GetNext().
- Errors detected here include: an array that is too long to decode, hit end of buffer unexpectedly,
- a few forms of invalid encoded CBOR
+ Errors detected here include: an array that is too long to decode,
+ hit end of buffer unexpectedly, a few forms of invalid encoded CBOR
*/
static QCBORError GetNext_Item(UsefulInputBuf *pUInBuf,
QCBORItem *pDecodedItem,
const QCORInternalAllocator *pAllocator)
{
- // Stack usage: int/ptr 3 -- 24
QCBORError nReturn;
- // Get the major type and the number. Number could be length of more bytes or the value depending on the major type
- // nAdditionalInfo is an encoding of the length of the uNumber and is needed to decode floats and doubles
- int uMajorType;
+ /*
+ Get the major type and the number. Number could be length of more
+ bytes or the value depending on the major type nAdditionalInfo is
+ an encoding of the length of the uNumber and is needed to decode
+ floats and doubles
+ */
+ int nMajorType;
uint64_t uNumber;
- uint8_t uAdditionalInfo;
+ int nAdditionalInfo;
memset(pDecodedItem, 0, sizeof(QCBORItem));
- nReturn = DecodeTypeAndNumber(pUInBuf, &uMajorType, &uNumber, &uAdditionalInfo);
+ nReturn = DecodeTypeAndNumber(pUInBuf, &nMajorType, &uNumber, &nAdditionalInfo);
- // Error out here if we got into trouble on the type and number.
- // The code after this will not work if the type and number is not good.
+ // Error out here if we got into trouble on the type and number. The
+ // code after this will not work if the type and number is not good.
if(nReturn) {
goto Done;
}
- // At this point the major type and the value are valid. We've got the type and the number that
- // starts every CBOR data item.
- switch (uMajorType) {
+ // At this point the major type and the value are valid. We've got
+ // the type and the number that starts every CBOR data item.
+ switch (nMajorType) {
case CBOR_MAJOR_TYPE_POSITIVE_INT: // Major type 0
case CBOR_MAJOR_TYPE_NEGATIVE_INT: // Major type 1
- if(uAdditionalInfo == LEN_IS_INDEFINITE) {
+ if(nAdditionalInfo == LEN_IS_INDEFINITE) {
nReturn = QCBOR_ERR_BAD_INT;
} else {
- nReturn = DecodeInteger(uMajorType, uNumber, pDecodedItem);
+ nReturn = DecodeInteger(nMajorType, uNumber, pDecodedItem);
}
break;
case CBOR_MAJOR_TYPE_BYTE_STRING: // Major type 2
case CBOR_MAJOR_TYPE_TEXT_STRING: // Major type 3
- if(uAdditionalInfo == LEN_IS_INDEFINITE) {
- pDecodedItem->uDataType = (uMajorType == CBOR_MAJOR_TYPE_BYTE_STRING) ? QCBOR_TYPE_BYTE_STRING : QCBOR_TYPE_TEXT_STRING;
+ if(nAdditionalInfo == LEN_IS_INDEFINITE) {
+ const bool bIsBstr = (nMajorType == CBOR_MAJOR_TYPE_BYTE_STRING);
+ pDecodedItem->uDataType = (uint8_t)(bIsBstr ? QCBOR_TYPE_BYTE_STRING
+ : QCBOR_TYPE_TEXT_STRING);
pDecodedItem->val.string = (UsefulBufC){NULL, SIZE_MAX};
} else {
- nReturn = DecodeBytes(pAllocator, uMajorType, uNumber, pUInBuf, pDecodedItem);
+ nReturn = DecodeBytes(pAllocator, nMajorType, uNumber, pUInBuf, pDecodedItem);
}
break;
@@ -793,16 +785,19 @@ static QCBORError GetNext_Item(UsefulInputBuf *pUInBuf,
nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
goto Done;
}
- if(uAdditionalInfo == LEN_IS_INDEFINITE) {
+ if(nAdditionalInfo == LEN_IS_INDEFINITE) {
pDecodedItem->val.uCount = UINT16_MAX; // Indicate indefinite length
} else {
- pDecodedItem->val.uCount = (uint16_t)uNumber; // type conversion OK because of check above
+ // type conversion OK because of check above
+ pDecodedItem->val.uCount = (uint16_t)uNumber;
}
- pDecodedItem->uDataType = uMajorType; // C preproc #if above makes sure constants align
+ // C preproc #if above makes sure constants for major types align
+ // DecodeTypeAndNumber never returns a major type > 7 so cast is safe
+ pDecodedItem->uDataType = (uint8_t)nMajorType;
break;
case CBOR_MAJOR_TYPE_OPTIONAL: // Major type 6, optional prepended tags
- if(uAdditionalInfo == LEN_IS_INDEFINITE) {
+ if(nAdditionalInfo == LEN_IS_INDEFINITE) {
nReturn = QCBOR_ERR_BAD_INT;
} else {
pDecodedItem->val.uTagV = uNumber;
@@ -810,11 +805,13 @@ static QCBORError GetNext_Item(UsefulInputBuf *pUInBuf,
}
break;
- case CBOR_MAJOR_TYPE_SIMPLE: // Major type 7, float, double, true, false, null...
- nReturn = DecodeSimple(uAdditionalInfo, uNumber, pDecodedItem);
+ case CBOR_MAJOR_TYPE_SIMPLE:
+ // Major type 7, float, double, true, false, null...
+ nReturn = DecodeSimple(nAdditionalInfo, uNumber, pDecodedItem);
break;
- default: // Should never happen because DecodeTypeAndNumber() should never return > 7
+ default:
+ // Never happens because DecodeTypeAndNumber() should never return > 7
nReturn = QCBOR_ERR_UNSUPPORTED;
break;
}
@@ -827,12 +824,13 @@ Done:
/*
This layer deals with indefinite length strings. It pulls all the
- individual chunk items together into one QCBORItem using the
- string allocator.
+ individual chunk items together into one QCBORItem using the string
+ allocator.
Code Reviewers: THIS FUNCTION DOES A LITTLE POINTER MATH
*/
-static inline QCBORError GetNext_FullItem(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
+static inline QCBORError
+GetNext_FullItem(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
{
// Stack usage; int/ptr 2 UsefulBuf 2 QCBORItem -- 96
QCBORError nReturn;
@@ -853,7 +851,8 @@ static inline QCBORError GetNext_FullItem(QCBORDecodeContext *me, QCBORItem *pDe
// indefinite length string tests, to be sure all is OK if this is removed.
// Only do indefinite length processing on strings
- if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING && pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
+ if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING &&
+ pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
goto Done; // no need to do any work here on non-string types
}
@@ -893,7 +892,8 @@ static inline QCBORError GetNext_FullItem(QCBORDecodeContext *me, QCBORItem *pDe
// Match data type of chunk to type at beginning.
// Also catches error of other non-string types that don't belong.
// Also catches indefinite length strings inside indefinite length strings
- if(StringChunkItem.uDataType != uStringType || StringChunkItem.val.string.len == SIZE_MAX) {
+ if(StringChunkItem.uDataType != uStringType ||
+ StringChunkItem.val.string.len == SIZE_MAX) {
nReturn = QCBOR_ERR_INDEFINITE_STRING_CHUNK;
break;
}
@@ -926,10 +926,13 @@ Done:
/*
- Returns an error if there was something wrong with the optional item or it couldn't
- be handled.
+ Gets all optional tag data items preceding a data item that is not an
+ optional tag and records them as bits in the tag map.
*/
-static QCBORError GetNext_TaggedItem(QCBORDecodeContext *me, QCBORItem *pDecodedItem, QCBORTagListOut *pTags)
+static QCBORError
+GetNext_TaggedItem(QCBORDecodeContext *me,
+ QCBORItem *pDecodedItem,
+ QCBORTagListOut *pTags)
{
// Stack usage: int/ptr: 3 -- 24
QCBORError nReturn;
@@ -938,6 +941,7 @@ static QCBORError GetNext_TaggedItem(QCBORDecodeContext *me, QCBORItem *pDecoded
pTags->uNumUsed = 0;
}
+ // Loop fetching items until the item fetched is not a tag
for(;;) {
nReturn = GetNext_FullItem(me, pDecodedItem);
if(nReturn) {
@@ -979,41 +983,19 @@ static QCBORError GetNext_TaggedItem(QCBORDecodeContext *me, QCBORItem *pDecoded
}
}
- switch(pDecodedItem->uTagBits & TAG_MAPPER_FIRST_FOUR) {
- case 0:
- // No tags at all or none we know about. Nothing to do.
- // This is part of the pass-through path of this function
- // that will mostly be taken when decoding any item.
- break;
-
- case QCBOR_TAGFLAG_DATE_STRING:
- nReturn = DecodeDateString(pDecodedItem);
- break;
-
- case QCBOR_TAGFLAG_DATE_EPOCH:
- nReturn = DecodeDateEpoch(pDecodedItem);
- break;
-
- case QCBOR_TAGFLAG_POS_BIGNUM:
- case QCBOR_TAGFLAG_NEG_BIGNUM:
- nReturn = DecodeBigNum(pDecodedItem);
- break;
-
- default:
- // Encountering some mixed up CBOR like something that
- // is tagged as both a string and integer date.
- nReturn = QCBOR_ERR_BAD_OPT_TAG;
- }
-
Done:
return nReturn;
}
/*
- This layer takes care of map entries. It combines the label and data items into one QCBORItem.
+ This layer takes care of map entries. It combines the label and data
+ items into one QCBORItem.
*/
-static inline QCBORError GetNext_MapEntry(QCBORDecodeContext *me, QCBORItem *pDecodedItem, QCBORTagListOut *pTags)
+static inline QCBORError
+GetNext_MapEntry(QCBORDecodeContext *me,
+ QCBORItem *pDecodedItem,
+ QCBORTagListOut *pTags)
{
// Stack use: int/ptr 1, QCBORItem -- 56
QCBORError nReturn = GetNext_TaggedItem(me, pDecodedItem, pTags);
@@ -1031,7 +1013,8 @@ static inline QCBORError GetNext_MapEntry(QCBORDecodeContext *me, QCBORItem *pDe
if(DecodeNesting_TypeIsMap(&(me->nesting))) {
// If in a map and the right decoding mode, get the label
- // Get the next item which will be the real data; Item will be the label
+ // Save label in pDecodedItem and get the next which will
+ // be the real data
QCBORItem LabelItem = *pDecodedItem;
nReturn = GetNext_TaggedItem(me, pDecodedItem, pTags);
if(nReturn)
@@ -1044,7 +1027,7 @@ static inline QCBORError GetNext_MapEntry(QCBORDecodeContext *me, QCBORItem *pDe
pDecodedItem->label.string = LabelItem.val.string;
pDecodedItem->uLabelType = QCBOR_TYPE_TEXT_STRING;
} else if (QCBOR_DECODE_MODE_MAP_STRINGS_ONLY == me->uDecodeMode) {
- // It's not a string and we only want strings, probably for easy translation to JSON
+ // It's not a string and we only want strings
nReturn = QCBOR_ERR_MAP_LABEL_TYPE;
goto Done;
} else if(LabelItem.uDataType == QCBOR_TYPE_INT64) {
@@ -1081,7 +1064,9 @@ Done:
/*
Public function, see header qcbor.h file
*/
-QCBORError QCBORDecode_GetNextWithTags(QCBORDecodeContext *me, QCBORItem *pDecodedItem, QCBORTagListOut *pTags)
+QCBORError QCBORDecode_GetNextMapOrArray(QCBORDecodeContext *me,
+ QCBORItem *pDecodedItem,
+ QCBORTagListOut *pTags)
{
// Stack ptr/int: 2, QCBORItem : 64
@@ -1176,6 +1161,281 @@ Done:
}
+/*
+ Mostly just assign the right data type for the date string.
+ */
+inline static QCBORError DecodeDateString(QCBORItem *pDecodedItem)
+{
+ // Stack Use: UsefulBuf 1 16
+ if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
+ return QCBOR_ERR_BAD_OPT_TAG;
+ }
+
+ const UsefulBufC Temp = pDecodedItem->val.string;
+ pDecodedItem->val.dateString = Temp;
+ pDecodedItem->uDataType = QCBOR_TYPE_DATE_STRING;
+ return QCBOR_SUCCESS;
+}
+
+
+/*
+ Mostly just assign the right data type for the bignum.
+ */
+inline static QCBORError DecodeBigNum(QCBORItem *pDecodedItem)
+{
+ // Stack Use: UsefulBuf 1 -- 16
+ if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
+ return QCBOR_ERR_BAD_OPT_TAG;
+ }
+ const UsefulBufC Temp = pDecodedItem->val.string;
+ pDecodedItem->val.bigNum = Temp;
+ const bool bIsPosBigNum = (bool)(pDecodedItem->uTagBits & QCBOR_TAGFLAG_POS_BIGNUM);
+ pDecodedItem->uDataType = (uint8_t)(bIsPosBigNum ? QCBOR_TYPE_POSBIGNUM
+ : QCBOR_TYPE_NEGBIGNUM);
+ return QCBOR_SUCCESS;
+}
+
+
+/*
+ The epoch formatted date. Turns lots of different forms of encoding
+ date into uniform one
+ */
+static QCBORError DecodeDateEpoch(QCBORItem *pDecodedItem)
+{
+ // Stack usage: 1
+ QCBORError nReturn = QCBOR_SUCCESS;
+
+ pDecodedItem->val.epochDate.fSecondsFraction = 0;
+
+ switch (pDecodedItem->uDataType) {
+
+ case QCBOR_TYPE_INT64:
+ pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.int64;
+ break;
+
+ case QCBOR_TYPE_UINT64:
+ if(pDecodedItem->val.uint64 > INT64_MAX) {
+ nReturn = QCBOR_ERR_DATE_OVERFLOW;
+ goto Done;
+ }
+ pDecodedItem->val.epochDate.nSeconds = (int64_t)pDecodedItem->val.uint64;
+ break;
+
+ case QCBOR_TYPE_DOUBLE:
+ {
+ // This comparison needs to be done as a float before
+ // conversion to an int64_t to be able to detect doubles
+ // that are too large to fit into an int64_t. A double
+ // has 52 bits of preceision. An int64_t has 63. Casting
+ // INT64_MAX to a double actually causes a round up which
+ // is bad and wrong for the comparison because it will
+ // allow conversion of doubles that can't fit into a
+ // uint64_t. To remedy this INT64_MAX - 0x7ff is used as
+ // the cutoff point as if that rounds up in conversion to
+ // double it will still be less than INT64_MAX. 0x7ff is
+ // picked because it has 11 bits set.
+ //
+ // INT64_MAX seconds is on the order of 10 billion years,
+ // and the earth is less than 5 billion years old, so for
+ // most uses this conversion error won't occur even though
+ // doubles can go much larger.
+ //
+ // Without the 0x7ff there is a ~30 minute range of time
+ // values 10 billion years in the past and in the future
+ // where this this code would go wrong.
+ const double d = pDecodedItem->val.dfnum;
+ if(d > (double)(INT64_MAX - 0x7ff)) {
+ nReturn = QCBOR_ERR_DATE_OVERFLOW;
+ goto Done;
+ }
+ pDecodedItem->val.epochDate.nSeconds = (int64_t)d;
+ pDecodedItem->val.epochDate.fSecondsFraction = d - (double)pDecodedItem->val.epochDate.nSeconds;
+ }
+ break;
+
+ default:
+ nReturn = QCBOR_ERR_BAD_OPT_TAG;
+ goto Done;
+ }
+ pDecodedItem->uDataType = QCBOR_TYPE_DATE_EPOCH;
+
+Done:
+ return nReturn;
+}
+
+
+#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+/*
+ Decode decimal fractions and big floats.
+
+ When called pDecodedItem must be the array that is tagged as a big
+ float or decimal fraction, the array that has the two members, the
+ exponent and mantissa.
+
+ This will fetch and decode the exponent and mantissa and put the
+ result back into pDecodedItem.
+ */
+inline static QCBORError
+QCBORDecode_MantissaAndExponent(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
+{
+ QCBORError nReturn;
+
+ // --- Make sure it is an array; track nesting level of members ---
+ if(pDecodedItem->uDataType != QCBOR_TYPE_ARRAY) {
+ nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
+ goto Done;
+ }
+
+ // A check for pDecodedItem->val.uCount == 2 would work for
+ // definite length arrays, but not for indefnite. Instead remember
+ // the nesting level the two integers must be at, which is one
+ // deeper than that of the array.
+ const int nNestLevel = pDecodedItem->uNestingLevel + 1;
+
+ // --- Is it a decimal fraction or a bigfloat? ---
+ const bool bIsTaggedDecimalFraction = QCBORDecode_IsTagged(me, pDecodedItem, CBOR_TAG_DECIMAL_FRACTION);
+ pDecodedItem->uDataType = bIsTaggedDecimalFraction ? QCBOR_TYPE_DECIMAL_FRACTION : QCBOR_TYPE_BIGFLOAT;
+
+ // --- Get the exponent ---
+ QCBORItem exponentItem;
+ nReturn = QCBORDecode_GetNextMapOrArray(me, &exponentItem, NULL);
+ if(nReturn != QCBOR_SUCCESS) {
+ goto Done;
+ }
+ if(exponentItem.uNestingLevel != nNestLevel) {
+ // Array is empty or a map/array encountered when expecting an int
+ nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
+ goto Done;
+ }
+ if(exponentItem.uDataType == QCBOR_TYPE_INT64) {
+ // Data arriving as an unsigned int < INT64_MAX has been converted
+ // to QCBOR_TYPE_INT64 and thus handled here. This is also means
+ // that the only data arriving here of type QCBOR_TYPE_UINT64 data
+ // will be too large for this to handle and thus an error that will
+ // get handled in the next else.
+ pDecodedItem->val.expAndMantissa.nExponent = exponentItem.val.int64;
+ } else {
+ // Wrong type of exponent or a QCBOR_TYPE_UINT64 > INT64_MAX
+ nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
+ goto Done;
+ }
+
+ // --- Get the mantissa ---
+ QCBORItem mantissaItem;
+ nReturn = QCBORDecode_GetNextWithTags(me, &mantissaItem, NULL);
+ if(nReturn != QCBOR_SUCCESS) {
+ goto Done;
+ }
+ if(mantissaItem.uNestingLevel != nNestLevel) {
+ // Mantissa missing or map/array encountered when expecting number
+ nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
+ goto Done;
+ }
+ if(mantissaItem.uDataType == QCBOR_TYPE_INT64) {
+ // Data arriving as an unsigned int < INT64_MAX has been converted
+ // to QCBOR_TYPE_INT64 and thus handled here. This is also means
+ // that the only data arriving here of type QCBOR_TYPE_UINT64 data
+ // will be too large for this to handle and thus an error that
+ // will get handled in an else below.
+ pDecodedItem->val.expAndMantissa.Mantissa.nInt = mantissaItem.val.int64;
+ } else if(mantissaItem.uDataType == QCBOR_TYPE_POSBIGNUM || mantissaItem.uDataType == QCBOR_TYPE_NEGBIGNUM) {
+ // Got a good big num mantissa
+ pDecodedItem->val.expAndMantissa.Mantissa.bigNum = mantissaItem.val.bigNum;
+ // Depends on numbering of QCBOR_TYPE_XXX
+ pDecodedItem->uDataType = (uint8_t)(pDecodedItem->uDataType +
+ mantissaItem.uDataType - QCBOR_TYPE_POSBIGNUM +
+ 1);
+ } else {
+ // Wrong type of mantissa or a QCBOR_TYPE_UINT64 > INT64_MAX
+ nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
+ goto Done;
+ }
+
+ // --- Check that array only has the two numbers ---
+ if(mantissaItem.uNextNestLevel == nNestLevel) {
+ // Extra items in the decimal fraction / big num
+ nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
+ goto Done;
+ }
+
+Done:
+
+ return nReturn;
+}
+#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+
+
+/*
+ Public function, see header qcbor.h file
+ */
+QCBORError
+QCBORDecode_GetNextWithTags(QCBORDecodeContext *me,
+ QCBORItem *pDecodedItem,
+ QCBORTagListOut *pTags)
+{
+ QCBORError nReturn;
+
+ nReturn = QCBORDecode_GetNextMapOrArray(me, pDecodedItem, pTags);
+ if(nReturn != QCBOR_SUCCESS) {
+ goto Done;
+ }
+
+#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+#define TAG_MAPPER_FIRST_XXX TAG_MAPPER_FIRST_SIX
+#else
+#define TAG_MAPPER_FIRST_XXX TAG_MAPPER_FIRST_FOUR
+#endif
+
+ // Only pay attention to tags this code knows how to decode.
+ switch(pDecodedItem->uTagBits & TAG_MAPPER_FIRST_XXX) {
+ case 0:
+ // No tags at all or none we know about. Nothing to do.
+ // This is the pass-through path of this function
+ // that will mostly be taken when decoding any item.
+ break;
+
+ case QCBOR_TAGFLAG_DATE_STRING:
+ nReturn = DecodeDateString(pDecodedItem);
+ break;
+
+ case QCBOR_TAGFLAG_DATE_EPOCH:
+ nReturn = DecodeDateEpoch(pDecodedItem);
+ break;
+
+ case QCBOR_TAGFLAG_POS_BIGNUM:
+ case QCBOR_TAGFLAG_NEG_BIGNUM:
+ nReturn = DecodeBigNum(pDecodedItem);
+ break;
+
+#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+ case QCBOR_TAGFLAG_DECIMAL_FRACTION:
+ case QCBOR_TAGFLAG_BIGFLOAT:
+ // For aggregate tagged types, what goes into pTags is only collected
+ // from the surrounding data item, not the contents, so pTags is not
+ // passed on here.
+
+ nReturn = QCBORDecode_MantissaAndExponent(me, pDecodedItem);
+ break;
+#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+
+ default:
+ // Encountering some mixed-up CBOR like something that
+ // is tagged as both a string and integer date.
+ nReturn = QCBOR_ERR_BAD_OPT_TAG;
+ }
+
+Done:
+ if(nReturn != QCBOR_SUCCESS) {
+ pDecodedItem->uDataType = QCBOR_TYPE_NONE;
+ pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
+ }
+ return nReturn;
+}
+
+
+/*
+ Public function, see header qcbor.h file
+ */
QCBORError QCBORDecode_GetNext(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
{
return QCBORDecode_GetNextWithTags(me, pDecodedItem, NULL);
@@ -1187,7 +1447,13 @@ QCBORError QCBORDecode_GetNext(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
next one down. If a layer has no work to do for a particular item
it returns quickly.
- - QCBORDecode_GetNext -- The top layer manages the beginnings and
+ - QCBORDecode_GetNext, GetNextWithTags -- The top layer processes
+ tagged data items, turning them into the local C representation.
+ For the most simple it is just associating a QCBOR_TYPE with the data. For
+ the complex ones that an aggregate of data items, there is some further
+ decoding and a little bit of recursion.
+
+ - QCBORDecode_GetNextMapOrArray - This manages the beginnings and
ends of maps and arrays. It tracks descending into and ascending
out of maps/arrays. It processes all breaks that terminate
maps and arrays.
@@ -1197,19 +1463,21 @@ QCBORError QCBORDecode_GetNext(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
It only does work on maps. It combines the label and data
items into one labeled item.
- - GetNext_TaggedItem -- This handles the type 6 tagged items.
- It accumulates all the tags and combines them with the following
- non-tagged item. If the tagged item is something that is understood
- like a date, the decoding of that item is invoked.
+ - GetNext_TaggedItem -- This decodes type 6 tagging. It turns the
+ tags into bit flags associated with the data item. No actual decoding
+ of the contents of the tagged item is performed here.
- - GetNext_FullItem -- This assembles the sub items that make up
+ - GetNext_FullItem -- This assembles the sub-items that make up
an indefinte length string into one string item. It uses the
string allocater to create contiguous space for the item. It
processes all breaks that are part of indefinite length strings.
- - GetNext_Item -- This gets and decodes the most atomic
- item in CBOR, the thing with an initial byte containing
- the major type.
+ - GetNext_Item -- This decodes the atomic data items in CBOR. Each
+ atomic data item has a "major type", an integer "argument" and optionally
+ some content. For text and byte strings, the content is the bytes
+ that make up the string. These are the smallest data items that are
+ considered to be well-formed. The content may also be other data items in
+ the case of aggregate types. They are not handled in this layer.
Roughly this takes 300 bytes of stack for vars. Need to
evaluate this more carefully and correctly.
@@ -1220,7 +1488,9 @@ QCBORError QCBORDecode_GetNext(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
/*
Public function, see header qcbor.h file
*/
-int QCBORDecode_IsTagged(QCBORDecodeContext *me, const QCBORItem *pItem, uint64_t uTag)
+int QCBORDecode_IsTagged(QCBORDecodeContext *me,
+ const QCBORItem *pItem,
+ uint64_t uTag)
{
const QCBORTagListIn *pCallerConfiguredTagMap = me->pCallerConfiguredTagList;
@@ -1241,7 +1511,7 @@ int QCBORDecode_IsTagged(QCBORDecodeContext *me, const QCBORItem *pItem, uint64_
*/
QCBORError QCBORDecode_Finish(QCBORDecodeContext *me)
{
- int nReturn = QCBOR_SUCCESS;
+ QCBORError nReturn = QCBOR_SUCCESS;
// Error out if all the maps/arrays are not closed out
if(DecodeNesting_IsNested(&(me->nesting))) {
@@ -1268,21 +1538,28 @@ Done:
Decoder errors handled in this file
- - Hit end of input before it was expected while decoding type and number QCBOR_ERR_HIT_END
+ - Hit end of input before it was expected while decoding type and
+ number QCBOR_ERR_HIT_END
- negative integer that is too large for C QCBOR_ERR_INT_OVERFLOW
- - Hit end of input while decoding a text or byte string QCBOR_ERR_HIT_END
+ - Hit end of input while decoding a text or byte string
+ QCBOR_ERR_HIT_END
- - Encountered conflicting tags -- e.g., an item is tagged both a date string and an epoch date QCBOR_ERR_UNSUPPORTED
+ - Encountered conflicting tags -- e.g., an item is tagged both a date
+ string and an epoch date QCBOR_ERR_UNSUPPORTED
- - Encontered an array or mapp that has too many items QCBOR_ERR_ARRAY_TOO_LONG
+ - Encontered an array or mapp that has too many items
+ QCBOR_ERR_ARRAY_TOO_LONG
- - Encountered array/map nesting that is too deep QCBOR_ERR_ARRAY_NESTING_TOO_DEEP
+ - Encountered array/map nesting that is too deep
+ QCBOR_ERR_ARRAY_NESTING_TOO_DEEP
- - An epoch date > INT64_MAX or < INT64_MIN was encountered QCBOR_ERR_DATE_OVERFLOW
+ - An epoch date > INT64_MAX or < INT64_MIN was encountered
+ QCBOR_ERR_DATE_OVERFLOW
- - The type of a map label is not a string or int QCBOR_ERR_MAP_LABEL_TYPE
+ - The type of a map label is not a string or int
+ QCBOR_ERR_MAP_LABEL_TYPE
- Hit end with arrays or maps still open -- QCBOR_ERR_EXTRA_BYTES
@@ -1315,15 +1592,17 @@ Decoder errors handled in this file
The sizes packed in are uint32_t to be the same on all CPU types
and simplify the code.
- =========================================================================== */
+ ========================================================================== */
-static inline int MemPool_Unpack(const void *pMem, uint32_t *puPoolSize, uint32_t *puFreeOffset)
+static inline int
+MemPool_Unpack(const void *pMem, uint32_t *puPoolSize, uint32_t *puFreeOffset)
{
// Use of UsefulInputBuf is overkill, but it is convenient.
UsefulInputBuf UIB;
- // Just assume the size here. It was checked during SetUp so the assumption is safe.
+ // Just assume the size here. It was checked during SetUp so
+ // the assumption is safe.
UsefulInputBuf_Init(&UIB, (UsefulBufC){pMem, QCBOR_DECODE_MIN_MEM_POOL_SIZE});
*puPoolSize = UsefulInputBuf_GetUint32(&UIB);
*puFreeOffset = UsefulInputBuf_GetUint32(&UIB);
@@ -1331,7 +1610,8 @@ static inline int MemPool_Unpack(const void *pMem, uint32_t *puPoolSize, uint32_
}
-static inline int MemPool_Pack(UsefulBuf Pool, uint32_t uFreeOffset)
+static inline int
+MemPool_Pack(UsefulBuf Pool, uint32_t uFreeOffset)
{
// Use of UsefulOutBuf is overkill, but convenient. The
// length check performed here is useful.
@@ -1352,7 +1632,8 @@ static inline int MemPool_Pack(UsefulBuf Pool, uint32_t uFreeOffset)
Code Reviewers: THIS FUNCTION DOES POINTER MATH
*/
-static UsefulBuf MemPool_Function(void *pPool, void *pMem, size_t uNewSize)
+static UsefulBuf
+MemPool_Function(void *pPool, void *pMem, size_t uNewSize)
{
UsefulBuf ReturnValue = NULLUsefulBuf;
@@ -1410,7 +1691,7 @@ static UsefulBuf MemPool_Function(void *pPool, void *pMem, size_t uNewSize)
if(uNewSize <= uPoolSize - uFreeOffset) {
ReturnValue.len = uNewSize;
ReturnValue.ptr = (uint8_t *)pPool + uFreeOffset;
- uFreeOffset += uNewSize;
+ uFreeOffset += (uint32_t)uNewSize;
}
}
} else {
@@ -1436,7 +1717,9 @@ Done:
/*
Public function, see header qcbor.h file
*/
-QCBORError QCBORDecode_SetMemPool(QCBORDecodeContext *pMe, UsefulBuf Pool, bool bAllStrings)
+QCBORError QCBORDecode_SetMemPool(QCBORDecodeContext *pMe,
+ UsefulBuf Pool,
+ bool bAllStrings)
{
// The pool size and free mem offset are packed into the beginning
// of the pool memory. This compile time check make sure the
diff --git a/lib/ext/qcbor/src/qcbor_encode.c b/lib/ext/qcbor/src/qcbor_encode.c
index 28fb225ff5..ce14e41b91 100644
--- a/lib/ext/qcbor/src/qcbor_encode.c
+++ b/lib/ext/qcbor/src/qcbor_encode.c
@@ -1,6 +1,6 @@
/*==============================================================================
Copyright (c) 2016-2018, The Linux Foundation.
- Copyright (c) 2018-2019, Laurence Lundblade.
+ Copyright (c) 2018-2020, Laurence Lundblade.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -28,9 +28,9 @@ 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_encode.c
DESCRIPTION: This file contains the implementation of QCBOR.
@@ -40,53 +40,65 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
This section contains comments describing changes made to the module.
Notice that changes are listed in reverse chronological order.
- when who what, where, why
- -------- ---- ---------------------------------------------------
- 8/7/19 llundblade Prevent encoding simple type reserved values 24..31
- 7/25/19 janjongboom Add indefinite length encoding for maps and arrays
- 4/6/19 llundblade Wrapped bstr returned now includes the wrapping bstr
- 12/30/18 llundblade Small efficient clever encode of type & argument.
- 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.
- 09/28/18 llundblade Added bstr wrapping feature for COSE implementation.
- 02/05/18 llundbla Works on CPUs which require integer alignment.
- Requires new version of UsefulBuf.
- 07/05/17 llundbla Add bstr wrapping of maps/arrays for COSE
- 03/01/17 llundbla More data types
- 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.
-
- =====================================================================================*/
+ when who what, where, why
+ -------- ---- ---------------------------------------------------
+ 01/25/2020 llundblade Refine use of integer types to quiet static analysis.
+ 01/08/2020 llundblade Documentation corrections & improved code formatting.
+ 12/30/19 llundblade Add support for decimal fractions and bigfloats.
+ 8/7/19 llundblade Prevent encoding simple type reserved values 24..31
+ 7/25/19 janjongboom Add indefinite length encoding for maps and arrays
+ 4/6/19 llundblade Wrapped bstr returned now includes the wrapping bstr
+ 12/30/18 llundblade Small efficient clever encode of type & argument.
+ 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.
+ 09/28/18 llundblade Added bstr wrapping feature for COSE implementation.
+ 02/05/18 llundbla Works on CPUs which require integer alignment.
+ Requires new version of UsefulBuf.
+ 07/05/17 llundbla Add bstr wrapping of maps/arrays for COSE
+ 03/01/17 llundbla More data types
+ 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.
+
+ =============================================================================*/
#include "qcbor.h"
#include "ieee754.h"
-/*...... This is a ruler that is 80 characters long...........................*/
-
/*
- CBOR's two nesting types, arrays and maps, are tracked here. There is a
- limit of QCBOR_MAX_ARRAY_NESTING to the number of arrays and maps
+ Nesting -- This tracks the nesting of maps and arrays.
+
+ The following functions and data type QCBORTrackNesting implement the
+ nesting management for encoding.
+
+ CBOR's two nesting types, arrays and maps, are tracked here. There is
+ a limit of QCBOR_MAX_ARRAY_NESTING to the number of arrays and maps
that can be nested in one encoding so the encoding context stays
small enough to fit on the stack.
When an array / map is opened, pCurrentNesting points to the element
- in pArrays that records the type, start position and accumluates a
+ in pArrays that records the type, start position and accumulates a
count of the number of items added. When closed the start position is
used to go back and fill in the type and number of items in the array
/ map.
- Encoded output be just items like ints and strings that are
- not part of any array / map. That is, the first thing encoded
- does not have to be an array or a map.
+ Encoded output can be just items like ints and strings that are not
+ part of any array / map. That is, the first thing encoded does not
+ have to be an array or a map.
+
+ QCBOR has a special feature to allow constructing bstr-wrapped CBOR
+ directly into the output buffer, so an extra buffer for it is not
+ needed. This is implemented as nesting with type
+ CBOR_MAJOR_TYPE_BYTE_STRING and uses this code. Bstr-wrapped CBOR is
+ used by COSE for data that is to be hashed.
*/
inline static void Nesting_Init(QCBORTrackNesting *pNesting)
{
- // assumes pNesting has been zeroed
+ // Assumes pNesting has been zeroed
pNesting->pCurrentNesting = &pNesting->pArrays[0];
// Implied CBOR array at the top nesting level. This is never returned,
// but makes the item count work correctly.
@@ -100,7 +112,7 @@ inline static QCBORError Nesting_Increase(QCBORTrackNesting *pNesting,
QCBORError nReturn = QCBOR_SUCCESS;
if(pNesting->pCurrentNesting == &pNesting->pArrays[QCBOR_MAX_ARRAY_NESTING]) {
- // trying to open one too many
+ // Trying to open one too many
nReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
} else {
pNesting->pCurrentNesting++;
@@ -136,9 +148,13 @@ inline static uint16_t Nesting_GetCount(QCBORTrackNesting *pNesting)
// items by two for maps to get the number of pairs. This implementation
// takes advantage of the map major type being one larger the array major
// type, hence uDivisor is either 1 or 2.
- const uint16_t uDivisor = pNesting->pCurrentNesting->uMajorType - CBOR_MAJOR_TYPE_ARRAY+1;
- return pNesting->pCurrentNesting->uCount / uDivisor;
+ if(pNesting->pCurrentNesting->uMajorType == CBOR_MAJOR_TYPE_MAP) {
+ // Cast back to uint16_t after integer promotion for bit shift
+ return (uint16_t)(pNesting->pCurrentNesting->uCount >> 1);
+ } else {
+ return pNesting->pCurrentNesting->uCount;
+ }
}
inline static uint32_t Nesting_GetStartPos(QCBORTrackNesting *pNesting)
@@ -151,17 +167,35 @@ inline static uint8_t Nesting_GetMajorType(QCBORTrackNesting *pNesting)
return pNesting->pCurrentNesting->uMajorType;
}
-inline static int Nesting_IsInNest(QCBORTrackNesting *pNesting)
+inline static bool Nesting_IsInNest(QCBORTrackNesting *pNesting)
{
- return pNesting->pCurrentNesting == &pNesting->pArrays[0] ? 0 : 1;
+ return pNesting->pCurrentNesting == &pNesting->pArrays[0] ? false : true;
}
/*
+ Encoding of the major CBOR types is by these functions:
+
+ CBOR Major Type Public Function
+ 0 QCBOREncode_AddUInt64()
+ 0, 1 QCBOREncode_AddUInt64(), QCBOREncode_AddInt64()
+ 2, 3 QCBOREncode_AddBuffer(), Also QCBOREncode_OpenMapOrArray(),
+ QCBOREncode_CloseMapOrArray()
+ 4, 5 QCBOREncode_OpenMapOrArray(), QCBOREncode_CloseMapOrArray(),
+ QCBOREncode_OpenMapOrArrayIndefiniteLength(),
+ QCBOREncode_CloseMapOrArrayIndefiniteLength()
+ 6 QCBOREncode_AddTag()
+ 7 QCBOREncode_AddDouble(), QCBOREncode_AddType7()
+
+ Additionally, encoding of decimal fractions and bigfloats is by
+ QCBOREncode_AddExponentAndMantissa()
+*/
+
+/*
Error tracking plan -- Errors are tracked internally and not returned
- until Finish is called. The CBOR errors are in me->uError.
+ until QCBOREncode_Finish is called. The CBOR errors are in me->uError.
UsefulOutBuf also tracks whether the buffer is full or not in its
context. Once either of these errors is set they are never
cleared. Only QCBOREncode_Init() resets them. Or said another way, they must
@@ -190,27 +224,24 @@ inline static int Nesting_IsInNest(QCBORTrackNesting *pNesting)
structures like array/map nesting resulting in some stack memory
savings.
- Errors returned here fall into three categories:
+ The 8 errors returned here fall into three categories:
Sizes
- QCBOR_ERR_BUFFER_TOO_LARGE -- Encoded output exceeded UINT32_MAX
- QCBOR_ERR_BUFFER_TOO_SMALL -- output buffer too small
-
- QCBOR_ERR_ARRAY_NESTING_TOO_DEEP -- Array/map nesting > QCBOR_MAX_ARRAY_NESTING1
- QCBOR_ERR_ARRAY_TOO_LONG -- Too many things added to an array/map
+ QCBOR_ERR_BUFFER_TOO_LARGE -- Encoded output exceeded UINT32_MAX
+ QCBOR_ERR_BUFFER_TOO_SMALL -- Output buffer too small
+ QCBOR_ERR_ARRAY_NESTING_TOO_DEEP -- Nesting > QCBOR_MAX_ARRAY_NESTING1
+ QCBOR_ERR_ARRAY_TOO_LONG -- Too many things added to an array/map
Nesting constructed incorrectly
- QCBOR_ERR_TOO_MANY_CLOSES -- more close calls than opens
- QCBOR_ERR_CLOSE_MISMATCH -- Type of close does not match open
+ QCBOR_ERR_TOO_MANY_CLOSES -- More close calls than opens
+ QCBOR_ERR_CLOSE_MISMATCH -- Type of close does not match open
QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN -- Finish called without enough closes
Would generate not-well-formed CBOR
- QCBOR_ERR_UNSUPPORTED -- Simple type between 24 and 31
+ QCBOR_ERR_UNSUPPORTED -- Simple type between 24 and 31
*/
-
-
/*
Public function for initialization. See header qcbor.h
*/
@@ -222,9 +253,18 @@ void QCBOREncode_Init(QCBOREncodeContext *me, UsefulBuf Storage)
}
+/**
+ @brief Encode a data item, the most atomic part of CBOR
+ @param[in,out] me Encoding context including output buffer
+ @param[in] uMajorType One of CBOR_MAJOR_TYPE_XX
+ @param[in] nMinLen Include zero bytes up to this length. If 0 include
+ no zero bytes. Non-zero to encode floats and doubles.
+ @param[in] uNumber The number to encode, the argument.
+ @param[in] uPos The position in the output buffer (which is inside
+ the encoding context) to insert the result. This is
+ usually at the end, an append.
-/*
All CBOR data items have a type and an "argument". The argument is
either the value of the item for integer types, the length of the
content for string, byte, array and map types, a tag for major type
@@ -263,17 +303,15 @@ void QCBOREncode_Init(QCBOREncodeContext *me, UsefulBuf Storage)
This function is also used to insert floats and doubles. Before this
function is called the float or double must be copied into a
uint64_t. That is how they are passed in. They are then converted to
- network byte order correctly. The uMinLen param makes sure that even
-
- if all the digits of a half, float or double are 0 it is still
+ network byte order correctly. The uMinLen parameter makes sure that
+ even if all the digits of a half, float or double are 0 it is still
correctly encoded in 2, 4 or 8 bytes.
*/
-
static void InsertEncodedTypeAndNumber(QCBOREncodeContext *me,
- uint8_t uMajorType,
- int nMinLen,
- uint64_t uNumber,
- size_t uPos)
+ uint8_t uMajorType,
+ int nMinLen,
+ uint64_t uNumber,
+ size_t uPos)
{
/*
This code does endian conversion without hton or knowing the
@@ -296,64 +334,97 @@ static void InsertEncodedTypeAndNumber(QCBOREncodeContext *me,
Code Reviewers: THIS FUNCTION DOES POINTER MATH
*/
- // Holds up to 9 bytes of type and argument
- // plus one extra so pointer always points to
- // valid bytes.
+ /*
+ The type int is used here for several variables because of the way
+ integer promotion works in C for integer variables that are
+ uint8_t or uint16_t. The basic rule is that they will always be
+ promoted to int if they will fit. All of these integer variables
+ need only hold values less than 255 or are promoted from uint8_t,
+ so they will always fit into an int. Note that promotion is only
+ to unsigned int if the value won't fit into an int even if the
+ promotion is for an unsigned like uint8_t.
+
+ By declaring them int, there are few implicit conversions and fewer
+ casts needed. Code size is reduced a little. It also makes static
+ analyzers happier.
+
+ Note also that declaring them uint8_t won't stop integer wrap
+ around if the code is wrong. It won't make the code more correct.
+
+ https://stackoverflow.com/questions/46073295/implicit-type-promotion-rules
+ https://stackoverflow.com/questions/589575/what-does-the-c-standard-state-the-size-of-int-long-type-to-be
+ */
+
+ // Holds up to 9 bytes of type and argument plus one extra so pointer
+ // always points to valid bytes.
uint8_t bytes[sizeof(uint64_t)+2];
// Point to the last bytes and work backwards
uint8_t *pByte = &bytes[sizeof(bytes)-1];
// This is the 5 bits in the initial byte that is not the major type
- uint8_t uAdditionalInfo;
+ int nAdditionalInfo;
if (uMajorType == CBOR_MAJOR_NONE_TYPE_ARRAY_INDEFINITE_LEN) {
uMajorType = CBOR_MAJOR_TYPE_ARRAY;
- uAdditionalInfo = LEN_IS_INDEFINITE;
+ nAdditionalInfo = LEN_IS_INDEFINITE;
} else if (uMajorType == CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN) {
uMajorType = CBOR_MAJOR_TYPE_MAP;
- uAdditionalInfo = LEN_IS_INDEFINITE;
+ nAdditionalInfo = LEN_IS_INDEFINITE;
} else if (uNumber < CBOR_TWENTY_FOUR && nMinLen == 0) {
// Simple case where argument is < 24
- uAdditionalInfo = uNumber;
+ nAdditionalInfo = (int)uNumber;
} else if (uMajorType == CBOR_MAJOR_TYPE_SIMPLE && uNumber == CBOR_SIMPLE_BREAK) {
// Break statement can be encoded in single byte too (0xff)
- uAdditionalInfo = uNumber;
+ nAdditionalInfo = (int)uNumber;
} else {
/*
- Encode argument in 1,2,4 or 8 bytes. Outer loop
- runs once for 1 byte and 4 times for 8 bytes.
- Inner loop runs 1, 2 or 4 times depending on
- outer loop counter. This works backwards taking
- 8 bits off the argument being encoded at a time
- until all bits from uNumber have been encoded
- and the minimum encoding size is reached.
- Minimum encoding size is for floating point
- numbers with zero bytes.
+ Encode argument in 1,2,4 or 8 bytes. Outer loop runs once for 1
+ byte and 4 times for 8 bytes. Inner loop runs 1, 2 or 4 times
+ depending on outer loop counter. This works backwards taking 8
+ bits off the argument being encoded at a time until all bits
+ from uNumber have been encoded and the minimum encoding size is
+ reached. Minimum encoding size is for floating-point numbers
+ with zero bytes.
*/
static const uint8_t aIterate[] = {1,1,2,4};
- uint8_t i;
+ int i;
for(i = 0; uNumber || nMinLen > 0; i++) {
- const uint8_t uIterations = aIterate[i];
- for(int j = 0; j < uIterations; j++) {
- *--pByte = uNumber & 0xff;
+ const int nIterations = aIterate[i];
+ for(int j = 0; j < nIterations; j++) {
+ *--pByte = (uint8_t)(uNumber & 0xff);
uNumber = uNumber >> 8;
}
- nMinLen -= uIterations;
+ nMinLen -= nIterations;
}
- // Additional info is the encoding of the
- // number of additional bytes to encode
- // argument.
- uAdditionalInfo = LEN_IS_ONE_BYTE-1 + i;
+ // Additional info is the encoding of the number of additional
+ // bytes to encode argument.
+ nAdditionalInfo = LEN_IS_ONE_BYTE-1 + i;
}
- *--pByte = (uMajorType << 5) + uAdditionalInfo;
- UsefulOutBuf_InsertData(&(me->OutBuf), pByte, &bytes[sizeof(bytes)-1] - pByte, uPos);
+ /*
+ Expression integer-promotes to type int. The code above in
+ function gaurantees that uAdditionalInfo will never be larger than
+ 0x1f. The caller may pass in a too-large uMajor type. The
+ conversion to unint8_t will cause an integer wrap around and
+ incorrect CBOR will be generated, but no security issue will
+ incur.
+ */
+ *--pByte = (uint8_t)((uMajorType << 5) + nAdditionalInfo);
+
+ /*
+ Will not go negative because the loops run for at most 8
+ decrements of pByte, only one other decrement is made and the
+ array is sized for this.
+ */
+ const size_t uHeadLen = (size_t)(&bytes[sizeof(bytes)-1] - pByte);
+
+ UsefulOutBuf_InsertData(&(me->OutBuf), pByte, uHeadLen, uPos);
}
/*
Append the type and number info to the end of the buffer.
- See InsertEncodedTypeAndNumber() function above for details
+ See InsertEncodedTypeAndNumber() function above for details.
*/
inline static void AppendEncodedTypeAndNumber(QCBOREncodeContext *me,
uint8_t uMajorType,
@@ -371,7 +442,7 @@ inline static void AppendEncodedTypeAndNumber(QCBOREncodeContext *me,
/*
- Public functions for closing arrays and maps. See header qcbor.h
+ Public functions for closing arrays and maps. See qcbor.h
*/
void QCBOREncode_AddUInt64(QCBOREncodeContext *me, uint64_t uValue)
{
@@ -383,7 +454,7 @@ void QCBOREncode_AddUInt64(QCBOREncodeContext *me, uint64_t uValue)
/*
- Public functions for closing arrays and maps. See header qcbor.h
+ Public functions for closing arrays and maps. See qcbor.h
*/
void QCBOREncode_AddInt64(QCBOREncodeContext *me, int64_t nNum)
{
@@ -410,7 +481,7 @@ void QCBOREncode_AddInt64(QCBOREncodeContext *me, int64_t nNum)
Semi-private function. It is exposed to user of the interface, but
they will usually call one of the inline wrappers rather than this.
- See header qcbor.h
+ See qcbor.h
Does the work of adding actual strings bytes to the CBOR output (as
opposed to numbers and opening / closing aggregate types).
@@ -450,7 +521,7 @@ void QCBOREncode_AddBuffer(QCBOREncodeContext *me, uint8_t uMajorType, UsefulBuf
/*
- Public functions for closing arrays and maps. See header qcbor.h
+ Public functions for closing arrays and maps. See qcbor.h
*/
void QCBOREncode_AddTag(QCBOREncodeContext *me, uint64_t uTag)
{
@@ -470,13 +541,14 @@ void QCBOREncode_AddType7(QCBOREncodeContext *me, size_t uSize, uint64_t uNum)
if(uNum >= CBOR_SIMPLEV_RESERVED_START && uNum <= CBOR_SIMPLEV_RESERVED_END) {
me->uError = QCBOR_ERR_UNSUPPORTED;
} else {
- // This function call takes care of endian swapping for the float / double
+ // This call takes care of endian swapping for the float / double
InsertEncodedTypeAndNumber(me,
// The major type for floats and doubles
CBOR_MAJOR_TYPE_SIMPLE,
- // size makes sure floats with zeros encode correctly
+ // Must pass size to ensure floats
+ // with zero bytes encode correctly
(int)uSize,
- // Bytes of the floating point number as a uint
+ // The floating-point number as a uint
uNum,
// end position because this is append
UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
@@ -488,7 +560,7 @@ void QCBOREncode_AddType7(QCBOREncodeContext *me, size_t uSize, uint64_t uNum)
/*
- Public functions for closing arrays and maps. See header qcbor.h
+ Public functions for closing arrays and maps. See qcbor.h
*/
void QCBOREncode_AddDouble(QCBOREncodeContext *me, double dNum)
{
@@ -498,6 +570,44 @@ void QCBOREncode_AddDouble(QCBOREncodeContext *me, double dNum)
}
+#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+/*
+ Semi-public function. It is exposed to the user of the interface, but
+ one of the inline wrappers will usually be called rather than this.
+
+ See qcbor.h
+ */
+void QCBOREncode_AddExponentAndMantissa(QCBOREncodeContext *pMe,
+ uint64_t uTag,
+ UsefulBufC BigNumMantissa,
+ bool bBigNumIsNegative,
+ int64_t nMantissa,
+ int64_t nExponent)
+{
+ /*
+ This is for encoding either a big float or a decimal fraction,
+ both of which are an array of two items, an exponent and a
+ mantissa. The difference between the two is that the exponent is
+ base-2 for big floats and base-10 for decimal fractions, but that
+ has no effect on the code here.
+ */
+ QCBOREncode_AddTag(pMe, uTag);
+ QCBOREncode_OpenArray(pMe);
+ QCBOREncode_AddInt64(pMe, nExponent);
+ if(!UsefulBuf_IsNULLC(BigNumMantissa)) {
+ if(bBigNumIsNegative) {
+ QCBOREncode_AddNegativeBignum(pMe, BigNumMantissa);
+ } else {
+ QCBOREncode_AddPositiveBignum(pMe, BigNumMantissa);
+ }
+ } else {
+ QCBOREncode_AddInt64(pMe, nMantissa);
+ }
+ QCBOREncode_CloseArray(pMe);
+}
+#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+
+
/*
Semi-public function. It is exposed to user of the interface,
but they will usually call one of the inline wrappers rather than this.
@@ -509,35 +619,41 @@ void QCBOREncode_OpenMapOrArray(QCBOREncodeContext *me, uint8_t uMajorType)
// Add one item to the nesting level we are in for the new map or array
me->uError = Nesting_Increment(&(me->nesting));
if(me->uError == QCBOR_SUCCESS) {
- // The offset where the length of an array or map will get written
- // is stored in a uint32_t, not a size_t to keep stack usage smaller. This
- // checks to be sure there is no wrap around when recording the offset.
- // Note that on 64-bit machines CBOR larger than 4GB can be encoded as long as no
- // array / map offsets occur past the 4GB mark, but the public interface
- // says that the maximum is 4GB to keep the discussion simpler.
+ /*
+ The offset where the length of an array or map will get written
+ is stored in a uint32_t, not a size_t to keep stack usage
+ smaller. This checks to be sure there is no wrap around when
+ recording the offset. Note that on 64-bit machines CBOR larger
+ than 4GB can be encoded as long as no array / map offsets occur
+ past the 4GB mark, but the public interface says that the
+ maximum is 4GB to keep the discussion simpler.
+ */
size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf));
- // QCBOR_MAX_ARRAY_OFFSET is slightly less than UINT32_MAX so this
- // code can run on a 32-bit machine and tests can pass on a 32-bit
- // machine. If it was exactly UINT32_MAX, then this code would
- // not compile or run on a 32-bit machine and an #ifdef or some
- // machine size detection would be needed reducing portability.
+ /*
+ QCBOR_MAX_ARRAY_OFFSET is slightly less than UINT32_MAX so this
+ code can run on a 32-bit machine and tests can pass on a 32-bit
+ machine. If it was exactly UINT32_MAX, then this code would not
+ compile or run on a 32-bit machine and an #ifdef or some
+ machine size detection would be needed reducing portability.
+ */
if(uEndPosition >= QCBOR_MAX_ARRAY_OFFSET) {
me->uError = QCBOR_ERR_BUFFER_TOO_LARGE;
} else {
- // Increase nesting level because this is a map or array.
- // Cast from size_t to uin32_t is safe because of check above
+ // Increase nesting level because this is a map or array. Cast
+ // from size_t to uin32_t is safe because of check above
me->uError = Nesting_Increase(&(me->nesting), uMajorType, (uint32_t)uEndPosition);
}
}
}
+
/*
Semi-public function. It is exposed to user of the interface,
but they will usually call one of the inline wrappers rather than this.
- See header qcbor.h
+ See qcbor.h
*/
void QCBOREncode_OpenMapOrArrayIndefiniteLength(QCBOREncodeContext *me, uint8_t uMajorType)
{
@@ -547,8 +663,9 @@ void QCBOREncode_OpenMapOrArrayIndefiniteLength(QCBOREncodeContext *me, uint8_t
QCBOREncode_OpenMapOrArray(me, uMajorType);
}
+
/*
- Public functions for closing arrays and maps. See header qcbor.h
+ Public functions for closing arrays and maps. See qcbor.h
*/
void QCBOREncode_CloseMapOrArray(QCBOREncodeContext *me,
uint8_t uMajorType,
@@ -560,36 +677,46 @@ void QCBOREncode_CloseMapOrArray(QCBOREncodeContext *me,
} else if(Nesting_GetMajorType(&(me->nesting)) != uMajorType) {
me->uError = QCBOR_ERR_CLOSE_MISMATCH;
} else {
- // When the array, map or bstr wrap was started, nothing was done
- // except note the position of the start of it. This code goes back
- // and inserts the actual CBOR array, map or bstr and its length.
- // That means all the data that is in the array, map or wrapped
- // needs to be slid to the right. This is done by UsefulOutBuf's
- // insert function that is called from inside
- // InsertEncodedTypeAndNumber()
- const size_t uInsertPosition = Nesting_GetStartPos(&(me->nesting));
- const size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf));
- // This can't go negative because the UsefulOutBuf always only grows
- // and never shrinks. UsefulOutBut itself also has defenses such that
- // it won't write were it should not even if given hostile input lengths
+ /*
+ When the array, map or bstr wrap was started, nothing was
+ gone except note the position of the start of it. This code
+ goes back and inserts the actual CBOR array, map or bstr and
+ its length. That means all the data that is in the array,
+ map or wrapped needs to be slid to the right. This is done
+ by UsefulOutBuf's insert function that is called from inside
+ InsertEncodedTypeAndNumber()
+ */
+ const size_t uInsertPosition = Nesting_GetStartPos(&(me->nesting));
+ const size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf));
+ /*
+ This can't go negative because the UsefulOutBuf always only
+ grows and never shrinks. UsefulOutBut itself also has
+ defenses such that it won't write were it should not even if
+ given hostile input lengths
+ */
const size_t uLenOfEncodedMapOrArray = uEndPosition - uInsertPosition;
- // Length is number of bytes for a bstr and number of items a for map & array
- const size_t uLength = uMajorType == CBOR_MAJOR_TYPE_BYTE_STRING ?
- uLenOfEncodedMapOrArray : Nesting_GetCount(&(me->nesting));
+ // Number of bytes for a bstr or number of items a for map & array
+ const bool bIsBstr = uMajorType == CBOR_MAJOR_TYPE_BYTE_STRING;
+ const size_t uLength = bIsBstr ? uLenOfEncodedMapOrArray
+ : Nesting_GetCount(&(me->nesting));
// Actually insert
InsertEncodedTypeAndNumber(me,
- uMajorType, // major type bstr, array or map
- 0, // no minimum length for encoding
- uLength, // either len of bstr or num map / array items
+ uMajorType, // bstr, array or map
+ 0, // no minimum length
+ uLength, // either len of bstr or
+ // num map / array items
uInsertPosition); // position in out buffer
- // Return pointer and length to the enclosed encoded CBOR. The intended
- // use is for it to be hashed (e.g., SHA-256) in a COSE implementation.
- // This must be used right away, as the pointer and length go invalid
- // on any subsequent calls to this function because there might be calls to
- // InsertEncodedTypeAndNumber() that slides data to the right.
+ /*
+ Return pointer and length to the enclosed encoded CBOR. The
+ intended use is for it to be hashed (e.g., SHA-256) in a
+ COSE implementation. This must be used right away, as the
+ pointer and length go invalid on any subsequent calls to
+ this function because there might be calls to
+ InsertEncodedTypeAndNumber() that slides data to the right.
+ */
if(pWrappedCBOR) {
const UsefulBufC PartialResult = UsefulOutBuf_OutUBuf(&(me->OutBuf));
*pWrappedCBOR = UsefulBuf_Tail(PartialResult, uInsertPosition);
@@ -599,10 +726,13 @@ void QCBOREncode_CloseMapOrArray(QCBOREncodeContext *me,
}
}
+
/*
- Public functions for closing arrays and maps. See header qcbor.h
+ Public functions for closing arrays and maps. See qcbor.h
*/
-void QCBOREncode_CloseMapOrArrayIndefiniteLength(QCBOREncodeContext *me, uint8_t uMajorType, UsefulBufC *pWrappedCBOR)
+void QCBOREncode_CloseMapOrArrayIndefiniteLength(QCBOREncodeContext *me,
+ uint8_t uMajorType,
+ UsefulBufC *pWrappedCBOR)
{
if(me->uError == QCBOR_SUCCESS) {
if(!Nesting_IsInNest(&(me->nesting))) {
@@ -611,13 +741,20 @@ void QCBOREncode_CloseMapOrArrayIndefiniteLength(QCBOREncodeContext *me, uint8_t
me->uError = QCBOR_ERR_CLOSE_MISMATCH;
} else {
// insert the break marker (0xff for both arrays and maps)
- InsertEncodedTypeAndNumber(me, CBOR_MAJOR_TYPE_SIMPLE, 0, CBOR_SIMPLE_BREAK, UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
+ InsertEncodedTypeAndNumber(me,
+ CBOR_MAJOR_TYPE_SIMPLE,
+ 0,
+ CBOR_SIMPLE_BREAK,
+ UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
- // Return pointer and length to the enclosed encoded CBOR. The intended
- // use is for it to be hashed (e.g., SHA-256) in a COSE implementation.
- // This must be used right away, as the pointer and length go invalid
- // on any subsequent calls to this function because there might be calls to
- // InsertEncodedTypeAndNumber() that slides data to the right.
+ /*
+ Return pointer and length to the enclosed encoded CBOR. The
+ intended use is for it to be hashed (e.g., SHA-256) in a
+ COSE implementation. This must be used right away, as the
+ pointer and length go invalid on any subsequent calls to
+ this function because there might be calls to
+ InsertEncodedTypeAndNumber() that slides data to the right.
+ */
if(pWrappedCBOR) {
const UsefulBufC PartialResult = UsefulOutBuf_OutUBuf(&(me->OutBuf));
*pWrappedCBOR = UsefulBuf_Tail(PartialResult, UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
@@ -631,7 +768,7 @@ void QCBOREncode_CloseMapOrArrayIndefiniteLength(QCBOREncodeContext *me, uint8_t
/*
- Public functions to finish and get the encoded result. See header qcbor.h
+ Public functions to finish and get the encoded result. See qcbor.h
*/
QCBORError QCBOREncode_Finish(QCBOREncodeContext *me, UsefulBufC *pEncodedCBOR)
{
@@ -655,7 +792,7 @@ Done:
/*
- Public functions to finish and get the encoded result. See header qcbor.h
+ Public functions to finish and get the encoded result. See qcbor.h
*/
QCBORError QCBOREncode_FinishGetSize(QCBOREncodeContext *me, size_t *puEncodedLen)
{
@@ -674,16 +811,6 @@ QCBORError QCBOREncode_FinishGetSize(QCBOREncodeContext *me, size_t *puEncodedLe
/*
- Notes on the code
-
- CBOR Major Type Public Function
- 0 QCBOREncode_AddUInt64
- 0, 1 QCBOREncode_AddUInt64, QCBOREncode_AddInt64
- 2, 3 QCBOREncode_AddBuffer, Also QCBOREncode_OpenMapOrArray
- 4, 5 QCBOREncode_OpenMapOrArray
- 6 QCBOREncode_AddTag
- 7 QCBOREncode_AddDouble, QCBOREncode_AddType7
-
Object code sizes on X86 with LLVM compiler and -Os (Dec 30, 2018)
_QCBOREncode_Init 69
diff --git a/lib/ext/qcbor/test/UsefulBuf_Tests.c b/lib/ext/qcbor/test/UsefulBuf_Tests.c
index f53693a1b8..1c2634e3db 100644
--- a/lib/ext/qcbor/test/UsefulBuf_Tests.c
+++ b/lib/ext/qcbor/test/UsefulBuf_Tests.c
@@ -1,6 +1,6 @@
/*==============================================================================
Copyright (c) 2016-2018, The Linux Foundation.
- Copyright (c) 2018-2019, Laurence Lundblade.
+ Copyright (c) 2018-2020, Laurence Lundblade.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -28,7 +28,7 @@ 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.
- ==============================================================================*/
+ =============================================================================*/
#include "UsefulBuf.h"
@@ -79,22 +79,17 @@ const char * UOBTest_NonAdversarial()
UsefulBufC UBC2 = {"unbounce ", 9};
UsefulOutBuf_InsertUsefulBuf(&UOB, UBC2, 10);
- // Make it a null terminated string (because all the appends and inserts above not strcpy !)
- UsefulOutBuf_AppendByte(&UOB, '\0');
+ const UsefulBufC Expected = UsefulBuf_FROM_SZ_LITERAL("heffalump unbounce bluster hunny");
UsefulBufC U = UsefulOutBuf_OutUBuf(&UOB);
-
- const char *expected = "heffalump unbounce bluster hunny";
-
- if(UsefulBuf_IsNULLC(U) || U.len-1 != strlen(expected) || strcmp(expected, U.ptr) || UsefulOutBuf_GetError(&UOB)) {
+ if(UsefulBuf_IsNULLC(U) || UsefulBuf_Compare(Expected, U) || UsefulOutBuf_GetError(&UOB)) {
szReturn = "OutUBuf";
}
UsefulBuf_MAKE_STACK_UB(buf, 50);
UsefulBufC Out = UsefulOutBuf_CopyOut(&UOB, buf);
-
- if(UsefulBuf_IsNULLC(Out) || Out.len-1 != strlen(expected) || strcmp(expected, Out.ptr)) {
+ if(UsefulBuf_IsNULLC(Out) || UsefulBuf_Compare(Expected, Out)) {
szReturn = "CopyOut";
}
@@ -160,7 +155,8 @@ static int InsertTest(UsefulOutBuf *pUOB, size_t num, size_t pos, int expected)
- around MAX size_t
- Test these for the buffer size and the cursor, the insert amount, the append amount and the insert position
+ Test these for the buffer size and the cursor, the insert amount, the
+ append amount and the insert position
*/
@@ -314,10 +310,9 @@ const char *UBMacroConversionsTest()
if(Boo.len != 3 || strncmp(Boo.ptr, "Boo", 3))
return "UsefulBuf_FROM_BYTE_ARRAY_LITERAL failed";
- char *sz = "not const"; // some data for the test
- UsefulBuf B = (UsefulBuf){sz, sizeof(sz)};
+ UsefulBuf B = (UsefulBuf){(void *)Too.ptr, Too.len};
UsefulBufC BC = UsefulBuf_Const(B);
- if(BC.len != sizeof(sz) || BC.ptr != sz)
+ if(BC.len != Too.len || BC.ptr != Too.ptr)
return "UsefulBufConst failed";
return NULL;
diff --git a/lib/ext/qcbor/test/float_tests.c b/lib/ext/qcbor/test/float_tests.c
index eaf75aa3ef..20057c32fb 100644
--- a/lib/ext/qcbor/test/float_tests.c
+++ b/lib/ext/qcbor/test/float_tests.c
@@ -1,14 +1,14 @@
/*==============================================================================
float_tests.c -- tests for float and conversion to/from half-precision
- Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved.
+ Copyright (c) 2018-2020, Laurence Lundblade. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause
See BSD-3-Clause license in README.md
Created on 9/19/18
- ==============================================================================*/
+ =============================================================================*/
#include "float_tests.h"
#include "qcbor.h"
@@ -26,7 +26,8 @@ static const uint8_t spExpectedHalf[] = {
0x69, 0x6E, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79,
0xF9, 0x7C, 0x00, // Infinity
0x73,
- 0x6E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x69, 0x6E, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79,
+ 0x6E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x69, 0x6E,
+ 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79,
0xF9, 0xFC, 0x00, // -Inifinity
0x63,
0x4E, 0x61, 0x4E,
@@ -38,21 +39,29 @@ static const uint8_t spExpectedHalf[] = {
0x6F, 0x6E, 0x65, 0x20, 0x74, 0x68, 0x69, 0x72, 0x64,
0xF9, 0x35, 0x55, // 0.333251953125
0x76,
- 0x6C, 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x68, 0x61, 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6F, 0x6E,
+ 0x6C, 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x68, 0x61, 0x6C,
+ 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6F, 0x6E,
0xF9, 0x7B, 0xFF, // 65504.0
- 0x78, 0x18, 0x74, 0x6F, 0x6F, 0x2D, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x20, 0x68, 0x61, 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6F, 0x6E,
+ 0x78, 0x18,
+ 0x74, 0x6F, 0x6F, 0x2D, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x20, 0x68,
+ 0x61, 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69,
+ 0x6F, 0x6E,
0xF9, 0x7C, 0x00, // Infinity
0x72,
- 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C,
+ 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x73, 0x75,
+ 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C,
0xF9, 0x00, 0x01, // 0.000000059604
0x6F,
- 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C,
+ 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x6E, 0x6F,
+ 0x72, 0x6D, 0x61, 0x6C,
0xF9, 0x03, 0xFF, // 0.0000609755516
0x71,
- 0x62, 0x69, 0x67, 0x67, 0x65, 0x73, 0x74, 0x20, 0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C,
+ 0x62, 0x69, 0x67, 0x67, 0x65, 0x73, 0x74, 0x20, 0x73, 0x75, 0x62,
+ 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C,
0xF9, 0x04, 0x00, // 0.000061988
0x70,
- 0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65,
+ 0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x20, 0x73,
+ 0x69, 0x6E, 0x67, 0x6C, 0x65,
0xF9, 0x00, 0x00,
0x03,
0xF9, 0xC0, 0x00, // -2
@@ -68,7 +77,7 @@ static const uint8_t spExpectedHalf[] = {
};
-int HalfPrecisionDecodeBasicTests()
+int32_t HalfPrecisionDecodeBasicTests()
{
UsefulBufC HalfPrecision = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedHalf);
@@ -97,7 +106,9 @@ int HalfPrecisionDecodeBasicTests()
return -4;
}
- QCBORDecode_GetNext(&DC, &Item); // TODO, is this really converting right? It is carrying payload, but this confuses things.
+ // TODO, is this really converting right? It is carrying payload, but
+ // this confuses things.
+ QCBORDecode_GetNext(&DC, &Item);
if(Item.uDataType != QCBOR_TYPE_DOUBLE || !isnan(Item.val.dfnum)) {
return -5;
}
@@ -149,19 +160,23 @@ int HalfPrecisionDecodeBasicTests()
// TODO: double check these four tests
QCBORDecode_GetNext(&DC, &Item); // qNaN
- if(Item.uDataType != QCBOR_TYPE_DOUBLE || UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum) != 0x7ff8000000000000ULL) {
+ if(Item.uDataType != QCBOR_TYPE_DOUBLE ||
+ UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum) != 0x7ff8000000000000ULL) {
return -15;
}
QCBORDecode_GetNext(&DC, &Item); // sNaN
- if(Item.uDataType != QCBOR_TYPE_DOUBLE || UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum) != 0x7ff0000000000001ULL) {
+ if(Item.uDataType != QCBOR_TYPE_DOUBLE ||
+ UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum) != 0x7ff0000000000001ULL) {
return -16;
}
QCBORDecode_GetNext(&DC, &Item); // qNaN with payload 0x0f
- if(Item.uDataType != QCBOR_TYPE_DOUBLE || UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum) != 0x7ff800000000000fULL) {
+ if(Item.uDataType != QCBOR_TYPE_DOUBLE ||
+ UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum) != 0x7ff800000000000fULL) {
return -17;
}
QCBORDecode_GetNext(&DC, &Item); // sNaN with payload 0x0f
- if(Item.uDataType != QCBOR_TYPE_DOUBLE || UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum) != 0x7ff000000000000fULL) {
+ if(Item.uDataType != QCBOR_TYPE_DOUBLE ||
+ UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum) != 0x7ff000000000000fULL) {
return -18;
}
@@ -175,12 +190,12 @@ int HalfPrecisionDecodeBasicTests()
-int HalfPrecisionAgainstRFCCodeTest()
+int32_t HalfPrecisionAgainstRFCCodeTest()
{
for(uint32_t uHalfP = 0; uHalfP < 0xffff; uHalfP += 60) {
unsigned char x[2];
- x[1] = uHalfP & 0xff;
- x[0] = uHalfP >> 8;
+ x[1] = (uint8_t)(uHalfP & 0xff);
+ x[0] = (uint8_t)(uHalfP >> 8); // uHalfP is always less than 0xffff
double d = decode_half(x);
// Contruct the CBOR for the half-precision float by hand
@@ -188,11 +203,12 @@ int HalfPrecisionAgainstRFCCodeTest()
UsefulOutBuf UOB;
UsefulOutBuf_Init(&UOB, __xx);
- const uint8_t uHalfPrecInitialByte = HALF_PREC_FLOAT + (CBOR_MAJOR_TYPE_SIMPLE << 5); // 0xf9
+ const uint8_t uHalfPrecInitialByte = (uint8_t)(HALF_PREC_FLOAT + (CBOR_MAJOR_TYPE_SIMPLE << 5)); // 0xf9
UsefulOutBuf_AppendByte(&UOB, uHalfPrecInitialByte); // The initial byte for a half-precision float
UsefulOutBuf_AppendUint16(&UOB, (uint16_t)uHalfP);
- // Now parse the hand-constructed CBOR. This will invoke the conversion to a float
+ // Now parse the hand-constructed CBOR. This will invoke the
+ // conversion to a float
QCBORDecodeContext DC;
QCBORDecode_Init(&DC, UsefulOutBuf_OutUBuf(&UOB), 0);
@@ -203,7 +219,8 @@ int HalfPrecisionAgainstRFCCodeTest()
return -1;
}
- //printf("%04x QCBOR:%15.15f RFC: %15.15f (%8x)\n", uHalfP,Item.val.fnum, d , UsefulBufUtil_CopyFloatToUint32(d));
+ //printf("%04x QCBOR:%15.15f RFC: %15.15f (%8x)\n",
+ // uHalfP, Item.val.fnum, d , UsefulBufUtil_CopyFloatToUint32(d));
if(isnan(d)) {
// The RFC code uses the native instructions which may or may not
@@ -290,7 +307,7 @@ static const uint8_t spExpectedSmallest[] = {
};
-int DoubleAsSmallestTest()
+int32_t DoubleAsSmallestTest()
{
UsefulBuf_MAKE_STACK_UB(EncodedHalfsMem, 420);
@@ -340,16 +357,17 @@ int DoubleAsSmallestTest()
QCBOREncode_AddDoubleAsSmallestToMap(&EC, "one third", 0.333251953125);
// 76 # text(22)
- // 6C6172676573742068616C662D707265636973696F6E # "largest half-precision"
+ // 6C6172676573742068616C662D707265636973696F6E # "largest half-precision"
// F9 7BFF # primitive(31743)
QCBOREncode_AddDoubleAsSmallestToMap(&EC, "largest half-precision",65504.0);
// 76 # text(22)
- // 6C6172676573742068616C662D707265636973696F6E # "largest half-precision"
+ // 6C6172676573742068616C662D707265636973696F6E # "largest half-precision"
// F9 7BFF # primitive(31743)
QCBOREncode_AddDoubleAsSmallestToMap(&EC, "largest half-precision point one",65504.1);
- // Float 65536.0F is 0x47800000 in hex. It has an exponent of 16, which is larger than 15, the largest half-precision exponent
+ // Float 65536.0F is 0x47800000 in hex. It has an exponent of 16, which
+ // is larger than 15, the largest half-precision exponent
// 78 18 # text(24)
// 746F6F2D6C617267652068616C662D707265636973696F6E # "too-large half-precision"
// FA 47800000 # primitive(31743)
@@ -395,17 +413,20 @@ int DoubleAsSmallestTest()
// 746F6F2D6C617267652073696E676C6520657870 # "too-large single exp"
// FB 47F8000000000000 # primitive(5185894970917126144)
// (0x01LL << (DOUBLE_NUM_SIGNIFICAND_BITS-1)) | ((128LL + DOUBLE_EXPONENT_BIAS) << DOUBLE_EXPONENT_SHIFT);
- QCBOREncode_AddDoubleAsSmallestToMap(&EC, "too-large single exp", 5.104235503814077E+38); // Exponent too large for single
+ // Exponent too large for single
+ QCBOREncode_AddDoubleAsSmallestToMap(&EC, "too-large single exp", 5.104235503814077E+38);
// 66 # text(6)
// 646664666465 # "dfdfde"
// FA 4B800000 # primitive(1266679808)
- QCBOREncode_AddDoubleAsSmallestToMap(&EC, "biggest single with prec",16777216); // Single with no precision loss
+ // Single with no precision loss
+ QCBOREncode_AddDoubleAsSmallestToMap(&EC, "biggest single with prec", 16777216);
// 78 18 # text(24)
// 626967676573742073696E676C6520776974682070726563 # "biggest single with prec"
// FA 4B800000 # primitive(1266679808)
- QCBOREncode_AddDoubleAsSmallestToMap(&EC, "first single with prec loss",16777217); // Double becuase of precision loss
+ // Double becuase of precision loss
+ QCBOREncode_AddDoubleAsSmallestToMap(&EC, "first single with prec loss", 16777217);
// Just a convenient marker when cutting and pasting encoded CBOR
QCBOREncode_AddSZStringToMapN(&EC, 1, "fin");
diff --git a/lib/ext/qcbor/test/float_tests.h b/lib/ext/qcbor/test/float_tests.h
index b7174c8065..f777156df7 100644
--- a/lib/ext/qcbor/test/float_tests.h
+++ b/lib/ext/qcbor/test/float_tests.h
@@ -1,23 +1,25 @@
/*==============================================================================
float_tests.h -- tests for float and conversion to/from half-precision
- Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved.
+ Copyright (c) 2018-2020, Laurence Lundblade. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause
See BSD-3-Clause license in README.md
Created on 9/19/18
- ==============================================================================*/
+ =============================================================================*/
#ifndef float_tests_h
#define float_tests_h
-int HalfPrecisionDecodeBasicTests(void);
+#include <stdint.h>
-int DoubleAsSmallestTest(void);
+int32_t HalfPrecisionDecodeBasicTests(void);
-int HalfPrecisionAgainstRFCCodeTest(void);
+int32_t DoubleAsSmallestTest(void);
+
+int32_t HalfPrecisionAgainstRFCCodeTest(void);
#endif /* float_tests_h */
diff --git a/lib/ext/qcbor/test/half_to_double_from_rfc7049.c b/lib/ext/qcbor/test/half_to_double_from_rfc7049.c
index 6380e519a9..d1e2f390f7 100644
--- a/lib/ext/qcbor/test/half_to_double_from_rfc7049.c
+++ b/lib/ext/qcbor/test/half_to_double_from_rfc7049.c
@@ -22,7 +22,7 @@
b) the license may be an issue
QCBOR does support half-precision, but rather than using
- floating point math like this, it does it with bit shifting
+ floating-point math like this, it does it with bit shifting
and masking.
This code is here to test that code.
diff --git a/lib/ext/qcbor/test/half_to_double_from_rfc7049.h b/lib/ext/qcbor/test/half_to_double_from_rfc7049.h
index 9f69e35c37..4642f04596 100644
--- a/lib/ext/qcbor/test/half_to_double_from_rfc7049.h
+++ b/lib/ext/qcbor/test/half_to_double_from_rfc7049.h
@@ -1,14 +1,14 @@
/*==============================================================================
half_to_double_from_rfc7049.h -- interface to IETF float conversion code.
- Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved.
+ Copyright (c) 2018-2020, Laurence Lundblade. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause
See BSD-3-Clause license in README.md
Created on 9/23/18
- ==============================================================================*/
+ ============================================================================*/
#ifndef half_to_double_from_rfc7049_h
#define half_to_double_from_rfc7049_h
diff --git a/lib/ext/qcbor/test/not_well_formed_cbor.h b/lib/ext/qcbor/test/not_well_formed_cbor.h
index d5bd233561..e905cd1325 100644
--- a/lib/ext/qcbor/test/not_well_formed_cbor.h
+++ b/lib/ext/qcbor/test/not_well_formed_cbor.h
@@ -58,22 +58,22 @@ static const struct someBinaryBytes paNotWellFormedCBOR[] = {
// indefinite length text string with indefinite string inside
{(uint8_t[]){0x7f, 0x7f, 0x61, 0x00, 0xff, 0xff}, 6},
- // Definite length maps and arrays must be closed by having the
+ // Definte length maps and arrays must be closed by having the
// right number of items
- // A definite length array that is supposed to have 1 item, but has none
+ // A definte length array that is supposed to have 1 item, but has none
{(uint8_t[]){0x81}, 1},
- // A definite length array that is supposed to have 2 items, but has only 1
+ // A definte length array that is supposed to have 2 items, but has only 1
{(uint8_t[]){0x82, 0x00}, 2},
- // A definite length array that is supposed to have 511 items, but has only 1
+ // A definte length array that is supposed to have 511 items, but has only 1
{(uint8_t[]){0x9a, 0x01, 0xff, 0x00}, 4},
- // A definite length map that is supposed to have 1 item, but has none
+ // A definte length map that is supposed to have 1 item, but has none
{(uint8_t[]){0xa1}, 1},
- // A definite length map that is supposed to have s item, but has only 1
+ // A definte length map that is supposed to have s item, but has only 1
{(uint8_t[]){0xa2, 0x01, 0x02}, 3},
- // Indefinite length maps and arrays must be ended by a break
+ // Indefinte length maps and arrays must be ended by a break
// Indefinite length array with zero items and no break
{(uint8_t[]){0x9f}, 1},
@@ -251,10 +251,10 @@ static const struct someBinaryBytes paNotWellFormedCBOR[] = {
{(uint8_t[]){0x41}, 1},
// A text string is of length 1 without the 1 byte
{(uint8_t[]){0x61}, 1},
- // Byte string should have 2^32-1 bytes, but has one
- {(uint8_t[]){0x5a, 0xff, 0xff, 0xff, 0xff, 0x00}, 6},
- // Byte string should have 2^32-1 bytes, but has one
- {(uint8_t[]){0x7a, 0xff, 0xff, 0xff, 0xff, 0x00}, 6},
+ // Byte string should have 2^32-15 bytes, but has one
+ {(uint8_t[]){0x5a, 0xff, 0xff, 0xff, 0xf0, 0x00}, 6},
+ // Byte string should have 2^32-15 bytes, but has one
+ {(uint8_t[]){0x7a, 0xff, 0xff, 0xff, 0xf0, 0x00}, 6},
// Use of unassigned additional information values
diff --git a/lib/ext/qcbor/test/qcbor_decode_tests.c b/lib/ext/qcbor/test/qcbor_decode_tests.c
index 7de8c6cc8f..a9e1fb29b5 100644
--- a/lib/ext/qcbor/test/qcbor_decode_tests.c
+++ b/lib/ext/qcbor/test/qcbor_decode_tests.c
@@ -1,6 +1,6 @@
/*==============================================================================
Copyright (c) 2016-2018, The Linux Foundation.
- Copyright (c) 2018-2019, Laurence Lundblade.
+ Copyright (c) 2018-2020, Laurence Lundblade.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -28,7 +28,7 @@ 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.
- ==============================================================================*/
+ =============================================================================*/
#include "qcbor_decode_tests.h"
#include "qcbor.h"
@@ -55,11 +55,6 @@ static void PrintUsefulBufC(const char *szLabel, UsefulBufC Buf)
fflush(stdout);
}
-
-/*static void printencoded(const char *szLabel, const uint8_t *pEncoded, size_t nLen)
-{
- PrintUsefulBufC(szLabel, (UsefulBufC){pEncoded, nLen});
-}*/
#endif
@@ -92,7 +87,7 @@ static const uint8_t spExpectedEncodedInts[] = {
// return CBOR error or -1 if type of value doesn't match
-static int IntegerValuesParseTestInternal(QCBORDecodeContext *pDCtx)
+static int32_t IntegerValuesParseTestInternal(QCBORDecodeContext *pDCtx)
{
QCBORItem Item;
int nCBORError;
@@ -104,7 +99,7 @@ static int IntegerValuesParseTestInternal(QCBORDecodeContext *pDCtx)
if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
- if(Item.uDataType != QCBOR_TYPE_INT64 || // Todo; fix this for 32-bit machines
+ if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != -9223372036854775807LL - 1)
return -1;
@@ -419,10 +414,10 @@ static int IntegerValuesParseTestInternal(QCBORDecodeContext *pDCtx)
}
-// The largest negative int possible in CBOR.
-// Not possible in C.
-static const uint8_t spTooBigNegative[] = {
- 0x3b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+// One less than the smallest negative integer allowed in C. Decoding
+// this should fail.
+static const uint8_t spTooSmallNegative[] = {
+ 0x3b, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
@@ -430,7 +425,7 @@ static const uint8_t spTooBigNegative[] = {
Tests the decoding of lots of different integers sizes
and values.
*/
-int IntegerValuesParseTest()
+int32_t IntegerValuesParseTest()
{
int nReturn;
QCBORDecodeContext DCtx;
@@ -447,7 +442,7 @@ int IntegerValuesParseTest()
// The one large negative integer that can be parsed
QCBORDecode_Init(&DCtx,
- UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTooBigNegative),
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTooSmallNegative),
QCBOR_DECODE_MODE_NORMAL);
QCBORItem item;
@@ -460,8 +455,8 @@ int IntegerValuesParseTest()
/*
- Creates a simple CBOR array and returns it in *pEncoded. The array is malloced
- and needs to be freed. This is used by several tests.
+ Creates a simple CBOR array and returns it in *pEncoded. The array is
+ malloced and needs to be freed. This is used by several tests.
Two of the inputs can be set. Two other items in the array are fixed.
@@ -469,7 +464,7 @@ int IntegerValuesParseTest()
static uint8_t spSimpleArrayBuffer[50];
-static int CreateSimpleArray(int nInt1, int nInt2, uint8_t **pEncoded, size_t *pEncodedLen)
+static int32_t CreateSimpleArray(int nInt1, int nInt2, uint8_t **pEncoded, size_t *pEncodedLen)
{
QCBOREncodeContext ECtx;
int nReturn = -1;
@@ -511,6 +506,9 @@ Done:
/*
+ Some basic CBOR with map and array used in a lot of tests.
+ The map labels are all strings
+
{"first integer": 42,
"an array of two strings": [
"string1", "string2"
@@ -523,8 +521,7 @@ Done:
}
}
*/
-
-static uint8_t pValidMapEncoded[] = {
+static const uint8_t pValidMapEncoded[] = {
0xa3, 0x6d, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x69, 0x6e,
0x74, 0x65, 0x67, 0x65, 0x72, 0x18, 0x2a, 0x77, 0x61, 0x6e,
0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x6f, 0x66, 0x20,
@@ -542,13 +539,22 @@ static uint8_t pValidMapEncoded[] = {
0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63,
0x73 } ;
-static int ParseOrderedArray(const uint8_t *pEncoded, size_t nLen, int64_t *pInt1, int64_t *pInt2, const uint8_t **pBuf3, size_t *pBuf3Len, const uint8_t **pBuf4, size_t *pBuf4Len)
+static int32_t ParseOrderedArray(const uint8_t *pEncoded,
+ size_t nLen,
+ int64_t *pInt1,
+ int64_t *pInt2,
+ const uint8_t **pBuf3,
+ size_t *pBuf3Len,
+ const uint8_t **pBuf4,
+ size_t *pBuf4Len)
{
QCBORDecodeContext DCtx;
QCBORItem Item;
int nReturn = -1; // assume error until success
- QCBORDecode_Init(&DCtx, (UsefulBufC){pEncoded, nLen}, QCBOR_DECODE_MODE_NORMAL);
+ QCBORDecode_Init(&DCtx,
+ (UsefulBufC){pEncoded, nLen},
+ QCBOR_DECODE_MODE_NORMAL);
// Make sure the first thing is a map
if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || Item.uDataType != QCBOR_TYPE_ARRAY)
@@ -585,7 +591,7 @@ Done:
-int SimpleArrayTest()
+int32_t SimpleArrayTest()
{
uint8_t *pEncoded;
size_t nEncodedLen;
@@ -636,12 +642,14 @@ int SimpleArrayTest()
static uint8_t sEmpties[] = {0x83, 0x00, 0x80, 0x84, 0x80, 0x81, 0x00, 0xa0,
0xa3, 0x01, 0xa0, 0x02, 0xa0, 0x03, 0x80};
-int EmptyMapsAndArraysTest()
+int32_t EmptyMapsAndArraysTest()
{
QCBORDecodeContext DCtx;
QCBORItem Item;
- QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(sEmpties), QCBOR_DECODE_MODE_NORMAL);
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(sEmpties),
+ QCBOR_DECODE_MODE_NORMAL);
// Array with 3 items
if(QCBORDecode_GetNext(&DCtx, &Item) != 0 ||
@@ -759,15 +767,18 @@ int EmptyMapsAndArraysTest()
}
-static uint8_t spDeepArrays[] = {0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x80};
+static uint8_t spDeepArrays[] = {0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+ 0x81, 0x81, 0x81, 0x80};
-int ParseDeepArrayTest()
+int32_t ParseDeepArrayTest()
{
QCBORDecodeContext DCtx;
int nReturn = 0;
int i;
- QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spDeepArrays), QCBOR_DECODE_MODE_NORMAL);
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spDeepArrays),
+ QCBOR_DECODE_MODE_NORMAL);
for(i = 0; i < 10; i++) {
QCBORItem Item;
@@ -784,12 +795,12 @@ int ParseDeepArrayTest()
}
// Big enough to test nesting to the depth of 24
-static uint8_t spTooDeepArrays[] = {0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
- 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
- 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
- 0x80};
+static uint8_t spTooDeepArrays[] = {0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+ 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+ 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+ 0x81, 0x81, 0x81, 0x80};
-int ParseTooDeepArrayTest()
+int32_t ParseTooDeepArrayTest()
{
QCBORDecodeContext DCtx;
int nReturn = 0;
@@ -797,7 +808,9 @@ int ParseTooDeepArrayTest()
QCBORItem Item;
- QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTooDeepArrays), QCBOR_DECODE_MODE_NORMAL);
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTooDeepArrays),
+ QCBOR_DECODE_MODE_NORMAL);
for(i = 0; i < QCBOR_MAX_ARRAY_NESTING1; i++) {
@@ -818,16 +831,18 @@ int ParseTooDeepArrayTest()
-int ShortBufferParseTest()
+int32_t ShortBufferParseTest()
{
int nResult = 0;
- for(int nNum = sizeof(spExpectedEncodedInts)-1; nNum; nNum--) {
+ for(size_t nNum = sizeof(spExpectedEncodedInts)-1; nNum; nNum--) {
QCBORDecodeContext DCtx;
- QCBORDecode_Init(&DCtx, (UsefulBufC){spExpectedEncodedInts, nNum}, QCBOR_DECODE_MODE_NORMAL);
+ QCBORDecode_Init(&DCtx,
+ (UsefulBufC){spExpectedEncodedInts, nNum},
+ QCBOR_DECODE_MODE_NORMAL);
- const QCBORError nErr = IntegerValuesParseTestInternal(&DCtx);
+ const int nErr = IntegerValuesParseTestInternal(&DCtx);
if(nErr != QCBOR_ERR_HIT_END && nErr != QCBOR_ERR_NO_MORE_ITEMS) {
nResult = -1;
@@ -840,7 +855,7 @@ Done:
-int ShortBufferParseTest2()
+int32_t ShortBufferParseTest2()
{
uint8_t *pEncoded;
int nReturn;
@@ -868,15 +883,18 @@ int ShortBufferParseTest2()
/*
Decode and thoroughly check a moderately complex
- set of maps
+ set of maps. Can be run in QCBOR_DECODE_MODE_NORMAL or in
+ QCBOR_DECODE_MODE_MAP_STRINGS_ONLY.
*/
-static int ParseMapTest1(QCBORDecodeMode nMode)
+static int32_t ParseMapTest1(QCBORDecodeMode nMode)
{
QCBORDecodeContext DCtx;
QCBORItem Item;
int nCBORError;
- QCBORDecode_Init(&DCtx, (UsefulBufC){pValidMapEncoded, sizeof(pValidMapEncoded)}, nMode);
+ QCBORDecode_Init(&DCtx,
+ (UsefulBufC){pValidMapEncoded, sizeof(pValidMapEncoded)},
+ nMode);
if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
return nCBORError;
@@ -995,13 +1013,15 @@ static int ParseMapTest1(QCBORDecodeMode nMode)
Decode and thoroughly check a moderately complex
set of maps
*/
-int ParseMapAsArrayTest()
+int32_t ParseMapAsArrayTest()
{
QCBORDecodeContext DCtx;
QCBORItem Item;
int nCBORError;
- QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), QCBOR_DECODE_MODE_MAP_AS_ARRAY);
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded),
+ QCBOR_DECODE_MODE_MAP_AS_ARRAY);
if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
return nCBORError;
@@ -1202,13 +1222,15 @@ int ParseMapAsArrayTest()
and made prettier and maybe a little more
thorough.
*/
-static int ExtraBytesTest(int nLevel)
+static int32_t ExtraBytesTest(int nLevel)
{
QCBORDecodeContext DCtx;
QCBORItem Item;
int nCBORError;
- QCBORDecode_Init(&DCtx, (UsefulBufC){pValidMapEncoded, sizeof(pValidMapEncoded)}, QCBOR_DECODE_MODE_NORMAL);
+ QCBORDecode_Init(&DCtx,
+ (UsefulBufC){pValidMapEncoded, sizeof(pValidMapEncoded)},
+ QCBOR_DECODE_MODE_NORMAL);
if(nLevel < 1) {
if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_EXTRA_BYTES) {
@@ -1394,37 +1416,52 @@ static int ExtraBytesTest(int nLevel)
-
-int ParseMapTest()
+/*
+ Public function for initialization. See header qcbor.h
+ */
+int32_t ParseMapTest()
{
- // Parse a moderatly complex map structure very thoroughl
- int n = ParseMapTest1(QCBOR_DECODE_MODE_NORMAL);
+ // Parse a moderatly complex map structure very thoroughly
+ int32_t nResult = ParseMapTest1(QCBOR_DECODE_MODE_NORMAL);
+ if(nResult) {
+ return nResult;
+ }
- n = ParseMapTest1(QCBOR_DECODE_MODE_MAP_STRINGS_ONLY);
+ // Again, but in strings-only mode. It should succeed since the input
+ // map has only string labels.
+ nResult = ParseMapTest1(QCBOR_DECODE_MODE_MAP_STRINGS_ONLY);
+ if(nResult) {
+ return nResult;
+ }
- if(!n) {
- for(int i = 0; i < 10; i++) {
- n = ExtraBytesTest(i);
- if(n) {
- break;
- }
+ // Again, but try to finish the decoding before the end of the
+ // input at 10 different place and see that the right error code
+ // is returned.
+ for(int i = 0; i < 10; i++) {
+ nResult = ExtraBytesTest(i);
+ if(nResult) {
+ break;
}
}
- return(n);
+ return nResult;
}
-static uint8_t spSimpleValues[] = {0x8a, 0xf4, 0xf5, 0xf6, 0xf7, 0xff, 0xe0, 0xf3, 0xf8, 0x00, 0xf8, 0x13, 0xf8, 0x1f, 0xf8, 0x20, 0xf8, 0xff};
+static uint8_t spSimpleValues[] = {0x8a, 0xf4, 0xf5, 0xf6, 0xf7, 0xff,
+ 0xe0, 0xf3, 0xf8, 0x00, 0xf8, 0x13,
+ 0xf8, 0x1f, 0xf8, 0x20, 0xf8, 0xff};
-int ParseSimpleTest()
+int32_t ParseSimpleTest()
{
QCBORDecodeContext DCtx;
QCBORItem Item;
int nCBORError;
- QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSimpleValues), QCBOR_DECODE_MODE_NORMAL);
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSimpleValues),
+ QCBOR_DECODE_MODE_NORMAL);
if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
@@ -1509,7 +1546,7 @@ static int IsNotWellFormedError(QCBORError nErr)
}
-int NotWellFormedTests()
+int32_t NotWellFormedTests()
{
// Loop over all the not-well-formed instance of CBOR
// that are test vectors in not_well_formed_cbor.h
@@ -1518,7 +1555,8 @@ int NotWellFormedTests()
const struct someBinaryBytes *pBytes = &paNotWellFormedCBOR[nIterate];
const UsefulBufC Input = (UsefulBufC){pBytes->p, pBytes->n};
- // Set up decoder context. String allocator needed for indefinite string test cases
+ // Set up decoder context. String allocator needed for indefinite
+ // string test cases
QCBORDecodeContext DCtx;
QCBORDecode_Init(&DCtx, Input, QCBOR_DECODE_MODE_NORMAL);
UsefulBuf_MAKE_STACK_UB(Pool, 100);
@@ -1545,10 +1583,48 @@ int NotWellFormedTests()
struct FailInput {
- UsefulBufC Input; // CBOR to decode
- QCBORError nError; // The error expected
+ UsefulBufC Input;
+ QCBORError nError;
};
+
+static int32_t ProcessFailures(struct FailInput *pFailInputs, size_t nNumFails)
+{
+ for(struct FailInput *pF = pFailInputs; pF < pFailInputs + nNumFails; pF++) {
+ // Set up the decoding context including a memory pool so that
+ // indefinite length items can be checked
+ QCBORDecodeContext DCtx;
+ QCBORDecode_Init(&DCtx, pF->Input, QCBOR_DECODE_MODE_NORMAL);
+ UsefulBuf_MAKE_STACK_UB(Pool, 100);
+ QCBORError nCBORError = QCBORDecode_SetMemPool(&DCtx, Pool, 0);
+ if(nCBORError) {
+ return -9;
+ }
+
+ // Iterate until there is an error of some sort error
+ QCBORItem Item;
+ do {
+ // Set to something none-zero other than QCBOR_TYPE_NONE
+ memset(&Item, 0x33, sizeof(Item));
+
+ nCBORError = QCBORDecode_GetNext(&DCtx, &Item);
+ } while(nCBORError == QCBOR_SUCCESS);
+
+ // Must get the expected error or the this test fails
+ // The data and label type must also be QCBOR_TYPE_NONE
+ if(nCBORError != pF->nError ||
+ Item.uDataType != QCBOR_TYPE_NONE ||
+ Item.uLabelType != QCBOR_TYPE_NONE) {
+ // return index of CBOR + 100
+ const size_t nIndex = (size_t)(pF - pFailInputs)/sizeof(struct FailInput);
+ return (int32_t)(nIndex * 100 + nCBORError);
+ }
+ }
+
+ return 0;
+}
+
+
struct FailInput Failures[] = {
// Most of this is copied from not_well_formed.h. Here the error code
// returned is also checked.
@@ -1616,9 +1692,11 @@ struct FailInput Failures[] = {
// Deeply nested indefinite length arrays with deepest one unclosed
{ {(uint8_t[]){0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0xff, 0xff, 0xff, 0xff}, 9}, QCBOR_ERR_HIT_END },
// Mixed nesting with indefinite unclosed
- { {(uint8_t[]){0x9f, 0x81, 0x9f, 0x81, 0x9f, 0x9f, 0xff, 0xff, 0xff}, 9}, QCBOR_ERR_BAD_BREAK }, // TODO: think through this one
+ // TODO: think through this one
+ { {(uint8_t[]){0x9f, 0x81, 0x9f, 0x81, 0x9f, 0x9f, 0xff, 0xff, 0xff}, 9}, QCBOR_ERR_BAD_BREAK },
// Mixed nesting with definite unclosed
- { {(uint8_t[]){0x9f, 0x82, 0x9f, 0x81, 0x9f, 0x9f, 0xff, 0xff, 0xff, 0xff}, 10}, QCBOR_ERR_BAD_BREAK }, // TODO: think through this one
+ // TODO: think through this one
+ { {(uint8_t[]){0x9f, 0x82, 0x9f, 0x81, 0x9f, 0x9f, 0xff, 0xff, 0xff, 0xff}, 10}, QCBOR_ERR_BAD_BREAK },
// The "argument" for the data item is incomplete
@@ -1746,10 +1824,10 @@ struct FailInput Failures[] = {
{ {(uint8_t[]){0x41}, 1}, QCBOR_ERR_HIT_END },
// A text string is of length 1 without the 1 byte
{ {(uint8_t[]){0x61}, 1}, QCBOR_ERR_HIT_END },
- // Byte string should have 2^32-1 bytes, but has one
- { {(uint8_t[]){0x5a, 0xff, 0xff, 0xff, 0xff, 0x00}, 6}, QCBOR_ERR_HIT_END },
- // Byte string should have 2^32-1 bytes, but has one
- { {(uint8_t[]){0x7a, 0xff, 0xff, 0xff, 0xff, 0x00}, 6}, QCBOR_ERR_HIT_END },
+ // Byte string should have 2^32-15 bytes, but has one
+ { {(uint8_t[]){0x5a, 0xff, 0xff, 0xff, 0xf0, 0x00}, 6}, QCBOR_ERR_HIT_END },
+ // Byte string should have 2^32-15 bytes, but has one
+ { {(uint8_t[]){0x7a, 0xff, 0xff, 0xff, 0xf0, 0x00}, 6}, QCBOR_ERR_HIT_END },
// Use of unassigned additional information values
@@ -1815,46 +1893,23 @@ struct FailInput Failures[] = {
// In addition to not-well-formed, some invalid CBOR
- { {(uint8_t[]){0xc0, 0x00}, 2}, QCBOR_ERR_BAD_OPT_TAG }, // Text-based date, with an integer
- { {(uint8_t[]){0xc1, 0x41, 0x33}, 3}, QCBOR_ERR_BAD_OPT_TAG }, // Epoch date, with an byte string
- { {(uint8_t[]){0xc1, 0xc0, 0x00}, 3}, QCBOR_ERR_BAD_OPT_TAG }, // tagged as both epoch and string dates
- { {(uint8_t[]){0xc2, 0x00}, 2}, QCBOR_ERR_BAD_OPT_TAG }, // big num tagged an int, not a byte string
+ // Text-based date, with an integer
+ { {(uint8_t[]){0xc0, 0x00}, 2}, QCBOR_ERR_BAD_OPT_TAG },
+ // Epoch date, with an byte string
+ { {(uint8_t[]){0xc1, 0x41, 0x33}, 3}, QCBOR_ERR_BAD_OPT_TAG },
+ // tagged as both epoch and string dates
+ { {(uint8_t[]){0xc1, 0xc0, 0x00}, 3}, QCBOR_ERR_BAD_OPT_TAG },
+ // big num tagged an int, not a byte string
+ { {(uint8_t[]){0xc2, 0x00}, 2}, QCBOR_ERR_BAD_OPT_TAG },
};
-int DecodeFailureTests()
+int32_t DecodeFailureTests()
{
- // Loop over the failures
- const struct FailInput * const pFEnd = &Failures[0] +
- sizeof(Failures)/sizeof(struct FailInput);
- for(const struct FailInput *pF = &Failures[0]; pF < pFEnd ;pF++) {
-
- // Set up the decoding context including a memory pool so that
- // indefinite length items can be checked
- QCBORDecodeContext DCtx;
- QCBORDecode_Init(&DCtx, pF->Input, QCBOR_DECODE_MODE_NORMAL);
- UsefulBuf_MAKE_STACK_UB(Pool, 100);
- QCBORError nCBORError = QCBORDecode_SetMemPool(&DCtx, Pool, 0);
- if(nCBORError) {
- return -9;
- }
-
- // Iterate until there is an error of some sort error
- QCBORItem Item;
- do {
- // Set to something none-zero other than QCBOR_TYPE_NONE
- memset(&Item, 0x33, sizeof(Item));
-
- nCBORError = QCBORDecode_GetNext(&DCtx, &Item);
- } while(nCBORError == QCBOR_SUCCESS);
+ int32_t nResult;
- // Must get the expected error or the this test fails
- // The data and label type must also be QCBOR_TYPE_NONE
- if(nCBORError != pF->nError ||
- Item.uDataType != QCBOR_TYPE_NONE ||
- Item.uLabelType != QCBOR_TYPE_NONE) {
- // return index of CBOR + 1000
- return 1000 + (int)(pF - &Failures[0]);
- }
+ nResult = ProcessFailures(Failures, sizeof(Failures)/sizeof(struct FailInput));
+ if(nResult) {
+ return nResult;
}
// Corrupt the UsefulInputBuf and see that
@@ -1885,6 +1940,29 @@ int DecodeFailureTests()
}
}
+/*
+ This test is disabled until QCBOREncode_EncodeHead() is brought in so
+ the size encoded can be tied to SIZE_MAX and work for all size CPUs.
+
+ This relies on the largest string allowed being SIZE_MAX -4 rather than
+ SIZE_MAX. That way the test can be performed.
+ {
+ QCBORDecodeContext DCtx;
+ QCBORItem Item;
+
+ static uint8_t foo[] = {0x5b, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff};
+
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(foo),
+ QCBOR_DECODE_MODE_NORMAL);
+
+ if(QCBOR_ERR_STRING_TOO_LONG != QCBORDecode_GetNext(&DCtx, &Item)) {
+ return -4;
+ }
+ }
+*/
+
return 0;
}
@@ -1892,7 +1970,7 @@ int DecodeFailureTests()
/* Try all 256 values of the byte at nLen including recursing for
each of the values to try values at nLen+1 ... up to nLenMax
*/
-static void ComprehensiveInputRecurser(uint8_t *pBuf, int nLen, int nLenMax)
+static void ComprehensiveInputRecurser(uint8_t *pBuf, size_t nLen, size_t nLenMax)
{
if(nLen >= nLenMax) {
return;
@@ -1900,7 +1978,7 @@ static void ComprehensiveInputRecurser(uint8_t *pBuf, int nLen, int nLenMax)
for(int inputByte = 0; inputByte < 256; inputByte++) {
// Set up the input
- pBuf[nLen] = inputByte;
+ pBuf[nLen] = (uint8_t)inputByte;
const UsefulBufC Input = {pBuf, nLen+1};
// Get ready to parse
@@ -1928,7 +2006,7 @@ static void ComprehensiveInputRecurser(uint8_t *pBuf, int nLen, int nLenMax)
/*
Public function for initialization. See header qcbor.h
*/
-int ComprehensiveInputTest()
+int32_t ComprehensiveInputTest()
{
// Size 2 tests 64K inputs and runs quickly
uint8_t pBuf[2];
@@ -1942,7 +2020,7 @@ int ComprehensiveInputTest()
/*
Public function for initialization. See header qcbor.h
*/
-int BigComprehensiveInputTest()
+int32_t BigComprehensiveInputTest()
{
// size 3 tests 16 million inputs and runs OK
// in seconds on fast machines. Size 4 takes
@@ -1998,13 +2076,15 @@ int CHECK_EXPECTED_DOUBLE(double val, double expected) {
}
-int DateParseTest()
+int32_t DateParseTest()
{
QCBORDecodeContext DCtx;
QCBORItem Item;
int nCBORError;
- QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spDateTestInput), QCBOR_DECODE_MODE_NORMAL);
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spDateTestInput),
+ QCBOR_DECODE_MODE_NORMAL);
const uint64_t uTags[] = {15};
QCBORTagListIn TagList = {1, uTags};
@@ -2070,7 +2150,8 @@ int DateParseTest()
Item.val.epochDate.nSeconds == 0) {
return -12;
}
- // TODO: could use a few more tests with float, double, and half precsion and negative (but coverage is still pretty good)
+ // TODO: could use a few more tests with float, double, and half precsion
+ // and negative (but coverage is still pretty good)
return 0;
}
@@ -2082,15 +2163,27 @@ static uint8_t spOptTestInput[] = {
0xd8, 0x04, // non-preferred serialization of tag 4
0x82, 0x01, 0x03}; // fraction 1/3
-static uint8_t spEncodedLargeTag[] = {0xdb, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x80};
+/*
+ DB 9192939495969798 # tag(10489608748473423768)
+ 80 # array(0)
+ */
+static uint8_t spEncodedLargeTag[] = {0xdb, 0x91, 0x92, 0x93, 0x94, 0x95,
+ 0x96, 0x97, 0x98, 0x80};
-// 0x9192939495969798, 0x88, 0x01, 0x04
-static uint8_t spLotsOfTags[] = {0xdb, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0xd8, 0x88, 0xc5, 0xc4, 0x80};
+/*
+DB 9192939495969798 # tag(10489608748473423768)
+ D8 88 # tag(136)
+ C6 # tag(6)
+ C7 # tag(7)
+ 80 # array(0)
+*/
+static uint8_t spLotsOfTags[] = {0xdb, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
+ 0x97, 0x98, 0xd8, 0x88, 0xc6, 0xc7, 0x80};
/*
The cbor.me parse of this.
55799(55799(55799({6(7(-23)): 5859837686836516696(7({7(-20): 11({17(-18): 17(17(17("Organization"))),
- 9(-17): 773("SSG"), -15: 4(5(6(7(8(9(10(11(12(13(14(15("Confusion")))))))))))), 17(-16): 17("San Diego"),
+ 9(-17): 773("SSG"), -15: 16(17(6(7(8(9(10(11(12(13(14(15("Confusion")))))))))))), 17(-16): 17("San Diego"),
17(-14): 17("US")}), 23(-19): 19({-11: 9({-9: -7}),
90599561(90599561(90599561(-10))): 12(h'0102030405060708090A')})})),
16(-22): 23({11(8(7(-5))): 8(-3)})})))
@@ -2108,7 +2201,7 @@ static uint8_t spCSRWithTags[] = {
0xd9, 0x03, 0x05, 0x63,
0x53, 0x53, 0x47,
0x2e,
- 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0x69,
+ 0xd0, 0xd1, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0x69,
0x43, 0x6f, 0x6e, 0x66, 0x75, 0x73, 0x69, 0x6f, 0x6e,
0xd1, 0x2f,
0xd1, 0x69,
@@ -2130,15 +2223,17 @@ static uint8_t spCSRWithTags[] = {
0xcb, 0xc8, 0xc7, 0x24,
0xc8, 0x22};
-static int CheckCSRMaps(QCBORDecodeContext *pDC);
+static int32_t CheckCSRMaps(QCBORDecodeContext *pDC);
-int OptTagParseTest()
+int32_t OptTagParseTest()
{
QCBORDecodeContext DCtx;
QCBORItem Item;
- QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spOptTestInput), QCBOR_DECODE_MODE_NORMAL);
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spOptTestInput),
+ QCBOR_DECODE_MODE_NORMAL);
//-------------------------
// This text matches the magic number tag and the fraction tag
@@ -2153,16 +2248,25 @@ int OptTagParseTest()
if(QCBORDecode_GetNext(&DCtx, &Item)) {
return -4;
}
+
+#ifdef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
if(Item.uDataType != QCBOR_TYPE_ARRAY ||
- !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_FRACTION) ||
+ !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_DECIMAL_FRACTION) ||
Item.val.uCount != 2) {
return -5;
}
+#else
+ if(Item.uDataType != QCBOR_TYPE_DECIMAL_FRACTION) {
+ return -6;
+ }
+#endif
// --------------------------------
// This test decodes the very large tag, but it is not in
// any list so it is ignored.
- QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spEncodedLargeTag), QCBOR_DECODE_MODE_NORMAL);
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spEncodedLargeTag),
+ QCBOR_DECODE_MODE_NORMAL);
if(QCBORDecode_GetNext(&DCtx, &Item)) {
return -6;
}
@@ -2171,8 +2275,11 @@ int OptTagParseTest()
}
// ----------------------------------
- // This test sets up a caller-config list that includes the very large tage and then matches it.
- QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spEncodedLargeTag), QCBOR_DECODE_MODE_NORMAL);
+ // This test sets up a caller-config list that includes the very large
+ // tage and then matches it.
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spEncodedLargeTag),
+ QCBOR_DECODE_MODE_NORMAL);
const uint64_t puList[] = {0x9192939495969798, 257};
const QCBORTagListIn TL = {2, puList};
QCBORDecode_SetCallerConfiguredTagList(&DCtx, &TL);
@@ -2189,10 +2296,12 @@ int OptTagParseTest()
}
//------------------------
- // This test sets up a caller-configured list, and looks up something not in it
+ // Sets up a caller-configured list and look up something not in it
const uint64_t puLongList[17] = {1,2,1};
const QCBORTagListIn TLLong = {17, puLongList};
- QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spEncodedLargeTag), QCBOR_DECODE_MODE_NORMAL);
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spEncodedLargeTag),
+ QCBOR_DECODE_MODE_NORMAL);
QCBORDecode_SetCallerConfiguredTagList(&DCtx, &TLLong);
if(QCBORDecode_GetNext(&DCtx, &Item)) {
return -11;
@@ -2200,7 +2309,9 @@ int OptTagParseTest()
// -----------------------
// This tests retrievel of the full tag list
- QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spLotsOfTags), QCBOR_DECODE_MODE_NORMAL);
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spLotsOfTags),
+ QCBOR_DECODE_MODE_NORMAL);
uint64_t puTags[16];
QCBORTagListOut Out = {0, 4, puTags};
if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) {
@@ -2208,14 +2319,16 @@ int OptTagParseTest()
}
if(puTags[0] != 0x9192939495969798 ||
puTags[1] != 0x88 ||
- puTags[2] != 0x05 ||
- puTags[3] != 0x04) {
+ puTags[2] != 0x06 ||
+ puTags[3] != 0x07) {
return -13;
}
// ----------------------
// This text if too small of an out list
- QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spLotsOfTags), QCBOR_DECODE_MODE_NORMAL);
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spLotsOfTags),
+ QCBOR_DECODE_MODE_NORMAL);
QCBORTagListOut OutSmall = {0, 3, puTags};
if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &OutSmall) != QCBOR_ERR_TOO_MANY_TAGS) {
return -14;
@@ -2223,14 +2336,18 @@ int OptTagParseTest()
// ---------------
// Parse a version of the "CSR" that has had a ton of tags randomly inserted
- QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRWithTags), QCBOR_DECODE_MODE_NORMAL);
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRWithTags),
+ QCBOR_DECODE_MODE_NORMAL);
int n = CheckCSRMaps(&DCtx);
if(n) {
return n-2000;
}
- Out = (QCBORTagListOut){0,16, puTags};
- QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRWithTags), QCBOR_DECODE_MODE_NORMAL);
+ Out = (QCBORTagListOut){0, 16, puTags};
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRWithTags),
+ QCBOR_DECODE_MODE_NORMAL);
const uint64_t puTagList[] = {773, 1, 90599561};
const QCBORTagListIn TagList = {3, puTagList};
@@ -2305,9 +2422,9 @@ int OptTagParseTest()
return -109;
}
if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
- !QCBORDecode_IsTagged(&DCtx, &Item, 4) ||
+ !QCBORDecode_IsTagged(&DCtx, &Item, 16) ||
Item.val.string.len != 9 ||
- puTags[0] != 4 ||
+ puTags[0] != 16 ||
puTags[11] != 0x0f ||
Out.uNumUsed != 12) {
return -110;
@@ -2429,13 +2546,15 @@ static uint8_t spBigNumInput[] = {
static uint8_t spBigNum[] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-int BignumParseTest()
+int32_t BignumParseTest()
{
QCBORDecodeContext DCtx;
QCBORItem Item;
int nCBORError;
- QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNumInput), QCBOR_DECODE_MODE_NORMAL);
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNumInput),
+ QCBOR_DECODE_MODE_NORMAL);
//
@@ -2507,7 +2626,12 @@ int BignumParseTest()
-static int CheckItemWithIntLabel(QCBORDecodeContext *pCtx, uint8_t uDataType, uint8_t uNestingLevel, uint8_t uNextNest, int64_t nLabel, QCBORItem *pItem)
+static int32_t CheckItemWithIntLabel(QCBORDecodeContext *pCtx,
+ uint8_t uDataType,
+ uint8_t uNestingLevel,
+ uint8_t uNextNest,
+ int64_t nLabel,
+ QCBORItem *pItem)
{
QCBORItem Item;
int nCBORError;
@@ -2515,7 +2639,10 @@ static int CheckItemWithIntLabel(QCBORDecodeContext *pCtx, uint8_t uDataType, ui
if((nCBORError = QCBORDecode_GetNext(pCtx, &Item))) return -1;
if(Item.uDataType != uDataType) return -1;
if(uNestingLevel > 0) {
- if(Item.uLabelType != QCBOR_TYPE_INT64 && Item.uLabelType != QCBOR_TYPE_UINT64) return -1;
+ if(Item.uLabelType != QCBOR_TYPE_INT64 &&
+ Item.uLabelType != QCBOR_TYPE_UINT64) {
+ return -1;
+ }
if(Item.uLabelType == QCBOR_TYPE_INT64) {
if(Item.label.int64 != nLabel) return -1;
} else {
@@ -2533,7 +2660,7 @@ static int CheckItemWithIntLabel(QCBORDecodeContext *pCtx, uint8_t uDataType, ui
// Same code checks definite and indefinite length versions of the map
-static int CheckCSRMaps(QCBORDecodeContext *pDC)
+static int32_t CheckCSRMaps(QCBORDecodeContext *pDC)
{
if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 0, 1, 0, NULL)) return -1;
@@ -2598,22 +2725,26 @@ static uint8_t spCSRInput[] = {
0x29, 0x4a, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
0x07, 0x08, 0x09, 0x0a, 0x35, 0xa1, 0x24, 0x22};
-int NestedMapTest()
+int32_t NestedMapTest()
{
QCBORDecodeContext DCtx;
- QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInput), QCBOR_DECODE_MODE_NORMAL);
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInput),
+ QCBOR_DECODE_MODE_NORMAL);
return CheckCSRMaps(&DCtx);
}
-int StringDecoderModeFailTest()
+int32_t StringDecoderModeFailTest()
{
QCBORDecodeContext DCtx;
- QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInput), QCBOR_DECODE_MODE_MAP_STRINGS_ONLY);
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInput),
+ QCBOR_DECODE_MODE_MAP_STRINGS_ONLY);
QCBORItem Item;
QCBORError nCBORError;
@@ -2647,11 +2778,13 @@ static uint8_t spCSRInputIndefLen[] = {
0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0xff, 0xff,
0x35, 0xbf, 0x24, 0x22, 0xff, 0xff};
-int NestedMapTestIndefLen()
+int32_t NestedMapTestIndefLen()
{
QCBORDecodeContext DCtx;
- QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInputIndefLen), QCBOR_DECODE_MODE_NORMAL);
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInputIndefLen),
+ QCBOR_DECODE_MODE_NORMAL);
return CheckCSRMaps(&DCtx);
}
@@ -2675,7 +2808,7 @@ static UsefulBufC make_nested_indefinite_arrays(int n, UsefulBuf Storage)
}
-static int parse_indeflen_nested(UsefulBufC Nested, int nNestLevel)
+static int32_t parse_indeflen_nested(UsefulBufC Nested, int nNestLevel)
{
QCBORDecodeContext DC;
QCBORDecode_Init(&DC, Nested, 0);
@@ -2709,7 +2842,7 @@ static int parse_indeflen_nested(UsefulBufC Nested, int nNestLevel)
}
-int IndefiniteLengthNestTest()
+int32_t IndefiniteLengthNestTest()
{
UsefulBuf_MAKE_STACK_UB(Storage, 50);
int i;
@@ -2724,15 +2857,20 @@ int IndefiniteLengthNestTest()
}
-
-static const uint8_t spIndefiniteArray[] = {0x9f, 0x01, 0x82, 0x02, 0x03, 0xff}; // [1, [2, 3]]
-static const uint8_t spIndefiniteArrayBad1[] = {0x9f}; // No closing break
-static const uint8_t spIndefiniteArrayBad2[] = {0x9f, 0x9f, 0x02, 0xff}; // Not enough closing breaks
-static const uint8_t spIndefiniteArrayBad3[] = {0x9f, 0x02, 0xff, 0xff}; // Too many closing breaks
-static const uint8_t spIndefiniteArrayBad4[] = {0x81, 0x9f}; // Unclosed indeflen inside def len
-static const uint8_t spIndefiniteArrayBad5[] = {0x9f, 0xd1, 0xff}; // confused tag
-
-int IndefiniteLengthArrayMapTest()
+// [1, [2, 3]]
+static const uint8_t spIndefiniteArray[] = {0x9f, 0x01, 0x82, 0x02, 0x03, 0xff};
+// No closing break
+static const uint8_t spIndefiniteArrayBad1[] = {0x9f};
+// Not enough closing breaks
+static const uint8_t spIndefiniteArrayBad2[] = {0x9f, 0x9f, 0x02, 0xff};
+// Too many closing breaks
+static const uint8_t spIndefiniteArrayBad3[] = {0x9f, 0x02, 0xff, 0xff};
+// Unclosed indeflen inside def len
+static const uint8_t spIndefiniteArrayBad4[] = {0x81, 0x9f};
+// confused tag
+static const uint8_t spIndefiniteArrayBad5[] = {0x9f, 0xd1, 0xff};
+
+int32_t IndefiniteLengthArrayMapTest()
{
int nResult;
// --- first test -----
@@ -2933,7 +3071,16 @@ static const uint8_t spIndefiniteLenStringLabel[] = {
0x01 // integer being labeled.
};
-static UsefulBufC MakeIndefiniteBigBstr(UsefulBuf Storage) // TODO: size this
+/**
+ Make an indefinite length string
+
+ @param Storage Storage for string, must be 144 bytes in size
+ @return The indefinite length string
+
+ This makes an array with one indefinite length string that has 7 chunks
+ from size of 1 byte up to 64 bytes.
+ */
+static UsefulBufC MakeIndefiniteBigBstr(UsefulBuf Storage)
{
UsefulOutBuf UOB;
@@ -2941,13 +3088,15 @@ static UsefulBufC MakeIndefiniteBigBstr(UsefulBuf Storage) // TODO: size this
UsefulOutBuf_AppendByte(&UOB, 0x81);
UsefulOutBuf_AppendByte(&UOB, 0x5f);
- int i = 0;
- for(int nChunkSize = 1; nChunkSize <= 128; nChunkSize *= 2) {
+ uint8_t uStringByte = 0;
+ // Use of type int is intentional
+ for(int uChunkSize = 1; uChunkSize <= 128; uChunkSize *= 2) {
+ // Not using preferred encoding here, but that is OK.
UsefulOutBuf_AppendByte(&UOB, 0x58);
- UsefulOutBuf_AppendByte(&UOB, (uint8_t)nChunkSize);
- for(int j = 0; j < nChunkSize; j++ ) {
- UsefulOutBuf_AppendByte(&UOB, i);
- i++;
+ UsefulOutBuf_AppendByte(&UOB, (uint8_t)uChunkSize);
+ for(int j = 0; j < uChunkSize; j++) {
+ UsefulOutBuf_AppendByte(&UOB, uStringByte);
+ uStringByte++;
}
}
UsefulOutBuf_AppendByte(&UOB, 0xff);
@@ -2970,7 +3119,7 @@ static int CheckBigString(UsefulBufC BigString)
}
-int IndefiniteLengthStringTest()
+int32_t IndefiniteLengthStringTest()
{
QCBORDecodeContext DC;
QCBORItem Item;
@@ -3003,7 +3152,9 @@ int IndefiniteLengthStringTest()
}
// ----- types mismatch ---
- QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringBad2), QCBOR_DECODE_MODE_NORMAL);
+ QCBORDecode_Init(&DC,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringBad2),
+ QCBOR_DECODE_MODE_NORMAL);
if(QCBORDecode_SetMemPool(&DC, MemPool, false)) {
return -7;
@@ -3021,7 +3172,9 @@ int IndefiniteLengthStringTest()
}
// ----- not a string ---
- QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringBad3), QCBOR_DECODE_MODE_NORMAL);
+ QCBORDecode_Init(&DC,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringBad3),
+ QCBOR_DECODE_MODE_NORMAL);
if(QCBORDecode_SetMemPool(&DC, MemPool, false)) {
return -11;
@@ -3039,7 +3192,9 @@ int IndefiniteLengthStringTest()
}
// ----- no end -----
- QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringBad4), QCBOR_DECODE_MODE_NORMAL);
+ QCBORDecode_Init(&DC,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringBad4),
+ QCBOR_DECODE_MODE_NORMAL);
if(QCBORDecode_SetMemPool(&DC, MemPool, false)) {
return -15;
@@ -3080,7 +3235,8 @@ int IndefiniteLengthStringTest()
UsefulBuf_MAKE_STACK_UB(BigIndefBStrStorage, 290);
const UsefulBufC BigIndefBStr = MakeIndefiniteBigBstr(BigIndefBStrStorage);
- UsefulBuf_MAKE_STACK_UB(MemPoolSmall, 80); // 80 is big enough for MemPool overhead, but not BigIndefBStr
+ // 80 is big enough for MemPool overhead, but not BigIndefBStr
+ UsefulBuf_MAKE_STACK_UB(MemPoolSmall, 80);
QCBORDecode_Init(&DC, BigIndefBStr, QCBOR_DECODE_MODE_NORMAL);
if(QCBORDecode_SetMemPool(&DC, MemPoolSmall, false)) {
@@ -3137,7 +3293,8 @@ int IndefiniteLengthStringTest()
if(QCBORDecode_GetNext(&DC, &Item)){
return -32;
}
- if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || Item.uDataType != QCBOR_TYPE_INT64 ||
+ if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+ Item.uDataType != QCBOR_TYPE_INT64 ||
Item.uDataAlloc || !Item.uLabelAlloc ||
UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("struuming"))) {
return -33;
@@ -3151,14 +3308,16 @@ int IndefiniteLengthStringTest()
}
-int AllocAllStringsTest()
+int32_t AllocAllStringsTest()
{
QCBORDecodeContext DC;
QCBORError nCBORError;
// First test, use the "CSRMap" as easy input and checking
- QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInput), QCBOR_DECODE_MODE_NORMAL);
+ QCBORDecode_Init(&DC,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInput),
+ QCBOR_DECODE_MODE_NORMAL);
UsefulBuf_MAKE_STACK_UB(Pool, sizeof(spCSRInput) + QCBOR_DECODE_MIN_MEM_POOL_SIZE);
@@ -3230,7 +3389,9 @@ int AllocAllStringsTest()
// Next parse with a pool that is too small
UsefulBuf_MAKE_STACK_UB(SmallPool, QCBOR_DECODE_MIN_MEM_POOL_SIZE + 1);
- QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), QCBOR_DECODE_MODE_NORMAL);
+ QCBORDecode_Init(&DC,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded),
+ QCBOR_DECODE_MODE_NORMAL);
QCBORDecode_SetMemPool(&DC, SmallPool, 1); // Turn on copying.
if((nCBORError = QCBORDecode_GetNext(&DC, &Item1)))
return -8;
@@ -3254,7 +3415,7 @@ int AllocAllStringsTest()
-int MemPoolTest(void)
+int32_t MemPoolTest(void)
{
// Set up the decoder with a tiny bit of CBOR to parse because
// nothing can be done with it unless that is set up.
@@ -3352,7 +3513,7 @@ static UsefulBuf AllocateTestFunction(void *pCtx, void *pOldMem, size_t uNewSize
}
-int SetUpAllocatorTest(void)
+int32_t SetUpAllocatorTest(void)
{
// Set up the decoder with a tiny bit of CBOR to parse because
// nothing can be done with it unless that is set up.
@@ -3385,3 +3546,235 @@ int SetUpAllocatorTest(void)
return 0;
}
+
+#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+/*
+ [
+ 4([-1, 3]),
+ 4([-20, 4759477275222530853136]),
+ 4([9223372036854775807, -4759477275222530853137]),
+ 5([300, 100]),
+ 5([-20, 4759477275222530853136]),
+ 5([-9223372036854775807, -4759477275222530853137])
+ 5([9223372036854775806, -4759477275222530853137])
+ 5([9223372036854775806, 9223372036854775806])]
+ ]
+ */
+
+static const uint8_t spExpectedExponentsAndMantissas[] = {
+ 0x87,
+ 0xC4, 0x82, 0x20,
+ 0x03,
+ 0xC4, 0x82, 0x33,
+ 0xC2, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10,
+ 0xC4, 0x82, 0x1B, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xC3, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10,
+ 0xC5, 0x82, 0x19, 0x01, 0x2C,
+ 0x18, 0x64,
+ 0xC5, 0x82, 0x33,
+ 0xC2, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10,
+ 0xC5, 0x82, 0x3B, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
+ 0xC3, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10,
+ 0xC5, 0x82, 0x1B, 0x7f, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
+ 0x1B, 0x7f, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE
+};
+
+int32_t ExponentAndMantissaDecodeTests(void)
+{
+ QCBORDecodeContext DC;
+ QCBORError nCBORError;
+ QCBORItem item;
+
+ static const uint8_t spBigNumMantissa[] = {0x01, 0x02, 0x03, 0x04, 0x05,
+ 0x06, 0x07, 0x08, 0x09, 0x010};
+ UsefulBufC BN = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNumMantissa);
+
+
+ QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedExponentsAndMantissas), QCBOR_DECODE_MODE_NORMAL);
+
+ nCBORError = QCBORDecode_GetNext(&DC, &item);
+ if(nCBORError != QCBOR_SUCCESS) {
+ return 1;
+ }
+
+ if(item.uDataType != QCBOR_TYPE_ARRAY) {
+ return 2;
+ }
+
+ nCBORError = QCBORDecode_GetNext(&DC, &item);
+ if(nCBORError != QCBOR_SUCCESS) {
+ return 3;
+ }
+
+ if(item.uDataType != QCBOR_TYPE_DECIMAL_FRACTION ||
+ item.val.expAndMantissa.Mantissa.nInt != 3 ||
+ item.val.expAndMantissa.nExponent != -1) {
+ return 4;
+ }
+
+ nCBORError = QCBORDecode_GetNext(&DC, &item);
+ if(nCBORError != QCBOR_SUCCESS) {
+ return 5;
+ }
+
+ if(item.uDataType != QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM ||
+ item.val.expAndMantissa.nExponent != -20 ||
+ UsefulBuf_Compare(item.val.expAndMantissa.Mantissa.bigNum, BN)) {
+ return 6;
+ }
+
+ nCBORError = QCBORDecode_GetNext(&DC, &item);
+ if(nCBORError != QCBOR_SUCCESS) {
+ return 7;
+ }
+
+ if(item.uDataType != QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM ||
+ item.val.expAndMantissa.nExponent != 9223372036854775807 ||
+ UsefulBuf_Compare(item.val.expAndMantissa.Mantissa.bigNum, BN)) {
+ return 8;
+ }
+
+ nCBORError = QCBORDecode_GetNext(&DC, &item);
+ if(nCBORError != QCBOR_SUCCESS) {
+ return 9;
+ }
+
+ if(item.uDataType != QCBOR_TYPE_BIGFLOAT ||
+ item.val.expAndMantissa.Mantissa.nInt != 100 ||
+ item.val.expAndMantissa.nExponent != 300) {
+ return 10;
+ }
+
+ nCBORError = QCBORDecode_GetNext(&DC, &item);
+ if(nCBORError != QCBOR_SUCCESS) {
+ return 11;
+ }
+
+ if(item.uDataType != QCBOR_TYPE_BIGFLOAT_POS_BIGNUM ||
+ item.val.expAndMantissa.nExponent != -20 ||
+ UsefulBuf_Compare(item.val.expAndMantissa.Mantissa.bigNum, BN)) {
+ return 12;
+ }
+
+ nCBORError = QCBORDecode_GetNext(&DC, &item);
+ if(nCBORError != QCBOR_SUCCESS) {
+ return 13;
+ }
+
+ if(item.uDataType != QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM ||
+ item.val.expAndMantissa.nExponent != -9223372036854775807 ||
+ UsefulBuf_Compare(item.val.expAndMantissa.Mantissa.bigNum, BN)) {
+ return 14;
+ }
+
+ nCBORError = QCBORDecode_GetNext(&DC, &item);
+ if(nCBORError != QCBOR_SUCCESS) {
+ return 15;
+ }
+
+ if(item.uDataType != QCBOR_TYPE_BIGFLOAT ||
+ item.val.expAndMantissa.nExponent != 9223372036854775806 ||
+ item.val.expAndMantissa.Mantissa.nInt!= 9223372036854775806 ) {
+ return 16;
+ }
+
+ /* Now encode some stuff and then decode it */
+ uint8_t pBuf[40];
+ QCBOREncodeContext EC;
+ UsefulBufC Encoded;
+
+ QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(pBuf));
+ QCBOREncode_OpenArray(&EC);
+ QCBOREncode_AddDecimalFraction(&EC, 999, 1000); // 999 * (10 ^ 1000)
+ QCBOREncode_AddBigFloat(&EC, 100, INT32_MIN);
+ QCBOREncode_AddDecimalFractionBigNum(&EC, BN, false, INT32_MAX);
+ QCBOREncode_CloseArray(&EC);
+ QCBOREncode_Finish(&EC, &Encoded);
+
+
+ QCBORDecode_Init(&DC, Encoded, QCBOR_DECODE_MODE_NORMAL);
+ nCBORError = QCBORDecode_GetNext(&DC, &item);
+ if(nCBORError != QCBOR_SUCCESS) {
+ return 13;
+ }
+
+ nCBORError = QCBORDecode_GetNext(&DC, &item);
+ if(nCBORError != QCBOR_SUCCESS) {
+ return 13;
+ }
+
+ if(item.uDataType != QCBOR_TYPE_DECIMAL_FRACTION ||
+ item.val.expAndMantissa.nExponent != 1000 ||
+ item.val.expAndMantissa.Mantissa.nInt != 999) {
+ return 15;
+ }
+
+ nCBORError = QCBORDecode_GetNext(&DC, &item);
+ if(nCBORError != QCBOR_SUCCESS) {
+ return 13;
+ }
+
+ if(item.uDataType != QCBOR_TYPE_BIGFLOAT ||
+ item.val.expAndMantissa.nExponent != INT32_MIN ||
+ item.val.expAndMantissa.Mantissa.nInt != 100) {
+ return 15;
+ }
+
+ nCBORError = QCBORDecode_GetNext(&DC, &item);
+ if(nCBORError != QCBOR_SUCCESS) {
+ return 13;
+ }
+
+ if(item.uDataType != QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM ||
+ item.val.expAndMantissa.nExponent != INT32_MAX ||
+ UsefulBuf_Compare(item.val.expAndMantissa.Mantissa.bigNum, BN)) {
+ return 12;
+ }
+
+ return 0;
+}
+
+
+static struct FailInput ExponentAndMantissaFailures[] = {
+ // Exponent > INT64_MAX
+ { {(uint8_t[]){0xC4, 0x82, 0x1B, 0x7f, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0x1B, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF,}, 20}, QCBOR_ERR_BAD_EXP_AND_MANTISSA},
+ // Mantissa > INT64_MAX
+ { {(uint8_t[]){0xC4, 0x82, 0x1B, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xC3, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05,
+ 0x06, 0x07, 0x08, 0x09, 0x10}, 23}, QCBOR_ERR_BAD_EXP_AND_MANTISSA},
+ // End of input
+ { {(uint8_t[]){0xC4, 0x82}, 2}, QCBOR_ERR_HIT_END},
+ // End of input
+ { {(uint8_t[]){0xC4, 0x82, 0x01}, 3}, QCBOR_ERR_HIT_END},
+ // bad content for big num
+ { {(uint8_t[]){0xC4, 0x82, 0x01, 0xc3, 0x01}, 5}, QCBOR_ERR_BAD_OPT_TAG},
+ // bad content for big num
+ { {(uint8_t[]){0xC4, 0x82, 0xc2, 0x01, 0x1f}, 5}, QCBOR_ERR_BAD_INT},
+ // Bad integer for exponent
+ { {(uint8_t[]){0xC4, 0x82, 0x01, 0x1f}, 4}, QCBOR_ERR_BAD_INT},
+ // Bad integer for mantissa
+ { {(uint8_t[]){0xC4, 0x82, 0x1f, 0x01}, 4}, QCBOR_ERR_BAD_INT},
+ // 3 items in array
+ { {(uint8_t[]){0xC4, 0x83, 0x03, 0x01, 02}, 5}, QCBOR_ERR_BAD_EXP_AND_MANTISSA},
+ // unterminated indefinite length array
+ { {(uint8_t[]){0xC4, 0x9f, 0x03, 0x01, 0x02}, 5}, QCBOR_ERR_BAD_EXP_AND_MANTISSA},
+ // Empty array
+ { {(uint8_t[]){0xC4, 0x80}, 2}, QCBOR_ERR_NO_MORE_ITEMS},
+ // Second is not an integer
+ { {(uint8_t[]){0xC4, 0x82, 0x03, 0x40}, 4}, QCBOR_ERR_BAD_EXP_AND_MANTISSA},
+ // First is not an integer
+ { {(uint8_t[]){0xC4, 0x82, 0x40}, 3}, QCBOR_ERR_BAD_EXP_AND_MANTISSA},
+ // Not an array
+ { {(uint8_t[]){0xC4, 0xa2}, 2}, QCBOR_ERR_BAD_EXP_AND_MANTISSA}
+};
+
+
+int32_t ExponentAndMantissaDecodeFailTests()
+{
+ return ProcessFailures(ExponentAndMantissaFailures,
+ sizeof(ExponentAndMantissaFailures)/sizeof(struct FailInput));
+}
+
+#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
diff --git a/lib/ext/qcbor/test/qcbor_decode_tests.h b/lib/ext/qcbor/test/qcbor_decode_tests.h
index 6423ccff33..e87490e9b4 100644
--- a/lib/ext/qcbor/test/qcbor_decode_tests.h
+++ b/lib/ext/qcbor/test/qcbor_decode_tests.h
@@ -1,6 +1,6 @@
/*==============================================================================
Copyright (c) 2016-2018, The Linux Foundation.
- Copyright (c) 2018-2019, Laurence Lundblade.
+ Copyright (c) 2018-2020, Laurence Lundblade.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -28,11 +28,12 @@ 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.
- ==============================================================================*/
+ ============================================================================*/
#ifndef __QCBOR__qcbort_decode_tests__
#define __QCBOR__qcbort_decode_tests__
+#include <stdint.h>
/*
Notes:
@@ -51,20 +52,20 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Parse a well-known set of integers including those around the boundaries and
make sure the expected values come out
*/
-int IntegerValuesParseTest(void);
+int32_t IntegerValuesParseTest(void);
/*
Decode a simple CBOR encoded array and make sure it returns all the correct values.
This is a decode test.
*/
-int SimpleArrayTest(void);
+int32_t SimpleArrayTest(void);
/*
Tests with empty maps and arrays
*/
-int EmptyMapsAndArraysTest(void);
+int32_t EmptyMapsAndArraysTest(void);
/*
@@ -72,21 +73,21 @@ int EmptyMapsAndArraysTest(void);
reported nesting level is correct. This uses test vector
of CBOR encoded data with a depth of 10. This a parse test.
*/
-int ParseDeepArrayTest(void);
+int32_t ParseDeepArrayTest(void);
/*
See that the correct error is reported when parsing
an array of depth 11, one too large.
*/
-int ParseTooDeepArrayTest(void);
+int32_t ParseTooDeepArrayTest(void);
/*
Try to parse some legit CBOR types that this parsers
doesn't support.
*/
-int UnsupportedCBORDecodeTest(void);
+int32_t UnsupportedCBORDecodeTest(void);
/*
@@ -94,33 +95,33 @@ int UnsupportedCBORDecodeTest(void);
it over and over with one more byte less each time. It should fail
every time on incorrect CBOR input. This is a hostile input decode test.
*/
-int ShortBufferParseTest(void);
+int32_t ShortBufferParseTest(void);
/*
Same as ShortBufferParseTest, but with a different encoded CBOR input.
It is another hostile input test
*/
-int ShortBufferParseTest2(void);
+int32_t ShortBufferParseTest2(void);
/*
Parses the somewhat complicated CBOR MAP and makes sure all the correct
values parse out. About 15 values are tested. This is a decode test.
*/
-int ParseMapTest(void);
+int32_t ParseMapTest(void);
/*
Test the decoder mode where maps are treated as arrays.
*/
-int ParseMapAsArrayTest(void);
+int32_t ParseMapAsArrayTest(void);
/*
Test parsing of some simple values like true, false, null...
*/
-int ParseSimpleTest(void);
+int32_t ParseSimpleTest(void);
/*
@@ -128,13 +129,13 @@ int ParseSimpleTest(void);
(This is the CBORbis RFC which is not yet published at the
time this test was added).
*/
-int NotWellFormedTests(void);
+int32_t NotWellFormedTests(void);
/*
Tests a number of failure cases on bad CBOR to get the right error code
*/
-int DecodeFailureTests(void);
+int32_t DecodeFailureTests(void);
/*
@@ -145,7 +146,7 @@ int DecodeFailureTests(void);
(Parsing all possible 3 byte strings takes too long on all but
very fast machines).
*/
-int ComprehensiveInputTest(void);
+int32_t ComprehensiveInputTest(void);
/*
@@ -155,64 +156,64 @@ int ComprehensiveInputTest(void);
is only practical as a once-in-a-while regression test on
fast machines.
*/
-int BigComprehensiveInputTest(void);
+int32_t BigComprehensiveInputTest(void);
/*
Thest the date types -- epoch and strings
*/
-int DateParseTest(void);
+int32_t DateParseTest(void);
/*
Test optional tags like the CBOR magic number.
*/
-int OptTagParseTest(void);
+int32_t OptTagParseTest(void);
/*
Parse some big numbers, positive and negative
*/
-int BignumParseTest(void);
+int32_t BignumParseTest(void);
/*
Test of mode where only string labels are allowed
*/
-int StringDecoderModeFailTest(void);
+int32_t StringDecoderModeFailTest(void);
/*
Parse some nested maps
*/
-int NestedMapTest(void);
+int32_t NestedMapTest(void);
/*
Parse maps with indefinite lengths
*/
-int NestedMapTestIndefLen(void);
+int32_t NestedMapTestIndefLen(void);
/*
Parse some maps and arrays with indefinite lengths.
Includes some error cases.
*/
-int IndefiniteLengthArrayMapTest(void);
+int32_t IndefiniteLengthArrayMapTest(void);
/*
Parse indefinite length strings. Uses
MemPool. Includes error cases.
*/
-int IndefiniteLengthStringTest(void);
+int32_t IndefiniteLengthStringTest(void);
/*
Test deep nesting of indefinite length
maps and arrays including too deep.
*/
-int IndefiniteLengthNestTest(void);
+int32_t IndefiniteLengthNestTest(void);
/*
@@ -220,19 +221,34 @@ int IndefiniteLengthNestTest(void);
just indefinite length strings, are
allocated. Includes error test cases.
*/
-int AllocAllStringsTest(void);
+int32_t AllocAllStringsTest(void);
/*
Direct test of MemPool string allocator
*/
-int MemPoolTest(void);
+int32_t MemPoolTest(void);
/*
Test the setting up of an external string allocator.
*/
-int SetUpAllocatorTest(void);
+int32_t SetUpAllocatorTest(void);
+
+
+#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+/*
+ Test decoding of decimal fractions and big floats, both of which are
+ made up of an exponent and mantissa.
+ */
+int32_t ExponentAndMantissaDecodeTests(void);
+
+
+/*
+ Hostile input tests for decimal fractions and big floats.
+ */
+int32_t ExponentAndMantissaDecodeFailTests(void);
+#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
#endif /* defined(__QCBOR__qcbort_decode_tests__) */
diff --git a/lib/ext/qcbor/test/qcbor_encode_tests.c b/lib/ext/qcbor/test/qcbor_encode_tests.c
index 7866b375f0..9ef596fafc 100644
--- a/lib/ext/qcbor/test/qcbor_encode_tests.c
+++ b/lib/ext/qcbor/test/qcbor_encode_tests.c
@@ -1,6 +1,6 @@
/*==============================================================================
Copyright (c) 2016-2018, The Linux Foundation.
- Copyright (c) 2018-2019, Laurence Lundblade.
+ Copyright (c) 2018-2020, Laurence Lundblade.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -28,7 +28,7 @@ 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.
- ==============================================================================*/
+ =============================================================================*/
#include "qcbor.h"
#include "qcbor_encode_tests.h"
@@ -47,11 +47,12 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-//#define PRINT_FUNCTIONS_FOR_DEBUGGINGXX
+//#define PRINT_FUNCTIONS_FOR_DEBUGGING
-#ifdef PRINT_FUNCTIONS_FOR_DEBUGGINGXX
+#ifdef PRINT_FUNCTIONS_FOR_DEBUGGING
#include <stdio.h>
+#if 0
// ifdef these out to not have compiler warnings
static void printencoded(const uint8_t *pEncoded, size_t nLen)
{
@@ -64,6 +65,7 @@ static void printencoded(const uint8_t *pEncoded, size_t nLen)
fflush(stdout);
}
+#endif
// Do the comparison and print out where it fails
@@ -71,7 +73,10 @@ static int UsefulBuf_Compare_Print(UsefulBufC U1, UsefulBufC U2) {
size_t i;
for(i = 0; i < U1.len; i++) {
if(((uint8_t *)U1.ptr)[i] != ((uint8_t *)U2.ptr)[i]) {
- printf("Position: %d Actual: 0x%x Expected: 0x%x\n", i, ((uint8_t *)U1.ptr)[i], ((uint8_t *)U2.ptr)[i]);
+ printf("Position: %d Actual: 0x%x Expected: 0x%x\n",
+ (uint32_t)i,
+ ((uint8_t *)U1.ptr)[i],
+ ((uint8_t *)U2.ptr)[i]);
return 1;
}
}
@@ -90,6 +95,42 @@ static int UsefulBuf_Compare_Print(UsefulBufC U1, UsefulBufC U2) {
#endif
+#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+/*
+ Returns 0 if UsefulBufs are equal
+ Returns 1000000 + offeset if they are not equal.
+
+
+
+*/
+struct UBCompareDiagnostic {
+ uint8_t uActual;
+ uint8_t uExpected;
+ size_t uOffset;
+};
+
+static int32_t
+UsefulBuf_CompareWithDiagnostic(UsefulBufC Actual,
+ UsefulBufC Expected,
+ struct UBCompareDiagnostic *pDiag) {
+ size_t i;
+ for(i = 0; i < Actual.len; i++) {
+ if(((uint8_t *)Actual.ptr)[i] != ((uint8_t *)Expected.ptr)[i]) {
+ if(pDiag) {
+ pDiag->uActual = ((uint8_t *)Actual.ptr)[i];
+ pDiag->uExpected = ((uint8_t *)Expected.ptr)[i];
+ pDiag->uOffset = i;
+ }
+ // Cast to int is OK as this is only a diagnostic and the sizes
+ // here are never over a few KB.
+ return (int32_t)i + 1000000;
+ }
+ }
+ return 0;
+
+}
+#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+
// One big buffer that is used by all the tests to encode into
// Putting it in uninitialized data is better than using a lot
@@ -101,7 +142,7 @@ static uint8_t spBigBuf[2200];
/*
Some very minimal tests.
*/
-int BasicEncodeTest()
+int32_t BasicEncodeTest()
{
// Very simple CBOR, a map with one boolean that is true in it
QCBOREncodeContext EC;
@@ -138,7 +179,8 @@ int BasicEncodeTest()
}
- // Make another encoded message with the CBOR from the previous put into this one
+ // Make another encoded message with the CBOR from the previous
+ // put into this one
UsefulBuf_MAKE_STACK_UB(MemoryForEncoded2, 20);
QCBOREncode_Init(&EC, MemoryForEncoded2);
QCBOREncode_OpenArray(&EC);
@@ -215,7 +257,10 @@ int BasicEncodeTest()
// 2 1:1 2:1 3:1
QCBORDecode_GetNext(&DC, &Item);
- if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 1 || Item.uLabelType != QCBOR_TYPE_INT64 || Item.label.int64 != -70000) {
+ if(Item.uDataType != QCBOR_TYPE_MAP ||
+ Item.val.uCount != 1 ||
+ Item.uLabelType != QCBOR_TYPE_INT64 ||
+ Item.label.int64 != -70000) {
return -11;
}
@@ -466,9 +511,10 @@ this is the attachment text\n\
--XXXXboundary text--";
-int AllAddMethodsTest()
+int32_t AllAddMethodsTest()
{
- // TODO: this test should be broken down into several so it is more managable. Tags and labels could be more sensible
+ // TODO: this test should be broken down into several so it is more
+ // managable. Tags and labels could be more sensible
QCBOREncodeContext ECtx;
int nReturn = 0;
@@ -476,7 +522,8 @@ int AllAddMethodsTest()
QCBOREncode_OpenArray(&ECtx);
- // Some ints that are tagged and have strings preceeding them (not labels becase it is not a map)
+ // Some ints that are tagged and have strings preceeding them
+ // (not labels becase it is not a map)
QCBOREncode_AddSZString(&ECtx, "UINT62");
QCBOREncode_AddTag(&ECtx, 100);
QCBOREncode_AddUInt64(&ECtx, 89989909);
@@ -519,7 +566,9 @@ int AllAddMethodsTest()
// text blobs
QCBOREncode_AddText(&ECtx, UsefulBuf_FROM_SZ_LITERAL("bar bar foo bar"));
QCBOREncode_AddSZString(&ECtx, "oof\n");
- QCBOREncode_AddURI(&ECtx, UsefulBuf_FROM_SZ_LITERAL("http://stackoverflow.com/questions/28059697/how-do-i-toggle-between-debug-and-release-builds-in-xcode-6-7-8"));
+ const char *szURL =
+ "http://stackoverflow.com/questions/28059697/how-do-i-toggle-between-debug-and-release-builds-in-xcode-6-7-8";
+ QCBOREncode_AddURI(&ECtx, UsefulBuf_FromSZ(szURL));
QCBOREncode_AddB64Text(&ECtx, UsefulBuf_FROM_SZ_LITERAL("YW55IGNhcm5hbCBwbGVhc3VyZQ=="));
QCBOREncode_AddRegex(&ECtx, UsefulBuf_FROM_SZ_LITERAL("[^abc]+"));
QCBOREncode_AddMIMEData(&ECtx, UsefulBuf_FromSZ(szMIME));
@@ -534,7 +583,9 @@ int AllAddMethodsTest()
QCBOREncode_AddTextToMapN(&ECtx,22, UsefulBuf_FROM_SZ_LITERAL("foo foo foo foo"));
QCBOREncode_AddSZStringToMap(&ECtx, "^^", "oooooooof");
QCBOREncode_AddSZStringToMapN(&ECtx, 99, "ffffoooooooof");
- QCBOREncode_AddURIToMap(&ECtx, "RFC", UsefulBuf_FROM_SZ_LITERAL("https://tools.ietf.org/html/rfc7049#section-2.4.5"));
+ QCBOREncode_AddURIToMap(&ECtx,
+ "RFC",
+ UsefulBuf_FROM_SZ_LITERAL("https://tools.ietf.org/html/rfc7049#section-2.4.5"));
QCBOREncode_AddURIToMapN(&ECtx, 0x89, UsefulBuf_FROM_SZ_LITERAL("http://cbor.me/"));
QCBOREncode_AddB64TextToMap(&ECtx, "whenim64", UsefulBuf_FROM_SZ_LITERAL("cGxlYXN1cmUu"));
QCBOREncode_AddB64TextToMapN(&ECtx, 64, UsefulBuf_FROM_SZ_LITERAL("c3VyZS4="));
@@ -608,7 +659,9 @@ int AllAddMethodsTest()
QCBOREncode_CloseMap(&ECtx);
// UUIDs
- static const uint8_t ppppUUID[] = {0x53, 0x4D, 0x41, 0x52, 0x54, 0x43, 0x53, 0x4C, 0x54, 0x54, 0x43, 0x46, 0x49, 0x43, 0x41, 0x32};
+ static const uint8_t ppppUUID[] = {0x53, 0x4D, 0x41, 0x52, 0x54, 0x43,
+ 0x53, 0x4C, 0x54, 0x54, 0x43, 0x46,
+ 0x49, 0x43, 0x41, 0x32};
const UsefulBufC XXUUID = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(ppppUUID);
QCBOREncode_AddBinaryUUID(&ECtx, XXUUID);
QCBOREncode_OpenMap(&ECtx);
@@ -738,7 +791,7 @@ static const uint8_t spExpectedEncodedInts[] = {
to expected values generated from http://cbor.me.
*/
-int IntegerValuesTest1()
+int32_t IntegerValuesTest1()
{
QCBOREncodeContext ECtx;
int nReturn = 0;
@@ -823,7 +876,7 @@ int IntegerValuesTest1()
static const uint8_t spExpectedEncodedSimple[] = {
0x85, 0xf5, 0xf4, 0xf6, 0xf7, 0xa1, 0x65, 0x55, 0x4e, 0x44, 0x65, 0x66, 0xf7};
-int SimpleValuesTest1()
+int32_t SimpleValuesTest1()
{
QCBOREncodeContext ECtx;
int nReturn = 0;
@@ -870,7 +923,7 @@ int SimpleValuesTest1()
static const uint8_t spExpectedEncodedSimpleIndefiniteLength[] = {
0x9f, 0xf5, 0xf4, 0xf6, 0xf7, 0xbf, 0x65, 0x55, 0x4e, 0x44, 0x65, 0x66, 0xf7, 0xff, 0xff};
-int SimpleValuesIndefiniteLengthTest1()
+int32_t SimpleValuesIndefiniteLengthTest1()
{
QCBOREncodeContext ECtx;
int nReturn = 0;
@@ -1065,7 +1118,7 @@ static const uint8_t EncodeLengthThirtyone[] = {
0x31
};
-int EncodeLengthThirtyoneTest()
+int32_t EncodeLengthThirtyoneTest()
{
QCBOREncodeContext ECtx;
int nReturn = 0;
@@ -1076,18 +1129,18 @@ int EncodeLengthThirtyoneTest()
// add array with 31 items
QCBOREncode_OpenArrayInMap(&ECtx, "arr");
for (size_t ix = 0; ix < 31; ix++) {
- QCBOREncode_AddInt64(&ECtx, ix);
+ QCBOREncode_AddInt64(&ECtx, (int64_t)ix);
}
QCBOREncode_CloseArray(&ECtx);
// add map with 31 items
QCBOREncode_OpenMapInMap(&ECtx, "map");
- for (size_t ix = 0; ix < 31; ix++) {
+ for (int ix = 0; ix < 31; ix++) {
// make sure we have unique keys in the map (a-z then follow by A-Z)
- char c = 'a';
+ int c = 'a';
if (ix < 26) c = c + ix;
else c = 'A' + (ix - 26);
- char buffer[2] = { c, 0 };
+ char buffer[2] = { (char)c, 0 };
QCBOREncode_AddInt64ToMap(&ECtx, buffer, ix);
}
QCBOREncode_CloseMap(&ECtx);
@@ -1145,7 +1198,7 @@ static const uint8_t spExpectedEncodedDates[] = {
0x32, 0x5a, 0x62, 0x53, 0x44, 0xc1, 0x19, 0x03, 0xe7
};
-int EncodeDateTest()
+int32_t EncodeDateTest()
{
QCBOREncodeContext ECtx;
int nReturn = 0;
@@ -1182,7 +1235,7 @@ int EncodeDateTest()
}
-int ArrayNestingTest1()
+int32_t ArrayNestingTest1()
{
QCBOREncodeContext ECtx;
int i;
@@ -1205,7 +1258,7 @@ int ArrayNestingTest1()
-int ArrayNestingTest2()
+int32_t ArrayNestingTest2()
{
QCBOREncodeContext ECtx;
int i;
@@ -1229,7 +1282,7 @@ int ArrayNestingTest2()
-int ArrayNestingTest3()
+int32_t ArrayNestingTest3()
{
QCBOREncodeContext ECtx;
int i;
@@ -1346,7 +1399,7 @@ static const uint8_t spEncodeRawExpected[] = {
0xff, 0xff};
-int EncodeRawTest()
+int32_t EncodeRawTest()
{
QCBOREncodeContext ECtx;
@@ -1372,7 +1425,7 @@ int EncodeRawTest()
/*
This returns a pointer to spBigBuf
*/
-static int CreateMap(uint8_t **pEncoded, size_t *pEncodedLen)
+static int32_t CreateMap(uint8_t **pEncoded, size_t *pEncodedLen)
{
QCBOREncodeContext ECtx;
int nReturn = -1;
@@ -1469,7 +1522,7 @@ static const uint8_t spValidMapEncoded[] = {
0x73 } ;
-int MapEncodeTest()
+int32_t MapEncodeTest()
{
uint8_t *pEncodedMaps;
size_t nEncodedMapLen;
@@ -1489,11 +1542,13 @@ int MapEncodeTest()
/*
@brief Encode the RTIC results
- @param[in] nRResult CBOR_SIMPLEV_TRUE, CBOR_SIMPLEV_FALSE or CBOR_SIMPLEV_NULL
- @param[in] time Time stamp in UNIX epoch time or 0 for no time stamp
+ @param[in] nRResult CBOR_SIMPLEV_TRUE, CBOR_SIMPLEV_FALSE or
+ CBOR_SIMPLEV_NULL
+ @param[in] time Time stamp in UNIX epoch time or 0 for none
@param[in] szAlexString Diagnostic code.
@param[in[ pOut Buffer to put the result in
- @param[in/out] pnLen Size of pOut buffer when called; length of data output in buffer on return
+ @param[in/out] pnLen Size of pOut buffer when called; length of data
+ output in buffer on return
@return
One of the CBOR encoder errors. QCBOR_SUCCESS, which is has value 0, if no error.
@@ -1507,11 +1562,17 @@ int MapEncodeTest()
*/
-static UsefulBufC FormatRTICResults(int nRResult, uint64_t time, const char *szType, const char *szAlexString, UsefulBuf Storage)
+static UsefulBufC
+FormatRTICResults(uint8_t uRResult,
+ int64_t time,
+ const char *szType,
+ const char *szAlexString,
+ UsefulBuf Storage)
{
// Buffer that the result will be written in to
// It is fixed size and small that a stack variable will be fine
- // QCBOREncode will never write off the end of this buffer. If it won't fit QCBOREncode_Finish will return an error.
+ // QCBOREncode will never write off the end of this buffer. If it won't
+ // fit QCBOREncode_Finish will return an error.
// Context for the encoder
QCBOREncodeContext ECtx;
@@ -1523,8 +1584,9 @@ static UsefulBufC FormatRTICResults(int nRResult, uint64_t time, const char *szT
{ // Brace / indention just to show CBOR encoding nesting
- // The result: 0 if scan happened and found nothing; 1 if it happened and found something wrong; 2 if it didn't happen
- QCBOREncode_AddSimpleToMap(&ECtx, "integrity", nRResult);
+ // The result: 0 if scan happened and found nothing; 1 if it happened and
+ // found something wrong; 2 if it didn't happen
+ QCBOREncode_AddSimpleToMap(&ECtx, "integrity", uRResult);
// Add the diagnostic code
QCBOREncode_AddSZStringToMap(&ECtx, "type", szType);
@@ -1616,7 +1678,7 @@ static const uint8_t spExpectedRTIC[] = {
0xaa, 0xbb, 0x01, 0x01};
-int RTICResultsTest()
+int32_t RTICResultsTest()
{
const UsefulBufC Encoded = FormatRTICResults(CBOR_SIMPLEV_FALSE, 1477263730,
"recent", "0xA1eC5001",
@@ -1652,7 +1714,7 @@ static const uint8_t spExpectedTypeAndLen[] = {0x81, 0x58, 0x25};
/*
Very basic bstr wrapping test
*/
-int BstrWrapTest()
+int32_t BstrWrapTest()
{
QCBOREncodeContext EC;
@@ -1690,7 +1752,8 @@ int BstrWrapTest()
QCBOREncode_CloseArray(&EC);
UsefulBufC BStr;
QCBOREncode_CloseBstrWrap(&EC, &BStr);
- // 3 is one byte for the wrapping bstr, 1 for an array of length 1, and 1 byte for a NULL
+ // 3 is one byte for the wrapping bstr, 1 for an array of length 1,
+ // and 1 byte for a NULL
if(BStr.ptr != NULL || BStr.len != 3) {
return -5;
}
@@ -1714,9 +1777,9 @@ int BstrWrapTest()
-int BstrWrapErrorTest()
+int32_t BstrWrapErrorTest()
{
- // -------------- Test closing a bstrwrap when it is an array that is open -----------
+ // ---- Test closing a bstrwrap when it is an array that is open ---------
QCBOREncodeContext EC;
QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
@@ -1738,7 +1801,7 @@ int BstrWrapErrorTest()
return -1;
}
- // ----------- test closing a bstrwrap when nothing is open ---------------------
+ // -------- test closing a bstrwrap when nothing is open ----------------
QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
QCBOREncode_CloseBstrWrap(&EC, &Wrapped);
if(QCBOREncode_Finish(&EC, &Encoded2) != QCBOR_ERR_TOO_MANY_CLOSES) {
@@ -1879,7 +1942,7 @@ static int DecodeNextNested(UsefulBufC Wrapped)
}
// Part of bstr_wrap_nest_test
-static int DecodeNextNested2(UsefulBufC Wrapped)
+static int32_t DecodeNextNested2(UsefulBufC Wrapped)
{
int nReturn;
QCBORDecodeContext DC;
@@ -1945,7 +2008,7 @@ static int DecodeNextNested2(UsefulBufC Wrapped)
}
-int BstrWrapNestTest()
+int32_t BstrWrapNestTest()
{
QCBOREncodeContext EC;
QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
@@ -1957,24 +2020,24 @@ int BstrWrapNestTest()
for(int i = 0; i < BSTR_TEST_DEPTH-2; i++) {
QCBOREncode_BstrWrap(&EC);
- QCBOREncode_AddUInt64(&EC, i);
+ QCBOREncode_AddInt64(&EC, i);
}
for(int i = 0; i < BSTR_TEST_DEPTH-2; i++) {
QCBOREncode_CloseBstrWrap(&EC, NULL);
- QCBOREncode_AddUInt64(&EC, i);
+ QCBOREncode_AddInt64(&EC, i);
}
for(int i = 0; i < (BSTR_TEST_DEPTH-2)/3; i++) {
QCBOREncode_OpenMap(&EC);
QCBOREncode_BstrWrapInMapN(&EC, i+0x20);
QCBOREncode_OpenArray(&EC);
- QCBOREncode_AddUInt64(&EC, i+0x10);
+ QCBOREncode_AddInt64(&EC, i+0x10);
}
for(int i = 0; i < (BSTR_TEST_DEPTH-2)/3; i++) {
QCBOREncode_CloseArray(&EC);
- QCBOREncode_AddUInt64(&EC, i+0x30);
+ QCBOREncode_AddInt64(&EC, i+0x30);
QCBOREncode_CloseBstrWrap(&EC, NULL);
QCBOREncode_AddSZStringToMapN(&EC, i+0x40, "hello");
QCBOREncode_CloseMap(&EC);
@@ -2101,7 +2164,7 @@ static const uint8_t pProtectedHeaders[] = {0xa1, 0x01, 0x26};
be nice as it would make the test really good. That would require
bring in ECDSA crypto to this test.
*/
-int CoseSign1TBSTest()
+int32_t CoseSign1TBSTest()
{
// All of this is from RFC 8152 C.2.1
const char *szKid = "11";
@@ -2167,13 +2230,14 @@ int CoseSign1TBSTest()
}
-int EncodeErrorTests()
+int32_t EncodeErrorTests()
{
QCBOREncodeContext EC;
// ------ Test for QCBOR_ERR_BUFFER_TOO_LARGE ------
- // Do all of these tests with NULL buffers so no actual large allocations are neccesary
+ // Do all of these tests with NULL buffers so no actual
+ // large allocations are neccesary
const UsefulBuf Buffer = (UsefulBuf){NULL, UINT32_MAX};
// First verify no error from a big buffer
@@ -2331,3 +2395,204 @@ int EncodeErrorTests()
return 0;
}
+
+
+#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+/*
+ [
+ 4([-1, 3]),
+ 4([-20, 4759477275222530853136]),
+ 4([9223372036854775807, -4759477275222530853137]),
+ 5([300, 100]),
+ 5([-20, 4759477275222530853136]),
+ 5([-9223372036854775808, -4759477275222530853137])
+ ]
+ */
+static const uint8_t spExpectedExponentAndMantissaArray[] = {
+ 0x86, 0xC4, 0x82, 0x20, 0x03, 0xC4, 0x82, 0x33,
+ 0xC2, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x07, 0x08, 0x09, 0x10, 0xC4, 0x82, 0x1B, 0x7F,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3,
+ 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x10, 0xC5, 0x82, 0x19, 0x01, 0x2C,
+ 0x18, 0x64, 0xC5, 0x82, 0x33, 0xC2, 0x4A, 0x01,
+ 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
+ 0x10, 0xC5, 0x82, 0x3B, 0x7F, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0x4A, 0x01, 0x02,
+ 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10};
+
+
+/*
+ {
+ "decimal fraction": 4([-1, 3]),
+ 300: 4([-1, 3]),
+ "decimal fraction bignum postive": 4([-200, 4759477275222530853136]),
+ 400: 4([2147483647, 4759477275222530853136]),
+ "decimal fraction bignum negative": 4([9223372036854775807, -4759477275222530853137]),
+ 500: 4([9223372036854775807, -4759477275222530853137]),
+ "big float": 5([300, 100]),
+ 600: 5([300, 100]),
+ "big float bignum positive": 5([-20, 4759477275222530853136]),
+ 700: 5([-20, 4759477275222530853136]),
+ "big float bignum negative": 5([-9223372036854775808, -4759477275222530853137]),
+ 800: 5([-9223372036854775808, -4759477275222530853137])
+ }
+ */
+static const uint8_t spExpectedExponentAndMantissaMap[] = {
+ 0xAC, 0x70, 0x64, 0x65, 0x63, 0x69, 0x6D, 0x61,
+ 0x6C, 0x20, 0x66, 0x72, 0x61, 0x63, 0x74, 0x69,
+ 0x6F, 0x6E, 0xC4, 0x82, 0x20, 0x03, 0x19, 0x01,
+ 0x2C, 0xC4, 0x82, 0x20, 0x03, 0x78, 0x1F, 0x64,
+ 0x65, 0x63, 0x69, 0x6D, 0x61, 0x6C, 0x20, 0x66,
+ 0x72, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20,
+ 0x62, 0x69, 0x67, 0x6E, 0x75, 0x6D, 0x20, 0x70,
+ 0x6F, 0x73, 0x74, 0x69, 0x76, 0x65, 0xC4, 0x82,
+ 0x38, 0xC7, 0xC2, 0x4A, 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x19, 0x01,
+ 0x90, 0xC4, 0x82, 0x1A, 0x7F, 0xFF, 0xFF, 0xFF,
+ 0xC2, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x07, 0x08, 0x09, 0x10, 0x78, 0x20, 0x64, 0x65,
+ 0x63, 0x69, 0x6D, 0x61, 0x6C, 0x20, 0x66, 0x72,
+ 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x62,
+ 0x69, 0x67, 0x6E, 0x75, 0x6D, 0x20, 0x6E, 0x65,
+ 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0xC4, 0x82,
+ 0x1B, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xC3, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05,
+ 0x06, 0x07, 0x08, 0x09, 0x10, 0x19, 0x01, 0xF4,
+ 0xC4, 0x82, 0x1B, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xC3, 0x4A, 0x01, 0x02, 0x03,
+ 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x69,
+ 0x62, 0x69, 0x67, 0x20, 0x66, 0x6C, 0x6F, 0x61,
+ 0x74, 0xC5, 0x82, 0x19, 0x01, 0x2C, 0x18, 0x64,
+ 0x19, 0x02, 0x58, 0xC5, 0x82, 0x19, 0x01, 0x2C,
+ 0x18, 0x64, 0x78, 0x19, 0x62, 0x69, 0x67, 0x20,
+ 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x20, 0x62, 0x69,
+ 0x67, 0x6E, 0x75, 0x6D, 0x20, 0x70, 0x6F, 0x73,
+ 0x69, 0x74, 0x69, 0x76, 0x65, 0xC5, 0x82, 0x33,
+ 0xC2, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x07, 0x08, 0x09, 0x10, 0x19, 0x02, 0xBC, 0xC5,
+ 0x82, 0x33, 0xC2, 0x4A, 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x78, 0x19,
+ 0x62, 0x69, 0x67, 0x20, 0x66, 0x6C, 0x6F, 0x61,
+ 0x74, 0x20, 0x62, 0x69, 0x67, 0x6E, 0x75, 0x6D,
+ 0x20, 0x6E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76,
+ 0x65, 0xC5, 0x82, 0x3B, 0x7F, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0x4A, 0x01, 0x02,
+ 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10,
+ 0x19, 0x03, 0x20, 0xC5, 0x82, 0x3B, 0x7F, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0x4A,
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x10
+};
+
+
+int32_t ExponentAndMantissaEncodeTests()
+{
+ QCBOREncodeContext EC;
+ UsefulBufC EncodedExponentAndMantissa;
+
+ // Constant for the big number used in all the tests.
+ static const uint8_t spBigNum[] = {0x01, 0x02, 0x03, 0x04, 0x05,
+ 0x06, 0x07, 0x08, 0x09, 0x010};
+ const UsefulBufC BigNum = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum);
+
+ QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
+ QCBOREncode_OpenArray(&EC);
+ QCBOREncode_AddDecimalFraction(&EC, 3, -1); // 3 * (10 ^ -1)
+ QCBOREncode_AddDecimalFractionBigNum(&EC, BigNum , false, -20);
+ QCBOREncode_AddDecimalFractionBigNum(&EC, BigNum, true, INT64_MAX);
+ QCBOREncode_AddBigFloat(&EC, 100, 300);
+ QCBOREncode_AddBigFloatBigNum(&EC, BigNum, false, -20);
+ QCBOREncode_AddBigFloatBigNum(&EC, BigNum, true, INT64_MIN);
+ QCBOREncode_CloseArray(&EC);
+
+ if(QCBOREncode_Finish(&EC, &EncodedExponentAndMantissa)) {
+ return -2;
+ }
+
+ int nReturn = UsefulBuf_CompareWithDiagnostic(EncodedExponentAndMantissa,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedExponentAndMantissaArray),
+ NULL);
+ if(nReturn) {
+ return nReturn;
+ }
+
+ QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
+ QCBOREncode_OpenMap(&EC);
+
+ QCBOREncode_AddDecimalFractionToMap(&EC, "decimal fraction", 3, -1);
+
+ QCBOREncode_AddDecimalFractionToMapN(&EC, 300, 3, -1);
+
+ QCBOREncode_AddDecimalFractionBigNumToMap(&EC,
+ "decimal fraction bignum postive",
+ BigNum,
+ false,
+ -200);
+
+ QCBOREncode_AddDecimalFractionBigNumToMapN(&EC,
+ 400,
+ BigNum,
+ false,
+ INT32_MAX);
+
+ QCBOREncode_AddDecimalFractionBigNumToMap(&EC,
+ "decimal fraction bignum negative",
+ BigNum,
+ true,
+ INT64_MAX);
+
+ QCBOREncode_AddDecimalFractionBigNumToMapN(&EC,
+ 500,
+ BigNum,
+ true,
+ INT64_MAX);
+
+ QCBOREncode_AddBigFloatToMap(&EC, "big float", 100, 300);
+
+ QCBOREncode_AddBigFloatToMapN(&EC, 600, 100, 300);
+
+ QCBOREncode_AddBigFloatBigNumToMap(&EC,
+ "big float bignum positive",
+ BigNum,
+ false,
+ -20);
+
+ QCBOREncode_AddBigFloatBigNumToMapN(&EC,
+ 700,
+ BigNum,
+ false,
+ -20);
+
+ QCBOREncode_AddBigFloatBigNumToMap(&EC,
+ "big float bignum negative",
+ BigNum,
+ true,
+ INT64_MIN);
+
+ QCBOREncode_AddBigFloatBigNumToMapN(&EC,
+ 800,
+ BigNum,
+ true,
+ INT64_MIN);
+
+ QCBOREncode_CloseMap(&EC);
+
+ if(QCBOREncode_Finish(&EC, &EncodedExponentAndMantissa)) {
+ return -3;
+ }
+
+
+ struct UBCompareDiagnostic Diag;
+
+ nReturn = UsefulBuf_CompareWithDiagnostic(EncodedExponentAndMantissa,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedExponentAndMantissaMap),
+ &Diag);
+ if(nReturn) {
+ return nReturn + 1000000; // +1000000 to distinguish from first test above
+ }
+
+ return 0;
+}
+
+#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
diff --git a/lib/ext/qcbor/test/qcbor_encode_tests.h b/lib/ext/qcbor/test/qcbor_encode_tests.h
index 790928834a..d768889139 100644
--- a/lib/ext/qcbor/test/qcbor_encode_tests.h
+++ b/lib/ext/qcbor/test/qcbor_encode_tests.h
@@ -1,6 +1,6 @@
/*==============================================================================
Copyright (c) 2016-2018, The Linux Foundation.
- Copyright (c) 2018-2019, Laurence Lundblade.
+ Copyright (c) 2018-2020, Laurence Lundblade.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -28,16 +28,18 @@ 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.
- ==============================================================================*/
+ =============================================================================*/
#ifndef __QCBOR__qcbor_encode_tests__
#define __QCBOR__qcbor_encode_tests__
+#include <stdint.h>
/*
Notes:
- - All the functions in qcbor.h are called once in the aggregation of all the tests below.
+ - All the functions in qcbor.h are called once in the aggregation of all
+ the tests below.
- All the types that are supported are given as input and parsed by these tests
@@ -50,122 +52,133 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/*
Most basic test.
*/
-int BasicEncodeTest(void);
+int32_t BasicEncodeTest(void);
/*
- Encode lots of integer values, particularly around the boundary and make sure they
- Match the expected binary output. Primarily an encoding test.
+ Encode lots of integer values, particularly around the boundary and
+ make sure they Match the expected binary output. Primarily an
+ encoding test.
*/
-int IntegerValuesTest1(void);
+int32_t IntegerValuesTest1(void);
/*
- Create nested arrays to the max depth allowed and make sure it succeeds.
- This is an encoding test.
+ Create nested arrays to the max depth allowed and make sure it
+ succeeds. This is an encoding test.
*/
-int ArrayNestingTest1(void);
+int32_t ArrayNestingTest1(void);
/*
- Create nested arrays to one more than the meax depth and make sure it fails.
- This is an encoding test.
+ Create nested arrays to one more than the meax depth and make sure it
+ fails. This is an encoding test.
*/
-int ArrayNestingTest2(void);
+int32_t ArrayNestingTest2(void);
/*
- Encoding test.
- Create arrays to max depth and close one extra time and look for correct error code
+ Encoding test. Create arrays to max depth and close one extra time
+ and look for correct error code
*/
-int ArrayNestingTest3(void);
+int32_t ArrayNestingTest3(void);
/*
- This tests the QCBOREncode_AddRaw() function by adding two chunks or RAWCBOR to an
- array and comparing with expected values. This is an encoding test.
+ This tests the QCBOREncode_AddRaw() function by adding two chunks or
+ RAWCBOR to an array and comparing with expected values. This is an
+ encoding test.
*/
-int EncodeRawTest(void);
+int32_t EncodeRawTest(void);
/*
- This creates a somewhat complicated CBOR MAP and verifies it against expected
- data. This is an encoding test.
+ This creates a somewhat complicated CBOR MAP and verifies it against
+ expected data. This is an encoding test.
*/
-int MapEncodeTest(void);
+int32_t MapEncodeTest(void);
/*
Encodes a goodly number of floats and doubles and checks encoding is right
*/
-int FloatValuesTest1(void);
+int32_t FloatValuesTest1(void);
/*
Encodes true, false and the like
*/
-int SimpleValuesTest1(void);
+int32_t SimpleValuesTest1(void);
/*
Encodes basic maps and arrays with indefinite length
*/
-int SimpleValuesIndefiniteLengthTest1(void);
+int32_t SimpleValuesIndefiniteLengthTest1(void);
+
/*
- Indefinite length arrays and maps use the 'magic' number 31, verify that
- everything with length 31 still works properly
+ Indefinite length arrays and maps use the 'magic' number 31, verify
+ that everything with length 31 still works properly
*/
-int EncodeLengthThirtyoneTest(void);
+int32_t EncodeLengthThirtyoneTest(void);
/*
Encodes most data formats that are supported */
-int EncodeDateTest(void);
+int32_t EncodeDateTest(void);
/*
Encodes particular data structure that a particular app will need...
*/
-int RTICResultsTest(void);
+int32_t RTICResultsTest(void);
/*
Calls all public encode methods in qcbor.h once.
*/
-int AllAddMethodsTest(void);
+int32_t AllAddMethodsTest(void);
/*
The binary string wrapping of maps and arrays used by COSE
*/
-int BstrWrapTest(void);
+int32_t BstrWrapTest(void);
/*
Test error cases for bstr wrapping encoding such as closing an open
array with CloseBstrWrap
*/
-int BstrWrapErrorTest(void);
+int32_t BstrWrapErrorTest(void);
/*
Test complicated nested bstr wrapping
*/
-int BstrWrapNestTest(void);
+int32_t BstrWrapNestTest(void);
/*
Test encoding a COSE_Sign1 with bstr wrapping
*/
-int CoseSign1TBSTest(void);
+int32_t CoseSign1TBSTest(void);
+
+#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+/*
+ Test encoding of decimal fractions and big floats, both of which are
+ made up of an exponent and mantissa
+ */
+int32_t ExponentAndMantissaEncodeTests(void);
+#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
/*
Test the error cases when encoding CBOR such as buffer too large,
buffer too small, array nesting too deep. Aims to cover the error
codes returned when encoding CBOR
*/
-int EncodeErrorTests(void);
+int32_t EncodeErrorTests(void);
#endif /* defined(__QCBOR__qcbor_encode_tests__) */
diff --git a/lib/ext/qcbor/test/run_tests.c b/lib/ext/qcbor/test/run_tests.c
index 52c4f8f0e8..f8ed83b78f 100644
--- a/lib/ext/qcbor/test/run_tests.c
+++ b/lib/ext/qcbor/test/run_tests.c
@@ -1,14 +1,14 @@
/*==============================================================================
run_tests.c -- test aggregator and results reporting
- Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved.
+ Copyright (c) 2018-2020, Laurence Lundblade. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause
See BSD-3-Clause license in README.md
Created on 9/30/18
- ==============================================================================*/
+ =============================================================================*/
#include "run_tests.h"
#include "UsefulBuf.h"
@@ -24,7 +24,7 @@
Test configuration
*/
-typedef int (test_fun_t)(void);
+typedef int32_t (test_fun_t)(void);
typedef const char * (test_fun2_t)(void);
@@ -103,6 +103,12 @@ static test_entry s_tests[] = {
TEST_ENTRY(SetUpAllocatorTest),
TEST_ENTRY(SimpleValuesIndefiniteLengthTest1),
TEST_ENTRY(EncodeLengthThirtyoneTest),
+#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+ TEST_ENTRY(EncodeLengthThirtyoneTest),
+ TEST_ENTRY(ExponentAndMantissaDecodeTests),
+ TEST_ENTRY(ExponentAndMantissaDecodeFailTests),
+ TEST_ENTRY(ExponentAndMantissaEncodeTests),
+#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
};
@@ -131,12 +137,12 @@ static const char *NumToString(int32_t nNum, UsefulBuf StringMem)
}
bool bDidSomeOutput = false;
- for(int n = nMax; n > 0; n/=10) {
- int x = nNum/n;
- if(x || bDidSomeOutput){
+ for(int32_t n = nMax; n > 0; n/=10) {
+ int nDigitValue = nNum/n;
+ if(nDigitValue || bDidSomeOutput){
bDidSomeOutput = true;
- UsefulOutBuf_AppendByte(&OutBuf, '0' + x);
- nNum -= x * n;
+ UsefulOutBuf_AppendByte(&OutBuf, (uint8_t)('0' + nDigitValue));
+ nNum -= nDigitValue * n;
}
}
if(!bDidSomeOutput){
@@ -151,10 +157,14 @@ static const char *NumToString(int32_t nNum, UsefulBuf StringMem)
/*
Public function. See run_test.h.
*/
-int RunTests(const char *szTestNames[], OutputStringCB pfOutput, void *poutCtx, int *pNumTestsRun)
+int RunTestsQCBOR(const char *szTestNames[],
+ OutputStringCB pfOutput,
+ void *poutCtx,
+ int *pNumTestsRun)
{
int nTestsFailed = 0;
int nTestsRun = 0;
+
UsefulBuf_MAKE_STACK_UB(StringStorage, 12);
test_entry2 *t2;
@@ -228,7 +238,7 @@ int RunTests(const char *szTestNames[], OutputStringCB pfOutput, void *poutCtx,
}
}
- int nTestResult = (t->test_fun)();
+ int32_t nTestResult = (t->test_fun)();
nTestsRun++;
if(pfOutput) {
(*pfOutput)(t->szTestName, poutCtx, 0);
@@ -269,13 +279,16 @@ int RunTests(const char *szTestNames[], OutputStringCB pfOutput, void *poutCtx,
/*
Public function. See run_test.h.
*/
-static void PrintSize(const char *szWhat, uint32_t uSize, OutputStringCB pfOutput, void *pOutCtx)
+static void PrintSize(const char *szWhat,
+ uint32_t uSize,
+ OutputStringCB pfOutput,
+ void *pOutCtx)
{
UsefulBuf_MAKE_STACK_UB(buffer, 20);
(*pfOutput)(szWhat, pOutCtx, 0);
(*pfOutput)(" ", pOutCtx, 0);
- (*pfOutput)(NumToString(uSize, buffer), pOutCtx, 0);
+ (*pfOutput)(NumToString((int32_t)uSize, buffer), pOutCtx, 0);
(*pfOutput)("", pOutCtx, 1);
}
@@ -283,15 +296,15 @@ static void PrintSize(const char *szWhat, uint32_t uSize, OutputStringCB pfOutpu
/*
Public function. See run_test.h.
*/
-void PrintSizes(OutputStringCB pfOutput, void *pOutCtx)
+void PrintSizesQCBOR(OutputStringCB pfOutput, void *pOutCtx)
{
- // Type and size of return from sizeof() varies. These will never be large so cast is safe
- PrintSize("sizeof(QCBORTrackNesting)", (uint32_t)sizeof(QCBORTrackNesting), pfOutput, pOutCtx);
+ // These will never be large so cast is safe
+ PrintSize("sizeof(QCBORTrackNesting)", (uint32_t)sizeof(QCBORTrackNesting), pfOutput, pOutCtx);
PrintSize("sizeof(QCBOREncodeContext)", (uint32_t)sizeof(QCBOREncodeContext), pfOutput, pOutCtx);
PrintSize("sizeof(QCBORDecodeNesting)", (uint32_t)sizeof(QCBORDecodeNesting), pfOutput, pOutCtx);
PrintSize("sizeof(QCBORDecodeContext)", (uint32_t)sizeof(QCBORDecodeContext), pfOutput, pOutCtx);
- PrintSize("sizeof(QCBORItem)", (uint32_t)sizeof(QCBORItem), pfOutput, pOutCtx);
- PrintSize("sizeof(QCBORTagListIn)", (uint32_t)sizeof(QCBORTagListIn), pfOutput, pOutCtx);
- PrintSize("sizeof(QCBORTagListOut)", (uint32_t)sizeof(QCBORTagListOut), pfOutput, pOutCtx);
+ PrintSize("sizeof(QCBORItem)", (uint32_t)sizeof(QCBORItem), pfOutput, pOutCtx);
+ PrintSize("sizeof(QCBORTagListIn)", (uint32_t)sizeof(QCBORTagListIn), pfOutput, pOutCtx);
+ PrintSize("sizeof(QCBORTagListOut)", (uint32_t)sizeof(QCBORTagListOut), pfOutput, pOutCtx);
(*pfOutput)("", pOutCtx, 1);
}
diff --git a/lib/ext/qcbor/test/run_tests.h b/lib/ext/qcbor/test/run_tests.h
index 734d4f830d..ce44673fd4 100644
--- a/lib/ext/qcbor/test/run_tests.h
+++ b/lib/ext/qcbor/test/run_tests.h
@@ -1,14 +1,14 @@
/*==============================================================================
run_tests.h -- test aggregator and results reporting
- Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved.
+ Copyright (c) 2018-2020, Laurence Lundblade. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause
See BSD-3-Clause license in README.md
Created 9/30/18
- ==============================================================================*/
+ =============================================================================*/
/**
@file run_tests.h
@@ -53,7 +53,10 @@ typedef void (*OutputStringCB)(const char *szString, void *pOutCtx, int bNewline
@return The number of tests that failed. Zero means overall success.
*/
-int RunTests(const char *szTestNames[], OutputStringCB pfOutput, void *pOutCtx, int *pNumTestsRun);
+int RunTestsQCBOR(const char *szTestNames[],
+ OutputStringCB pfOutput,
+ void *pOutCtx,
+ int *pNumTestsRun);
/**
@@ -62,5 +65,5 @@ int RunTests(const char *szTestNames[], OutputStringCB pfOutput, void *pOutCtx,
@param[in] pfOutput Function that is called to output text strings.
@param[in] pOutCtx Context pointer passed to output function.
*/
-void PrintSizes(OutputStringCB pfOutput, void *pOutCtx);
+void PrintSizesQCBOR(OutputStringCB pfOutput, void *pOutCtx);
diff --git a/test/suites/qcbor/non_secure/qcbor_ns_testsuite.c b/test/suites/qcbor/non_secure/qcbor_ns_testsuite.c
index 95f3972627..109b181d30 100644
--- a/test/suites/qcbor/non_secure/qcbor_ns_testsuite.c
+++ b/test/suites/qcbor/non_secure/qcbor_ns_testsuite.c
@@ -119,8 +119,8 @@ static void tfm_qcbor_test_7001(struct test_result_t *ret)
{
int32_t test_failed_cnt = 0;
- test_failed_cnt = RunTests(qcbor_test_cases_all, fputs_wrapper,
- NULL, NULL);
+ test_failed_cnt = RunTestsQCBOR(qcbor_test_cases_all, fputs_wrapper,
+ NULL, NULL);
if (test_failed_cnt != 0) {
TEST_FAIL("QCBOR test failed");
return;