merge recent changes in from master
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..9c5b625
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,20 @@
+os:
+ - linux
+
+language: c
+compiler:
+ - gcc
+
+env:
+sudo: false
+addons:
+ apt:
+ packages:
+ - make
+
+install:
+ - make
+
+script:
+ - ./qcbortest
+
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..8a5bcd0
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 3.10.2)
+project(qcbor
+ DESCRIPTION "QCBOR"
+ LANGUAGES C
+ VERSION 1.0.0)
+
+set(CMAKE_C_FLAGS "-pedantic -Wall -O3 -ffunction-sections")
+
+include_directories(inc)
+
+set(SOURCE
+ src/ieee754.c
+ src/qcbor_decode.c
+ src/qcbor_encode.c
+ src/qcbor_err_to_str.c
+ src/UsefulBuf.c
+)
+
+add_library(qcbor ${SOURCE})
diff --git a/Makefile b/Makefile
index 805e702..f7e2e8c 100644
--- a/Makefile
+++ b/Makefile
@@ -1,22 +1,27 @@
# Makefile -- UNIX-style make for qcbor as a lib and command line test
#
-# Copyright (c) 2018-2020, Laurence Lundblade. All rights reserved.
+# Copyright (c) 2018-2021, Laurence Lundblade. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
# See BSD-3-Clause license in README.md
#
-CC=cc
-#CC=/usr/local/bin/gcc-9
+# The math library is needed for floating-point support. To
+# avoid need for it #define QCBOR_DISABLE_FLOAT_HW_USE
LIBS=-lm
-CFLAGS=$(CMD_LINE) -I inc -I test -Os -fPIC
-# The following are used before a release of QCBOR help to make sure
-# the code compiles and runs in the most strict environments, but not
-# all compilers support them so they are not turned on.
-#CFLAGS=-I inc -I test -Os -fpic -Wall -pedantic-errors -Wextra -Wshadow -Wparentheses -Wconversion -xc -std=c99
+
+# The QCBOR makefile uses a minimum of compiler flags so that it will
+# work out-of-the-box with a wide variety of compilers. For example,
+# some compiler error out on some of the warnings flags available with
+# gcc. The $(CMD_LINE) variable allows passing in extra flags. This is
+# used on the stringent build script that is in
+# https://github.com/laurencelundblade/qdv. This script is used
+# before pushes to master (though not yet through and automated build
+# process)
+CFLAGS=$(CMD_LINE) -I inc -I test -Os -fPIC
QCBOR_OBJ=src/UsefulBuf.o src/qcbor_encode.o src/qcbor_decode.o src/ieee754.o src/qcbor_err_to_str.o
@@ -37,6 +42,7 @@
libqcbor.a: $(QCBOR_OBJ)
ar -r $@ $^
+
# The shared library is not made by default because of platform
# variability For example MacOS and Linux behave differently and some
# IoT OS's don't support them at all.
diff --git a/QCBOR.xcodeproj/project.pbxproj b/QCBOR.xcodeproj/project.pbxproj
index 783af79..5b3ef68 100644
--- a/QCBOR.xcodeproj/project.pbxproj
+++ b/QCBOR.xcodeproj/project.pbxproj
@@ -164,7 +164,7 @@
E743D13124DE05CC0017899F /* QCBOR_Disable_Preferred_Float */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = QCBOR_Disable_Preferred_Float; sourceTree = BUILT_PRODUCTS_DIR; };
E743D132251014E60017899F /* Tagging.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; name = Tagging.md; path = doc/Tagging.md; sourceTree = "<group>"; };
E743D13325115A270017899F /* TRY SPIFFY DECODE.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = "TRY SPIFFY DECODE.md"; sourceTree = "<group>"; };
- E74BF411245D6713002CE8E8 /* UsefulBuf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UsefulBuf.h; path = inc/qcbor/UsefulBuf.h; sourceTree = "<group>"; };
+ E74BF411245D6713002CE8E8 /* UsefulBuf.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.h; name = UsefulBuf.h; path = inc/qcbor/UsefulBuf.h; sourceTree = "<group>"; tabWidth = 3; };
E772022723B52C02006E966E /* QCBOR_Disable_Exp_Mantissa */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = QCBOR_Disable_Exp_Mantissa; sourceTree = BUILT_PRODUCTS_DIR; };
E776E07C214ADF7F00E67947 /* QCBOR */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = QCBOR; sourceTree = BUILT_PRODUCTS_DIR; };
E776E08C214AE07400E67947 /* qcbor_encode.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.c; name = qcbor_encode.c; path = src/qcbor_encode.c; sourceTree = "<group>"; tabWidth = 3; };
diff --git a/README.md b/README.md
index 1f689c8..ecc93df 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# QCBOR
-QCBOR is an implementation of nearly everything in
+QCBOR is a powerful, commercial quality implementation of nearly everything in
[RFC8949](https://tools.ietf.org/html/rfc8949). This RFC defines the
Concise Binary Object Representation (CBOR). Since RFC 8949 is fully
compatible with RFC 7049, this is also a near-complete implementation
@@ -227,6 +227,65 @@
code. Its main use is on CPUs that have no floating-point hardware.
See discussion in qcbor_encode.h for details.
+G
+## Comparison to TinyCBOR
+
+TinyCBOR is a popular widely used implementation. Like QCBOR,
+it is a solid, well-maintained commercial quality implementation. This
+section is for folks trying to understand the difference in
+the approach between QCBOR and TinyCBOR.
+
+TinyCBOR's API is a bit more minimalist and closer to the CBOR
+encoding mechanics than QCBOR's. QCBOR's API is at a somewhat higher
+level of abstraction.
+
+QCBOR really does implement just about everything described in
+RFC 8949. The main part missing is sorting of maps when encoding.
+TinyCBOR implements a smaller part of the standard.
+
+No detailed code size comparison has been made, but in a spot check
+that encodes and decodes a single integer shows QCBOR about 25%
+larger. QCBOR encoding is actually smaller, but QCBOR decoding is
+larger. This includes the code to call the library, which is about the
+same for both libraries, and the code linked from the libraries. QCBOR
+is a bit more powerful, so you get value for the extra code brought
+in, especially when decoding more complex protocols.
+
+QCBOR tracks encoding and decoding errors internally so the caller
+doesn't have to check the return code of every call to an encode or
+decode function. In many cases the error check is only needed as the
+last step or an encode or decode. TinyCBOR requires an error check on
+each call.
+
+QCBOR provides a substantial feature that allows searching for data
+items in a map by label. It works for integer and text string labels
+(and at some point byte-string labels). This includes detection of
+items with duplicate labels. This makes the code for decoding CBOR
+simpler, similar to the encoding code and easier to read. TinyCBOR
+supports search by string, but no integer, nor duplicate detection.
+
+QCBOR provides explicit support many of the registered CBOR tags. For
+example, QCBOR supports big numbers and decimal fractions including
+their conversion to floats, uint64_t and such.
+
+Generally, QCBOR supports safe conversion of most CBOR number formats
+into number formats supported in C. For example, a data item can be
+fetched and converted to a C uint64_t whether the input CBOR is an
+unsigned 64-bit integer, signed 64-bit integer, floating-point number,
+big number, decimal fraction or a big float. The conversion is
+performed with full proper error detection of overflow and underflow.
+
+QCBOR has a special feature for decoding byte-string wrapped CBOR. It
+treats this similar to entering an array with one item. This is
+particularly use for CBOR protocols like COSE that make use of
+byte-string wrapping. The implementation of these protocols is
+simpler and uses less memory.
+
+QCBOR's test suite is written in the same portable C that QCBOR is
+where TinyCBOR requires Qt for its test. QCBOR's test suite is
+designed to be able to run on small embedded devices the same as
+QCBOR.
+
## Code Size
@@ -235,7 +294,7 @@
| | smallest | largest |
|---------------|----------|---------|
| encode only | 850 | 2100 |
- | decode only | 2000 | 13400 |
+ | decode only | 2000 | 13300 |
| combined | 2850 | 15500 |
From the table above, one can see that the amount of code pulled in
@@ -275,7 +334,7 @@
carefully written to be defensive.
Disable features with defines like:
- QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA (saves about 400 bytes)
+ QCBOR_DISABLE_EXP_AND_MANTISSA (saves about 400 bytes)
QCBOR_DISABLE_ENCODE_USAGE_GUARDS (saves about 150), and
QCBOR_DISABLE_PREFERRED_FLOAT (saves about 900 bytes), and
QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS (saves about 400 bytes).
@@ -351,6 +410,7 @@
* Michael Eckel for Makefile improvements
* Jan Jongboom for indefinite length encoding
* Peter Uiterwijk for error strings and other
+* Michael Richarson for CI set up and additional compiler warnings
## Copyright and License
diff --git a/example.c b/example.c
index 5ec3f2f..4921e13 100644
--- a/example.c
+++ b/example.c
@@ -1,7 +1,7 @@
/* =========================================================================
example.c -- Example code for QCBOR
- Copyright (c) 2020, Laurence Lundblade. All rights reserved.
+ Copyright (c) 2020-2021, Laurence Lundblade. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause
@@ -17,11 +17,20 @@
#include "qcbor/qcbor_spiffy_decode.h"
+/**
+ * This is a simple example of encoding and decoding some CBOR from
+ * and to a C structure.
+ *
+ * This also includes a comparison between the original structure
+ * and the one decoded from the CBOR to confirm correctness.
+ */
+
+
#define MAX_CYLINDERS 16
/**
- The data structure representing a car engine that is encoded and
- decoded in this example.
+ * The data structure representing a car engine that is encoded and
+ * decoded in this example.
*/
typedef struct
{
@@ -32,15 +41,15 @@
int64_t uNumCylinders;
bool bTurboCharged;
struct {
- double uMeasuredCompression;
+ double dMeasuredCompression;
} cylinders[MAX_CYLINDERS];
} CarEngine;
/**
- @brief Initialize the Engine data structure with values to encode/decode.
-
- @param[out] pE The Engine structure to fill in
+ * @brief Initialize the Engine data structure with values to encode.
+ *
+ * @param[out] pE The Engine structure to fill in
*/
void EngineInit(CarEngine *pE)
{
@@ -51,88 +60,91 @@
pE->uNumCylinders = 6;
pE->bTurboCharged = false;
- pE->cylinders[0].uMeasuredCompression = 9.0;
- pE->cylinders[1].uMeasuredCompression = 9.2;
- pE->cylinders[2].uMeasuredCompression = 8.9;
- pE->cylinders[3].uMeasuredCompression = 8.9;
- pE->cylinders[4].uMeasuredCompression = 9.1;
- pE->cylinders[5].uMeasuredCompression = 9.0;
+ pE->cylinders[0].dMeasuredCompression = 9.0;
+ pE->cylinders[1].dMeasuredCompression = 9.2;
+ pE->cylinders[2].dMeasuredCompression = 8.9;
+ pE->cylinders[3].dMeasuredCompression = 8.9;
+ pE->cylinders[4].dMeasuredCompression = 9.1;
+ pE->cylinders[5].dMeasuredCompression = 9.0;
}
/**
- @brief Compare two Engine structure for equality.
-
- @param[in] pE1 First Engine to compare.
- @param[in] pE2 Second Engine to compare.
-
- @retval Return @c true if the two Engine data structures are exactly the
- same.
+ * @brief Compare two Engine structure for equality.
+ *
+ * @param[in] pE1 First Engine to compare.
+ * @param[in] pE2 Second Engine to compare.
+ *
+ * @retval Return @c true if the two Engine data structures are exactly the
+ * same.
*/
-bool EngineCompare(CarEngine *pE1, CarEngine *pE2)
+static bool EngineCompare(const CarEngine *pE1, const CarEngine *pE2)
{
- if(pE1->uNumCylinders != pE2->uNumCylinders) {
- return false;
- }
- if(pE1->bTurboCharged != pE2->bTurboCharged) {
- return false;
- }
- if(pE1->uDisplacement != pE2->uDisplacement) {
- return false;
- }
- if(pE1->uHorsePower != pE2->uHorsePower) {
- return false;
- }
- if(pE1->dDesignedCompresion != pE2->dDesignedCompresion) {
- return false;
- }
- for(int64_t i = 0; i < pE2->uNumCylinders; i++) {
- if(pE1->cylinders[i].uMeasuredCompression !=
- pE2->cylinders[i].uMeasuredCompression) {
- return false;
- }
- }
+ if(pE1->uNumCylinders != pE2->uNumCylinders) {
+ return false;
+ }
+ if(pE1->bTurboCharged != pE2->bTurboCharged) {
+ return false;
+ }
+ if(pE1->uDisplacement != pE2->uDisplacement) {
+ return false;
+ }
+ if(pE1->uHorsePower != pE2->uHorsePower) {
+ return false;
+ }
+ if(pE1->dDesignedCompresion != pE2->dDesignedCompresion) {
+ return false;
+ }
+ for(int64_t i = 0; i < pE2->uNumCylinders; i++) {
+ if(pE1->cylinders[i].dMeasuredCompression !=
+ pE2->cylinders[i].dMeasuredCompression) {
+ return false;
+ }
+ }
- if(UsefulBuf_Compare(pE1->Manufacturer, pE2->Manufacturer)) {
- return false;
- }
+ if(UsefulBuf_Compare(pE1->Manufacturer, pE2->Manufacturer)) {
+ return false;
+ }
return true;
}
-#ifndef EXAMPLE_DISABLE_DEFINITE_LENGTH_ENCODE
/**
- @brief Encode an initialized Engine data structure in CBOR.
-
- @param[in] pEngine The data structure to encode.
- @param[in] Buffer Pointer and length of buffer to output to.
-
- @return The pointer and length of the encoded CBOR or
- @ref NULLUsefulBufC on error.
-
- This is a simple CBOR encoding example. It outputs the Engine data
- structure as a map of label-value pairs as well as an array of
- floating point values.
-
- @c Buffer must be big enough to hold the output. If it is not @ref
- NULLUsefulBufC will be returned. @ref @ref NULLUsefulBufC will be
- returned for any other encoding errors.
-
- This encoding will use definite CBOR lengths. Definite lengths are
- preferred in CBOR. See EncodeEngineIndefinteLen() that encodes using
- indefinite lengths.
+ * @brief Encode an initialized CarEngine data structure in CBOR.
+ *
+ * @param[in] pEngine The data structure to encode.
+ * @param[in] Buffer Pointer and length of buffer to output to.
+ *
+ * @return The pointer and length of the encoded CBOR or
+ * @ref NULLUsefulBufC on error.
+ *
+ * This encodes the input structure \c pEngine as a CBOR map of
+ * label-value pairs. An array of float is one of the items in the
+ * map.
+ *
+ * This uses the UsefulBuf convention of passing in a non-const empty
+ * buffer to be filled in and returning a filled in const buffer. The
+ * buffer to write into is given as a pointer and length in a
+ * UsefulBuf. The buffer returned with the encoded CBOR is a
+ * UsefulBufC also a pointer and length. In this implementation the
+ * pointer to the returned data is exactly the same as that of the
+ * empty buffer. The returned length will be smaller than or equal to
+ * that of the empty buffer. This gives correct const-ness for the
+ * buffer passed in and the data returned.
+ *
+ * @c Buffer must be big enough to hold the output. If it is not @ref
+ * NULLUsefulBufC will be returned. @ref NULLUsefulBufC will be
+ * returned for any other encoding errors.
*/
UsefulBufC EncodeEngineDefiniteLength(const CarEngine *pEngine, UsefulBuf Buffer)
{
- /* Initialize the encoder with the buffer big enough to hold the
- expected output. If it is too small, QCBOREncode_Finish() will
- return an error. */
+ /* Set up the encoding context with the output buffer */
QCBOREncodeContext EncodeCtx;
QCBOREncode_Init(&EncodeCtx, Buffer);
/* Proceed to output all the items, letting the internal error
- tracking do its work. */
+ * tracking do its work */
QCBOREncode_OpenMap(&EncodeCtx);
QCBOREncode_AddTextToMap(&EncodeCtx, "Manufacturer", pEngine->Manufacturer);
QCBOREncode_AddInt64ToMap(&EncodeCtx, "NumCylinders", pEngine->uNumCylinders);
@@ -141,14 +153,15 @@
QCBOREncode_AddDoubleToMap(&EncodeCtx, "DesignedCompression", pEngine->dDesignedCompresion);
QCBOREncode_OpenArrayInMap(&EncodeCtx, "Cylinders");
for(int64_t i = 0 ; i < pEngine->uNumCylinders; i++) {
- QCBOREncode_AddDouble(&EncodeCtx, pEngine->cylinders[i].uMeasuredCompression);
+ QCBOREncode_AddDouble(&EncodeCtx,
+ pEngine->cylinders[i].dMeasuredCompression);
}
QCBOREncode_CloseArray(&EncodeCtx);
QCBOREncode_AddBoolToMap(&EncodeCtx, "Turbo", pEngine->bTurboCharged);
QCBOREncode_CloseMap(&EncodeCtx);
/* Get the pointer and length of the encoded output. If there was
- any error it will be returned here. */
+ * any encoding error, it will be returned here */
UsefulBufC EncodedCBOR;
QCBORError uErr;
uErr = QCBOREncode_Finish(&EncodeCtx, &EncodedCBOR);
@@ -158,72 +171,10 @@
return EncodedCBOR;
}
}
-#endif /* EXAMPLE_DISABLE_DEFINITE_LENGTH_ENCODE */
-
-
-
-
-#ifndef EXAMPLE_DISABLE_INDEFINITE_LENGTH_ENCODE_ENCODE
-/**
- @brief Encode an initialized Engine data structure using indefinite lengths.
-
- @param[in] pEngine The data structure to encode.
- @param[in] Buffer Pointer and length of buffer to output to.
-
- @return The pointer and length of the encoded CBOR or
- @ref NULLUsefulBufC on error.
-
- This is virtually the same as EncodeEngineDefiniteLength(). The
- encoded CBOR is slightly different as the map and array use
- indefinite lengths, rather than definite lengths.
-
- A definite length array is encoded as an integer indicating the
- number of items in it. An indefinite length array is encoded as an
- opening byte, the items in it and a "break" byte to end
- it. Indefinite length arrays and maps are easier to encode, but
- harder to decode.
-
- The advantage of this implementation is that the encoding side will
- be a little less object code. (Eventually QCBOR will an ifdef to
- disable definite length encoding and the object code will be even
- smaller). However, note that the encoding implementation for a
- protocol is just about always much smaller than the decoding
- implementation and that code savings for use of indefinite lengths is
- relatively small.
- */
-UsefulBufC EncodeEngineIndefinteLen(const CarEngine *pEngine, UsefulBuf Buffer)
-{
- QCBOREncodeContext EncodeCtx;
-
- QCBOREncode_Init(&EncodeCtx, Buffer);
- QCBOREncode_OpenMapIndefiniteLength(&EncodeCtx);
- QCBOREncode_AddTextToMap(&EncodeCtx, "Manufacturer", pEngine->Manufacturer);
- QCBOREncode_AddInt64ToMap(&EncodeCtx, "Displacement", pEngine->uDisplacement);
- QCBOREncode_AddInt64ToMap(&EncodeCtx, "Horsepower", pEngine->uHorsePower);
- QCBOREncode_AddDoubleToMap(&EncodeCtx, "DesignedCompression", pEngine->dDesignedCompresion);
- QCBOREncode_AddInt64ToMap(&EncodeCtx, "NumCylinders", pEngine->uNumCylinders);
- QCBOREncode_OpenArrayIndefiniteLengthInMap(&EncodeCtx, "Cylinders");
- for(int64_t i = 0 ; i < pEngine->uNumCylinders; i++) {
- QCBOREncode_AddDouble(&EncodeCtx, pEngine->cylinders[i].uMeasuredCompression);
- }
- QCBOREncode_CloseArrayIndefiniteLength(&EncodeCtx);
- QCBOREncode_AddBoolToMap(&EncodeCtx, "Turbo", pEngine->bTurboCharged);
- QCBOREncode_CloseMapIndefiniteLength(&EncodeCtx);
-
- UsefulBufC EncodedCBOR;
- QCBORError uErr;
- uErr = QCBOREncode_Finish(&EncodeCtx, &EncodedCBOR);
- if(uErr != QCBOR_SUCCESS) {
- return NULLUsefulBufC;
- } else {
- return EncodedCBOR;
- }
-}
-#endif /* EXAMPLE_DISABLE_INDEFINITE_LENGTH_ENCODE */
/**
- Error results when decoding an Engine data structure.
+ * Error results when decoding an Engine data structure.
*/
typedef enum {
EngineSuccess,
@@ -235,9 +186,9 @@
/**
- Convert @ref QCBORError to @ref EngineDecodeErrors.
+ * Convert @ref QCBORError to @ref EngineDecodeErrors.
*/
-EngineDecodeErrors ConvertError(QCBORError uErr)
+static EngineDecodeErrors ConvertError(QCBORError uErr)
{
EngineDecodeErrors uReturn;
@@ -260,39 +211,40 @@
}
-#ifndef EXAMPLE_DISABLE_SPIFFY_DECODE
/**
- @brief Simplest engine decode using spiffy decode features.
-
- @param[in] EncodedEngine Pointer and length of CBOR-encoded engine.
- @param[out] pE The structure filled in from the decoding.
-
- @return The decode error or success.
-
- This decodes the CBOR into the engine structure.
-
- As QCBOR automatically supports both definite and indefinite maps and
- arrays, this will decode either.
-
- This uses QCBOR's spiffy decode, so the implementation is simplest
- and closely parallels the encode implementation in
- EncodeEngineDefiniteLength().
-
- See two other ways to implement decoding in
- DecodeEngineSpiffyFaster() and DecodeEngineBasic().
-
- This version of the decoder has the simplest implementation, but
- pulls in more code from the QCBOR library. This version uses the
- most CPU cycles because it scans the all the CBOR each time a data
- item is decoded. The CPU cycles used for a data structure as small as
- this is probably insignificant. CPU use for this style of decode is
- probably only a factor on slow CPUs with big CBOR inputs.
+ * @brief Simplest engine decode using spiffy decode features.
+ *
+ * @param[in] EncodedEngine Pointer and length of CBOR-encoded engine.
+ * @param[out] pE The structure filled in from the decoding.
+ *
+ * @return The decode error or success.
+ *
+ * This decodes the CBOR into the engine structure.
+ *
+ * As QCBOR automatically supports both definite and indefinite maps
+ * and arrays, this will decode either.
+ *
+ * This uses QCBOR's spiffy decode functions, so the implementation is
+ * simple and closely parallels the encode implementation in
+ * EncodeEngineDefiniteLength().
+ *
+ * Another way to decode without using spiffy decode functions is to
+ * use QCBORDecode_GetNext() to traverse the whole tree. This
+ * requires a more complex implementation, but is faster and will pull
+ * in less code from the CBOR library. The speed advantage is likely
+ * of consequence when decoding much much larger CBOR on slow small
+ * CPUs.
+ *
+ * A middle way is to use the spiffy decode
+ * QCBORDecode_GetItemsInMap(). The implementation has middle
+ * complexity and uses less CPU.
*/
EngineDecodeErrors DecodeEngineSpiffy(UsefulBufC EncodedEngine, CarEngine *pE)
{
- QCBORError uErr;
+ QCBORError uErr;
QCBORDecodeContext DecodeCtx;
+ /* Let QCBORDecode internal error tracking do its work. */
QCBORDecode_Init(&DecodeCtx, EncodedEngine, QCBOR_DECODE_MODE_NORMAL);
QCBORDecode_EnterMap(&DecodeCtx, NULL);
QCBORDecode_GetTextStringInMapSZ(&DecodeCtx, "Manufacturer", &(pE->Manufacturer));
@@ -303,9 +255,9 @@
QCBORDecode_GetInt64InMapSZ(&DecodeCtx, "NumCylinders", &(pE->uNumCylinders));
- /* Must check error before referencing pE->uNumCylinders to be
- sure it is valid. If any of the above errored, it won't be
- valid. */
+ /* Check the internal tracked error now before going on to
+ * reference any of the decoded data, particularly
+ * pE->uNumCylinders */
uErr = QCBORDecode_GetError(&DecodeCtx);
if(uErr != QCBOR_SUCCESS) {
goto Done;
@@ -317,357 +269,33 @@
QCBORDecode_EnterArrayFromMapSZ(&DecodeCtx, "Cylinders");
for(int64_t i = 0; i < pE->uNumCylinders; i++) {
- QCBORDecode_GetDouble(&DecodeCtx, &(pE->cylinders[i].uMeasuredCompression));
+ QCBORDecode_GetDouble(&DecodeCtx,
+ &(pE->cylinders[i].dMeasuredCompression));
}
QCBORDecode_ExitArray(&DecodeCtx);
QCBORDecode_ExitMap(&DecodeCtx);
- /* Catch the remainder of errors here */
+ /* Catch further decoding error here */
uErr = QCBORDecode_Finish(&DecodeCtx);
Done:
return ConvertError(uErr);
}
-#endif /* EXAMPLE_DISABLE_SPIFFY_DECODE */
-
-
-
-#ifndef EXAMPLE_DISABLE_SPIFFY_DECODE_FAST
-/**
- @brief Decode an Engine structure with the faster spiffy decode features.
-
- @param[in] EncodedEngine Pointer and length of CBOR-encoded engine.
- @param[out] pE The structure filled in from the decoding.
-
- @return The decode error or success.
-
- This decodes the same as DecodeEngineSpiffy(), but uses different
- spiffy decode features.
-
- This version uses QCBORDecode_GetItemsInMap() which uses less CPU
- cycles because all the items except the array are pulled out of the
- map in one pass, rather than having to decode the whole map for each
- decoded item. This also pulls in less object code from the QCBOR
- library.
-
- See also DecodeEngineAdvanced() and DecodeEngineBasic().
-*/
-EngineDecodeErrors DecodeEngineSpiffyFaster(UsefulBufC EncodedEngine, CarEngine *pE)
-{
- QCBORError uErr;
- QCBORDecodeContext DecodeCtx;
-
- QCBORDecode_Init(&DecodeCtx, EncodedEngine, QCBOR_DECODE_MODE_NORMAL);
- QCBORDecode_EnterMap(&DecodeCtx, NULL);
-
- QCBORItem EngineItems[7];
- EngineItems[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
- EngineItems[0].label.string = UsefulBuf_FROM_SZ_LITERAL("Manufacturer");
- EngineItems[0].uDataType = QCBOR_TYPE_TEXT_STRING;
-
- EngineItems[1].uLabelType = QCBOR_TYPE_TEXT_STRING;
- EngineItems[1].label.string = UsefulBuf_FROM_SZ_LITERAL("Displacement");
- EngineItems[1].uDataType = QCBOR_TYPE_INT64;
-
- EngineItems[2].uLabelType = QCBOR_TYPE_TEXT_STRING;
- EngineItems[2].label.string = UsefulBuf_FROM_SZ_LITERAL("Horsepower");
- EngineItems[2].uDataType = QCBOR_TYPE_INT64;
-
- EngineItems[3].uLabelType = QCBOR_TYPE_TEXT_STRING;
- EngineItems[3].label.string = UsefulBuf_FROM_SZ_LITERAL("DesignedCompression");
- EngineItems[3].uDataType = QCBOR_TYPE_DOUBLE;
-
- EngineItems[4].uLabelType = QCBOR_TYPE_TEXT_STRING;
- EngineItems[4].label.string = UsefulBuf_FROM_SZ_LITERAL("Turbo");
- EngineItems[4].uDataType = QCBOR_TYPE_ANY;
-
- EngineItems[5].uLabelType = QCBOR_TYPE_TEXT_STRING;
- EngineItems[5].label.string = UsefulBuf_FROM_SZ_LITERAL("NumCylinders");
- EngineItems[5].uDataType = QCBOR_TYPE_INT64;
-
- EngineItems[6].uLabelType = QCBOR_TYPE_NONE;
-
- QCBORDecode_GetItemsInMap(&DecodeCtx, EngineItems);
- uErr = QCBORDecode_GetError(&DecodeCtx);
- if(uErr != QCBOR_SUCCESS) {
- goto Done;
- }
-
- pE->Manufacturer = EngineItems[0].val.string;
- pE->uDisplacement = EngineItems[1].val.int64;
- pE->uHorsePower = EngineItems[2].val.int64;
- pE->dDesignedCompresion = EngineItems[3].val.dfnum;
- pE->uNumCylinders = EngineItems[5].val.int64;
-
- if(EngineItems[4].uDataType == QCBOR_TYPE_TRUE) {
- pE->bTurboCharged = true;
- } else if(EngineItems[4].uDataType == QCBOR_TYPE_FALSE) {
- pE->bTurboCharged = false;
- } else {
- return EngineProtocolerror;
- }
-
-
- /* Must check error before referencing pE->uNumCylinders to be
- sure it is valid. If any of the above errored, it won't be
- valid. */
- uErr = QCBORDecode_GetError(&DecodeCtx);
- if(uErr != QCBOR_SUCCESS) {
- goto Done;
- }
-
- if(pE->uNumCylinders > MAX_CYLINDERS) {
- return TooManyCylinders;
- }
-
- QCBORDecode_EnterArrayFromMapSZ(&DecodeCtx, "Cylinders");
- for(int64_t i = 0; i < pE->uNumCylinders; i++) {
- QCBORDecode_GetDouble(&DecodeCtx, &(pE->cylinders[i].uMeasuredCompression));
- }
- QCBORDecode_ExitArray(&DecodeCtx);
- QCBORDecode_ExitMap(&DecodeCtx);
-
- /* Catch the remainder of errors here */
- uErr = QCBORDecode_Finish(&DecodeCtx);
-
-Done:
- return ConvertError(uErr);
-}
-
-#endif /* EXAMPLE_DISABLE_SPIFFY_DECODE_FAST */
-
-
-#ifndef EXAMPLE_DISABLE_BASIC_DECODE
-/**
- @brief Check the type and lable of an item.
-
- @param[in] szLabel The expected string label.
- @param[in] uQCBORType The expected type or @c QCBOR_TYPE_ANY.
- @param[in] pItem The item to check.
-
- @retval QCBOR_ERR_LABEL_NOT_FOUND The label doesn't match.
- @retval QCBOR_ERR_UNEXPECTED_TYPE The label matches, but the type is
- not as expected.
- @retval QCBOR_SUCCESS Both label and type match.
- */
-QCBORError CheckLabelAndType(const char *szLabel, uint8_t uQCBORType, const QCBORItem *pItem)
-{
- if(pItem->uLabelType != QCBOR_TYPE_TEXT_STRING) {
- return QCBOR_ERR_LABEL_NOT_FOUND;
- }
-
- UsefulBufC Label = UsefulBuf_FromSZ(szLabel);
-
- if(UsefulBuf_Compare(Label, pItem->label.string)) {
- return QCBOR_ERR_LABEL_NOT_FOUND;
- }
-
- if(pItem->uDataType != uQCBORType && uQCBORType != QCBOR_TYPE_ANY) {
- return QCBOR_ERR_UNEXPECTED_TYPE;
- }
-
- return QCBOR_SUCCESS;
-}
-
-
-/**
- @brief Decode the array of engine cylinders.
-
- @param[in] pDecodeCtx The decode context from which to get items.
- @param[out] pE The structure filled in from the decoding.
- @param[in] pItem The data item that is the start of the array.
-
- @return Either @ref EngineSuccess or an error.
-
- This always consumes the whole array. If it has the wrong number of
- items in it, an error is returned.
- */
-EngineDecodeErrors DecodeCylinders(QCBORDecodeContext *pDecodeCtx,
- CarEngine *pE,
- const QCBORItem *pItem)
-{
- int i = 0;
- QCBORItem Item;
-
- /* Loop getting all the items in the array. This uses nesting
- level to detect the end so it works for both definite and
- indefinite length arrays. */
- do {
- QCBORError uErr;
-
- uErr = QCBORDecode_GetNext(pDecodeCtx, &Item);
- if(uErr != QCBOR_SUCCESS) {
- return CBORNotWellFormed;
- }
- if(Item.uDataType != QCBOR_TYPE_DOUBLE) {
- return CBORNotWellFormed;
- }
-
- if(i < MAX_CYLINDERS) {
- pE->cylinders[i].uMeasuredCompression = Item.val.dfnum;
- i++;
- }
-
- } while (Item.uNextNestLevel == pItem->uNextNestLevel);
-
- if(i != pE->uNumCylinders) {
- return WrongNumberOfCylinders;
- } else {
- return EngineSuccess;
- }
-}
-
-
-/**
- @brief Engine decode without spiffy decode.
-
- @param[in] EncodedEngine Pointer and length of CBOR-encoded engine.
- @param[out] pE The structure filled in from the decoding.
-
- @return The decode error or success.
-
- This is the third implementation of engine decoding, again
- implementing the same functionality as DecodeEngineSpiffy() and
- DecodeEngineSpiffyFaster().
-
- This version of the deocde is the most complex, but uses
- significantly less code (2-3KB less on 64-bit Intel) from the QCBOR
- library. It is also the most CPU-efficient since it does only one
- pass through the CBOR.
-*/
-EngineDecodeErrors DecodeEngineBasic(UsefulBufC EncodedEngine, CarEngine *pE)
-{
- QCBORDecodeContext DecodeCtx;
-
- QCBORDecode_Init(&DecodeCtx, EncodedEngine, QCBOR_DECODE_MODE_NORMAL);
-
- QCBORItem Item;
- QCBORError uErr;
- EngineDecodeErrors uReturn;
-
-
- uErr = QCBORDecode_GetNext(&DecodeCtx, &Item);
- if(uErr != QCBOR_SUCCESS) {
- uReturn = CBORNotWellFormed;
- goto Done;
- }
- if(Item.uDataType != QCBOR_TYPE_MAP) {
- uReturn = CBORNotWellFormed;
- goto Done;
- }
-
- while(1) {
- uErr = QCBORDecode_GetNext(&DecodeCtx, &Item);
- if(uErr != QCBOR_SUCCESS) {
- if(uErr == QCBOR_ERR_NO_MORE_ITEMS) {
- break; /* Non-error exit from the loop */
- } else {
- uReturn = CBORNotWellFormed;
- goto Done;
- }
- }
-
- uErr = CheckLabelAndType("Manufacturer", QCBOR_TYPE_TEXT_STRING, &Item);
- if(uErr == QCBOR_SUCCESS) {
- pE->Manufacturer = Item.val.string;
- continue;
- } else if(uErr != QCBOR_ERR_LABEL_NOT_FOUND){
- /* Maunfacturer field missing or badly formed */
- return EngineProtocolerror;
- } /* continue on and try for another match */
-
- uErr = CheckLabelAndType("NumCylinders", QCBOR_TYPE_INT64, &Item);
- if(uErr == QCBOR_SUCCESS) {
- if(Item.val.int64 > MAX_CYLINDERS) {
- return TooManyCylinders;
- } else {
- pE->uNumCylinders = (uint8_t)Item.val.int64;
- continue;
- }
- } else if(uErr != QCBOR_ERR_LABEL_NOT_FOUND){
- /* NumCylinders field missing or badly formed */
- return EngineProtocolerror;
- } /* continue on and try for another match */
-
- uErr = CheckLabelAndType("Cylinders", QCBOR_TYPE_ARRAY, &Item);
- if(uErr == QCBOR_SUCCESS) {
- DecodeCylinders(&DecodeCtx, pE, &Item);
- continue;
- } else if(uErr != QCBOR_ERR_LABEL_NOT_FOUND){
- return EngineProtocolerror;
- }
-
- uErr = CheckLabelAndType("Displacement", QCBOR_TYPE_INT64, &Item);
- if(uErr == QCBOR_SUCCESS) {
- pE->uDisplacement = Item.val.int64;
- continue;
- } else if(uErr != QCBOR_ERR_LABEL_NOT_FOUND){
- return EngineProtocolerror;
- }
-
- uErr = CheckLabelAndType("Horsepower", QCBOR_TYPE_INT64, &Item);
- if(uErr == QCBOR_SUCCESS) {
- pE->uHorsePower = Item.val.int64;
- continue;
- } else if(uErr != QCBOR_ERR_LABEL_NOT_FOUND){
- return EngineProtocolerror;
- }
-
- uErr = CheckLabelAndType("DesignedCompression", QCBOR_TYPE_DOUBLE, &Item);
- if(uErr == QCBOR_SUCCESS) {
- pE->dDesignedCompresion = Item.val.dfnum;
- continue;
- } else if(uErr != QCBOR_ERR_LABEL_NOT_FOUND){
- return EngineProtocolerror;
- }
-
- uErr = CheckLabelAndType("Turbo", QCBOR_TYPE_ANY, &Item);
- if(uErr == QCBOR_SUCCESS) {
- if(Item.uDataType == QCBOR_TYPE_TRUE) {
- pE->bTurboCharged = true;
- } else if(Item.uDataType == QCBOR_TYPE_FALSE) {
- pE->bTurboCharged = false;
- } else {
- return EngineProtocolerror;
- }
- continue;
- } else if(uErr != QCBOR_ERR_LABEL_NOT_FOUND){
- return EngineProtocolerror;
- }
-
- /* Some label data item that is not known (could just ignore
- extras data items) */
- return EngineProtocolerror;
- }
- uReturn = EngineSuccess;
-
- /* Catch the remainder of errors here */
- uErr = QCBORDecode_Finish(&DecodeCtx);
- if(uErr) {
- uReturn = ConvertError(uErr);
- }
-
-
-
-Done:
- return uReturn;
-}
-
-#endif /* EXAMPLE_DISABLE_BASIC_DECODE */
-
int32_t RunQCborExample()
{
- CarEngine E, DecodedEngine;
+ CarEngine InitialEngine;
+ CarEngine DecodedEngine;
/* For every buffer used by QCBOR a pointer and a length are always
* carried in a UsefulBuf. This is a secure coding and hygene
- * practice to help make sure code never runs off the end of a buffer.
+ * practice to help make sure code never runs off the end of a
+ * buffer.
*
* UsefulBuf structures are passed as a stack parameter to make the
- * code prettier. The object code generated isn't much different from
- * passing a pointer parameter and a length parameter.
+ * code prettier. The object code generated isn't much different
+ * from passing a pointer parameter and a length parameter.
*
* This macro is equivalent to:
* uint8_t __pBufEngineBuffer[300];
@@ -680,53 +308,33 @@
* and is used to represent a buffer that has been written to.
*/
UsefulBufC EncodedEngine;
-
- UsefulBuf_MAKE_STACK_UB( InDefEngineBuffer, 300);
- UsefulBufC InDefEncodedEngine;
-
EngineDecodeErrors uErr;
- EngineInit(&E);
+ /* Initialize the structure with some values. */
+ EngineInit(&InitialEngine);
-#ifndef EXAMPLE_DISABLE_DEFINITE_LENGTH_ENCODE
- EncodedEngine = EncodeEngineDefiniteLength(&E, EngineBuffer);
- printf("Definite Length Engine Encoded in %zu bytes\n", EncodedEngine.len);
-#endif /* EXAMPLE_DISABLE_DEFINITE_LENGTH_ENCODE */
+ /* Encode the engine structure. */
+ EncodedEngine = EncodeEngineDefiniteLength(&InitialEngine, EngineBuffer);
+ if(UsefulBuf_IsNULLC(EncodedEngine)) {
+ printf("Engine encode failed\n");
+ goto Done;
+ }
+ printf("Example: Definite Length Engine Encoded in %zu bytes\n",
+ EncodedEngine.len);
-
-#ifndef EXAMPLE_DISABLE_INDEFINITE_LENGTH_ENCODE_ENCODE
- InDefEncodedEngine = EncodeEngineIndefinteLen(&E, InDefEngineBuffer);
- printf("Indef Engine Encoded in %zu bytes\n", InDefEncodedEngine.len);
-#endif /* EXAMPLE_DISABLE_INDEFINITE_LENGTH_ENCODE_ENCODE */
-
-
-#ifndef EXAMPLE_DISABLE_SPIFFY_DECODE
+ /* Decode the CBOR */
uErr = DecodeEngineSpiffy(EncodedEngine, &DecodedEngine);
- printf("Spiffy Engine Decode Result: %d\n", uErr);
-
- if(!EngineCompare(&E, &DecodedEngine)) {
- printf("Spiffy Engine Decode comparison fail\n");
+ printf("Example: Spiffy Engine Decode Result: %d\n", uErr);
+ if(uErr) {
+ goto Done;
}
-#endif /* EXAMPLE_DISABLE_SPIFFY_DECODE */
-#ifndef EXAMPLE_DISABLE_SPIFFY_DECODE_FAST
- uErr = DecodeEngineSpiffyFaster(EncodedEngine, &DecodedEngine);
- printf("Faster Spiffy Engine Decode Result: %d\n", uErr);
-
- if(!EngineCompare(&E, &DecodedEngine)) {
- printf("Faster Spiffy Engine Decode comparison fail\n");
+ /* Check the results */
+ if(!EngineCompare(&InitialEngine, &DecodedEngine)) {
+ printf("Example: Spiffy Engine Decode comparison fail\n");
}
-#endif /* EXAMPLE_DISABLE_SPIFFY_DECODE_FAST */
-#ifndef EXAMPLE_DISABLE_BASIC_DECODE
- uErr = DecodeEngineBasic(EncodedEngine, &DecodedEngine);
- printf("Engine Basic Decode Result: %d\n", uErr);
-
- if(!EngineCompare(&E, &DecodedEngine)) {
- printf("Engine Basic Decode comparison fail\n");
- }
-#endif /* EXAMPLE_DISABLE_BASIC_DECODE */
-
+Done:
printf("\n");
return 0;
diff --git a/inc/qcbor/UsefulBuf.h b/inc/qcbor/UsefulBuf.h
index 6792e49..31a2868 100644
--- a/inc/qcbor/UsefulBuf.h
+++ b/inc/qcbor/UsefulBuf.h
@@ -41,7 +41,9 @@
when who what, where, why
-------- ---- --------------------------------------------------
- 1/25/2021 llundblade Improve comments and comment formatting.
+ 5/11/2021 llundblade Improve comments and comment formatting.
+ 3/6/2021 mcr/llundblade Fix warnings related to --Wcast-qual
+ 2/17/2021 llundblade Add method to go from a pointer to an offset.
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().
@@ -214,9 +216,15 @@
* that has been filled in. The length is amount of valid data pointed
* to.
*
- * A common use is to pass a @ref UsefulBuf to a function, the
- * function fills it in, the function returns a @ref UsefulBufC. The
- * pointer is the same in both.
+ * A commn use mode is to pass a @ref UsefulBuf to a function, the
+ * function puts some data in it, then the function returns a @ref
+ * UsefulBufC refering to the data. The @ref UsefulBuf is a non-const
+ * "in" parameter and the @ref UsefulBufC is a const "out" parameter
+ * so the constness stays correct. There is no single "in,out"
+ * parameter (if there was, it would have to be non-const). Note that
+ * the pointer returned in the @ref UsefulBufC usually ends up being
+ * the same pointer passed in as a @ref UsefulBuf, though this is not
+ * striclty required.
*
* A @ref UsefulBuf is null, it has no value, when @c ptr in it is
* @c NULL.
@@ -364,6 +372,15 @@
* @param[in] UBC The @ref UsefulBuf to convert.
*
* @return A non-const @ref UsefulBuf struct.
+ *
+ * TODO: REWRITE THIS
+ * It is better to avoid use of this. The intended convention for
+ * UsefulBuf is to make an empty buffer, some memory, as a UsefulBuf,
+ * fill it in, and then make it a UsefulBufC. In that convension this
+ * function is not needed.
+ *
+ * This is an explicit way to quiet compiler warnings from
+ * -Wcast-qual.
*/
static inline UsefulBuf UsefulBuf_Unconst(const UsefulBufC UBC);
@@ -582,7 +599,18 @@
size_t UsefulBuf_FindBytes(UsefulBufC BytesToSearch, UsefulBufC BytesToFind);
-#if 1 // NOT_DEPRECATED
+/**
+ @brief Convert a pointer to an offset with bounds checking.
+
+ @param[in] UB Pointer to the UsefulInputBuf.
+ @param[in] p Pointer to convert to offset.
+
+ @return SIZE_MAX if @c p is out of range, the byte offset if not.
+*/
+static inline size_t UsefulBuf_PointerToOffset(UsefulBufC UB, const void *p);
+
+
+#ifndef USEFULBUF_DISABLE_DEPRECATED
/** Deprecated macro; use @ref UsefulBuf_FROM_SZ_LITERAL instead */
#define SZLiteralToUsefulBufC(szString) \
((UsefulBufC) {(szString), sizeof(szString)-1})
@@ -599,9 +627,13 @@
/** Deprecated function; use UsefulBuf_Unconst() instead */
static inline UsefulBuf UsefulBufC_Unconst(const UsefulBufC UBC)
{
+ // See UsefulBuf_Unconst() implementation for comment on pragmas
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-qual"
return (UsefulBuf){(void *)UBC.ptr, UBC.len};
+#pragma GCC diagnostic pop
}
-#endif
+#endif /* USEFULBUF_DISABLE_DEPRECATED */
@@ -1325,6 +1357,18 @@
static int UsefulInputBuf_BytesAvailable(UsefulInputBuf *pUInBuf, size_t uLen);
+
+/**
+ * @brief Convert a pointer to an offset with bounds checking.
+ *
+ * @param[in] pUInBuf Pointer to the UsefulInputBuf.
+ * @param[in] p Pointer to convert to offset.
+ *
+ * @return SIZE_MAX if @c p is out of range, the byte offset if not.
+ * TODO: details for this?
+*/
+static inline size_t UsefulInputBuf_PointerToOffset(UsefulInputBuf *pUInBuf, const void *p);
+
/**
* @brief Get pointer to bytes out of the input buffer.
*
@@ -1575,10 +1619,15 @@
return (UsefulBufC){UB.ptr, UB.len};
}
-
static inline UsefulBuf UsefulBuf_Unconst(const UsefulBufC UBC)
{
+ /* -Wcast-qual is a good warning flag to use in general. This is
+ * the one place in UsefulBuf where it needs to be quieted. Since
+ * clang supports GCC pragmas, this works for clang too. */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-qual"
return (UsefulBuf){(void *)UBC.ptr, UBC.len};
+#pragma GCC diagnostic pop
}
@@ -1625,13 +1674,35 @@
} else if(UB.ptr == NULL) {
ReturnValue = (UsefulBufC){NULL, UB.len - uAmount};
} else {
- ReturnValue = (UsefulBufC){(uint8_t *)UB.ptr + uAmount, UB.len - uAmount};
+ ReturnValue = (UsefulBufC){(const uint8_t *)UB.ptr + uAmount, UB.len - uAmount};
}
return ReturnValue;
}
+static inline size_t UsefulBuf_PointerToOffset(UsefulBufC UB, const void *p)
+{
+ if(UB.ptr == NULL) {
+ return SIZE_MAX;
+ }
+
+ if(p < UB.ptr) {
+ /* given pointer is before start of buffer */
+ return SIZE_MAX;
+ }
+
+ // Cast to size_t (from ptrdiff_t) is OK because of check above
+ const size_t uOffset = (size_t)((const uint8_t *)p - (const uint8_t *)UB.ptr);
+
+ if(uOffset >= UB.len) {
+ /* given pointer is off the end of the buffer */
+ return SIZE_MAX;
+ }
+
+ return uOffset;
+}
+
static inline uint32_t UsefulBufUtil_CopyFloatToUint32(float f)
{
@@ -2005,6 +2076,12 @@
}
+static inline size_t UsefulInputBuf_PointerToOffset(UsefulInputBuf *pUInBuf, const void *p)
+{
+ return UsefulBuf_PointerToOffset(pUInBuf->UB, p);
+}
+
+
static inline UsefulBufC UsefulInputBuf_GetUsefulBuf(UsefulInputBuf *pMe, size_t uNum)
{
const void *pResult = UsefulInputBuf_GetBytes(pMe, uNum);
@@ -2025,7 +2102,7 @@
* needed to be completely explicit about types (for static
* analyzers).
*/
- return (uint8_t)(pResult ? *(uint8_t *)pResult : 0);
+ return (uint8_t)(pResult ? *(const uint8_t *)pResult : 0);
}
static inline uint16_t UsefulInputBuf_GetUint16(UsefulInputBuf *pMe)
diff --git a/inc/qcbor/qcbor_common.h b/inc/qcbor/qcbor_common.h
index 853de87..6883e1b 100644
--- a/inc/qcbor/qcbor_common.h
+++ b/inc/qcbor/qcbor_common.h
@@ -49,6 +49,14 @@
#define QCBOR_SPIFFY_DECODE
+/* It was originally defined as QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA,
+ * but this is incosistent with all the other QCBOR_DISABLE_
+ * #defines, so the name was changed and this was added for backwards
+ * compatibility
+ */
+#ifdef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+#define QCBOR_DISABLE_EXP_AND_MANTISSA
+#endif
/* Standard CBOR Major type for positive integers of various lengths */
@@ -435,7 +443,7 @@
/** All well-formed data items have been consumed and there are no
more. If parsing a CBOR stream this indicates the non-error end
- of the stream. If parsing a CBOR stream / sequence, this
+ of the stream. If not 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 = 33,
diff --git a/inc/qcbor/qcbor_decode.h b/inc/qcbor/qcbor_decode.h
index 960e810..94126bd 100644
--- a/inc/qcbor/qcbor_decode.h
+++ b/inc/qcbor/qcbor_decode.h
@@ -1,6 +1,6 @@
/*==============================================================================
Copyright (c) 2016-2018, The Linux Foundation.
- Copyright (c) 2018-2020, Laurence Lundblade.
+ Copyright (c) 2018-2021, Laurence Lundblade.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -318,7 +318,7 @@
UsefulBufC bigNum;
/** The integer value for unknown simple types. */
uint8_t uSimple;
-#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
/** @anchor expAndMantissa
The value for bigfloats and decimal fractions. The use of the
@@ -348,7 +348,7 @@
UsefulBufC bigNum;
} Mantissa;
} expAndMantissa;
-#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
uint64_t uTagV; // Used internally during decoding
} val;
@@ -866,6 +866,21 @@
/**
+ @brief QCBORDecode_GetNext() and consume entire map or array.
+
+ @param[in] pCtx The decoder context.
+ @param[out] pDecodedItem Holds the CBOR item just decoded.
+
+ This is the same as QCBORDecode_VGetNext() but the contents of the
+ entire map or array will be consumed if the next item is a map or array.
+
+ In order to go back to decode the contents of a map or array consumed
+ by this, the decoder must be rewound using QCBORDecode_Rewind().
+*/
+void QCBORDecode_VGetNextConsume(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem);
+
+
+/**
@brief Get the next data item without consuming it.
@param[in] pCtx The decoder context.
@@ -881,12 +896,13 @@
This is useful for looking ahead to determine the type
of a data item to know which type-specific spiffy decode
- function to call.
+ function to call.
*/
QCBORError
QCBORDecode_PeekNext(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem);
+
/**
@brief Gets the next item including full list of tags for item.
@@ -1031,10 +1047,39 @@
input was well-formed and there are extra bytes at the end @ref
QCBOR_ERR_EXTRA_BYTES will be returned. This can be considered a
successful decode.
+
+ See also QCBORDecode_PartialFinish().
*/
QCBORError QCBORDecode_Finish(QCBORDecodeContext *pCtx);
+/**
+ @brief Return number of bytes consumed so far.
+
+ @param[in] pCtx The context to check.
+ @param[out] puConsumed The number of bytes consumed so far. May be @c NULL.
+
+ @returns The same as QCBORDecode_Finish();
+
+ This is primarily for partially decoding CBOR sequences. It is the
+ same as QCBORDecode_Finish() except it returns the number of bytes
+ consumed and doesn't call the destructor for the string allocator
+ (See @ref and QCBORDecode_SetMemPool()).
+
+ When this is called before all input bytes are consumed, @ref
+ QCBOR_ERR_EXTRA_BYTES will be returned as QCBORDecode_Finish()
+ does. For typical use of this, that particular error is disregarded.
+
+ Decoding with the same @ref QCBORDecodeContext can continue after
+ calling this and this may be called many times.
+
+ Another way to resume decoding is to call QCBORDecode_Init() on the
+ bytes not decoded, but this only works on CBOR sequences when the
+ decoding stopped with no open arrays, maps or byte strings.
+ */
+QCBORError
+QCBORDecode_PartialFinish(QCBORDecodeContext *pCtx, size_t *puConsumed);
+
/**
@brief Get the decoding error.
@@ -1236,12 +1281,12 @@
static inline QCBORError QCBORDecode_GetError(QCBORDecodeContext *pMe)
{
- return pMe->uLastError;
+ return (QCBORError)pMe->uLastError;
}
static inline QCBORError QCBORDecode_GetAndResetError(QCBORDecodeContext *pMe)
{
- const QCBORError uReturn = pMe->uLastError;
+ const QCBORError uReturn = (QCBORError)pMe->uLastError;
pMe->uLastError = QCBOR_SUCCESS;
return uReturn;
}
diff --git a/inc/qcbor/qcbor_encode.h b/inc/qcbor/qcbor_encode.h
index 2460897..ba654ee 100644
--- a/inc/qcbor/qcbor_encode.h
+++ b/inc/qcbor/qcbor_encode.h
@@ -1,6 +1,6 @@
/*==============================================================================
Copyright (c) 2016-2018, The Linux Foundation.
- Copyright (c) 2018-2020, Laurence Lundblade.
+ Copyright (c) 2018-2021, Laurence Lundblade.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -920,7 +920,7 @@
UsefulBufC Bytes);
-#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
/**
@brief Add a decimal fraction to the encoded output.
@@ -1162,7 +1162,7 @@
UsefulBufC Mantissa,
bool bIsNegative,
int64_t nBase2Exponent);
-#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
/**
@@ -1722,6 +1722,8 @@
@param[out] pEncodedCBOR Structure in which the pointer and length of the encoded
CBOR is returned.
+ @retval QCBOR_SUCCESS Encoded CBOR is returned.
+
@retval QCBOR_ERR_TOO_MANY_CLOSES Nesting error
@retval QCBOR_ERR_CLOSE_MISMATCH Nesting error
@@ -2390,7 +2392,7 @@
-#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
static inline void
QCBOREncode_AddTDecimalFraction(QCBOREncodeContext *pMe,
@@ -2683,7 +2685,7 @@
{
QCBOREncode_AddTBigFloatBigNumToMapN(pMe, nLabel, QCBOR_ENCODE_AS_TAG, Mantissa, bIsNegative, nBase2Exponent);
}
-#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
static inline void
diff --git a/inc/qcbor/qcbor_private.h b/inc/qcbor/qcbor_private.h
index 5ddc16f..abd6ba2 100644
--- a/inc/qcbor/qcbor_private.h
+++ b/inc/qcbor/qcbor_private.h
@@ -152,11 +152,11 @@
QCBOR_TYPE_MAP or QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP_AS_ARRAY
for 2).
- Item tracking is either be for definite or indefinite length
+ Item tracking is either for definite or indefinite-length
maps/arrays. For definite lengths, the total count and items
- unconsumed are tracked. For indefinite length, uTotalCount is
+ unconsumed are tracked. For indefinite-length, uTotalCount is
QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH (UINT16_MAX) and there
- is no per-item count of members. For indefinite length maps and
+ is no per-item count of members. For indefinite-length maps and
arrays, uCountCursor is UINT16_MAX if not consumed and zero if
it is consumed in the pre-order traversal. Additionally, if
entered in bounded mode, uCountCursor is
@@ -185,9 +185,12 @@
uint32_t uStartOffset;
} ma; /* for maps and arrays */
struct {
- uint32_t uEndOfBstr;
- uint32_t uPreviousEndOffset;
- } bs; /* for top-level sequence and bstr wrapped CBOR */
+ /* The end of the input before the bstr was entered so that
+ * it can be restored when the bstr is exited. */
+ uint32_t uSavedEndOffset;
+ /* The beginning of the bstr so that it can be rewound. */
+ uint32_t uBstrStartOffset;
+ } bs; /* for top-level sequence and bstr-wrapped CBOR */
} u;
} pLevels[QCBOR_MAX_ARRAY_NESTING1+1],
*pCurrent,
diff --git a/inc/qcbor/qcbor_spiffy_decode.h b/inc/qcbor/qcbor_spiffy_decode.h
index 0ea6a71..3e69221 100644
--- a/inc/qcbor/qcbor_spiffy_decode.h
+++ b/inc/qcbor/qcbor_spiffy_decode.h
@@ -1,7 +1,7 @@
/*============================================================================
qcbor_spiffy_decode.h -- higher-level easier-to-use CBOR decoding.
- Copyright (c) 2020, Laurence Lundblade. All rights reserved.
+ Copyright (c) 2020-2021, Laurence Lundblade. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause
@@ -32,7 +32,7 @@
This section just discusses spiff decoding assuming familiarity with
the general description of this encoder / decoder in section
- @ref Overview and @ref BasicDecoding.
+ @ref Overview and @ref BasicDecode.
Spiffy decode is extra decode features over and above the @ref
BasicDecode features that generally are easier to use, mirror the
@@ -102,23 +102,34 @@
An easy and clean way to use this decoder is to always use EnterMap
and EnterArray for each array or map. They will error if the input
- CBOR is not the expected array or map. Then use GetInt, GetString to
- get the individual items of of the maps and arrays making use of the
- internal error tracking provided by this decoder. The only error
- check needed is the call to Finish.
+ CBOR is not the expected array or map. Then use GetInt, GetString
+ and such to get the individual items of the maps and arrays making
+ use of the internal error tracking provided by this decoder. The only
+ error check needed is the call to QCBORDecode_Finish().
QCBORDecode_GetNext() is the exception to this. It returns an
error. It doesn't set the internal error state. It will attempt to
- decode evening when in the error state.
+ decode even when in the error state.
- When getting an item by label from a map the whole map is traversed
- including traversal of nested arrays and maps. If there is any
- unrecoverable error anywhere in the that traversal the retrieval by
- label will fail and the unrecoverable error will be returned even if
- it is not due to the labeled item being sought. Recoverable errors
- will be ignored unless they are on the item being sought, in which
- case the unrecoverable error will be returned. Unrecoverable errors
- are those indicated by QCBORDecode_IsUnrecoverableError().
+ The effect of a decoding error on the traversal cursor position
+ varies by the type of decoding method called. The methods for getting
+ an item in a map by label don't affect the traversal cursor when
+ there is an error (nor when they succeed).
+ QCBORDecode_GetInt64InMapN() is an example of this. The other methods
+ like QCBORDecode_GetInt64() and QCBORDecode_GetNext() that normally
+ advance the traversal cursor will also advance it also when there is
+ an error unless the error is unrecoverable due to CBOR that is not
+ well formed or such. QCBORDecode_Rewind() can be used to reset the
+ cursor position after any error.
+
+ When getting an item by label from a map the whole map is internally
+ traversed including traversal of nested arrays and maps. If there is
+ any unrecoverable error anywhere in the that traversal the retrieval
+ by label will fail and the unrecoverable error will be returned even
+ if it is not because item being sought is in error. Recoverable
+ errors will be ignored unless they are on the item being sought, in
+ which case the unrecoverable error will be returned. Unrecoverable
+ errors are those indicated by QCBORDecode_IsUnrecoverableError().
@anchor Tag-Usage
## Tag Usage
@@ -151,7 +162,7 @@
example, to decode an epoch date tag the content must be an integer
or floating-point value.
- If the parameter indicates it should not be a tag
+ If the parameter indicates it should not be a tag
(@ref QCBOR_TAG_REQUIREMENT_NOT_A_TAG), then
@ref QCBOR_ERR_UNEXPECTED_TYPE set if it is a tag or the type of the
encoded CBOR is not what is expected. In the example of an epoch
@@ -659,6 +670,10 @@
This sets the pre-order traversal cursor to the item after the array
that was exited.
+
+ This will result in an error if any item in the array is not well
+ formed (since all items in the array must be decoded to find its
+ end), or there are not enough items in the array.
*/
static void QCBORDecode_ExitArray(QCBORDecodeContext *pCtx);
@@ -729,13 +744,36 @@
The items in the map that was entered do not have to have been
consumed for this to succeed.
- This sets the pre-order traversal cursor to the item after
- the map that was exited.
+ This sets the pre-order traversal cursor to the item after the map
+ that was exited.
+
+ This will result in an error if any item in the map is not well
+ formed (since all items in the map must be decoded to find its end),
+ or there are not enough items in the map.
*/
static void QCBORDecode_ExitMap(QCBORDecodeContext *pCtx);
/**
+ @brief Reset traversal cursor to start of map, array, byte-string
+ wrapped CBOR or start of input.
+
+ @param[in] pCtx The decode context.
+
+ If an array, map or wrapping byte string has been entered this sets
+ the traversal cursor to its beginning. If several arrays, maps or
+ byte strings have been entered, this sets the traversal cursor to the
+ beginning of the one most recently entered.
+
+ If no map or array has been entered, this resets the traversal cursor
+ to the beginning of the input CBOR.
+
+ This also resets the error state.
+ */
+void QCBORDecode_Rewind(QCBORDecodeContext *pCtx);
+
+
+/**
@brief Get an item in map by label and type.
@param[in] pCtx The decode context.
@@ -743,8 +781,8 @@
@param[in] uQcborType The QCBOR type. One of @c QCBOR_TYPE_XXX.
@param[out] pItem The returned item.
- A map must have been entered to use this. If not @ref QCBOR_ERR_MAP_NOT_ENTERED is
- set.
+ A map must have been entered to use this. If not @ref
+ QCBOR_ERR_MAP_NOT_ENTERED is set.
The map is searched for an item of the requested label and type.
@ref QCBOR_TYPE_ANY can be given to search for the label without
@@ -894,7 +932,7 @@
The CBOR item to decode must be either the CBOR simple value (CBOR
type 7) @c true or @c false.
- See @ref Decode-Errors for discussion on how error handling works. It
+ See @ref Decode-Errors for discussion on how error handling works. If
the CBOR item to decode is not true or false the @ref
QCBOR_ERR_UNEXPECTED_TYPE error is set.
*/
@@ -909,8 +947,43 @@
bool *pbBool);
+/**
+ @brief Decode the next item as a null.
+
+ @param[in] pCtx The decode context.
+
+ The CBOR item to decode must be the CBOR simple value (CBOR type 7)
+ @c null. The reason to call this is to see if an error is returned or
+ not indicating whether the item is a CBOR null. If it is not then the
+ @ref QCBOR_ERR_UNEXPECTED_TYPE error is set.
+*/
+static void QCBORDecode_GetNull(QCBORDecodeContext *pCtx);
+
+static void QCBORDecode_GetNullInMapN(QCBORDecodeContext *pCtx,
+ int64_t nLabel);
+
+static void QCBORDecode_GetNullInMapSZ(QCBORDecodeContext *pCtx,
+ const char *szLabel);
+/**
+ @brief Decode the next item as a CBOR "undefined" item.
+
+ @param[in] pCtx The decode context.
+
+ The CBOR item to decode must be the CBOR simple value (CBOR type 7)
+ @c undefined. The reason to call this is to see if an error is
+ returned or not indicating whether the item is a CBOR undefed
+ item. If it is not then the @ref QCBOR_ERR_UNEXPECTED_TYPE error is
+ set.
+*/
+static void QCBORDecode_GetUndefined(QCBORDecodeContext *pCtx);
+
+static void QCBORDecode_GetUndefinedInMapN(QCBORDecodeContext *pCtx,
+ int64_t nLabel);
+
+static void QCBORDecode_GetUndefinedInMapSZ(QCBORDecodeContext *pCtx,
+ const char *szLabel);
/**
@@ -1055,7 +1128,7 @@
-#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
/**
@brief Decode the next item as a decimal fraction.
@@ -1253,7 +1326,7 @@
UsefulBufC *pMantissa,
bool *pbMantissaIsNegative,
int64_t *pnExponent);
-#endif /* #ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+#endif /* #ifndef QCBOR_DISABLE_EXP_AND_MANTISSA */
@@ -1512,6 +1585,9 @@
CBOR. QCBORDecode_ExitBstrWrapped() must be called to resume processing
CBOR outside the wrapped CBOR.
+ This does not (currently) work on indefinite-length strings. The
+ (confusing) error @ref QCBOR_ERR_INPUT_TOO_LARGE will be set.
+
If @c pBstr is not @c NULL the pointer and length of the wrapped
CBOR will be returned. This is usually not needed, but sometimes
useful, particularly in the case of verifying signed data like the
@@ -1906,7 +1982,7 @@
static inline void
QCBORDecode_GetByteString(QCBORDecodeContext *pMe, UsefulBufC *pValue)
{
- // Complier should make this just 64-bit integer parameter
+ // Complier should make this just a 64-bit integer parameter
const TagSpecification TagSpec =
{
QCBOR_TAG_REQUIREMENT_NOT_A_TAG,
@@ -1993,6 +2069,60 @@
QCBORDecode_GetTaggedStringInMapSZ(pMe, szLabel, TagSpec, pText);
}
+static inline void
+QCBORDecode_GetNull(QCBORDecodeContext *pMe)
+{
+ QCBORItem item;
+
+ QCBORDecode_VGetNext(pMe, &item);
+ if(pMe->uLastError == QCBOR_SUCCESS && item.uDataType != QCBOR_TYPE_NULL) {
+ pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
+ }
+}
+
+static inline void
+QCBORDecode_GetNullInMapN(QCBORDecodeContext *pMe,
+ int64_t nLabel)
+{
+ QCBORItem Item;
+ QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_NULL, &Item);
+}
+
+static inline void
+QCBORDecode_GetNullInMapSZ(QCBORDecodeContext *pMe,
+ const char * szLabel)
+{
+ QCBORItem Item;
+ QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_NULL, &Item);
+}
+
+static inline void
+QCBORDecode_GetUndefined(QCBORDecodeContext *pMe)
+{
+ QCBORItem item;
+
+ QCBORDecode_VGetNext(pMe, &item);
+ if(pMe->uLastError == QCBOR_SUCCESS && item.uDataType != QCBOR_TYPE_UNDEF) {
+ pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
+ }
+}
+
+static inline void
+QCBORDecode_GetUndefinedInMapN(QCBORDecodeContext *pMe,
+ int64_t nLabel)
+{
+ QCBORItem Item;
+ QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_UNDEF, &Item);
+}
+
+static inline void
+QCBORDecode_GetUndefinedInMapSZ(QCBORDecodeContext *pMe,
+ const char * szLabel)
+{
+ QCBORItem Item;
+ QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_UNDEF, &Item);
+}
+
static inline void
QCBORDecode_GetDateString(QCBORDecodeContext *pMe,
diff --git a/src/UsefulBuf.c b/src/UsefulBuf.c
index a96f74e..e5be98a 100644
--- a/src/UsefulBuf.c
+++ b/src/UsefulBuf.c
@@ -1,6 +1,6 @@
/*==============================================================================
Copyright (c) 2016-2018, The Linux Foundation.
- Copyright (c) 2018-2020, Laurence Lundblade.
+ Copyright (c) 2018-2021, 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 @@
when who what, where, why
-------- ---- ---------------------------------------------------
+ 3/6/2021 mcr/llundblade Fix warnings related to --Wcast-qual
01/28/2020 llundblade Refine integer signedness to quiet static analysis.
01/08/2020 llundblade Documentation corrections & improved code formatting.
11/08/2019 llundblade Re check pointer math and update comments
@@ -106,12 +107,12 @@
return 0;
}
- const uint8_t * const pEnd = (uint8_t *)UB.ptr + UB.len;
+ const uint8_t * const pEnd = (const uint8_t *)UB.ptr + UB.len;
for(const uint8_t *p = UB.ptr; p < pEnd; p++) {
if(*p != uValue) {
/* Byte didn't match */
/* Cast from signed to unsigned . Safe because the loop increments.*/
- return (size_t)(p - (uint8_t *)UB.ptr);
+ return (size_t)(p - (const uint8_t *)UB.ptr);
}
}
@@ -130,7 +131,7 @@
}
for(size_t uPos = 0; uPos <= BytesToSearch.len - BytesToFind.len; uPos++) {
- if(!UsefulBuf_Compare((UsefulBufC){((uint8_t *)BytesToSearch.ptr) + uPos, BytesToFind.len}, BytesToFind)) {
+ if(!UsefulBuf_Compare((UsefulBufC){((const uint8_t *)BytesToSearch.ptr) + uPos, BytesToFind.len}, BytesToFind)) {
return uPos;
}
}
@@ -358,7 +359,7 @@
}
// This is going to succeed
- const void * const result = ((uint8_t *)pMe->UB.ptr) + pMe->cursor;
+ const void * const result = ((const uint8_t *)pMe->UB.ptr) + pMe->cursor;
// Will not overflow because of check using UsefulInputBuf_BytesAvailable()
pMe->cursor += uAmount;
return result;
diff --git a/src/qcbor_decode.c b/src/qcbor_decode.c
index ebcbc97..4d31b69 100644
--- a/src/qcbor_decode.c
+++ b/src/qcbor_decode.c
@@ -46,12 +46,6 @@
-/*
- * This casts away the const-ness of a pointer, usually so it can be
- * freed or realloced.
- */
-#define UNCONST_POINTER(ptr) ((void *)(ptr))
-
#define SIZEOF_C_ARRAY(array,type) (sizeof(array)/sizeof(type))
@@ -422,10 +416,10 @@
static inline QCBORError
DecodeNesting_DescendIntoBstrWrapped(QCBORDecodeNesting *pNesting,
- uint32_t uEndOffset,
- uint32_t uEndOfBstr)
+ uint32_t uEndOffset,
+ uint32_t uStartOffset)
{
- QCBORError uError = QCBOR_SUCCESS;
+ QCBORError uError;
uError = DecodeNesting_Descend(pNesting, QCBOR_TYPE_BYTE_STRING);
if(uError != QCBOR_SUCCESS) {
@@ -433,8 +427,8 @@
}
/* Fill in the new byte string level */
- pNesting->pCurrent->u.bs.uPreviousEndOffset = uEndOffset;
- pNesting->pCurrent->u.bs.uEndOfBstr = uEndOfBstr;
+ pNesting->pCurrent->u.bs.uSavedEndOffset = uEndOffset;
+ pNesting->pCurrent->u.bs.uBstrStartOffset = uStartOffset;
/* Bstr wrapped levels are always bounded */
pNesting->pCurrentBounded = pNesting->pCurrent;
@@ -454,7 +448,9 @@
static inline void
DecodeNesting_ResetMapOrArrayCount(QCBORDecodeNesting *pNesting)
{
- pNesting->pCurrentBounded->u.ma.uCountCursor = pNesting->pCurrentBounded->u.ma.uCountTotal;
+ if(pNesting->pCurrent->u.ma.uCountCursor != QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
+ pNesting->pCurrentBounded->u.ma.uCountCursor = pNesting->pCurrentBounded->u.ma.uCountTotal;
+ }
}
@@ -472,8 +468,6 @@
QCBORDecodeNesting *pSave)
{
*pSave = *pNesting;
- pNesting->pCurrent = pNesting->pCurrentBounded;
- DecodeNesting_ResetMapOrArrayCount(pNesting);
}
@@ -486,16 +480,9 @@
static inline uint32_t
-DecodeNesting_GetEndOfBstr(const QCBORDecodeNesting *pMe)
-{
- return pMe->pCurrentBounded->u.bs.uEndOfBstr;
-}
-
-
-static inline uint32_t
DecodeNesting_GetPreviousBoundedEnd(const QCBORDecodeNesting *pMe)
{
- return pMe->pCurrentBounded->u.bs.uPreviousEndOffset;
+ return pMe->pCurrentBounded->u.bs.uSavedEndOffset;
}
@@ -511,19 +498,30 @@
===========================================================================*/
static inline void
-StringAllocator_Free(const QCBORInternalAllocator *pMe, void *pMem)
+StringAllocator_Free(const QCBORInternalAllocator *pMe, const void *pMem)
{
- (pMe->pfAllocator)(pMe->pAllocateCxt, pMem, 0);
+ /* These pragmas allow the "-Wcast-qual" warnings flag to be set for
+ * gcc and clang. This is the one place where the const needs to be
+ * cast away so const can be use in the rest of the code.
+ */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-qual"
+ (pMe->pfAllocator)(pMe->pAllocateCxt, (void *)pMem, 0);
+#pragma GCC diagnostic pop
}
// StringAllocator_Reallocate called with pMem NULL is
// equal to StringAllocator_Allocate()
static inline UsefulBuf
StringAllocator_Reallocate(const QCBORInternalAllocator *pMe,
- void *pMem,
+ const void *pMem,
size_t uSize)
{
- return (pMe->pfAllocator)(pMe->pAllocateCxt, pMem, uSize);
+ /* See comment in StringAllocator_Free() */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-qual"
+ return (pMe->pfAllocator)(pMe->pAllocateCxt, (void *)pMem, uSize);
+#pragma GCC diagnostic pop
}
static inline UsefulBuf
@@ -535,9 +533,13 @@
static inline void
StringAllocator_Destruct(const QCBORInternalAllocator *pMe)
{
+ /* See comment in StringAllocator_Free() */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-qual"
if(pMe->pfAllocator) {
(pMe->pfAllocator)(pMe->pAllocateCxt, NULL, 0);
}
+#pragma GCC diagnostic pop
}
#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
@@ -1297,7 +1299,7 @@
* not NULL and a reallocation happens.
*/
UsefulBuf NewMem = StringAllocator_Reallocate(pAllocator,
- UNCONST_POINTER(FullString.ptr),
+ FullString.ptr,
FullString.len + StringChunkItem.val.string.len);
if(UsefulBuf_IsNULL(NewMem)) {
@@ -1311,7 +1313,7 @@
if(uReturn != QCBOR_SUCCESS && !UsefulBuf_IsNULLC(FullString)) {
/* Getting the item failed, clean up the allocated memory */
- StringAllocator_Free(pAllocator, UNCONST_POINTER(FullString.ptr));
+ StringAllocator_Free(pAllocator, FullString.ptr);
}
#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
uReturn = QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED;
@@ -1466,7 +1468,7 @@
memmove(&auItemsTags[1], auItemsTags, sizeof(auItemsTags) - sizeof(auItemsTags[0]));
/* Map the tag */
- uint16_t uMappedTagNumer;
+ uint16_t uMappedTagNumer = 0;
uReturn = MapTagNumber(pMe, pDecodedItem->val.uTagV, &uMappedTagNumer);
/* Continue even on error so as to consume all tags wrapping
* this data item so decoding can go on. If MapTagNumber()
@@ -1985,7 +1987,7 @@
}
-#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
/**
* @brief Decode decimal fractions and big floats.
*
@@ -2096,7 +2098,7 @@
Done:
return uReturn;
}
-#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
@@ -2253,11 +2255,11 @@
} else if(uTagToProcess == CBOR_TAG_DATE_EPOCH) {
uReturn = DecodeDateEpoch(pDecodedItem);
-#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
} else if(uTagToProcess == CBOR_TAG_DECIMAL_FRACTION ||
uTagToProcess == CBOR_TAG_BIGFLOAT) {
uReturn = QCBORDecode_MantissaAndExponent(pMe, pDecodedItem);
-#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
} else if(uTagToProcess == CBOR_TAG_MIME ||
uTagToProcess == CBOR_TAG_BINARY_MIME) {
@@ -2398,8 +2400,12 @@
/*
* Public function, see header qcbor/qcbor_decode.h file
*/
-QCBORError QCBORDecode_Finish(QCBORDecodeContext *pMe)
+QCBORError QCBORDecode_PartialFinish(QCBORDecodeContext *pMe, size_t *puConsumed)
{
+ if(puConsumed != NULL) {
+ *puConsumed = pMe->InBuf.cursor;
+ }
+
QCBORError uReturn = pMe->uLastError;
if(uReturn != QCBOR_SUCCESS) {
@@ -2418,6 +2424,15 @@
}
Done:
+ return uReturn;
+}
+
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+QCBORError QCBORDecode_Finish(QCBORDecodeContext *pMe)
+{
#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
/* Call the destructor for the string allocator if there is one.
* Always called, even if there are errors; always have to clean up.
@@ -2425,7 +2440,7 @@
StringAllocator_Destruct(&(pMe->StringAllocator));
#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
- return uReturn;
+ return QCBORDecode_PartialFinish(pMe, NULL);
}
@@ -2703,6 +2718,71 @@
}
+void QCBORDecode_VGetNextConsume(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
+{
+ uint8_t uNextNestLevel;
+
+ QCBORDecode_VGetNext(pMe, pDecodedItem);
+
+ if(pMe->uLastError == QCBOR_SUCCESS) {
+ pMe->uLastError = (uint8_t)ConsumeItem(pMe, pDecodedItem, &uNextNestLevel);
+ pDecodedItem->uNextNestLevel = uNextNestLevel;
+ }
+}
+
+
+
+/* Call only on maps and arrays. Rewinds the cursor
+ * to the start as if it was just entered.
+ */
+static void RewindMapOrArray(QCBORDecodeContext *pMe)
+{
+ /* Reset nesting tracking to the deepest bounded level */
+ DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
+
+ DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
+
+ /* Reposition traversal cursor to the start of the map/array */
+ UsefulInputBuf_Seek(&(pMe->InBuf),
+ DecodeNesting_GetMapOrArrayStart(&(pMe->nesting)));
+}
+
+
+/*
+ Public function, see header qcbor/qcbor_decode.h file
+ */
+void QCBORDecode_Rewind(QCBORDecodeContext *pMe)
+{
+ if(pMe->nesting.pCurrentBounded != NULL) {
+ /* In a bounded map, array or bstr-wrapped CBOR */
+
+ if(DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
+ /* In bstr-wrapped CBOR. */
+
+ /* Reposition traversal cursor to start of wrapping byte string */
+ UsefulInputBuf_Seek(&(pMe->InBuf),
+ pMe->nesting.pCurrentBounded->u.bs.uBstrStartOffset);
+ DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
+
+ } else {
+ /* In a map or array */
+ RewindMapOrArray(pMe);
+ }
+
+ } else {
+ /* Not in anything bounded */
+
+ /* Reposition traversal cursor to the start of input CBOR */
+ UsefulInputBuf_Seek(&(pMe->InBuf), 0ULL);
+
+ /* Reset nesting tracking to beginning of input. */
+ DecodeNesting_Init(&(pMe->nesting));
+ }
+
+ pMe->uLastError = QCBOR_SUCCESS;
+}
+
+
/* Return true if the labels in Item1 and Item2 are the same.
Works only for integer and string labels. Returns false
for any other type. */
@@ -2823,8 +2903,7 @@
DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
/* Reposition to search from the start of the map / array */
- UsefulInputBuf_Seek(&(pMe->InBuf),
- DecodeNesting_GetMapOrArrayStart(&(pMe->nesting)));
+ RewindMapOrArray(pMe);
/*
Loop over all the items in the map or array. Each item
@@ -2872,14 +2951,14 @@
uReturn = QCBOR_ERR_DUPLICATE_LABEL;
goto Done;
}
- /* Also try to match its type */
- if(!MatchType(Item, pItemArray[nIndex])) {
- uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
+ if(uResult != QCBOR_SUCCESS) {
+ /* The label matches, but the data item is in error */
+ uReturn = uResult;
goto Done;
}
-
- if(uResult != QCBOR_SUCCESS) {
- uReturn = uResult;
+ if(!MatchType(Item, pItemArray[nIndex])) {
+ /* The data item is not of the type(s) requested */
+ uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
goto Done;
}
@@ -3194,7 +3273,9 @@
return;
}
- /*
+
+ /* The map or array was found. Now enter it.
+ *
* QCBORDecode_EnterBoundedMapOrArray() used here, requires the
* next item for the pre-order traversal cursor to be the map/array
* found by MapSearch(). The next few lines of code force the
@@ -3435,16 +3516,11 @@
}
if(pMe->uLastError != QCBOR_SUCCESS) {
- // Already in error state; do nothing.
+ /* Already in error state; do nothing. */
return pMe->uLastError;
}
- QCBORError uError = QCBOR_SUCCESS;
-
- if(pItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
- uError = QCBOR_ERR_UNEXPECTED_TYPE;
- goto Done;;
- }
+ QCBORError uError;
const TagSpecification TagSpec =
{
@@ -3459,9 +3535,10 @@
}
if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
- // Reverse the decrement done by GetNext() for the bstr so the
- // increment in QCBORDecode_NestLevelAscender() called by ExitBoundedLevel()
- // will work right.
+ /* Reverse the decrement done by GetNext() for the bstr so the
+ * increment in QCBORDecode_NestLevelAscender() called by
+ * ExitBoundedLevel() will work right.
+ */
DecodeNesting_ReverseDecrement(&(pMe->nesting));
}
@@ -3469,34 +3546,40 @@
*pBstr = pItem->val.string;
}
- // This saves the current length of the UsefulInputBuf and then
- // narrows the UsefulInputBuf to start and length of the wrapped
- // CBOR that is being entered.
- //
- // This makes sure the length is less than
- // QCBOR_MAX_DECODE_INPUT_SIZE which is slighly less than
- // UINT32_MAX. The value UINT32_MAX is used as a special indicator
- // value. The checks against QCBOR_MAX_DECODE_INPUT_SIZE also make
- // the casts safe. uEndOfBstr will always be less than
- // uPreviousLength because of the way UsefulInputBuf works so there
- // is no need to check it. There is also a range check in the
- // seek.
- //
- // Most of these calls are simple inline accessors so this doesn't
- // amount to much code.
- // Cast of uPreviousLength to uint32_t for cases where SIZE_MAX < UINT32_MAX.
+ /* This saves the current length of the UsefulInputBuf and then
+ * narrows the UsefulInputBuf to start and length of the wrapped
+ * CBOR that is being entered.
+ *
+ * Most of these calls are simple inline accessors so this doesn't
+ * amount to much code.
+ */
+
const size_t uPreviousLength = UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
- if((uint32_t)uPreviousLength >= QCBOR_MAX_DECODE_INPUT_SIZE) {
+ /* This check makes the cast of uPreviousLength to uint32_t below safe. */
+ if(uPreviousLength >= QCBOR_MAX_DECODE_INPUT_SIZE) {
uError = QCBOR_ERR_INPUT_TOO_LARGE;
goto Done;
}
- const size_t uEndOfBstr = UsefulInputBuf_Tell(&(pMe->InBuf));
- UsefulInputBuf_Seek(&(pMe->InBuf), uEndOfBstr - pItem->val.string.len);
+
+ const size_t uStartOfBstr = UsefulInputBuf_PointerToOffset(&(pMe->InBuf),
+ pItem->val.string.ptr);
+ /* This check makes the cast of uStartOfBstr to uint32_t below safe. */
+ if(uStartOfBstr == SIZE_MAX || uStartOfBstr > QCBOR_MAX_DECODE_INPUT_SIZE) {
+ /* This should never happen because pItem->val.string.ptr should
+ * always be valid since it was just returned.
+ */
+ uError = QCBOR_ERR_INPUT_TOO_LARGE;
+ goto Done;
+ }
+
+ const size_t uEndOfBstr = uStartOfBstr + pItem->val.string.len;
+
+ UsefulInputBuf_Seek(&(pMe->InBuf), uStartOfBstr);
UsefulInputBuf_SetBufferLength(&(pMe->InBuf), uEndOfBstr);
uError = DecodeNesting_DescendIntoBstrWrapped(&(pMe->nesting),
(uint32_t)uPreviousLength,
- (uint32_t)uEndOfBstr);
+ (uint32_t)uStartOfBstr);
Done:
return uError;
}
@@ -3514,7 +3597,7 @@
return;
}
- /* Get the data item that is the map that is being searched */
+ /* Get the data item that is the byte string being entered */
QCBORItem Item;
pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
if(pMe->uLastError != QCBOR_SUCCESS) {
@@ -3579,6 +3662,8 @@
return;
}
+ const uint32_t uEndOfBstr = (uint32_t)UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
+
/*
Reset the length of the UsefulInputBuf to what it was before
the bstr wrapped CBOR was entered.
@@ -3587,83 +3672,77 @@
DecodeNesting_GetPreviousBoundedEnd(&(pMe->nesting)));
- QCBORError uErr = ExitBoundedLevel(pMe, DecodeNesting_GetEndOfBstr(&(pMe->nesting)));
+ QCBORError uErr = ExitBoundedLevel(pMe, uEndOfBstr);
pMe->uLastError = (uint8_t)uErr;
}
-
-
-
-
-static QCBORError
-InterpretBool(QCBORDecodeContext *pMe, const QCBORItem *pItem, bool *pBool)
+static inline void
+ProcessBool(QCBORDecodeContext *pMe, const QCBORItem *pItem, bool *pBool)
{
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ /* Already in error state, do nothing */
+ return;
+ }
+
switch(pItem->uDataType) {
case QCBOR_TYPE_TRUE:
*pBool = true;
- return QCBOR_SUCCESS;
break;
case QCBOR_TYPE_FALSE:
*pBool = false;
- return QCBOR_SUCCESS;
break;
default:
- return QCBOR_ERR_UNEXPECTED_TYPE;
+ pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
break;
}
CopyTags(pMe, pItem);
}
-
/*
- Public function, see header qcbor/qcbor_decode.h file
-*/
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
void QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue)
{
if(pMe->uLastError != QCBOR_SUCCESS) {
- // Already in error state, do nothing
+ /* Already in error state, do nothing */
return;
}
- QCBORError nError;
QCBORItem Item;
- nError = QCBORDecode_GetNext(pMe, &Item);
- if(nError != QCBOR_SUCCESS) {
- pMe->uLastError = (uint8_t)nError;
- return;
- }
- pMe->uLastError = (uint8_t)InterpretBool(pMe, &Item, pValue);
+ pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
+
+ ProcessBool(pMe, &Item, pValue);
}
/*
- Public function, see header qcbor/qcbor_decode.h file
-*/
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
void QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pMe, int64_t nLabel, bool *pValue)
{
QCBORItem Item;
QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
- pMe->uLastError = (uint8_t)InterpretBool(pMe, &Item, pValue);
+ ProcessBool(pMe, &Item, pValue);
}
/*
- Public function, see header qcbor/qcbor_decode.h file
-*/
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
void QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, bool *pValue)
{
QCBORItem Item;
QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
- pMe->uLastError = (uint8_t)InterpretBool(pMe, &Item, pValue);
+ ProcessBool(pMe, &Item, pValue);
}
@@ -3923,7 +4002,7 @@
-#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
typedef QCBORError (*fExponentiator)(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult);
@@ -4070,7 +4149,7 @@
return (*pfExp)(uMantissa, nExponent, puResult);
}
-#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
@@ -4308,7 +4387,7 @@
}
break;
-#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
case QCBOR_TYPE_DECIMAL_FRACTION:
if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
return ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
@@ -4398,7 +4477,7 @@
return QCBOR_ERR_UNEXPECTED_TYPE;
}
break;
-#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
default:
@@ -4653,7 +4732,7 @@
}
break;
-#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
case QCBOR_TYPE_DECIMAL_FRACTION:
if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
@@ -4726,7 +4805,7 @@
return QCBOR_ERR_UNEXPECTED_TYPE;
}
break;
-#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
default:
return QCBOR_ERR_UNEXPECTED_TYPE;
}
@@ -4972,7 +5051,7 @@
*/
switch(pItem->uDataType) {
-#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
case QCBOR_TYPE_DECIMAL_FRACTION:
if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
// Underflow gives 0, overflow gives infinity
@@ -4992,7 +5071,7 @@
return QCBOR_ERR_UNEXPECTED_TYPE;
}
break;
-#endif /* ndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+#endif /* ndef QCBOR_DISABLE_EXP_AND_MANTISSA */
case QCBOR_TYPE_POSBIGNUM:
if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
@@ -5010,7 +5089,7 @@
}
break;
-#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
double dMantissa = ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
@@ -5046,7 +5125,7 @@
return QCBOR_ERR_UNEXPECTED_TYPE;
}
break;
-#endif /* ndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+#endif /* ndef QCBOR_DISABLE_EXP_AND_MANTISSA */
default:
return QCBOR_ERR_UNEXPECTED_TYPE;
@@ -5143,7 +5222,7 @@
-#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
static inline UsefulBufC ConvertIntToBigNum(uint64_t uInt, UsefulBuf Buffer)
{
while((uInt & 0xff00000000000000UL) == 0) {
@@ -5694,4 +5773,4 @@
pnExponent);
}
-#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
diff --git a/src/qcbor_encode.c b/src/qcbor_encode.c
index 654bda9..59c420b 100644
--- a/src/qcbor_encode.c
+++ b/src/qcbor_encode.c
@@ -734,7 +734,7 @@
}
-#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+#ifndef QCBOR_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
@@ -775,7 +775,7 @@
}
QCBOREncode_CloseArray(pMe);
}
-#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
/*
diff --git a/test/UsefulBuf_Tests.c b/test/UsefulBuf_Tests.c
index 1c2634e..264fbca 100644
--- a/test/UsefulBuf_Tests.c
+++ b/test/UsefulBuf_Tests.c
@@ -1,6 +1,6 @@
/*==============================================================================
Copyright (c) 2016-2018, The Linux Foundation.
- Copyright (c) 2018-2020, Laurence Lundblade.
+ Copyright (c) 2018-2021, Laurence Lundblade.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -41,7 +41,7 @@
There is nothing adversarial in this test
*/
-const char * UOBTest_NonAdversarial()
+const char * UOBTest_NonAdversarial(void)
{
const char *szReturn = NULL;
@@ -160,7 +160,7 @@
*/
-const char *UOBTest_BoundaryConditionsTest()
+const char *UOBTest_BoundaryConditionsTest(void)
{
UsefulBuf_MAKE_STACK_UB(outbuf,2);
@@ -248,7 +248,7 @@
// Test function to get size and magic number check
-const char *TestBasicSanity()
+const char *TestBasicSanity(void)
{
UsefulBuf_MAKE_STACK_UB(outbuf,10);
@@ -293,7 +293,7 @@
-const char *UBMacroConversionsTest()
+const char *UBMacroConversionsTest(void)
{
char *szFoo = "foo";
@@ -310,16 +310,17 @@
if(Boo.len != 3 || strncmp(Boo.ptr, "Boo", 3))
return "UsefulBuf_FROM_BYTE_ARRAY_LITERAL failed";
- UsefulBuf B = (UsefulBuf){(void *)Too.ptr, Too.len};
+ char *String = "string"; // Intentionally not const
+ UsefulBuf B = (UsefulBuf){(void *)String, strlen(String)};
UsefulBufC BC = UsefulBuf_Const(B);
- if(BC.len != Too.len || BC.ptr != Too.ptr)
+ if(BC.len != strlen(String) || BC.ptr != String)
return "UsefulBufConst failed";
return NULL;
}
-const char *UBUtilTests()
+const char *UBUtilTests(void)
{
UsefulBuf UB = NULLUsefulBuf;
@@ -591,13 +592,46 @@
return "Failed to find 3";
}
+
+ const uint8_t pB[] = {0x01, 0x02, 0x03};
+ UsefulBufC Boo = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pB);
+ // Try to map a pointer before
+ if(UsefulBuf_PointerToOffset(Boo, pB-1) != SIZE_MAX) {
+ return "Didn't error on pointer before";
+ }
+
+ // Try to map a pointer after
+ if(UsefulBuf_PointerToOffset(Boo, pB+sizeof(pB)) != SIZE_MAX) {
+ return "Didn't error on pointer after";
+ }
+
+ // Try to map a pointer inside
+ if(UsefulBuf_PointerToOffset(Boo, pB+1) != 1) {
+ return "Incorrect pointer offset";
+ }
+
+ // Try to map a pointer at the start
+ if(UsefulBuf_PointerToOffset(Boo, pB) != 0) {
+ return "Incorrect pointer offset for start";
+ }
+
+ // Try to map a pointer at the end
+ if(UsefulBuf_PointerToOffset(Boo, pB + sizeof(pB)-1) != 2) {
+ return "Incorrect pointer offset for end";
+ }
+
+ // Try to map a pointer on a NULL UB
+ if(UsefulBuf_PointerToOffset(NULLUsefulBufC, pB ) != SIZE_MAX) {
+ return "Incorrect pointer offset for start";
+ }
+
return NULL;
}
-const char * UIBTest_IntegerFormat()
+const char * UIBTest_IntegerFormat(void)
{
- UsefulOutBuf_MakeOnStack(UOB,100);
+ UsefulOutBuf_MakeOnStack(UOB, 100);
const uint32_t u32 = 0x0A0B0C0D; // from https://en.wikipedia.org/wiki/Endianness
const uint64_t u64 = 1984738472938472;
@@ -695,11 +729,15 @@
return "expected error after seek";
}
+ if(UsefulInputBuf_PointerToOffset(&UIB, O.ptr) != 0) {
+ return "PointerToOffset not working";
+ }
+
return NULL;
}
-const char *UBUTest_CopyUtil()
+const char *UBUTest_CopyUtil(void)
{
if(UsefulBufUtil_CopyFloatToUint32(65536.0F) != 0x47800000) {
return "CopyFloatToUint32 failed";
diff --git a/test/qcbor_decode_tests.c b/test/qcbor_decode_tests.c
index acde3ca..236f59c 100644
--- a/test/qcbor_decode_tests.c
+++ b/test/qcbor_decode_tests.c
@@ -1,6 +1,6 @@
/*==============================================================================
Copyright (c) 2016-2018, The Linux Foundation.
- Copyright (c) 2018-2020, Laurence Lundblade.
+ Copyright (c) 2018-2021, Laurence Lundblade.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -918,6 +918,48 @@
return 0;
}
+
+static const uint8_t sEmptyMap[] = {
+ 0xA1, //# map(1)
+ 0x02, //# unsigned(2)
+ 0xA0, //# map(0)
+};
+
+int32_t ParseEmptyMapInMapTest(void)
+{
+ QCBORDecodeContext DCtx;
+ QCBORItem Item;
+ int nReturn = 0;
+ QCBORError uErr;
+
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(sEmptyMap),
+ QCBOR_DECODE_MODE_NORMAL);
+
+ /* now open the first Map */
+ uErr = QCBORDecode_GetNext(&DCtx, &Item);
+ if(uErr != QCBOR_SUCCESS ||
+ Item.uDataType != QCBOR_TYPE_MAP) {
+ nReturn = -3;
+ goto done;
+ }
+
+ if(QCBORDecode_GetNext(&DCtx, &Item) != 0) {
+ nReturn = -1;
+ goto done;
+ }
+ if(Item.uDataType != QCBOR_TYPE_MAP ||
+ Item.uNestingLevel != 1 ||
+ Item.label.int64 != 2) {
+ nReturn = -2;
+ goto done;
+ }
+
+ done:
+ return(nReturn);
+}
+
+
/* [[[[[[[[[[]]]]]]]]]] */
static const uint8_t spDeepArrays[] = {
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
@@ -1771,7 +1813,7 @@
}
#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
-
+
// Iterate until there is an error of some sort error
QCBORItem Item;
do {
@@ -2985,7 +3027,7 @@
4([1,3])
*/
uError = QCBORDecode_GetNext(&DCtx, &Item);
-#ifdef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+#ifdef QCBOR_DISABLE_EXP_AND_MANTISSA
if(uError != QCBOR_SUCCESS ||
Item.uDataType != QCBOR_TYPE_ARRAY ||
!QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_DECIMAL_FRACTION) ||
@@ -3001,7 +3043,7 @@
uError = QCBORDecode_GetNext(&DCtx, &Item);
uError = QCBORDecode_GetNext(&DCtx, &Item);
-#else /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+#else /* QCBOR_DISABLE_EXP_AND_MANTISSA */
if(uError != QCBOR_SUCCESS ||
Item.uDataType != QCBOR_TYPE_DECIMAL_FRACTION ||
QCBORDecode_GetNthTag(&DCtx, &Item, 0) != CBOR_TAG_INVALID64 ||
@@ -3011,7 +3053,7 @@
QCBORDecode_GetNthTag(&DCtx, &Item, 4) != CBOR_TAG_INVALID64 ) {
return -5;
}
-#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
/*
More than 4 tags on an item 225(226(227(228(229([])))))
@@ -4449,7 +4491,7 @@
#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
-#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
/* exponent, mantissa
[
@@ -4754,7 +4796,7 @@
struct FailInput));
}
-#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
@@ -5001,7 +5043,7 @@
/* Repeatedly enter and exit maps and arrays, go off the end of maps
and arrays and such. */
-static int32_t DecodeNestedIterate()
+static int32_t DecodeNestedIterate(void)
{
QCBORDecodeContext DCtx;
int32_t nReturn;
@@ -5151,6 +5193,9 @@
};
#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
+const unsigned char not_well_formed_submod_section[] = {
+ 0xa1, 0x14, 0x1f,
+};
int32_t EnterMapTest()
{
@@ -5440,9 +5485,65 @@
}
#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
+ QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0);
+ QCBORDecode_VGetNextConsume(&DCtx, &Item1);
+ if(Item1.uDataType != QCBOR_TYPE_MAP) {
+ return 2401;
+ }
+ if(QCBORDecode_GetError(&DCtx)) {
+ return 2402;
+ }
+
+ QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0);
+ QCBORDecode_VGetNext(&DCtx, &Item1);
+ if(Item1.uDataType != QCBOR_TYPE_MAP ||
+ Item1.val.uCount != 3 ||
+ Item1.uNextNestLevel != 1) {
+ return 2403;
+ }
+ if(QCBORDecode_GetError(&DCtx)) {
+ return 2404;
+ }
+ QCBORDecode_VGetNextConsume(&DCtx, &Item1);
+ if(Item1.uDataType != QCBOR_TYPE_INT64 ||
+ Item1.uNextNestLevel != 1 ||
+ Item1.val.int64 != 42) {
+ return 2405;
+ }
+ if(QCBORDecode_GetError(&DCtx)) {
+ return 2406;
+ }
+ QCBORDecode_VGetNextConsume(&DCtx, &Item1);
+ if(Item1.uDataType != QCBOR_TYPE_ARRAY ||
+ Item1.uNestingLevel != 1 ||
+ Item1.uNextNestLevel != 1 ||
+ Item1.val.uCount != 2) {
+ return 2407;
+ }
+ if(QCBORDecode_GetError(&DCtx)) {
+ return 2408;
+ }
+ QCBORDecode_VGetNextConsume(&DCtx, &Item1);
+ if(Item1.uDataType != QCBOR_TYPE_MAP ||
+ Item1.uNestingLevel != 1 ||
+ Item1.uNextNestLevel != 0 ||
+ Item1.val.uCount != 4) {
+ return 2409;
+ }
+ if(QCBORDecode_GetError(&DCtx)) {
+ return 2410;
+ }
nReturn = DecodeNestedIterate();
+
+ QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(not_well_formed_submod_section), 0);
+ QCBORDecode_EnterMap(&DCtx, NULL);
+ QCBORDecode_EnterMapFromMapN(&DCtx, 20);
+ if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_BAD_INT) {
+ return 2500;
+ }
+
return nReturn;
}
@@ -5493,61 +5594,61 @@
"Decimal Fraction with positive bignum 257 * 10e3",
{(uint8_t[]){0xC4, 0x82, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
0xC2, 0x42, 0x01, 0x01}, 15},
-#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
257000,
QCBOR_SUCCESS,
257000,
QCBOR_SUCCESS,
257000.0,
QCBOR_SUCCESS
-#else /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+#else /* QCBOR_DISABLE_EXP_AND_MANTISSA */
0,
QCBOR_ERR_UNEXPECTED_TYPE,
0,
QCBOR_ERR_UNEXPECTED_TYPE,
0.0,
QCBOR_ERR_UNEXPECTED_TYPE
-#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA*/
+#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA*/
},
{
"bigfloat with negative bignum -258 * 2e3",
{(uint8_t[]){0xC5, 0x82, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
0xC3, 0x42, 0x01, 0x01}, 15},
-#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
-2064,
QCBOR_SUCCESS,
0,
QCBOR_ERR_NUMBER_SIGN_CONVERSION,
-2064.0,
QCBOR_SUCCESS
-#else /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+#else /* QCBOR_DISABLE_EXP_AND_MANTISSA */
0,
QCBOR_ERR_UNEXPECTED_TYPE,
0,
QCBOR_ERR_UNEXPECTED_TYPE,
0.0,
QCBOR_ERR_UNEXPECTED_TYPE
-#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA*/
+#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA*/
},
{
"bigfloat with positive bignum 257 * 2e3",
{(uint8_t[]){0xC5, 0x82, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
0xC2, 0x42, 0x01, 0x01}, 15},
-#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
2056,
QCBOR_SUCCESS,
2056,
QCBOR_SUCCESS,
2056.0,
QCBOR_SUCCESS
-#else /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+#else /* QCBOR_DISABLE_EXP_AND_MANTISSA */
0,
QCBOR_ERR_UNEXPECTED_TYPE,
0,
QCBOR_ERR_UNEXPECTED_TYPE,
0.0,
QCBOR_ERR_UNEXPECTED_TYPE
-#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA*/
+#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA*/
},
{
"negative bignum 0xc349010000000000000000 -18446744073709551617",
@@ -5575,60 +5676,60 @@
"Decimal Fraction with neg bignum [9223372036854775807, -4759477275222530853137]",
{(uint8_t[]){0xC4, 0x82, 0x1B, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xC3, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10,}, 23},
-#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
0,
QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW,
0,
QCBOR_ERR_NUMBER_SIGN_CONVERSION,
-INFINITY,
QCBOR_SUCCESS
-#else /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+#else /* QCBOR_DISABLE_EXP_AND_MANTISSA */
0,
QCBOR_ERR_UNEXPECTED_TYPE,
0,
QCBOR_ERR_UNEXPECTED_TYPE,
0.0,
QCBOR_ERR_UNEXPECTED_TYPE
-#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
},
{
"big float [9223372036854775806, 9223372036854775806]",
{(uint8_t[]){0xC5, 0x82, 0x1B, 0x7f, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
0x1B, 0x7f, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE}, 20},
-#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
0,
QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW,
0,
QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW,
INFINITY,
QCBOR_SUCCESS
-#else /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+#else /* QCBOR_DISABLE_EXP_AND_MANTISSA */
0,
QCBOR_ERR_UNEXPECTED_TYPE,
0,
QCBOR_ERR_UNEXPECTED_TYPE,
0.0,
QCBOR_ERR_UNEXPECTED_TYPE
-#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
},
{
"Big float 3 * 2^^2",
{(uint8_t[]){0xC5, 0x82, 0x02, 0x03}, 4},
-#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
12,
QCBOR_SUCCESS,
12,
QCBOR_SUCCESS,
12.0,
QCBOR_SUCCESS
-#else /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+#else /* QCBOR_DISABLE_EXP_AND_MANTISSA */
0,
QCBOR_ERR_UNEXPECTED_TYPE,
0,
QCBOR_ERR_UNEXPECTED_TYPE,
0.0,
QCBOR_ERR_UNEXPECTED_TYPE
-#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
},
{
"Positive integer 18446744073709551615",
@@ -5738,21 +5839,21 @@
{
"Decimal fraction 3/10",
{(uint8_t[]){0xC4, 0x82, 0x20, 0x03}, 4},
-#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
0,
QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW,
0,
QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW,
0.30000000000000004,
QCBOR_SUCCESS
-#else /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+#else /* QCBOR_DISABLE_EXP_AND_MANTISSA */
0,
QCBOR_ERR_UNEXPECTED_TYPE,
0,
QCBOR_ERR_UNEXPECTED_TYPE,
0.0,
QCBOR_ERR_UNEXPECTED_TYPE
-#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
},
{
"+inifinity",
@@ -5914,21 +6015,21 @@
0xC5, 0x82,
0x3B, 0x7f, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
0x1B, 0x7f, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE}, 20},
-#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
0,
QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW,
0,
QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW,
0,
QCBOR_SUCCESS
-#else /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+#else /* QCBOR_DISABLE_EXP_AND_MANTISSA */
0,
QCBOR_ERR_UNEXPECTED_TYPE,
0,
QCBOR_ERR_UNEXPECTED_TYPE,
0.0,
QCBOR_ERR_UNEXPECTED_TYPE
-#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
},
{
@@ -5937,21 +6038,21 @@
0xC5, 0x82,
0x1B, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
0xC3, 0x42, 0x01, 0x01}, 15},
-#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
0,
QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW,
0,
QCBOR_ERR_NUMBER_SIGN_CONVERSION,
-INFINITY,
QCBOR_SUCCESS
-#else /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+#else /* QCBOR_DISABLE_EXP_AND_MANTISSA */
0,
QCBOR_ERR_UNEXPECTED_TYPE,
0,
QCBOR_ERR_UNEXPECTED_TYPE,
0.0,
QCBOR_ERR_UNEXPECTED_TYPE
-#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA*/
+#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA*/
},
};
@@ -6048,8 +6149,9 @@
int32_t CBORSequenceDecodeTests(void)
{
QCBORDecodeContext DCtx;
- QCBORItem Item;
- QCBORError uCBORError;
+ QCBORItem Item;
+ QCBORError uCBORError;
+ size_t uConsumed;
// --- Test a sequence with extra bytes ---
@@ -6069,12 +6171,24 @@
return 2;
}
+ uCBORError = QCBORDecode_PartialFinish(&DCtx, &uConsumed);
+ if(uCBORError != QCBOR_ERR_EXTRA_BYTES ||
+ uConsumed != 12) {
+ return 102;
+ }
+
// Get a second item
uCBORError = QCBORDecode_GetNext(&DCtx, &Item);
if(uCBORError != QCBOR_ERR_BAD_OPT_TAG) {
return 66;
}
+ uCBORError = QCBORDecode_PartialFinish(&DCtx, &uConsumed);
+ if(uCBORError != QCBOR_ERR_EXTRA_BYTES ||
+ uConsumed != 14) {
+ return 102;
+ }
+
// Get a third item
uCBORError = QCBORDecode_GetNext(&DCtx, &Item);
if(uCBORError != QCBOR_SUCCESS) {
@@ -6984,8 +7098,90 @@
#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
+/*
+ * An array of an integer and an array. The second array contains
+ * a bstr-wrapped map.
+ *
+ * [7, [h'A36D6669... (see next lines) 73']]
+ *
+ * {"first integer": 42,
+ * "an array of two strings": ["string1", "string2"],
+ * "map in a map":
+ * { "bytes 1": h'78787878',
+ * "bytes 2": h'79797979',
+ * "another int": 98,
+ * "text 2": "lies, damn lies and statistics"
+ * }
+ * }
+ */
-int32_t PeekTest()
+static const uint8_t pValidWrappedMapEncoded[] = {
+ 0x82, 0x07, 0x81, 0x58, 0x97,
+ 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,
+ 0x74, 0x77, 0x6f, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67,
+ 0x73, 0x82, 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x31,
+ 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x32, 0x6c, 0x6d,
+ 0x61, 0x70, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x6d, 0x61,
+ 0x70, 0xa4, 0x67, 0x62, 0x79, 0x74, 0x65, 0x73, 0x20, 0x31,
+ 0x44, 0x78, 0x78, 0x78, 0x78, 0x67, 0x62, 0x79, 0x74, 0x65,
+ 0x73, 0x20, 0x32, 0x44, 0x79, 0x79, 0x79, 0x79, 0x6b, 0x61,
+ 0x6e, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x74,
+ 0x18, 0x62, 0x66, 0x74, 0x65, 0x78, 0x74, 0x20, 0x32, 0x78,
+ 0x1e, 0x6c, 0x69, 0x65, 0x73, 0x2c, 0x20, 0x64, 0x61, 0x6d,
+ 0x6e, 0x20, 0x6c, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64,
+ 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63,
+ 0x73
+};
+
+#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
+
+/* As above, but the arrays are indefinite length */
+static const uint8_t pValidIndefWrappedMapEncoded[] = {
+ 0x9f, 0x07, 0x9f, 0x58, 0x97,
+ 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,
+ 0x74, 0x77, 0x6f, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67,
+ 0x73, 0x82, 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x31,
+ 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x32, 0x6c, 0x6d,
+ 0x61, 0x70, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x6d, 0x61,
+ 0x70, 0xa4, 0x67, 0x62, 0x79, 0x74, 0x65, 0x73, 0x20, 0x31,
+ 0x44, 0x78, 0x78, 0x78, 0x78, 0x67, 0x62, 0x79, 0x74, 0x65,
+ 0x73, 0x20, 0x32, 0x44, 0x79, 0x79, 0x79, 0x79, 0x6b, 0x61,
+ 0x6e, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x74,
+ 0x18, 0x62, 0x66, 0x74, 0x65, 0x78, 0x74, 0x20, 0x32, 0x78,
+ 0x1e, 0x6c, 0x69, 0x65, 0x73, 0x2c, 0x20, 0x64, 0x61, 0x6d,
+ 0x6e, 0x20, 0x6c, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64,
+ 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63,
+ 0x73,
+ 0xff, 0xff
+};
+#endif
+
+
+static const uint8_t pWithEmptyMap[] = {0x82, 0x18, 0x64, 0xa0};
+
+#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
+static const uint8_t pWithEmptyMapInDef[] = {0x9f, 0x18, 0x64, 0xbf, 0xff, 0xff};
+#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
+
+#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
+static const uint8_t pWrappedByIndefiniteLength[] = {
+ 0x81,
+ 0xd8, 0x18,
+ 0x5f,
+ 0x41, 0x83,
+ 0x41, 0x18,
+ 0x43, 0x2A, 0x18, 0x2B,
+ 0x42, 0x18, 0x2C,
+ 0xff
+};
+#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
+
+
+int32_t PeekAndRewindTest()
{
QCBORItem Item;
QCBORError nCBORError;
@@ -7055,8 +7251,9 @@
Item.uLabelAlloc ||
UsefulBufCompareToSZ(Item.label.string, "an array of two strings") ||
Item.uDataType != QCBOR_TYPE_ARRAY ||
- Item.val.uCount != 2)
+ Item.val.uCount != 2) {
return 1400;
+ }
if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
return 1500 + (int32_t)nCBORError;
@@ -7155,8 +7352,9 @@
Item.uLabelAlloc ||
UsefulBufCompareToSZ(Item.label.string, "another int") ||
Item.uDataType != QCBOR_TYPE_INT64 ||
- Item.val.int64 != 98)
+ Item.val.int64 != 98) {
return 2900;
+ }
if((nCBORError = QCBORDecode_PeekNext(&DCtx, &Item))) {
return 3000 + (int32_t)nCBORError;
@@ -7182,5 +7380,571 @@
return 3300;
}
+
+
+ // Rewind to top level after entering several maps
+ QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0);
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return (int32_t)nCBORError;
+ }
+ if(Item.uDataType != QCBOR_TYPE_MAP ||
+ Item.val.uCount != 3) {
+ return 400;
+ }
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return 4000+(int32_t)nCBORError;
+ }
+
+ if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+ Item.uDataType != QCBOR_TYPE_INT64 ||
+ Item.val.int64 != 42 ||
+ Item.uDataAlloc ||
+ Item.uLabelAlloc ||
+ UsefulBufCompareToSZ(Item.label.string, "first integer")) {
+ return 4100;
+ }
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return 4100+(int32_t)nCBORError;
+ }
+ if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+ Item.uDataAlloc ||
+ Item.uLabelAlloc ||
+ UsefulBufCompareToSZ(Item.label.string, "an array of two strings") ||
+ Item.uDataType != QCBOR_TYPE_ARRAY ||
+ Item.val.uCount != 2) {
+ return 4200;
+ }
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return 4200+(int32_t)nCBORError;
+ }
+ if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+ Item.uDataAlloc ||
+ Item.uLabelAlloc ||
+ UsefulBufCompareToSZ(Item.val.string, "string1")) {
+ return 4300;
+ }
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return 4300+(int32_t)nCBORError;
+ }
+ if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+ Item.uDataAlloc ||
+ Item.uLabelAlloc ||
+ UsefulBufCompareToSZ(Item.val.string, "string2")) {
+ return 4400;
+ }
+
+ QCBORDecode_Rewind(&DCtx);
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return 4400+(int32_t)nCBORError;
+ }
+ if(Item.uDataType != QCBOR_TYPE_MAP ||
+ Item.val.uCount != 3) {
+ return 4500;
+ }
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return (int32_t)nCBORError;
+ }
+
+ if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+ Item.uDataType != QCBOR_TYPE_INT64 ||
+ Item.val.int64 != 42 ||
+ Item.uDataAlloc ||
+ Item.uLabelAlloc ||
+ UsefulBufCompareToSZ(Item.label.string, "first integer")) {
+ return 4600;
+ }
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return (int32_t)nCBORError;
+ }
+ if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+ Item.uDataAlloc ||
+ Item.uLabelAlloc ||
+ UsefulBufCompareToSZ(Item.label.string, "an array of two strings") ||
+ Item.uDataType != QCBOR_TYPE_ARRAY ||
+ Item.val.uCount != 2) {
+ return 4700;
+ }
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return (int32_t)nCBORError;
+ }
+ if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+ Item.uDataAlloc ||
+ Item.uLabelAlloc ||
+ UsefulBufCompareToSZ(Item.val.string, "string1")) {
+ return 4800;
+ }
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return 4900+(int32_t)nCBORError;
+ }
+ if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+ Item.uDataAlloc ||
+ Item.uLabelAlloc ||
+ UsefulBufCompareToSZ(Item.val.string, "string2")) {
+ return 5000;
+ }
+
+
+ // Rewind an entered map
+ QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0);
+
+ QCBORDecode_EnterMap(&DCtx, NULL);
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return 5100+(int32_t)nCBORError;
+ }
+
+ if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+ Item.uDataType != QCBOR_TYPE_INT64 ||
+ Item.val.int64 != 42 ||
+ Item.uDataAlloc ||
+ Item.uLabelAlloc ||
+ UsefulBufCompareToSZ(Item.label.string, "first integer")) {
+ return 5200;
+ }
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return 5200+(int32_t)nCBORError;
+ }
+ if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+ Item.uDataAlloc ||
+ Item.uLabelAlloc ||
+ UsefulBufCompareToSZ(Item.label.string, "an array of two strings") ||
+ Item.uDataType != QCBOR_TYPE_ARRAY ||
+ Item.val.uCount != 2) {
+ return -5300;
+ }
+
+ QCBORDecode_Rewind(&DCtx);
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return 5300+(int32_t)nCBORError;
+ }
+
+ if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+ Item.uDataType != QCBOR_TYPE_INT64 ||
+ Item.val.int64 != 42 ||
+ Item.uDataAlloc ||
+ Item.uLabelAlloc ||
+ UsefulBufCompareToSZ(Item.label.string, "first integer")) {
+ return 5400;
+ }
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return 5400+(int32_t)nCBORError;
+ }
+ if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
+ Item.uDataAlloc ||
+ Item.uLabelAlloc ||
+ UsefulBufCompareToSZ(Item.label.string, "an array of two strings") ||
+ Item.uDataType != QCBOR_TYPE_ARRAY ||
+ Item.val.uCount != 2) {
+ return 5500;
+ }
+
+
+ // Rewind and entered array inside an entered map
+ QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0);
+
+ QCBORDecode_EnterMap(&DCtx, NULL);
+
+ QCBORDecode_EnterArrayFromMapSZ(&DCtx, "an array of two strings");
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return 5600+(int32_t)nCBORError;
+ }
+ if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+ Item.uDataAlloc ||
+ Item.uLabelAlloc ||
+ UsefulBufCompareToSZ(Item.val.string, "string1")) {
+ return 5700;
+ }
+
+ QCBORDecode_Rewind(&DCtx);
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return 5700+(int32_t)nCBORError;
+ }
+ if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+ Item.uDataAlloc ||
+ Item.uLabelAlloc ||
+ UsefulBufCompareToSZ(Item.val.string, "string1")) {
+ return 5800;
+ }
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return (int32_t)nCBORError;
+ }
+ if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+ Item.uDataAlloc ||
+ Item.uLabelAlloc ||
+ UsefulBufCompareToSZ(Item.val.string, "string2")) {
+ return 5900;
+ }
+
+ QCBORDecode_Rewind(&DCtx);
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return 5900+(int32_t)nCBORError;
+ }
+ if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+ Item.uDataAlloc ||
+ Item.uLabelAlloc ||
+ UsefulBufCompareToSZ(Item.val.string, "string1")) {
+ return 6000;
+ }
+
+
+ // Rewind a byte string inside an array inside an array
+ QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidWrappedMapEncoded), 0);
+
+ QCBORDecode_EnterArray(&DCtx, NULL);
+
+ uint64_t i;
+ QCBORDecode_GetUInt64(&DCtx, &i);
+
+ QCBORDecode_EnterArray(&DCtx, NULL);
+
+ QCBORDecode_EnterBstrWrapped(&DCtx, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL);
+ if(QCBORDecode_GetError(&DCtx)) {
+ return 6100;
+ }
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return (int32_t)nCBORError;
+ }
+ if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) {
+ return 6200;
+ }
+
+ QCBORDecode_Rewind(&DCtx);
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return 6300+(int32_t)nCBORError;
+ }
+ if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) {
+ return 6400;
+ }
+
+#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
+ // Rewind a byte string inside an indefinite-length array inside
+ // indefinite-length array
+
+ QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidIndefWrappedMapEncoded), 0);
+
+ QCBORDecode_EnterArray(&DCtx, NULL);
+
+ QCBORDecode_GetUInt64(&DCtx, &i);
+
+ QCBORDecode_EnterArray(&DCtx, NULL);
+
+ QCBORDecode_EnterBstrWrapped(&DCtx, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, NULL);
+ if(QCBORDecode_GetError(&DCtx)) {
+ return 6500;
+ }
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return 6600+(int32_t)nCBORError;
+ }
+ if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) {
+ return 6700;
+ }
+
+ QCBORDecode_Rewind(&DCtx);
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return 6800+(int32_t)nCBORError;
+ }
+ if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 3) {
+ return 6900;
+ }
+#endif
+
+ // Rewind an empty map
+ // [100, {}]
+ QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pWithEmptyMap), 0);
+ QCBORDecode_EnterArray(&DCtx, NULL);
+ QCBORDecode_GetUInt64(&DCtx, &i);
+ if(i != 100) {
+ return 7010;
+ }
+ QCBORDecode_EnterMap(&DCtx, NULL);
+
+ /* Do it 5 times to be sure multiple rewinds work */
+ for(int n = 0; n < 5; n++) {
+ nCBORError = QCBORDecode_GetNext(&DCtx, &Item);
+ if(nCBORError != QCBOR_ERR_NO_MORE_ITEMS) {
+ return 7000 + n;
+ }
+ QCBORDecode_Rewind(&DCtx);
+ }
+ QCBORDecode_ExitMap(&DCtx);
+ QCBORDecode_Rewind(&DCtx);
+ QCBORDecode_GetUInt64(&DCtx, &i);
+ if(i != 100) {
+ return 7010;
+ }
+ QCBORDecode_ExitArray(&DCtx);
+ QCBORDecode_Rewind(&DCtx);
+ QCBORDecode_EnterArray(&DCtx, NULL);
+ i = 9;
+ QCBORDecode_GetUInt64(&DCtx, &i);
+ if(i != 100) {
+ return 7020;
+ }
+ if(QCBORDecode_GetError(&DCtx)){
+ return 7030;
+ }
+
+ // Rewind an empty indefinite length map
+#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
+ QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pWithEmptyMapInDef), 0);
+ QCBORDecode_EnterArray(&DCtx, NULL);
+ QCBORDecode_GetUInt64(&DCtx, &i);
+ if(i != 100) {
+ return 7810;
+ }
+ QCBORDecode_EnterMap(&DCtx, NULL);
+
+ /* Do it 5 times to be sure multiple rewinds work */
+ for(int n = 0; n < 5; n++) {
+ nCBORError = QCBORDecode_GetNext(&DCtx, &Item);
+ if(nCBORError != QCBOR_ERR_NO_MORE_ITEMS) {
+ return 7800 + n;
+ }
+ QCBORDecode_Rewind(&DCtx);
+ }
+ QCBORDecode_ExitMap(&DCtx);
+ QCBORDecode_Rewind(&DCtx);
+ QCBORDecode_GetUInt64(&DCtx, &i);
+ if(i != 100) {
+ return 7810;
+ }
+ QCBORDecode_ExitArray(&DCtx);
+ QCBORDecode_Rewind(&DCtx);
+ QCBORDecode_EnterArray(&DCtx, NULL);
+ i = 9;
+ QCBORDecode_GetUInt64(&DCtx, &i);
+ if(i != 100) {
+ return 7820;
+ }
+ if(QCBORDecode_GetError(&DCtx)){
+ return 7830;
+ }
+#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
+
+ // Rewind an indefnite length byte-string wrapped sequence
+#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pWrappedByIndefiniteLength),
+ 0);
+ UsefulBuf_MAKE_STACK_UB(Pool, 100);
+ QCBORDecode_SetMemPool(&DCtx, Pool, 0);
+
+ QCBORDecode_EnterArray(&DCtx, NULL);
+ QCBORDecode_EnterBstrWrapped(&DCtx, 2, NULL);
+ if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_INPUT_TOO_LARGE) {
+ /* this is what happens when trying to enter
+ indefinite-length byte string
+ wrapped CBOR. Tolerate for now. Eventually it needs
+ to be fixed so this works, but that is not simple. */
+ return 7300;
+ }
+
+ /*
+ QCBORDecode_GetUInt64(&DCtx, &i);
+ if(i != 42) {
+ return 7110;
+ }
+ QCBORDecode_Rewind(&DCtx);
+ QCBORDecode_GetUInt64(&DCtx, &i);
+ if(i != 42) {
+ return 7220;
+ }*/
+#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
+
+
+ // Rewind an indefnite length byte-string wrapped sequence
+
+ return 0;
+}
+
+
+
+
+static const uint8_t spBooleansInMap[] =
+{
+ 0xa1, 0x08, 0xf5
+};
+
+static const uint8_t spBooleansInMapWrongType[] =
+{
+ 0xa1, 0x08, 0xf6
+};
+
+static const uint8_t spBooleansInMapNWF[] =
+{
+ 0xa1, 0x08, 0x1a
+};
+
+static const uint8_t spNullInMap[] =
+{
+ 0xa1, 0x08, 0xf6
+};
+
+static const uint8_t spUndefinedInMap[] =
+{
+ 0xa1, 0x08, 0xf7
+};
+
+
+int32_t BoolTest(void)
+{
+ QCBORDecodeContext DCtx;
+ bool b;
+
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMap),
+ 0);
+ QCBORDecode_EnterMap(&DCtx, NULL);
+ QCBORDecode_GetBool(&DCtx, &b);
+ if(QCBORDecode_GetAndResetError(&DCtx) || !b) {
+ return 1;
+ }
+
+ QCBORDecode_GetBoolInMapN(&DCtx, 7, &b);
+ if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_LABEL_NOT_FOUND) {
+ return 2;
+ }
+
+ QCBORDecode_GetBoolInMapN(&DCtx, 8, &b);
+ if(QCBORDecode_GetAndResetError(&DCtx) || !b) {
+ return 3;
+ }
+
+
+ QCBORDecode_GetBoolInMapSZ(&DCtx, "xx", &b);
+ if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_LABEL_NOT_FOUND) {
+ return 4;
+ }
+
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMapWrongType),
+ 0);
+ QCBORDecode_EnterMap(&DCtx, NULL);
+ QCBORDecode_GetBool(&DCtx, &b);
+ if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) {
+ return 5;
+ }
+
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMapNWF),
+ 0);
+ QCBORDecode_EnterMap(&DCtx, NULL);
+ QCBORDecode_GetBool(&DCtx, &b);
+ if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_HIT_END) {
+ return 6;
+ }
+
+
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spNullInMap),
+ 0);
+ QCBORDecode_EnterMap(&DCtx, NULL);
+ QCBORDecode_GetNull(&DCtx);
+ if(QCBORDecode_GetAndResetError(&DCtx)) {
+ return 7;
+ }
+
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMap),
+ 0);
+ QCBORDecode_EnterMap(&DCtx, NULL);
+ QCBORDecode_GetNull(&DCtx);
+ if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) {
+ return 8;
+ }
+
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spNullInMap),
+ 0);
+ QCBORDecode_EnterMap(&DCtx, NULL);
+ QCBORDecode_GetNullInMapN(&DCtx, 8);
+ if(QCBORDecode_GetAndResetError(&DCtx)) {
+ return 9;
+ }
+
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMap),
+ 0);
+ QCBORDecode_EnterMap(&DCtx, NULL);
+ QCBORDecode_GetNullInMapN(&DCtx, 8);
+ if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) {
+ return 10;
+ }
+
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMapNWF),
+ 0);
+ QCBORDecode_EnterMap(&DCtx, NULL);
+ QCBORDecode_GetUndefined(&DCtx);
+ if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_HIT_END) {
+ return 11;
+ }
+
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spUndefinedInMap),
+ 0);
+ QCBORDecode_EnterMap(&DCtx, NULL);
+ QCBORDecode_GetUndefined(&DCtx);
+ if(QCBORDecode_GetAndResetError(&DCtx)) {
+ return 12;
+ }
+
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMap),
+ 0);
+ QCBORDecode_EnterMap(&DCtx, NULL);
+ QCBORDecode_GetUndefined(&DCtx);
+ if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) {
+ return 13;
+ }
+
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spUndefinedInMap),
+ 0);
+ QCBORDecode_EnterMap(&DCtx, NULL);
+ QCBORDecode_GetUndefinedInMapN(&DCtx, 8);
+ if(QCBORDecode_GetAndResetError(&DCtx)) {
+ return 14;
+ }
+
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMap),
+ 0);
+ QCBORDecode_EnterMap(&DCtx, NULL);
+ QCBORDecode_GetUndefinedInMapN(&DCtx, 8);
+ if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_UNEXPECTED_TYPE) {
+ return 15;
+ }
+
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBooleansInMapNWF),
+ 0);
+ QCBORDecode_EnterMap(&DCtx, NULL);
+ QCBORDecode_GetUndefined(&DCtx);
+ if(QCBORDecode_GetAndResetError(&DCtx) != QCBOR_ERR_HIT_END) {
+ return 15;
+ }
+
return 0;
}
diff --git a/test/qcbor_decode_tests.h b/test/qcbor_decode_tests.h
index 7e11e35..54e125a 100644
--- a/test/qcbor_decode_tests.h
+++ b/test/qcbor_decode_tests.h
@@ -1,6 +1,6 @@
/*==============================================================================
Copyright (c) 2016-2018, The Linux Foundation.
- Copyright (c) 2018-2020, Laurence Lundblade.
+ Copyright (c) 2018-2021, Laurence Lundblade.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -112,6 +112,10 @@
*/
int32_t ParseMapTest(void);
+/*
+ Parses a map that contains a zero-length map as value.
+*/
+int32_t ParseEmptyMapInMapTest(void);
/*
Test the decoder mode where maps are treated as arrays.
@@ -243,7 +247,7 @@
int32_t SetUpAllocatorTest(void);
-#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
/*
Test decoding of decimal fractions and big floats, both of which are
made up of an exponent and mantissa.
@@ -255,7 +259,7 @@
Hostile input tests for decimal fractions and big floats.
*/
int32_t ExponentAndMantissaDecodeFailTests(void);
-#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
int32_t EnterMapTest(void);
@@ -301,8 +305,13 @@
/*
Test PeekNext().
*/
-int32_t PeekTest(void);
+int32_t PeekAndRewindTest(void);
+/*
+Test decoding of booleans
+*/
+int32_t BoolTest(void);
+
#endif /* defined(__QCBOR__qcbort_decode_tests__) */
diff --git a/test/qcbor_encode_tests.c b/test/qcbor_encode_tests.c
index f9d8507..6655aed 100644
--- a/test/qcbor_encode_tests.c
+++ b/test/qcbor_encode_tests.c
@@ -1,6 +1,6 @@
/*==============================================================================
Copyright (c) 2016-2018, The Linux Foundation.
- Copyright (c) 2018-2020, Laurence Lundblade.
+ Copyright (c) 2018-2021, Laurence Lundblade.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -96,7 +96,7 @@
#endif
-#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
/*
Returns 0 if UsefulBufs are equal
Returns 1000000 + offeset if they are not equal.
@@ -116,10 +116,10 @@
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(((const uint8_t *)Actual.ptr)[i] != ((const uint8_t *)Expected.ptr)[i]) {
if(pDiag) {
- pDiag->uActual = ((uint8_t *)Actual.ptr)[i];
- pDiag->uExpected = ((uint8_t *)Expected.ptr)[i];
+ pDiag->uActual = ((const uint8_t *)Actual.ptr)[i];
+ pDiag->uExpected = ((const uint8_t *)Expected.ptr)[i];
pDiag->uOffset = i;
}
// Cast to int is OK as this is only a diagnostic and the sizes
@@ -130,7 +130,7 @@
return 0;
}
-#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
// One big buffer that is used by all the tests to encode into
@@ -2513,7 +2513,7 @@
}
-#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
/*
[
4([-1, 3]),
@@ -2711,7 +2711,7 @@
return 0;
}
-#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
int32_t QCBORHeadTest()
diff --git a/test/qcbor_encode_tests.h b/test/qcbor_encode_tests.h
index e54168a..ae64f7d 100644
--- a/test/qcbor_encode_tests.h
+++ b/test/qcbor_encode_tests.h
@@ -1,6 +1,6 @@
/*==============================================================================
Copyright (c) 2016-2018, The Linux Foundation.
- Copyright (c) 2018-2020, Laurence Lundblade.
+ Copyright (c) 2018-2021, Laurence Lundblade.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -165,13 +165,13 @@
int32_t CoseSign1TBSTest(void);
-#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+#ifndef QCBOR_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 */
+#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
/*
diff --git a/test/run_tests.c b/test/run_tests.c
index 0146d93..53d83f6 100644
--- a/test/run_tests.c
+++ b/test/run_tests.c
@@ -1,7 +1,7 @@
/*==============================================================================
run_tests.c -- test aggregator and results reporting
- Copyright (c) 2018-2020, Laurence Lundblade. All rights reserved.
+ Copyright (c) 2018-2021, Laurence Lundblade. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause
@@ -20,6 +20,12 @@
#include "UsefulBuf_Tests.h"
+
+// For size printing and some conditionals
+#include "qcbor/qcbor_encode.h"
+#include "qcbor/qcbor_decode.h"
+#include "qcbor/qcbor_spiffy_decode.h"
+
/*
Test configuration
*/
@@ -123,13 +129,15 @@
TEST_ENTRY(CBORSequenceDecodeTests),
TEST_ENTRY(IntToTests),
TEST_ENTRY(DecodeTaggedTypeTests),
- TEST_ENTRY(PeekTest),
-#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
+ TEST_ENTRY(PeekAndRewindTest),
+#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
TEST_ENTRY(EncodeLengthThirtyoneTest),
TEST_ENTRY(ExponentAndMantissaDecodeTests),
TEST_ENTRY(ExponentAndMantissaDecodeFailTests),
TEST_ENTRY(ExponentAndMantissaEncodeTests),
-#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
+#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
+ TEST_ENTRY(ParseEmptyMapInMapTest),
+ TEST_ENTRY(BoolTest)
};
@@ -295,10 +303,6 @@
}
-// For size printing
-#include "qcbor/qcbor_encode.h"
-#include "qcbor/qcbor_decode.h"
-#include "qcbor/qcbor_spiffy_decode.h"
/*