Merge branch 'master' into AdvancedDecode
diff --git a/QCBOR.xcodeproj/project.pbxproj b/QCBOR.xcodeproj/project.pbxproj
index c6ba72d..a193355 100644
--- a/QCBOR.xcodeproj/project.pbxproj
+++ b/QCBOR.xcodeproj/project.pbxproj
@@ -68,6 +68,7 @@
E73B575D2161CA7C0080D658 /* half_to_double_from_rfc7049.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = half_to_double_from_rfc7049.c; path = test/half_to_double_from_rfc7049.c; sourceTree = "<group>"; };
E73B57632161F8F70080D658 /* run_tests.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.c; name = run_tests.c; path = test/run_tests.c; sourceTree = "<group>"; tabWidth = 3; };
E73B57642161F8F80080D658 /* run_tests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = run_tests.h; path = test/run_tests.h; sourceTree = "<group>"; };
+ E74BF411245D6713002CE8E8 /* UsefulBuf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UsefulBuf.h; path = inc/qcbor/UsefulBuf.h; sourceTree = "<group>"; };
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; };
@@ -137,6 +138,7 @@
E776E092214AE07C00E67947 /* inc */ = {
isa = PBXGroup;
children = (
+ E74BF411245D6713002CE8E8 /* UsefulBuf.h */,
E78C91DF240C90C100F4CECE /* qcbor_common.h */,
E78C91DE240C90C100F4CECE /* qcbor_decode.h */,
E78C91E1240C90C100F4CECE /* qcbor_encode.h */,
@@ -210,7 +212,7 @@
E776E074214ADF7F00E67947 /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 0940;
+ LastUpgradeCheck = 1140;
ORGANIZATIONNAME = "Laurence Lundblade";
TargetAttributes = {
E776E07B214ADF7F00E67947 = {
@@ -361,7 +363,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_LABEL = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- HEADER_SEARCH_PATHS = inc;
+ "HEADER_SEARCH_PATHS[arch=*]" = inc;
MACOSX_DEPLOYMENT_TARGET = 10.13;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
@@ -421,7 +423,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_LABEL = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- HEADER_SEARCH_PATHS = inc;
+ "HEADER_SEARCH_PATHS[arch=*]" = inc;
MACOSX_DEPLOYMENT_TARGET = 10.13;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
diff --git a/inc/qcbor/UsefulBuf.h b/inc/qcbor/UsefulBuf.h
index a8da83b..16a53d3 100644
--- a/inc/qcbor/UsefulBuf.h
+++ b/inc/qcbor/UsefulBuf.h
@@ -134,7 +134,7 @@
These #define config options affect the inline implementation of
UsefulOutBuf_InsertUint64() and UsefulInputBuf_GetUint64(). They
also affect the 16-, 32-bit, float and double versions of these
- instructions. Since they are inline, they size effect is not in the
+ instructions. Since they are inline, the size effect is not in the
UsefulBuf object code, but in the calling code.
Summary:
diff --git a/inc/qcbor/qcbor_decode.h b/inc/qcbor/qcbor_decode.h
index 8f7c416..af1354e 100644
--- a/inc/qcbor/qcbor_decode.h
+++ b/inc/qcbor/qcbor_decode.h
@@ -130,7 +130,6 @@
can't be relied upon.
-
*/
/**
@@ -909,12 +908,35 @@
@param[in] pCtx The context to check.
- @return An error or @ref QCBOR_SUCCESS.
-
- This tells you if all the bytes given to QCBORDecode_Init() have been
- consumed and whether all maps and arrays were closed. The decode is
- considered to be incorrect or incomplete if not and an error will be
- returned.
+ @retval QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN The CBOR is not well-formed
+ as some map or array was not closed off. This should always be treated as an
+ unrecoverable error.
+
+ @retval QCBOR_ERR_EXTRA_BYTES The CBOR was decoded correctly and
+ all maps and arrays are closed, but some of the bytes in the input were not consumed.
+ This may or may not be considered an error.
+
+ @retval QCBOR_SUCCES There were no errors and all bytes were
+ consumed.
+
+ This should always be called to determine if all maps and arrays
+ where correctly closed and that the CBOR was well-formed.
+
+ This calls the destructor for the string allocator, if one is in use.
+
+ Some CBOR protocols use a CBOR sequence [RFC 8742]
+ (https://tools.ietf.org/html/rfc8742) . A CBOR sequence typically
+ doesn't start out with a map or an array. The end of the CBOR is
+ determined in some other way, perhaps by external framing, or by the
+ occurrence of some particular CBOR data item or such. The buffer given
+ to decode must start out with valid CBOR, but it can have extra bytes
+ at the end that are not CBOR or CBOR that is to be ignored.
+
+ QCBORDecode_Finish() should still be called when decoding CBOR
+ Sequences to check that the input decoded was well-formed. If the
+ 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.
*/
QCBORError QCBORDecode_Finish(QCBORDecodeContext *pCtx);
diff --git a/inc/qcbor/qcbor_encode.h b/inc/qcbor/qcbor_encode.h
index 31fda52..46fa578 100644
--- a/inc/qcbor/qcbor_encode.h
+++ b/inc/qcbor/qcbor_encode.h
@@ -210,6 +210,13 @@
Note that when you nest arrays or maps in a map, the nested array or
map has a label.
+
+ Many CBOR-based protocols start with an array or map. This makes them
+ self-delimiting. No external length or end marker is needed to know
+ the end. It is also possible not start this way, in which case this
+ it is usually called a CBOR sequence which is described in [RFC 8742] (https://tools.ietf.org/html/rfc8742 ).
+ This encoder supports either just by whether the first item added is an
+ array, map or other.
@anchor Tags-Overview
Any CBOR data item can be tagged to add semantics, define a new data
diff --git a/test/qcbor_decode_tests.c b/test/qcbor_decode_tests.c
index 39a5c7a..b18d40b 100644
--- a/test/qcbor_decode_tests.c
+++ b/test/qcbor_decode_tests.c
@@ -3974,3 +3974,133 @@
return 0;
}
+
+
+int32_t CBORSequenceDecodeTests(void)
+{
+ QCBORDecodeContext DCtx;
+ QCBORItem Item;
+ QCBORError uCBORError;
+
+ // --- Test a sequence with extra bytes ---
+
+ // The input for the date test happens to be a sequence so it
+ // is reused. It is a sequence because it doesn't start as
+ // an array or map.
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spDateTestInput),
+ QCBOR_DECODE_MODE_NORMAL);
+
+ // Get the first item
+ uCBORError = QCBORDecode_GetNext(&DCtx, &Item);
+ if(uCBORError != QCBOR_SUCCESS) {
+ return 1;
+ }
+ if(Item.uDataType != QCBOR_TYPE_DATE_STRING) {
+ return 2;
+ }
+
+ // Get a second item
+ uCBORError = QCBORDecode_GetNext(&DCtx, &Item);
+ if(uCBORError != QCBOR_SUCCESS) {
+ return 2;
+ }
+ if(Item.uDataType != QCBOR_TYPE_DATE_EPOCH) {
+ return 3;
+ }
+
+ // A sequence can have stuff at the end that may
+ // or may not be valid CBOR. The protocol decoder knows
+ // when to stop by definition of the protocol, not
+ // when the top-level map or array is ended.
+ // Finish still has to be called to know that
+ // maps and arrays (if there were any) were closed
+ // off correctly. When called like this it
+ // must return the error QCBOR_ERR_EXTRA_BYTES.
+ uCBORError = QCBORDecode_Finish(&DCtx);
+ if(uCBORError != QCBOR_ERR_EXTRA_BYTES) {
+ return 4;
+ }
+
+
+ // --- Test an empty input ----
+ uint8_t empty[1];
+ UsefulBufC Empty = {empty, 0};
+ QCBORDecode_Init(&DCtx,
+ Empty,
+ QCBOR_DECODE_MODE_NORMAL);
+
+ uCBORError = QCBORDecode_Finish(&DCtx);
+ if(uCBORError != QCBOR_SUCCESS) {
+ return 5;
+ }
+
+
+ // --- Sequence with unclosed indefinite length array ---
+ static const uint8_t xx[] = {0x01, 0x9f, 0x02};
+
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(xx),
+ QCBOR_DECODE_MODE_NORMAL);
+
+ // Get the first item
+ uCBORError = QCBORDecode_GetNext(&DCtx, &Item);
+ if(uCBORError != QCBOR_SUCCESS) {
+ return 7;
+ }
+ if(Item.uDataType != QCBOR_TYPE_INT64) {
+ return 8;
+ }
+
+ // Get a second item
+ uCBORError = QCBORDecode_GetNext(&DCtx, &Item);
+ if(uCBORError != QCBOR_SUCCESS) {
+ return 9;
+ }
+ if(Item.uDataType != QCBOR_TYPE_ARRAY) {
+ return 10;
+ }
+
+ // Try to finish before consuming all bytes to confirm
+ // that the still-open error is returned.
+ uCBORError = QCBORDecode_Finish(&DCtx);
+ if(uCBORError != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) {
+ return 11;
+ }
+
+
+ // --- Sequence with a closed indefinite length array ---
+ static const uint8_t yy[] = {0x01, 0x9f, 0xff};
+
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(yy),
+ QCBOR_DECODE_MODE_NORMAL);
+
+ // Get the first item
+ uCBORError = QCBORDecode_GetNext(&DCtx, &Item);
+ if(uCBORError != QCBOR_SUCCESS) {
+ return 12;
+ }
+ if(Item.uDataType != QCBOR_TYPE_INT64) {
+ return 13;
+ }
+
+ // Get a second item
+ uCBORError = QCBORDecode_GetNext(&DCtx, &Item);
+ if(uCBORError != QCBOR_SUCCESS) {
+ return 14;
+ }
+ if(Item.uDataType != QCBOR_TYPE_ARRAY) {
+ return 15;
+ }
+
+ // Try to finish before consuming all bytes to confirm
+ // that the still-open error is returned.
+ uCBORError = QCBORDecode_Finish(&DCtx);
+ if(uCBORError != QCBOR_SUCCESS) {
+ return 16;
+ }
+
+
+ return 0;
+}
diff --git a/test/qcbor_decode_tests.h b/test/qcbor_decode_tests.h
index f69a8a3..daabeab 100644
--- a/test/qcbor_decode_tests.h
+++ b/test/qcbor_decode_tests.h
@@ -255,5 +255,10 @@
int32_t EnterMapTest(void);
int32_t IntegerConvertTest(void);
+/*
+ Tests decoding of CBOR Sequences defined in RFC 8742
+ */
+int32_t CBORSequenceDecodeTests(void);
+
#endif /* defined(__QCBOR__qcbort_decode_tests__) */
diff --git a/test/run_tests.c b/test/run_tests.c
index 27fb9c2..bcf3fd1 100644
--- a/test/run_tests.c
+++ b/test/run_tests.c
@@ -106,6 +106,7 @@
TEST_ENTRY(SetUpAllocatorTest),
TEST_ENTRY(SimpleValuesIndefiniteLengthTest1),
TEST_ENTRY(EncodeLengthThirtyoneTest),
+ TEST_ENTRY(CBORSequenceDecodeTests),
#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
TEST_ENTRY(EncodeLengthThirtyoneTest),
TEST_ENTRY(ExponentAndMantissaDecodeTests),