merge in optimized type and argument encode
diff --git a/Makefile b/Makefile
index 15a2c17..454d811 100644
--- a/Makefile
+++ b/Makefile
@@ -26,40 +26,38 @@
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-CFLAGS=-I inc -I test -Os -Wall -Werror -pedantic-errors -Wextra -Wshadow
+CFLAGS=-I inc -I test -Os -Wall -Werror -pedantic-errors -Wextra -Wshadow -Wparentheses -xc -std=c99
QCBOR_OBJ=src/UsefulBuf.o src/qcbor_encode.o src/qcbor_decode.o src/ieee754.o
-QCBOR_OBJ2=$(QCBOR_OBJ) src/qcbor_decode_malloc.o
TEST_OBJ=test/UsefulBuf_Tests.o test/qcbor_encode_tests.o test/qcbor_decode_tests.o test/run_tests.o \
- test/float_tests.o test/half_to_double_from_rfc7049.o test/qcbor_decode_malloc_tests.o
+ test/float_tests.o test/half_to_double_from_rfc7049.o
-CMD_LINE_OBJ=$(QCBOR_OBJ2) $(TEST_OBJ) cmd_line_main.o
+qcbortest: libqcbor.a $(TEST_OBJ) cmd_line_main.o
+ cc -o $@ $^ libqcbor.a
-qcbortest: $(CMD_LINE_OBJ)
- cc -o $@ $^ $(CFLAGS)
+qcbormin: libqcbor.a min_use_main.o
+ cc -dead_strip -o $@ $^ libqcbor.a
-qcbormin: $(QCBOR_OBJ) min_use_main.c
- cc -dead_strip -o $@ $^ $(CFLAGS)
+libqcbor.a: $(QCBOR_OBJ)
+ ar -r $@ $^
src/UsefulBuf.o: inc/UsefulBuf.h
src/qcbor_decode.o: inc/UsefulBuf.h inc/qcbor.h src/ieee754.h
src/qcbor_encode.o: inc/UsefulBuf.h inc/qcbor.h src/ieee754.h
src/iee754.o: src/ieee754.h
-src/qcbor_malloc_decode.o: inc/qcbor.h
test/run_tests.o: test/UsefulBuf_Tests.h test/float_tests.h test/run_tests.h test/qcbor_encode_tests.h\
- test/qcbor_decode_tests.h test/qcbor_decode_malloc_tests.h
+ test/qcbor_decode_tests.h
test/UsefulBuf_Tests.o: test/UsefulBuf_Tests.h inc/qcbor.h inc/UsefulBuf.h
test/qcbor_encode_tests.o: test/qcbor_encode_tests.h inc/qcbor.h inc/UsefulBuf.h
test/qcbor_decode_tests.o: test/qcbor_decode_tests.h inc/qcbor.h inc/UsefulBuf.h
test/float_tests.o: inc/qcbor.h inc/UsefulBuf.h test/float_tests.h test/half_to_double_from_rfc7049.h
test/half_to_double_from_rfc7049.o: test/half_to_double_from_rfc7049.h
-test/qcbor_decode_malloc_test.o: test/qcbor_decode_malloc_tests.h
cmd_line_main.o: test/run_tests.h inc/qcbor.h
min_use_main.o: inc/qcbor.h inc/UsefulBuf.h
clean:
- rm $(CMD_LINE_OBJ)
+ rm -f $(QCBOR_OBJ2) $(TEST_OBJ) libqcbor.a
diff --git a/QCBOR.xcodeproj/project.pbxproj b/QCBOR.xcodeproj/project.pbxproj
index f599141..9c5a03a 100644
--- a/QCBOR.xcodeproj/project.pbxproj
+++ b/QCBOR.xcodeproj/project.pbxproj
@@ -7,11 +7,9 @@
objects = {
/* Begin PBXBuildFile section */
- 0F58EB9C216A388E002FD6D1 /* qcbor_decode_malloc.c in Sources */ = {isa = PBXBuildFile; fileRef = 0F58EB9B216A388E002FD6D1 /* qcbor_decode_malloc.c */; };
0FA9BEB7216CE6CA00BA646B /* qcbor_decode_tests.c in Sources */ = {isa = PBXBuildFile; fileRef = 0FA9BEB5216CE6CA00BA646B /* qcbor_decode_tests.c */; };
0FA9BEBA216DC7AD00BA646B /* qcbor_encode_tests.c in Sources */ = {isa = PBXBuildFile; fileRef = 0FA9BEB8216DC7AD00BA646B /* qcbor_encode_tests.c */; };
0FA9BEBD216DE31700BA646B /* UsefulBuf_Tests.c in Sources */ = {isa = PBXBuildFile; fileRef = 0FA9BEBC216DE31700BA646B /* UsefulBuf_Tests.c */; };
- 0FA9BF9021788F4A00BA646B /* qcbor_decode_malloc_tests.c in Sources */ = {isa = PBXBuildFile; fileRef = 0FA9BF8F21788F4A00BA646B /* qcbor_decode_malloc_tests.c */; };
E73B57592161CA690080D658 /* ieee754.c in Sources */ = {isa = PBXBuildFile; fileRef = E73B57582161CA690080D658 /* ieee754.c */; };
E73B575E2161CA7C0080D658 /* float_tests.c in Sources */ = {isa = PBXBuildFile; fileRef = E73B575A2161CA7C0080D658 /* float_tests.c */; };
E73B575F2161CA7C0080D658 /* half_to_double_from_rfc7049.c in Sources */ = {isa = PBXBuildFile; fileRef = E73B575D2161CA7C0080D658 /* half_to_double_from_rfc7049.c */; };
@@ -35,15 +33,12 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
- 0F58EB9B216A388E002FD6D1 /* qcbor_decode_malloc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = qcbor_decode_malloc.c; path = src/qcbor_decode_malloc.c; sourceTree = "<group>"; };
0FA9BEB5216CE6CA00BA646B /* qcbor_decode_tests.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.c; name = qcbor_decode_tests.c; path = test/qcbor_decode_tests.c; sourceTree = "<group>"; tabWidth = 3; };
0FA9BEB6216CE6CA00BA646B /* qcbor_decode_tests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = qcbor_decode_tests.h; path = test/qcbor_decode_tests.h; sourceTree = "<group>"; };
0FA9BEB8216DC7AD00BA646B /* qcbor_encode_tests.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.c; name = qcbor_encode_tests.c; path = test/qcbor_encode_tests.c; sourceTree = "<group>"; tabWidth = 3; };
0FA9BEB9216DC7AD00BA646B /* qcbor_encode_tests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = qcbor_encode_tests.h; path = test/qcbor_encode_tests.h; sourceTree = "<group>"; };
0FA9BEBB216DE31700BA646B /* UsefulBuf_Tests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UsefulBuf_Tests.h; path = test/UsefulBuf_Tests.h; sourceTree = "<group>"; };
0FA9BEBC216DE31700BA646B /* UsefulBuf_Tests.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.c; name = UsefulBuf_Tests.c; path = test/UsefulBuf_Tests.c; sourceTree = "<group>"; tabWidth = 3; };
- 0FA9BF8E21788F4A00BA646B /* qcbor_decode_malloc_tests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = qcbor_decode_malloc_tests.h; path = test/qcbor_decode_malloc_tests.h; sourceTree = "<group>"; };
- 0FA9BF8F21788F4A00BA646B /* qcbor_decode_malloc_tests.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = qcbor_decode_malloc_tests.c; path = test/qcbor_decode_malloc_tests.c; sourceTree = "<group>"; };
E73B57572161CA680080D658 /* ieee754.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ieee754.h; path = src/ieee754.h; sourceTree = "<group>"; };
E73B57582161CA690080D658 /* ieee754.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ieee754.c; path = src/ieee754.c; sourceTree = "<group>"; };
E73B575A2161CA7C0080D658 /* float_tests.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = float_tests.c; path = test/float_tests.c; sourceTree = "<group>"; };
@@ -98,7 +93,6 @@
children = (
E776E08C214AE07400E67947 /* qcbor_encode.c */,
E776E08E214AE07500E67947 /* qcbor_decode.c */,
- 0F58EB9B216A388E002FD6D1 /* qcbor_decode_malloc.c */,
E776E08D214AE07500E67947 /* UsefulBuf.c */,
E73B57582161CA690080D658 /* ieee754.c */,
E73B57572161CA680080D658 /* ieee754.h */,
@@ -130,8 +124,6 @@
E73B575C2161CA7C0080D658 /* float_tests.h */,
E73B575D2161CA7C0080D658 /* half_to_double_from_rfc7049.c */,
E73B575B2161CA7C0080D658 /* half_to_double_from_rfc7049.h */,
- 0FA9BF8E21788F4A00BA646B /* qcbor_decode_malloc_tests.h */,
- 0FA9BF8F21788F4A00BA646B /* qcbor_decode_malloc_tests.c */,
);
name = test;
sourceTree = "<group>";
@@ -192,9 +184,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- 0FA9BF9021788F4A00BA646B /* qcbor_decode_malloc_tests.c in Sources */,
E776E08F214AE07500E67947 /* qcbor_encode.c in Sources */,
- 0F58EB9C216A388E002FD6D1 /* qcbor_decode_malloc.c in Sources */,
E73B57592161CA690080D658 /* ieee754.c in Sources */,
E73B575F2161CA7C0080D658 /* half_to_double_from_rfc7049.c in Sources */,
E73B57652161F8F80080D658 /* run_tests.c in Sources */,
diff --git a/README.md b/README.md
index b4a40e7..8e52dba 100644
--- a/README.md
+++ b/README.md
@@ -1,60 +1,92 @@
# QCBOR
-QCBOR encodes and decodes [RFC 7049](https://tools.ietf.org/html/rfc7049) CBOR.
+QCBOR encodes and decodes [RFC 7049](https://tools.ietf.org/html/rfc7049) CBOR.
## Characteristics
-**Implemented in C with minimal dependecy** – Only dependencies are C99, stdint.h, stddef.h, stdbool.h and string.h making it highly portable. There are no #ifdefs.
+**Implemented in C with minimal dependecy** – Only dependencies are
+C99, stdint.h, stddef.h, stdbool.h and string.h making it highly
+portable. There are no #ifdefs.
-**Focused on C / native data representation** – Simpler code because there is no support for encoding/decoding to/from JSON, pretty printing, diagnostic notation... Only encoding from native C representations and decoding to native C representations is supported.
+**Focused on C / native data representation** – Simpler code because
+there is no support for encoding/decoding to/from JSON, pretty
+printing, diagnostic notation... Only encoding from native C
+representations and decoding to native C representations is supported.
-**Small simple memory model** – Malloc is not needed. The encode context is 136 bytes, decode context is 104 bytes and the description of decoded data item is 56 bytes. Stack use is light and there is no recursion. The caller supplies the memory to hold the encoded CBOR and encode/decode contexts so caller has full control of memory usage making it good for embedded implementations that have to run in small fixed memory.
+**Small simple memory model** – Malloc is not needed. The encode
+ context is 136 bytes, decode context is 104 bytes and the
+ description of decoded data item is 56 bytes. Stack use is light and
+ there is no recursion. The caller supplies the memory to hold the
+ encoded CBOR and encode/decode contexts so caller has full control
+ of memory usage making it good for embedded implementations that
+ have to run in small fixed memory.
-**Supports nearly all of RFC 7049** – Only minor, corner-case parts of RFC 7049 are not directly supported (canonicalization, decimal fractions, big floats). Decoding
-indefinite length strings but requires a string allocator (see documentation). Encoding indefinite length strings is not supported, but
-is also not necessary or preferred.
+**Supports nearly all of RFC 7049** – Only minor, corner-case parts of
+ RFC 7049 are not directly supported (canonicalization, decimal
+ fractions, big floats). Decoding indefinite length strings but
+ requires a string allocator (see documentation). Encoding indefinite
+ length strings is not supported, but is also not necessary or
+ preferred.
-**Extensible and General** – Provides a way to handle data types that are not directly supported.
+**Extensible and General** – Provides a way to handle data types that
+ are not directly supported.
-**Secure Coding Style** – Uses a construct called UsefulBuf as a discipline for very safe coding the handling of binary data.
+**Secure Coding Style** – Uses a construct called UsefulBuf as a
+ discipline for very safe coding the handling of binary data.
**Small Code Size** – When optimized for size using the compiler -Os
option, x86 code is less than 5KB (~1.1B encode, ~2.8KB decode,
~0.4KB common).
-**Clear documented public interface** – The public interface is separated from the implementation. It can be put to use without reading the source.
+**Clear documented public interface** – The public interface is
+ separated from the implementation. It can be put to use without
+ reading the source.
## Code Status
-QCBOR was originally developed by Qualcomm. It was [open sourced through CAF](https://source.codeaurora.org/quic/QCBOR/QCBOR/) with a permissive Linux license, September 2018 (thanks Qualcomm!).
-This code in Laurence's GitHub has diverged some from the CAF source with some small simplifications and tidying up.
+QCBOR was originally developed by Qualcomm. It was [open sourced
+through CAF](https://source.codeaurora.org/quic/QCBOR/QCBOR/) with a
+permissive Linux license, September 2018 (thanks Qualcomm!).
-From Nov 3, 2018, the interface and code are fairly stable. Large changes are not planned or expected, particularly in the interface. The test coverage
-is pretty good.
+This code in [Laurence's
+GitHub](https://github.com/laurencelundblade/QCBOR) has diverged from
+the CAF source with some small simplifications and tidying up.
+
+From Nov 3, 2018, the interface and code are fairly stable. Large
+changes are not planned or expected, particularly in the
+interface. The test coverage is pretty good.
## Building
-There is a simple makefile for the UNIX style command line binary that compiles everything to run the tests.
-The actual non-test source files are these eight:
+There is a simple makefile for the UNIX style command line binary that
+compiles everything to run the tests.
+
+The actual non-test source files are these seven:
* inc/UsefulBuf.h
* inc/qcbor.h
* src/UsefulBuf.c
* src/qcbor_encode.c
* src/qcbor_decode.c
-* src/qcbor_decode_malloc.c (optional; only for indefinite length strings you want handled with malloc)
* src/ieee754.h
* src/ieee754.c
-For most use cases you should just be able to add them to your project. Hopefully the easy portability of this implementation makes this work straight away, whatever your development environment is.
+For most use cases you should just be able to add them to your
+project. Hopefully the easy portability of this implementation makes
+this work straight away, whatever your development environment is.
-The files ieee754.c and ieee754.h are support for half-precision floating point. The encoding side of the floating point functionality is about
-500 bytes. If it is never called because no floating point numbers are ever encoded, all 500 bytes will be dead stripped and not
-impact code size. The decoding side is about 150 bytes of object code. It is never dead stripped because it directly referenced by
-the core decoder, however it doesn't add very much to the size.
+The files ieee754.c and ieee754.h are support for half-precision
+floating point. The encoding side of the floating point functionality
+is about 500 bytes. If it is never called because no floating point
+numbers are ever encoded, all 500 bytes will be dead stripped and not
+impact code size. The decoding side is about 150 bytes of object
+code. It is never dead stripped because it directly referenced by the
+core decoder, however it doesn't add very much to the size.
-The test directory includes some tests that are nearly as portable as the main implementation. If your development environment
-doesn't support UNIX style command line and make, you should be able to make a simple project and add the test files to it.
-Then just call run_tests() to invole them all.
+The test directory includes some tests that are nearly as portable as
+the main implementation. If your development environment doesn't
+support UNIX style command line and make, you should be able to make a
+simple project and add the test files to it. Then just call
+run_tests() to invoke them all.
## Changes from CAF Version
@@ -62,15 +94,33 @@
* Minimal length float encoding is added
* indefinite length arrays/maps are supported
* indefinite length strings are supported
-* Tag decoding is changed; unlimited number of tags supported, any tag value supported, tag utility function for easier tag checking
+* Tag decoding is changed; unlimited number of tags supported, any tag
+value supported, tag utility function for easier tag checking
* Addition functions in UsefulBuf
* QCBOREncode_Init takes a UsefulBuf instead of a pointer and size
* QCBOREncode_Finish takes a UsefulBufC and EncodedCBOR is remove
* bstr wrapping of arrays/maps is replaced with OpenBstrwrap
-* AddRaw renamed to AddEncoded and can now only add whole arrays or maps, not partial maps and arrays (simplification; was a dangerous feature)
-* Finish cannot be called repeatedly on a partial decode (some tests used this, but it is not really a good thing to use in the first place)
-* UsefulOutBuf_OutUBuf changed to work differently
+* AddRaw renamed to AddEncoded and can now only add whole arrays or maps,
+not partial maps and arrays (simplification; was a dangerous feature)
+* Finish cannot be called repeatedly on a partial decode (some tests used
+this, but it is not really a good thing to use in the first place)
+* UsefulOutBuf_OutUBuf changed to work differently
* UsefulOutBuf_Init works differently
+<<<<<<< HEAD
+* The "_3" functions are replaced with a small number of simpler functions
+* There is a new AddTag functon instead of the "_3" functions, making
+the interface simpler and saving some code
+* QCBOREncode_AddRawSimple_2 is removed (the macros that referenced
+still exist and work the same)
+
+
+
+
+
+
+
+=======
* The "_3" functions are replaced with "_2" functions (the macros that referenced _3, now reference _2 and work the same)
* There is a new AddTag functon instead of the "_3" functions, making the interface simpler and saving some code
* QCBOREncode_AddRawSimple_2 is removed (the macros that referenced still exist and work the same)
+>>>>>>> origin/smallinsert
diff --git a/cmd_line_main.c b/cmd_line_main.c
index 4357d07..927beee 100644
--- a/cmd_line_main.c
+++ b/cmd_line_main.c
@@ -1,9 +1,9 @@
/*==============================================================================
cmd_line_mainc.c -- basic tests for qcbor encoder / decoder
-
+
Copyright (c) 2018, Laurence Lundblade.
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
@@ -17,7 +17,7 @@
contributors, nor the name "Laurence Lundblade" may be used to
endorse or promote products derived from this software without
specific prior written permission.
-
+
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
@@ -46,7 +46,7 @@
static void PrintSize(const char *szWhat, uint32_t uSize)
{
UsefulBuf_MAKE_STACK_UB(foo, 20);
-
+
fputs_wrapper(szWhat, stdout);
fputs_wrapper(" ", stdout);
fputs_wrapper(NumToString(uSize,foo), stdout);
@@ -67,7 +67,7 @@
fputs_wrapper("\n", stdout);
int nNumTestsFailed = 0;
-
+
if(argc > 1) {
nNumTestsFailed += run_tests(argv[1], &fputs_wrapper, stdout, NULL);
} else {
diff --git a/inc/UsefulBuf.h b/inc/UsefulBuf.h
index 9c44ef7..d3d828d 100644
--- a/inc/UsefulBuf.h
+++ b/inc/UsefulBuf.h
@@ -2,7 +2,7 @@
Copyright (c) 2016-2018, The Linux Foundation.
Copyright (c) 2018, Laurence Lundblade.
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
@@ -16,7 +16,7 @@
contributors, nor the name "Laurence Lundblade" may be used to
endorse or promote products derived from this software without
specific prior written permission.
-
+
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
@@ -32,16 +32,19 @@
/*===================================================================================
FILE: UsefulBuf.h
-
+
DESCRIPTION: General purpose input and output buffers
-
+
EDIT HISTORY FOR FILE:
-
+
This section contains comments describing changes made to the module.
Notice that changes are listed in reverse chronological order.
-
+
when who what, where, why
-------- ---- ---------------------------------------------------
+ 12/17/2018 llundblade Remove const from UsefulBuf and UsefulBufC .len
+ 12/13/2018 llundblade Documentation improvements
+ 09/18/2018 llundblade Cleaner distinction between UsefulBuf and UsefulBufC
02/02/18 llundbla Full support for integers in and out; fix pointer alignment bug
Incompatible change: integers in/out are now in network byte order.
08/12/17 llundbla Added UsefulOutBuf_AtStart and UsefulBuf_Find
@@ -51,7 +54,7 @@
05/30/17 llundbla Functions for NULL UsefulBufs and const / unconst
11/13/16 llundbla Initial Version.
-
+
=====================================================================================*/
#ifndef _UsefulBuf_h
@@ -64,18 +67,18 @@
/**
@file UsefulBuf.h
-
+
The goal of this code is to make buffer and pointer manipulation
easier and safer when working with binary data.
-
+
You use the UsefulBuf, UsefulOutBuf and UsefulInputBuf
structures to represent buffers rather than ad hoc pointers and lengths.
-
+
With these it will often be possible to write code that does little or no
direct pointer manipulation for copying and formatting data. For example
the QCBOR encoder was rewritten using these and has no direct pointer
manipulation.
-
+
While it is true that object code using these functions will be a little
larger and slower than a white-knuckle clever use of pointers might be, but
not by that much or enough to have an affect for most use cases. For
@@ -101,28 +104,28 @@
length for a binary data. In C99 this data structure can be passed on the
stack making a lot of code cleaner than carrying around a pointer and
length as two parameters.
-
+
This is also conducive to secure code practice as the lengths are
always carried with the pointer and the convention for handling a
pointer and a length is clear.
-
+
While it might be possible to write buffer and pointer code more
efficiently in some use cases, the thought is that unless there is an
extreme need for performance (e.g., you are building a gigabit-per-second
IP router), it is probably better to have cleaner code you can be most
certain about the security of.
-
+
The non-const UsefulBuf is usually used to refer a buffer to be filled in.
The length is the size of the buffer.
-
+
The const UsefulBufC is usually used to refer to some data that has been
filled in. The length is amount of valid data pointed to.
-
+
A common use is to pass a UsefulBuf to a function, the function fills it
in, the function returns a UsefulBufC. The pointer is the same in both.
-
+
A UsefulBuf is NULL, it has no value, when the ptr in it is NULL.
-
+
There are utility functions for the following:
- Checking for UsefulBufs that are NULL, empty or both
- Copying, copying with offset, copying head or tail
@@ -131,20 +134,20 @@
- Create initialized const UsefulBufC from compiler literals
- Create initialized const UsefulBufC from NULL-terminated string
- Make an empty UsefulBuf on the stack
-
+
See also UsefulOutBuf. It is a richer structure that has both the size of
the valid data and the size of the buffer.
-
+
UsefulBuf is only 16 or 8 bytes on a 64- or 32-bit machine so it can go
on the stack and be a function parameter or return value.
-
+
UsefulBuf is kind of like the Useful Pot Pooh gave Eeyore on his birthday.
Eeyore's balloon fits beautifully, "it goes in and out like anything".
-
+
*/
typedef struct {
const void *ptr;
- const size_t len;
+ size_t len;
} UsefulBufC;
@@ -155,7 +158,7 @@
*/
typedef struct {
void *ptr;
- const size_t len;
+ size_t len;
} UsefulBuf;
@@ -174,9 +177,9 @@
/**
@brief Check if a UsefulBuf is NULL or not
-
+
@param[in] UB The UsefulBuf to check
-
+
@return 1 if it is NULL, 0 if not.
*/
static inline int UsefulBuf_IsNULL(UsefulBuf UB) {
@@ -186,9 +189,9 @@
/**
@brief Check if a UsefulBufC is NULL or not
-
+
@param[in] UB The UsefulBufC to check
-
+
@return 1 if it is NULL, 0 if not.
*/
static inline int UsefulBuf_IsNULLC(UsefulBufC UB) {
@@ -198,15 +201,15 @@
/**
@brief Check if a UsefulBuf is empty or not
-
+
@param[in] UB The UsefulBuf to check
-
+
@return 1 if it is empty, 0 if not.
-
+
An "Empty" UsefulBuf is one that has a value and can be considered to be set,
but that value is of zero length. It is empty when len is zero. It
doesn't matter what the ptr is.
-
+
A lot of uses will not need to clearly distinguish a NULL UsefulBuf
from an empty one and can have the ptr NULL and the len 0. However
if a use of UsefulBuf needs to make a distinction then ptr should
@@ -220,9 +223,9 @@
/**
@brief Check if a UsefulBufC is empty or not
-
+
@param[in] UB The UsefulBufC to check
-
+
@return 1 if it is empty, 0 if not.
*/
static inline int UsefulBuf_IsEmptyC(UsefulBufC UB) {
@@ -232,9 +235,9 @@
/**
@brief Check if a UsefulBuf is NULL or empty
-
+
@param[in] UB The UsefulBuf to check
-
+
@return 1 if it is either NULL or empty, 0 if not.
*/
static inline int UsefulBuf_IsNULLOrEmpty(UsefulBuf UB) {
@@ -244,9 +247,9 @@
/**
@brief Check if a UsefulBufC is NULL or empty
-
+
@param[in] UB The UsefulBufC to check
-
+
@return 1 if it is either NULL or empty, 0 if not.
*/
static inline int UsefulBuf_IsNULLOrEmptyC(UsefulBufC UB) {
@@ -256,9 +259,9 @@
/**
@brief Convert a non const UsefulBuf to a const UsefulBufC
-
+
@param[in] UB The UsefulBuf to convert
-
+
Returns: a UsefulBufC struct
*/
@@ -270,9 +273,9 @@
/**
@brief Convert a const UsefulBufC to a non-const UsefulBuf
-
+
@param[in] UBC The UsefulBuf to convert
-
+
Returns: a non const UsefulBuf struct
*/
static inline UsefulBuf UsefulBuf_Unconst(const UsefulBufC UBC)
@@ -283,14 +286,14 @@
/**
Convert a literal string to a UsefulBufC.
-
+
szString must be a literal string that you can take sizeof.
This is better for literal strings than UsefulBuf_FromSZ()
because it generates less code. It will not work on
non-literal strings.
-
+
The terminating \0 (NULL) is NOT included in the length!
-
+
*/
#define UsefulBuf_FROM_SZ_LITERAL(szString) \
((UsefulBufC) {(szString), sizeof(szString)-1})
@@ -298,10 +301,10 @@
/**
Convert a literal byte array to a UsefulBufC.
-
+
pBytes must be a literal string that you can take sizeof.
It will not work on non-literal arrays.
-
+
*/
#define UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pBytes) \
((UsefulBufC) {(pBytes), sizeof(pBytes)})
@@ -326,14 +329,14 @@
@brief Convert a NULL terminated string to a UsefulBufC.
@param[in] szString The string to convert
-
+
@return a UsefulBufC struct
UsefulBufC.ptr points to the string so it's lifetime
must be maintained.
-
+
The terminating \0 (NULL) is NOT included in the length!
-
+
*/
static inline UsefulBufC UsefulBuf_FromSZ(const char *szString){
return ((UsefulBufC) {szString, strlen(szString)});
@@ -342,42 +345,42 @@
/**
@brief Copy one UsefulBuf into another at an offset
-
+
@param[in] Dest Destiation buffer to copy into
@param[in] uOffset The byte offset in Dest at which to copy to
@param[in] Src The bytes to copy
-
+
@return Pointer and length of the copy
-
+
This fails and returns NULLUsefulBufC Src.len + uOffset > Dest.len.
-
+
Like memcpy, there is no check for NULL. If NULL is passed
this will crash.
-
+
There is an assumption that there is valid data in Dest up to
uOffset as the resulting UsefulBufC returned starts
at the beginning of Dest and goes to Src.len + uOffset.
-
+
*/
UsefulBufC UsefulBuf_CopyOffset(UsefulBuf Dest, size_t uOffset, const UsefulBufC Src);
/**
@brief Copy one UsefulBuf into another
-
+
@param[in] Dest The destination buffer to copy into
@param[out] Src The source to copy from
-
+
@return filled in UsefulBufC on success, NULLUsefulBufC on failure
-
+
This fails if Src.len is greater than Dest.len.
-
+
Note that like memcpy, the pointers are not checked and
this will crash, rather than return NULLUsefulBufC if
they are NULL or invalid.
-
+
Results are undefined if Dest and Src overlap.
-
+
*/
static inline UsefulBufC UsefulBuf_Copy(UsefulBuf Dest, const UsefulBufC Src) {
return UsefulBuf_CopyOffset(Dest, 0, Src);
@@ -386,13 +389,13 @@
/**
@brief Set all bytes in a UsefulBuf to a value, for example 0
-
+
@param[in] pDest The destination buffer to copy into
@param[in] value The value to set the bytes to
-
+
Note that like memset, the pointer in pDest is not checked and
this will crash if NULL or invalid.
-
+
*/
static inline UsefulBufC UsefulBuf_Set(UsefulBuf pDest, uint8_t value)
{
@@ -403,20 +406,20 @@
/**
@brief Copy a pointer into a UsefulBuf
-
+
@param[in,out] Dest The destination buffer to copy into
@param[in] ptr The source to copy from
@param[in] len Length of the source; amoutn to copy
-
+
@return 0 on success, 1 on failure
-
+
This fails and returns NULLUsefulBufC if len is greater than
pDest->len.
-
+
Note that like memcpy, the pointers are not checked and
this will crash, rather than return 1 if they are NULL
or invalid.
-
+
*/
inline static UsefulBufC UsefulBuf_CopyPtr(UsefulBuf Dest, const void *ptr, size_t len)
{
@@ -426,12 +429,12 @@
/**
@brief Returns a truncation of a UsefulBufC
-
+
@param[in] UB The buffer to get the head of
@param[in] uAmount The number of bytes in the head
-
+
@return A UsefulBufC that is the head of UB
-
+
*/
static inline UsefulBufC UsefulBuf_Head(UsefulBufC UB, size_t uAmount)
{
@@ -444,12 +447,12 @@
/**
@brief Returns bytes from the end of a UsefulBufC
-
+
@param[in] UB The buffer to get the tail of
@param[in] uAmount The offset from the start where the tail is to begin
-
+
@return A UsefulBufC that is the tail of UB
-
+
*/
static inline UsefulBufC UsefulBuf_Tail(UsefulBufC UB, size_t uAmount)
{
@@ -462,36 +465,36 @@
/**
@brief Compare two UsefulBufCs
-
+
@param[in] UB1 The destination buffer to copy into
@param[in] UB2 The source to copy from
-
+
@return 0 if equal...
-
+
Returns a negative value if UB1 if is less than UB2. UB1 is
less than UB2 if it is shorter or the first byte that is not
- the same is less.
-
+ the same is less.
+
Returns 0 if the UsefulBufs are the same.
-
+
Returns a positive value if UB2 is less than UB1.
-
+
All that is of significance is that the result is positive,
negative or 0. (This doesn't return the difference between
the first non-matching byte like memcmp).
-
+
*/
int UsefulBuf_Compare(const UsefulBufC UB1, const UsefulBufC UB2);
/**
@brief Find one UsefulBuf in another
-
+
@param[in] BytesToSearch UsefulBuf to search through
@param[in] BytesToFind UsefulBuf with bytes to be found
-
+
@return position of found bytes or SIZE_MAX if not found.
-
+
*/
size_t UsefulBuf_FindBytes(UsefulBufC BytesToSearch, UsefulBufC BytesToFind);
@@ -562,64 +565,64 @@
UsefulOutBuf is a structure and functions (an object) that are good
for serializing data into a buffer such as is often done with network
protocols or data written to files.
-
+
The main idea is that all the pointer manipulation for adding data is
done by UsefulOutBuf functions so the caller doesn't have to do any.
All the pointer manipulation is centralized here. This code will
have been reviewed and written carefully so it spares the caller of
much of this work and results in much safer code with much less work.
-
+
The functions to add data to the output buffer always check the
length and will never write off the end of the output buffer. If an
attempt to add data that will not fit is made, an internal error flag
will be set and further attempts to add data will not do anything.
-
+
Basically, if you initialized with the correct buffer, there is no
way to ever write off the end of that buffer when calling the Add
and Insert functions here.
-
+
The functions to add data do not return an error. The working model
is that the caller just makes all the calls to add data without any
error checking on each one. The error is instead checked after all the
data is added when the result is to be used. This makes the caller's
code cleaner.
-
+
There is a utility function to get the error status anytime along the
way if the caller wants. There are functions to see how much room is
left and see if some data will fit too, but their use is generally
not necessary.
-
+
The general call flow is like this:
- Initialize the UsefulOutBuf with the buffer that is to have the
data added. The caller allocates the buffer. It can be heap
or stack or shared memory (or other).
-
+
- Make calls to add data to the output buffer. Insert and append
are both supported. The append and insert calls will never write
off the end of the buffer.
-
+
- When all data is added, check the error status to make sure
everything fit.
-
+
- Get the resulting serialized data either as a UsefulBuf (a
pointer and length) or have it copied to another buffer.
-
+
UsefulOutBuf can be initialized with just a buffer length by passing
NULL as the pointer to the output buffer. This is useful if you want
to go through the whole serialization process to either see if it
will fit into a given buffer or compute the size of the buffer
needed. Pass a very large buffer size when calling Init, if you want
just to compute the size.
-
+
Some inexpensive simple sanity checks are performed before every data
addition to guard against use of an uninitialized or corrupted
UsefulOutBuf.
-
+
This has been used to create a CBOR encoder. The CBOR encoder has
almost no pointer manipulation in it, is much easier to read, and
easier to review.
-
+
A UsefulOutBuf is 27 bytes or 15 bytes on 64- or 32-bit machines so it
can go on the stack or be a C99 function parameter.
*/
@@ -634,22 +637,17 @@
/**
@brief Initialize and supply the actual output buffer
-
+
@param[out] me The UsefulOutBuf to initialize
@param[in] Storage Buffer to output into
-
+
Intializes the UsefulOutBuf with storage. Sets the current position
to the beginning of the buffer clears the error.
-
+
This must be called before the UsefulOutBuf is used.
*/
void UsefulOutBuf_Init(UsefulOutBuf *me, UsefulBuf Storage);
-static inline void UsefulOutBuf_Realloc(UsefulOutBuf *me, UsefulBuf Storage)
-{
- me->UB = Storage;
-}
-
@@ -665,15 +663,15 @@
/**
@brief Reset a UsefulOutBuf for re use
-
+
@param[in] me Pointer to the UsefulOutBuf
This sets the amount of data in the output buffer to none and
- clears the error state.
-
+ clears the error state.
+
The output buffer is still the same one and size as from the
UsefulOutBuf_Init() call.
-
+
It doesn't zero the data, just resets to 0 bytes of valid data.
*/
static inline void UsefulOutBuf_Reset(UsefulOutBuf *me)
@@ -685,18 +683,18 @@
/**
@brief Returns position of end of data in the UsefulOutBuf
-
+
@param[in] me Pointer to the UsefulOutBuf
-
+
@return position of end of data
-
+
On a freshly initialized UsefulOutBuf with no data added, this will
return 0. After ten bytes have been added, it will return 10 and so
on.
-
+
Generally callers will not need this function for most uses of
UsefulOutBuf.
-
+
*/
static inline size_t UsefulOutBuf_GetEndPosition(UsefulOutBuf *me)
{
@@ -706,11 +704,11 @@
/**
@brief Returns whether any data has been added to the UsefulOutBuf
-
+
@param[in] me Pointer to the UsefulOutBuf
-
+
@return 1 if output position is at start
-
+
*/
static inline int UsefulOutBuf_AtStart(UsefulOutBuf *me)
{
@@ -720,50 +718,50 @@
/**
@brief Inserts bytes into the UsefulOutBuf
-
+
@param[in] me Pointer to the UsefulOutBuf
@param[in] NewData UsefulBuf with the bytes to insert
@param[in] uPos Index in output buffer at which to insert
-
+
NewData is the pointer and length for the bytes to be added to the
output buffer. There must be room in the output buffer for all of
NewData or an error will occur.
-
+
The insertion point must be between 0 and the current valid data. If
not an error will occur. Appending data to the output buffer is
achieved by inserting at the end of the valid data. This can be
retrieved by calling UsefulOutBuf_GetEndPosition().
-
+
When insertion is performed, the bytes between the insertion point and
the end of data previously added to the output buffer is slid to the
right to make room for the new data.
-
+
Overlapping buffers are OK. NewData can point to data in the output
buffer.
If an error occurs an error state is set in the UsefulOutBuf. No
error is returned. All subsequent attempts to add data will do
nothing.
-
+
Call UsefulOutBuf_GetError() to find out if there is an error. This
is usually not needed until all additions of data are complete.
-
+
*/
void UsefulOutBuf_InsertUsefulBuf(UsefulOutBuf *me, UsefulBufC NewData, size_t uPos);
/**
@brief Insert a data buffer into the UsefulOutBuf
-
+
@param[in] me Pointer to the UsefulOutBul
@param[in] pBytes Pointer to the bytes to insert
@param[in] uLen Length of the bytes to insert
@param[in] uPos Index in output buffer at which to insert
-
+
See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
the difference being a pointer and length is passed in rather than an
UsefulBuf.
-
+
*/
static inline void UsefulOutBuf_InsertData(UsefulOutBuf *me, const void *pBytes, size_t uLen, size_t uPos)
{
@@ -774,10 +772,10 @@
/**
@brief Insert a NULL-terminated string into the UsefulOutBuf
-
+
@param[in] me Pointer to the UsefulOutBuf
@param[in] szString string to append
-
+
*/
static inline void UsefulOutBuf_InsertString(UsefulOutBuf *me, const char *szString, size_t uPos)
{
@@ -787,11 +785,11 @@
/**
@brief Insert a byte into the UsefulOutBuf
-
+
@param[in] me Pointer to the UsefulOutBul
@param[in] byte Bytes to insert
@param[in] uPos Index in output buffer at which to insert
-
+
See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
the difference being a single byte is to be inserted.
*/
@@ -803,14 +801,14 @@
/**
@brief Insert a 16-bit integer into the UsefulOutBuf
-
+
@param[in] me Pointer to the UsefulOutBul
@param[in] uInteger16 Integer to insert
@param[in] uPos Index in output buffer at which to insert
-
+
See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
the difference being a single byte is to be inserted.
-
+
The integer will be inserted in network byte order (big endian)
*/
static inline void UsefulOutBuf_InsertUint16(UsefulOutBuf *me, uint16_t uInteger16, size_t uPos)
@@ -825,14 +823,14 @@
/**
@brief Insert a 32-bit integer into the UsefulOutBuf
-
+
@param[in] me Pointer to the UsefulOutBul
@param[in] uInteger32 Integer to insert
@param[in] uPos Index in output buffer at which to insert
-
+
See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
the difference being a single byte is to be inserted.
-
+
The integer will be inserted in network byte order (big endian)
*/
static inline void UsefulOutBuf_InsertUint32(UsefulOutBuf *me, uint32_t uInteger32, size_t uPos)
@@ -849,14 +847,14 @@
/**
@brief Insert a 64-bit integer into the UsefulOutBuf
-
+
@param[in] me Pointer to the UsefulOutBul
@param[in] uInteger64 Integer to insert
@param[in] uPos Index in output buffer at which to insert
-
+
See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
the difference being a single byte is to be inserted.
-
+
The integer will be inserted in network byte order (big endian)
*/
static inline void UsefulOutBuf_InsertUint64(UsefulOutBuf *me, uint64_t uInteger64, size_t uPos)
@@ -877,14 +875,14 @@
/**
@brief Insert a float into the UsefulOutBuf
-
+
@param[in] me Pointer to the UsefulOutBul
@param[in] f Integer to insert
@param[in] uPos Index in output buffer at which to insert
-
+
See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
the difference being a single byte is to be inserted.
-
+
The float will be inserted in network byte order (big endian)
*/
static inline void UsefulOutBuf_InsertFloat(UsefulOutBuf *me, float f, size_t uPos)
@@ -895,14 +893,14 @@
/**
@brief Insert a double into the UsefulOutBuf
-
+
@param[in] me Pointer to the UsefulOutBul
@param[in] d Integer to insert
@param[in] uPos Index in output buffer at which to insert
-
+
See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with
the difference being a single byte is to be inserted.
-
+
The double will be inserted in network byte order (big endian)
*/
static inline void UsefulOutBuf_InsertDouble(UsefulOutBuf *me, double d, size_t uPos)
@@ -914,13 +912,13 @@
/**
Append a UsefulBuf into the UsefulOutBuf
-
+
@param[in] me Pointer to the UsefulOutBuf
@param[in] NewData UsefulBuf with the bytes to append
-
+
See UsefulOutBuf_InsertUsefulBuf() for details. This does the same
with the insertion point at the end of the valid data.
-
+
*/
static inline void UsefulOutBuf_AppendUsefulBuf(UsefulOutBuf *me, UsefulBufC NewData)
{
@@ -931,11 +929,11 @@
/**
Append bytes to the UsefulOutBuf
-
+
@param[in] me Pointer to the UsefulOutBuf
@param[in] pBytes Pointer to bytes to append
@param[in] uLen Index in output buffer at which to append
-
+
See UsefulOutBuf_InsertUsefulBuf() for details. This does the same
with the insertion point at the end of the valid data.
*/
@@ -949,10 +947,10 @@
/**
Append a NULL-terminated string to the UsefulOutBuf
-
+
@param[in] me Pointer to the UsefulOutBuf
@param[in] szString string to append
-
+
*/
static inline void UsefulOutBuf_AppendString(UsefulOutBuf *me, const char *szString)
{
@@ -962,10 +960,10 @@
/**
@brief Append a byte to the UsefulOutBuf
-
+
@param[in] me Pointer to the UsefulOutBuf
@param[in] byte Bytes to append
-
+
See UsefulOutBuf_InsertUsefulBuf() for details. This does the same
with the insertion point at the end of the valid data.
*/
@@ -976,13 +974,13 @@
/**
@brief Append an integer to the UsefulOutBuf
-
+
@param[in] me Pointer to the UsefulOutBuf
@param[in] uInteger16 Integer to append
-
+
See UsefulOutBuf_InsertUsefulBuf() for details. This does the same
with the insertion point at the end of the valid data.
-
+
The integer will be appended in network byte order (big endian).
*/
static inline void UsefulOutBuf_AppendUint16(UsefulOutBuf *me, uint16_t uInteger16){
@@ -991,13 +989,13 @@
/**
@brief Append an integer to the UsefulOutBuf
-
+
@param[in] me Pointer to the UsefulOutBuf
@param[in] uInteger32 Integer to append
-
+
See UsefulOutBuf_InsertUsefulBuf() for details. This does the same
with the insertion point at the end of the valid data.
-
+
The integer will be appended in network byte order (big endian).
*/
static inline void UsefulOutBuf_AppendUint32(UsefulOutBuf *me, uint32_t uInteger32){
@@ -1006,13 +1004,13 @@
/**
@brief Append an integer to the UsefulOutBuf
-
+
@param[in] me Pointer to the UsefulOutBuf
@param[in] uInteger64 Integer to append
-
+
See UsefulOutBuf_InsertUsefulBuf() for details. This does the same
with the insertion point at the end of the valid data.
-
+
The integer will be appended in network byte order (big endian).
*/
static inline void UsefulOutBuf_AppendUint64(UsefulOutBuf *me, uint64_t uInteger64){
@@ -1022,13 +1020,13 @@
/**
@brief Append a float to the UsefulOutBuf
-
+
@param[in] me Pointer to the UsefulOutBuf
@param[in] f Float to append
-
+
See UsefulOutBuf_InsertUsefulBuf() for details. This does the same
with the insertion point at the end of the valid data.
-
+
The float will be appended in network byte order (big endian).
*/
static inline void UsefulOutBuf_AppendFloat(UsefulOutBuf *me, float f){
@@ -1037,13 +1035,13 @@
/**
@brief Append a float to the UsefulOutBuf
-
+
@param[in] me Pointer to the UsefulOutBuf
@param[in] d Double to append
-
+
See UsefulOutBuf_InsertUsefulBuf() for details. This does the same
with the insertion point at the end of the valid data.
-
+
The double will be appended in network byte order (big endian).
*/
static inline void UsefulOutBuf_AppendDouble(UsefulOutBuf *me, double d){
@@ -1052,15 +1050,15 @@
/**
@brief Returns the current error status
-
+
@param[in] me Pointer to the UsefulOutBuf
-
+
@return 0 if all OK, 1 on error
-
+
This is the error status since the call to either
UsefulOutBuf_Reset() of UsefulOutBuf_Init(). Once it goes into error
state it will stay until one of those functions is called.
-
+
Possible error conditions are:
- bytes to be inserted will not fit
- insertion point is out of buffer or past valid data
@@ -1076,11 +1074,11 @@
/**
@brief Returns number of bytes unused used in the output buffer
-
+
@param[in] me Pointer to the UsefulOutBuf
-
+
@return Number of unused bytes or zero
-
+
Because of the error handling strategy and checks in UsefulOutBuf_InsertUsefulBuf()
it is usually not necessary to use this.
*/
@@ -1093,12 +1091,12 @@
/**
@brief Returns true / false if some number of bytes will fit in the UsefulOutBuf
-
+
@param[in] me Pointer to the UsefulOutBuf
@param[in] uLen Number of bytes for which to check
-
+
@return 1 or 0 if nLen bytes would fit
-
+
Because of the error handling strategy and checks in UsefulOutBuf_InsertUsefulBuf()
it is usually not necessary to use this.
*/
@@ -1111,14 +1109,14 @@
/**
@brief Returns the resulting valid data in a UsefulOutBuf
-
+
@param[in] me Pointer to the UsefulOutBuf.
-
+
@return The valid data in UsefulOutBuf.
-
+
The storage for the returned data is Storage parameter passed
to UsefulOutBuf_Init(). See also UsefulOutBuf_CopyOut().
-
+
This can be called anytime and many times to get intermediate
results. It doesn't change the data or reset the current position
so you can keep adding data.
@@ -1129,12 +1127,12 @@
/**
@brief Copies the valid data out into a supplied buffer
-
+
@param[in] me Pointer to the UsefulOutBuf
@param[out] Dest The destination buffer to copy into
-
+
@return Pointer and length of copied data.
-
+
This is the same as UsefulOutBuf_OutUBuf() except it copies the data.
*/
@@ -1162,7 +1160,7 @@
makes sure it never goes off the end of the buffer. The QCBOR
implementation parser makes use of this for all its pointer math and
length checking.
-
+
UsefulInputBuf also maintains an internal error state so you do not have
to. Once data has been requested off the end of the buffer, it goes
into an error state. You can keep calling functions to get more data
@@ -1170,17 +1168,17 @@
dereference the NULL, you can wait until all data items have been
fetched before checking for the error and this can simplify your
code.
-
+
The integer and float parsing expects network byte order (big endian).
Network byte order is what is used by TCP/IP, CBOR and most internet
protocols.
-
+
Lots of inlining is used to keep code size down. The code optimizer,
particularly with the -Os, also reduces code size a lot. The only
non-inline code is UsefulInputBuf_GetBytes() which is less than 100
bytes so use of UsefulInputBuf doesn't add much code for all the messy
hard-to-get right issues with parsing in C that is solves.
-
+
The parse context size is:
64-bit machine: 16 + 8 + 2 + 1 (5 bytes padding to align) = 32 bytes
32-bit machine: 8 + 4 + 2 + 1 (1 byte padding to align) = 16 bytes
@@ -1201,10 +1199,10 @@
/**
@brief Initialize the UsefulInputBuf structure before use.
-
+
@param[in] me Pointer to the UsefulInputBuf instance.
@param[in] UB Pointer to the data to parse.
-
+
*/
static inline void UsefulInputBuf_Init(UsefulInputBuf *me, UsefulBufC UB)
{
@@ -1217,13 +1215,13 @@
/**
@brief Returns current position in input buffer
-
+
@param[in] me Pointer to the UsefulInputBuf.
-
+
@return Integer position of the cursor
-
+
The position that the next bytes will be returned from.
-
+
*/
static inline size_t UsefulInputBuf_Tell(UsefulInputBuf *me)
{
@@ -1233,16 +1231,16 @@
/**
@brief Sets current position in input buffer
-
+
@param[in] me Pointer to the UsefulInputBuf.
@param[in] uPos Position to set to
-
+
If the position is off the end of the input buffer, the error state
is entered and all functions will do nothing.
-
+
Seeking to a valid position in the buffer will not reset the error
state. Only re initialization will do that.
-
+
*/
static inline void UsefulInputBuf_Seek(UsefulInputBuf *me, size_t uPos)
{
@@ -1257,17 +1255,17 @@
/**
@brief Returns the number of bytes from the cursor to the end of the buffer,
the uncomsummed bytes.
-
+
@param[in] me Pointer to the UsefulInputBuf.
@return number of bytes unconsumed or 0 on error.
-
+
This is a critical function for input length validation. This does
some pointer / offset math.
-
+
Returns 0 if the cursor it invalid or corruption of the structure is
detected.
-
+
Code Reviewers: THIS FUNCTION DOES POINTER MATH
*/
static inline size_t UsefulInputBuf_BytesUnconsumed(UsefulInputBuf *me)
@@ -1277,7 +1275,7 @@
if(me->magic != UIB_MAGIC) {
return 0;
}
-
+
// The cursor is off the end of the input buffer given
// Presuming there are no bugs in this code, this should never happen.
// If it so, the struct was corrupted. The check is retained as
@@ -1285,7 +1283,7 @@
if(me->cursor > me->UB.len) {
return 0;
}
-
+
// subtraction can't go neative because of check above
return me->UB.len - me->cursor;
}
@@ -1293,11 +1291,11 @@
/**
@brief Check if there are any unconsumed bytes
-
+
@param[in] me Pointer to the UsefulInputBuf.
@return 1 if len bytes are available after the cursor, and 0 if not
-
+
*/
static inline int UsefulInputBuf_BytesAvailable(UsefulInputBuf *me, size_t uLen)
{
@@ -1307,18 +1305,18 @@
/**
@brief Get pointer to bytes out of the input buffer
-
+
@param[in] me Pointer to the UsefulInputBuf.
@param[in] uNum Number of bytes to get
-
+
@return Pointer to bytes.
-
+
This consumes n bytes from the input buffer. It returns a pointer to
the start of the n bytes.
-
+
If there are not n bytes in the input buffer, NULL will be returned
and an error will be set.
-
+
It advances the current position by n bytes.
*/
const void * UsefulInputBuf_GetBytes(UsefulInputBuf *me, size_t uNum);
@@ -1326,18 +1324,18 @@
/**
@brief Get UsefulBuf out of the input buffer
-
+
@param[in] me Pointer to the UsefulInputBuf.
@param[in] uNum Number of bytes to get
-
+
@return UsefulBufC with ptr and length for bytes consumed.
-
+
This consumes n bytes from the input buffer and returns the pointer
and len to them as a UsefulBufC. The len returned will always be n.
-
+
If there are not n bytes in the input buffer, UsefulBufC.ptr will be
NULL and UsefulBufC.len will be 0. An error will be set.
-
+
It advances the current position by n bytes.
*/
static inline UsefulBufC UsefulInputBuf_GetUsefulBuf(UsefulInputBuf *me, size_t uNum)
@@ -1353,13 +1351,13 @@
/**
@brief Get a byte out of the input buffer.
-
+
@param[in] me Pointer to the UsefulInputBuf.
-
+
@return The byte
-
+
This consumes 1 byte from the input buffer. It returns the byte.
-
+
If there is not 1 byte in the buffer, 0 will be returned for the byte
and an error set internally. You must check the error at some point
to know whether the 0 was the real value or just returned in error,
@@ -1367,85 +1365,85 @@
with UsefulInputBuf_GetError(). You can also know you are in the
error state if UsefulInputBuf_GetBytes() returns NULL or the ptr from
UsefulInputBuf_GetUsefulBuf() is NULL.
-
+
It advances the current position by 1 byte.
*/
static inline uint8_t UsefulInputBuf_GetByte(UsefulInputBuf *me)
{
const void *pResult = UsefulInputBuf_GetBytes(me, sizeof(uint8_t));
-
+
return pResult ? *(uint8_t *)pResult : 0;
}
/**
@brief Get a uint16_t out of the input buffer
-
+
@param[in] me Pointer to the UsefulInputBuf.
-
+
@return The uint16_t
-
+
See UsefulInputBuf_GetByte(). This works the same, except it returns
a uint16_t and two bytes are consumed.
-
+
The input bytes must be in network order (big endian).
*/
static inline uint16_t UsefulInputBuf_GetUint16(UsefulInputBuf *me)
{
const uint8_t *pResult = (const uint8_t *)UsefulInputBuf_GetBytes(me, sizeof(uint16_t));
-
+
if(!pResult) {
return 0;
}
-
+
return ((uint16_t)pResult[0] << 8) + (uint16_t)pResult[1];
}
/**
@brief Get a uint32_t out of the input buffer
-
+
@param[in] me Pointer to the UsefulInputBuf.
-
+
@return The uint32_t
-
+
See UsefulInputBuf_GetByte(). This works the same, except it returns
a uint32_t and four bytes are consumed.
-
+
The input bytes must be in network order (big endian).
*/
static inline uint32_t UsefulInputBuf_GetUint32(UsefulInputBuf *me)
{
const uint8_t *pResult = (const uint8_t *)UsefulInputBuf_GetBytes(me, sizeof(uint32_t));
-
+
if(!pResult) {
return 0;
}
-
+
return ((uint32_t)pResult[0]<<24) + ((uint32_t)pResult[1]<<16) + ((uint32_t)pResult[2]<<8) + (uint32_t)pResult[3];
}
/**
@brief Get a uint64_t out of the input buffer
-
+
@param[in] me Pointer to the UsefulInputBuf.
-
+
@return The uint64_t
-
+
See UsefulInputBuf_GetByte(). This works the same, except it returns
a uint64_t and eight bytes are consumed.
-
+
The input bytes must be in network order (big endian).
*/
static inline uint64_t UsefulInputBuf_GetUint64(UsefulInputBuf *me)
{
const uint8_t *pResult = (const uint8_t *)UsefulInputBuf_GetBytes(me, sizeof(uint64_t));
-
+
if(!pResult) {
return 0;
}
-
+
return ((uint64_t)pResult[0]<<56) +
((uint64_t)pResult[1]<<48) +
((uint64_t)pResult[2]<<40) +
@@ -1459,14 +1457,14 @@
/**
@brief Get a float out of the input buffer
-
+
@param[in] me Pointer to the UsefulInputBuf.
-
+
@return The float
-
+
See UsefulInputBuf_GetByte(). This works the same, except it returns
a float and four bytes are consumed.
-
+
The input bytes must be in network order (big endian).
*/
static inline float UsefulInputBuf_GetFloat(UsefulInputBuf *me)
@@ -1478,14 +1476,14 @@
/**
@brief Get a double out of the input buffer
-
+
@param[in] me Pointer to the UsefulInputBuf.
-
+
@return The double
-
+
See UsefulInputBuf_GetByte(). This works the same, except it returns
a double and eight bytes are consumed.
-
+
The input bytes must be in network order (big endian).
*/
static inline double UsefulInputBuf_GetDouble(UsefulInputBuf *me)
@@ -1498,19 +1496,19 @@
/**
@brief Get the error status
-
+
@param[in] me Pointer to the UsefulInputBuf.
-
+
@return The error.
-
+
Zero is success, non-zero is error. Once in the error state, the only
way to clear it is to call Init again.
-
+
You may be able to only check the error state at the end after all
the Get()'s have been done, but if what you get later depends on what
you get sooner you cannot. For example if you get a length or count
of following items you will have to check the error.
-
+
*/
static inline int UsefulInputBuf_GetError(UsefulInputBuf *me)
{
diff --git a/inc/qcbor.h b/inc/qcbor.h
index bf7f55a..c945757 100644
--- a/inc/qcbor.h
+++ b/inc/qcbor.h
@@ -2,7 +2,7 @@
Copyright (c) 2016-2018, The Linux Foundation.
Copyright (c) 2018, Laurence Lundblade.
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
@@ -16,7 +16,7 @@
contributors, nor the name "Laurence Lundblade" may be used to
endorse or promote products derived from this software without
specific prior written permission.
-
+
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
@@ -33,16 +33,18 @@
/*===================================================================================
FILE: qcbor.h
-
+
DESCRIPTION: This is the full public API and data structures for QCBOR
-
+
EDIT HISTORY FOR FILE:
-
+
This section contains comments describing changes made to the module.
Notice that changes are listed in reverse chronological order.
-
+
when who what, where, why
-------- ---- ---------------------------------------------------
+ 12/18/18 llundblade Move decode malloc optional code to separate repository
+ 12/13/18 llundblade Documentatation improvements
11/29/18 llundblade Rework to simpler handling of tags and labels.
11/9/18 llundblade Error codes are now enums.
11/1/18 llundblade Floating support.
@@ -55,7 +57,7 @@
11/13/16 llundbla Integrate most TZ changes back into github version.
09/30/16 gkanike Porting to TZ.
03/15/16 llundbla Initial Version.
-
+
=====================================================================================*/
#ifndef __QCBOR__qcbor__
@@ -80,24 +82,24 @@
/*
- The maxium nesting of arrays and maps when encoding or decoding.
- (Further down in the file there is a definition that refers to this
+ The maxium nesting of arrays and maps when encoding or decoding.
+ (Further down in the file there is a definition that refers to this
that is public. This is done this way so there can be a nice
separation of public and private parts in this file.
*/
#define QCBOR_MAX_ARRAY_NESTING1 15 // Do not increase this over 255
-/*
- PRIVATE DATA STRUCTURE
-
+/*
+ PRIVATE DATA STRUCTURE
+
Holds the data for tracking array and map nesting during encoding. Pairs up with
the Nesting_xxx functions to make an "object" to handle nesting encoding.
-
+
uStart is a uint32_t instead of a size_t to keep the size of this
struct down so it can be on the stack without any concern. It would be about
double if size_t was used instead.
-
+
Size approximation (varies with CPU/compiler):
64-bit machine: (15 + 1) * (4 + 2 + 1 + 1 pad) + 8 = 136 bytes
32-bit machine: (15 + 1) * (4 + 2 + 1 + 1 pad) + 4 = 132 bytes
@@ -107,19 +109,19 @@
struct {
// See function OpenArrayInternal() for detailed comments on how this works
uint32_t uStart; // uStart is the byte position where the array starts
- uint16_t uCount; // Number of items in the arrary or map; counts items in a map, not pairs of items
+ uint16_t uCount; // Number of items in the arrary or map; counts items in a map, not pairs of items
uint8_t uMajorType; // Indicates if item is a map or an array
} pArrays[QCBOR_MAX_ARRAY_NESTING1+1], // stored state for the nesting levels
*pCurrentNesting; // the current nesting level
} QCBORTrackNesting;
-/*
- PRIVATE DATA STRUCTURE
-
- Context / data object for encoding some CBOR. Used by all encode functions to
+/*
+ PRIVATE DATA STRUCTURE
+
+ Context / data object for encoding some CBOR. Used by all encode functions to
form a public "object" that does the job of encdoing.
-
+
Size approximation (varies with CPU/compiler):
64-bit machine: 27 + 1 (+ 4 padding) + 136 = 32 + 136 = 168 bytes
32-bit machine: 15 + 1 + 132 = 148 bytes
@@ -134,11 +136,11 @@
/*
PRIVATE DATA STRUCTURE
-
+
Holds the data for array and map nesting for decoding work. This structure
and the DecodeNesting_xxx functions form an "object" that does the work
for arrays and maps.
-
+
Size approximation (varies with CPU/compiler):
64-bit machine: 4 * 16 + 8 = 72
32-bit machine: 4 * 16 + 4 = 68
@@ -146,14 +148,14 @@
typedef struct __QCBORDecodeNesting {
// PRIVATE DATA STRUCTURE
struct {
- uint16_t uCount;
+ uint16_t uCount;
uint8_t uMajorType;
} pMapsAndArrays[QCBOR_MAX_ARRAY_NESTING1+1],
*pCurrent;
} QCBORDecodeNesting;
-/*
+/*
PRIVATE DATA STRUCTURE
The decode context. This data structure plus the public QCBORDecode_xxx
@@ -164,20 +166,20 @@
32-bit machine: 16 + 1 + 1 + 2 bytes padding + 68 + 8 = 68 bytes
*/
struct _QCBORDecodeContext {
- // PRIVATE DATA STRUCTURE
+ // PRIVATE DATA STRUCTURE
UsefulInputBuf InBuf;
-
+
uint8_t uDecodeMode;
uint8_t bStringAllocateAll;
-
+
QCBORDecodeNesting nesting;
-
+
// This is NULL or points to a QCBORStringAllocator. It is void
// here because _QCBORDecodeContext is defined early in the
// private part of this file and QCBORStringAllocat is defined
// later in the public part of this file.
void *pStringAllocator;
-
+
// This is NULL or points to QCBORTagList.
// It is type void for the same reason as above.
const void *pCallerConfiguredTagList;
@@ -199,7 +201,7 @@
/* ===========================================================================
BEGINNING OF CONSTANTS THAT COME FROM THE CBOR STANDARD, RFC 7049
-
+
It is not necessary to use these directly when encoding or decoding
CBOR with this implementation.
=========================================================================== */
@@ -320,27 +322,27 @@
/* ===========================================================================
-
+
END OF CONSTANTS THAT COME FROM THE CBOR STANDARD, RFC 7049
-
+
BEGINNING OF PUBLIC INTERFACE FOR QCBOR ENCODER / DECODER
-
+
=========================================================================== */
/**
-
+
@file qcbor.h
-
+
Q C B O R E n c o d e / D e c o d e
-
+
This implements CBOR -- Concise Binary Object Representation as defined
in RFC 7049. More info is at http://cbor.io. This is a near-complete
implementation of the specification. Limitations are listed further down.
-
+
CBOR is intentionally designed to be translatable to JSON, but not
all CBOR can convert to JSON. See RFC 7049 for more info on how to
construct CBOR that is the most JSON friendly.
-
+
The memory model for encoding and decoding is that encoded CBOR
must be in a contiguous buffer in memory. During encoding the
caller must supply an output buffer and if the encoding would go
@@ -348,10 +350,10 @@
the caller supplies the encoded CBOR in a contiguous buffer
and the decoder returns pointers and lengths into that buffer
for strings.
-
+
This implementation does not require malloc. All data structures
passed in/out of the APIs can fit on the stack.
-
+
Decoding of indefinite length strings is a special case that requires
a "string allocator" to allocate memory into which the segments of
the string are coalesced. Without this, decoding will error out if
@@ -360,42 +362,42 @@
allocator called MemPool is built-in and will work if supplied with
a block of memory to allocate. The string allocator can optionally
use malloc() or some other custom scheme.
-
+
Here are some terms and definitions:
-
+
- "Item", "Data Item": An integer or string or such. The basic "thing" that
CBOR is about. An array is an item itself that contains some items.
-
+
- "Array": An ordered sequence of items, the same as JSON.
-
+
- "Map": A collection of label/value pairs. Each pair is a data
item. A JSON "object" is the same as a CBOR "map".
-
+
- "Label": The data item in a pair in a map that names or identifies the
pair, not the value. This implementation refers to it as a "label".
JSON refers to it as the "name". The CBOR RFC refers to it this as a "key".
This implementation chooses label instead because key is too easily confused
with a cryptographic key. The COSE standard, which uses CBOR, has also
chosen to use the term "label" rather than "key" for this same reason.
-
+
- "Key": See "Label" above.
-
+
- "Tag": Optional info that can be added before each data item. This is always
CBOR major type 6.
-
+
- "Initial Byte": The first byte of an encoded item. Encoding and decoding of
this byte is taken care of by the implementation.
-
+
- "Additional Info": In addition to the major type, all data items have some
other info. This is usually the length of the data, but can be several
other things. Encoding and decoding of this is taken care of by the
implementation.
-
+
CBOR has two mechanisms for tagging and labeling the data
values like integers and strings. For example, an integer that
represents someone's birthday in epoch seconds since Jan 1, 1970
could be encoded like this:
-
+
- First it is CBOR_MAJOR_TYPE_POSITIVE_INT, the primitive positive
integer.
- Next it has a "tag" CBOR_TAG_DATE_EPOCH indicating the integer
@@ -403,7 +405,7 @@
Jan 1, 1970.
- Last it has a string "label" like "BirthDate" indicating
the meaning of the data.
-
+
The encoded binary looks like this:
a1 # Map of 1 item
69 # Indicates text string of 9 bytes
@@ -411,38 +413,38 @@
c1 # Tags next int as epoch date
1a # Indicates 4 byte integer
580d4172 # unsigned integer date 1477263730
-
+
Implementors using this API will primarily work with labels. Generally
tags are only needed for making up new data types. This implementation
covers most of the data types defined in the RFC using tags. It also,
allows for the creation of news tags if necessary.
-
+
This implementation explicitly supports labels that are text strings
and integers. Text strings translate nicely into JSON objects and
are very readable. Integer labels are much less readable, but
can be very compact. If they are in the range of -23 to
23 they take up only one byte.
-
- CBOR allows a label to be any type of data including an array or
+
+ CBOR allows a label to be any type of data including an array or
a map. It is possible to use this API to construct and
parse such labels, but it is not explicitly supported.
-
+
A common encoding usage mode is to invoke the encoding twice. First
with no output buffer to compute the length of the needed output
buffer. Then the correct sized output buffer is allocated. Last the
encoder is invoked again, this time with the output buffer.
-
+
The double invocation is not required if the max output buffer size
can be predicted. This is usually possible for simple CBOR structures.
If the double invocation is implemented, it can be
in a loop or function as in the example code so that the code doesn't
have to actually be written twice, saving code size.
-
+
If a buffer too small to hold the encoded output is given, the error
QCBOR_ERR_BUFFER_TOO_SMALL will be returned. Data will never be
written off the end of the output buffer no matter which functions
here are called or what parameters are passed to them.
-
+
The error handling is simple. The only possible errors are trying to
encode structures that are too large or too complex. There are no
internal malloc calls so there will be no failures for out of memory.
@@ -450,13 +452,13 @@
Once an error happens, the encoder goes into an error state and calls
to it will do nothing so the encoding can just go on. An error
check is not needed after every data item is added.
-
+
Encoding generally proceeds by calling QCBOREncode_Init(), calling
lots of "Add" functions and calling QCBOREncode_Finish(). There
are many "Add" functions for various data types. The input
- buffers need only to be valid during the "Add" calls. The
+ buffers need only to be valid during the "Add" calls. The
data is copied into the output buf during the "Add" call.
-
+
There are three `Add` functions for each data type. The first
/ main one for the type is for adding the data item to an array.
The second one's name ends in `ToMap`, is used for adding
@@ -464,30 +466,30 @@
argument that is its label in the map. The third one ends in
`ToMapN`, is also used for adding data items to maps, and
takes an integer argument that is its label in the map.
-
+
The simplest aggregate type is an array, which is a simple ordered
- set of items without labels the same as JSON arrays. Call
+ set of items without labels the same as JSON arrays. Call
QCBOREncode_OpenArray() to open a new array, then "Add" to
put items in the array and then QCBOREncode_CloseArray(). Nesting
to a limit is allowed. All opens must be matched by closes or an
encoding error will be returned.
-
+
The other aggregate type is a map which does use labels. The
`Add` functions that end in `ToMap` and `ToMapN` are convenient
ways to add labeled data items to a map. You can also call
any type of `Add` function once to add a label of any time and
then call any type of `Add` again to add its value.
-
+
Note that when you nest arrays or maps in a map, the nested
array or map has a label.
Usually it is not necessary to add tags explicitly as most
tagged types have functions here, but they can be added by
calling QCBOREncode_AddTag(). There is an IANA registry for new tags that are
- for broad use and standardization as per RFC 7049. It is also
+ for broad use and standardization as per RFC 7049. It is also
allowed for protocols to make up new tags in the range above 256.
Note that even arrays and maps can be tagged.
-
+
Summary Limits of this implementation:
- The entire encoded CBOR must fit into contiguous memory.
- Max size of encoded / decoded CBOR data is UINT32_MAX (4GB).
@@ -501,21 +503,21 @@
- Does not directly support int labels greater than INT64_MAX
- Epoch dates limited to INT64_MAX (+/- 292 billion years)
- Tags on labels are ignored during decoding
-
+
This implementation is intended to run on 32 and 64-bit CPUs. It
will probably work on 16-bit CPUs but less efficiently.
-
+
The public interface uses size_t for all lengths. Internally the
implementation uses 32-bit lengths by design to use less memory and
fit structures on the stack. This limits the encoded
CBOR it can work with to size UINT32_MAX (4GB) which should be
enough.
-
+
This implementation assumes two's compliment integer
machines. Stdint.h also requires this. It of course would be easy to
fix this implementation for another integer representation, but all
modern machines seem to be two's compliment.
-
+
*/
@@ -524,7 +526,7 @@
*/
#define QCBOR_MAX_ITEMS_IN_ARRAY (UINT16_MAX) // This value is 65,535 a lot of items for an array
-/**
+/**
The maximum nesting of arrays and maps when encoding or decoding. The
error QCBOR_ERR_ARRAY_NESTING_TOO_DEEP will be returned on encoding
of decoding if it is exceeded
@@ -630,23 +632,32 @@
/** During decoding, too many tags in the caller-configured tag list, or not
enough space in QCBORTagListOut. */
- QCBOR_ERR_TOO_MANY_TAGS
+ QCBOR_ERR_TOO_MANY_TAGS,
+
+ /** Returned by QCBORDecode_SetMemPool() when xx is too small. This should
+ never happen on a machine with 64-bit or smaller pointers. Fixing
+ it is probably by increasing QCBOR_DECODE_MIN_MEM_POOL_SIZE. */
+ QCBOR_ERR_MEM_POOL_INTERNAL
} QCBORError;
-/** See QCBORDecode_Init() */
-#define QCBOR_DECODE_MODE_NORMAL 0
-/** See QCBORDecode_Init() */
-#define QCBOR_DECODE_MODE_MAP_STRINGS_ONLY 1
-/** See QCBORDecode_Init() */
-#define QCBOR_DECODE_MODE_MAP_AS_ARRAY 2
+typedef enum {
+ /** See QCBORDecode_Init() */
+ QCBOR_DECODE_MODE_NORMAL = 0,
+ /** See QCBORDecode_Init() */
+ QCBOR_DECODE_MODE_MAP_STRINGS_ONLY = 1,
+ /** See QCBORDecode_Init() */
+ QCBOR_DECODE_MODE_MAP_AS_ARRAY = 2
+} QCBORDecodeMode;
/* Do not renumber these. Code depends on some of these values. */
+/** The type is unknown, unset or invalid */
+#define QCBOR_TYPE_NONE 0
/** Type for an integer that decoded either between INT64_MIN and INT32_MIN or INT32_MAX and INT64_MAX; val.int64 */
#define QCBOR_TYPE_INT64 2
/** Type for an integer that decoded to a more than INT64_MAX and UINT64_MAX; val.uint64 */
@@ -659,10 +670,6 @@
#define QCBOR_TYPE_BYTE_STRING 6
/** Type for a UTF-8 string. It is not NULL terminated. Data is in val.string. */
#define QCBOR_TYPE_TEXT_STRING 7
-/** Type for a floating point number. Data is in val.float. */
-#define QCBOR_TYPE_FLOAT 26
-/** Type for a double floating point number. Data is in val.double. */
-#define QCBOR_TYPE_DOUBLE 27
/** Type for a positive big number. Data is in val.bignum, a pointer and a length. */
#define QCBOR_TYPE_POSBIGNUM 9
/** Type for a negative big number. Data is in val.bignum, a pointer and a length. */
@@ -681,6 +688,12 @@
#define QCBOR_TYPE_NULL 22
/** Type for the simple value undef; nothing more; nothing in val union. */
#define QCBOR_TYPE_UNDEF 23
+/** Type for a floating point number. Data is in val.float. */
+#define QCBOR_TYPE_FLOAT 26
+/** Type for a double floating point number. Data is in val.double. */
+#define QCBOR_TYPE_DOUBLE 27
+/** For QCBOR_DECODE_MODE_MAP_AS_ARRAY decode mode, a map that is being traversed as an array. See QCBORDecode_Init() */
+#define QCBOR_TYPE_MAP_AS_ARRAY 32
#define QCBOR_TYPE_BREAK 31 // Used internally; never returned
@@ -706,7 +719,7 @@
uint8_t uDataAlloc; /** 1 if allocated with string allocator, 0 if not. See QCBORDecode_MakeMallocStringAllocator() */
uint8_t uLabelAlloc; /** Like uDataAlloc, but for label */
uint8_t uNextNestLevel; /** If not equal to uNestingLevel, this item closed out at least one map/array */
-
+
union {
int64_t int64; /** The value for uDataType QCBOR_TYPE_INT64 */
uint64_t uint64; /** The value for uDataType QCBOR_TYPE_UINT64 */
@@ -723,17 +736,17 @@
UsefulBufC bigNum; /** The value for uDataType QCBOR_TYPE_BIGNUM */
uint8_t uSimple; /** The integer value for unknown simple types */
uint64_t uTagV;
-
+
} val; /** The union holding the item's value. Select union member based on uDataType */
-
+
union {
UsefulBufC string; /** The label for uLabelType QCBOR_TYPE_BYTE_STRING and QCBOR_TYPE_TEXT_STRING */
int64_t int64; /** The label for uLabelType for QCBOR_TYPE_INT64 */
uint64_t uint64; /** The label for uLabelType for QCBOR_TYPE_UINT64 */
} label; /** Union holding the different label types selected based on uLabelType */
-
+
uint64_t uTagBits; /** Bit indicating which tags (major type 6) on this item. */
-
+
} QCBORItem;
@@ -741,22 +754,22 @@
This is a set of functions and pointer context (in object-oriented parlance,
an "object") used to allocate memory for coalescing the segments of an indefinite
length string into one.
-
+
The fAllocate function works as an initial allocator and a reallocator to
expand the string for each new segment. When it is an initial allocator
pOldMem is NULL.
-
+
The fFree function is called to clean up an individual allocation when an error occurs.
-
+
The fDesctructor function is called when QCBORDecode_Finish is called.
-
+
Any memory allocated with this will be marked by setting uDataAlloc
or uLabelAlloc in the QCBORItem structure so the caller knows they
have to free it.
-
+
fAllocate is only ever called to increase the single most recent
allocation made, making implementation of a memory pool very simple.
-
+
fFree is also only called on the single most recent allocation.
*/
typedef struct {
@@ -767,6 +780,16 @@
} QCBORStringAllocator;
+/**
+ This only matters if you use a string allocator
+ and and set it up with QCBORDecode_SetMemPool(). It is
+ the size of the overhead needed needed by
+ QCBORDecode_SetMemPool(). If you write your own
+ string allocator or use the separately available malloc
+ based string allocator, this size will not apply
+ */
+#define QCBOR_DECODE_MIN_MEM_POOL_SIZE 72
+
/**
This is used to tell the decoder about tags that it should
@@ -788,11 +811,11 @@
full list of tags on an item. It not needed for most CBOR protocol
implementations. Its primary use is for pretty-printing CBOR or
protocol conversion to another format.
-
+
On input, puTags points to a buffer to be filled in
and uNumAllocated is the number of uint64_t values
in the buffer.
-
+
On output the buffer contains the tags for the item.
uNumUsed tells how many there are.
*/
@@ -815,19 +838,19 @@
/**
Initialize the the encoder to prepare to encode some CBOR.
-
+
@param[in,out] pCtx The encoder context to initialize.
@param[in] Storage The buffer into which this encoded result will be placed.
-
+
Call this once at the start of an encoding of a CBOR structure. Then
call the various QCBOREncode_AddXXX() functions to add the data
items. Then call QCBOREncode_Finish().
-
+
The maximum output buffer is UINT32_MAX (4GB). This is not a practical
limit in any way and reduces the memory needed by the implementation.
The error QCBOR_ERR_BUFFER_TOO_LARGE will be returned by QCBOR_Finish()
if a larger buffer length is passed in.
-
+
If this is called with pBuf as NULL and uBufLen a large value like
UINT32_MAX, all the QCBOREncode_AddXXXX() functions and
QCBORE_Encode_Finish() can still be called. No data will be encoded,
@@ -835,7 +858,7 @@
length of the encoded structure will be handed back in the call to
QCBOREncode_Finish(). You can then allocate a buffer of that size
and call all the encoding again, this time to fill in the buffer.
-
+
A QCBORContext can be reused over and over as long as
QCBOREncode_Init() is called.
*/
@@ -844,12 +867,12 @@
/**
@brief Add a signed 64-bit integer to the encoded output.
-
+
@param[in] pCtx The encoding context to add the integer to.
@param[in] nNum The integer to add.
-
+
The integer will be encoded and added to the CBOR output.
-
+
This function figures out the size and the sign and encodes in the
correct minimal CBOR. Specifically, it will select CBOR major type 0 or 1
based on sign and will encode to 1, 2, 4 or 8 bytes depending on the
@@ -859,7 +882,7 @@
advantage of when designing CBOR-based protocols. If integers like
tags can be kept between -23 and 23 they will be encoded in one byte
including the major type.
-
+
If you pass a smaller int, say an int16_t or a small value, say 100,
the encoding will still be CBOR's most compact that can represent the
value. For example, CBOR always encodes the value 0 as one byte,
@@ -867,17 +890,17 @@
as an integer too as the major type for an integer is 0. See RFC 7049
Appendix A for more examples of CBOR encoding. This compact encoding
is also canonical CBOR as per section 3.9 in RFC 7049.
-
+
There are no functions to add int16_t or int32_t because they are
not necessary because this always encodes to the smallest number
of bytes based on the value (If this code is running on a 32-bit
machine having a way to add 32-bit integers would reduce code size some).
-
+
If the encoding context is in an error state, this will do
nothing. If an error occurs when adding this integer, the internal
error flag will be set, and the error will be returned when
QCBOREncode_Finish() is called.
-
+
See also QCBOREncode_AddUInt64().
*/
void QCBOREncode_AddInt64(QCBOREncodeContext *pCtx, int64_t nNum);
@@ -889,16 +912,16 @@
/**
@brief Add an unsigned 64-bit integer to the encoded output.
-
+
@param[in] pCtx The encoding context to add the integer to.
@param[in] uNum The integer to add.
-
+
The integer will be encoded and added to the CBOR output.
-
+
The only reason so use this function is for integers larger than
INT64_MAX and smaller than UINT64_MAX. Otherwise QCBOREncode_AddInt64()
will work fine.
-
+
Error handling is the same as for QCBOREncode_AddInt64().
*/
void QCBOREncode_AddUInt64(QCBOREncodeContext *pCtx, uint64_t uNum);
@@ -909,24 +932,24 @@
/**
-
+
@brief Add a UTF-8 text string to the encoded output
-
+
@param[in] pCtx The context to initialize.
@param[in] Text Pointer and length of text to add.
-
+
The text passed in must be unencoded UTF-8 according to RFC
3629. There is no NULL termination. The text is added as CBOR
major type 3.
-
+
If called with nBytesLen equal to 0, an empty string will be
added. When nBytesLen is 0, pBytes may be NULL.
-
+
Note that the restriction of the buffer length to an uint32_t is
entirely intentional as this encoder is not capable of encoding
lengths greater. This limit to 4GB for a text string should not be a
problem.
-
+
Error handling is the same as QCBOREncode_AddInt64().
*/
static void QCBOREncode_AddText(QCBOREncodeContext *pCtx, UsefulBufC Text);
@@ -938,10 +961,10 @@
/**
@brief Add a UTF-8 text string to the encoded output
-
+
@param[in] pCtx The context to initialize.
@param[in] szString Null-terminated text to add.
-
+
This works the same as QCBOREncode_AddText().
*/
static void QCBOREncode_AddSZString(QCBOREncodeContext *pCtx, const char *szString);
@@ -953,27 +976,27 @@
/**
@brief Add a floating-point number to the encoded output
-
+
@param[in] pCtx The encoding context to add the float to.
@param[in] dNum The double precision number to add.
-
+
This outputs a floating-point number with CBOR major type 7.
-
+
This will selectively encode the double-precision floating point number as either
double-precision, single-precision or half-precision. It will always encode infinity, NaN and 0
has half precision. If no precision will be lost in the conversion to half-precision
then it will be converted and encoded. If not and no precision will be lost in
conversion to single-precision, then it will be converted and encoded. If not, then
no conversion is performed, and it encoded as a double.
-
+
Half-precision floating point numbers take up 2 bytes, half that of single-precision,
one quarter of double-precision
-
+
This automatically reduces the size of encoded messages a lot, maybe even by four if most of values are
0, infinity or NaN.
-
+
On decode, these will always be returned as a double.
-
+
Error handling is the same as QCBOREncode_AddInt64().
*/
void QCBOREncode_AddDouble(QCBOREncodeContext *pCtx, double dNum);
@@ -985,17 +1008,17 @@
/**
@brief[in] Add an optional tag
-
+
@param[in] pCtx The encoding context to add the integer to.
@param[in] uTag The tag to add
-
+
This outputs a CBOR major type 6 optional tag.
-
+
The tag is applied to the next data item added to the encoded
output. That data item that is to be tagged can be of any major
CBOR type. Any number of tags can be added to a data item by calling
this multiple times before the data item is added.
-
+
For many of the common standard tags a function to encode
data using it already exists and this is not needed. For example,
QCBOREncode_AddDateEpoch() already exists to output
@@ -1006,29 +1029,29 @@
/**
@brief Add an epoch-based date
-
+
@param[in] pCtx The encoding context to add the simple value to.
@param[in] date Number of seconds since 1970-01-01T00:00Z in UTC time.
-
+
As per RFC 7049 this is similar to UNIX/Linux/POSIX dates. This is
the most compact way to specify a date and time in CBOR. Note that this
is always UTC and does not include the time zone. Use
QCBOREncode_AddDateString() if you want to include the time zone.
-
+
The integer encoding rules apply here so the date will be encoded in a
minimal number of 1, 2 4 or 8 bytes. Until about the year 2106 these
dates should encode in 6 bytes -- one byte for the tag, one byte for the type
and 4 bytes for the integer.
-
+
If you care about leap-seconds and that level of accuracy, make sure the
system you are running this code on does it correctly. This code just takes
the value passed in.
-
+
This implementation cannot encode fractional seconds using float or double
even though that is allowed by CBOR, but you can encode them if you
want to by calling QCBOREncode_AddDouble()
with the right parameters.
-
+
Error handling is the same as QCBOREncode_AddInt64().
*/
static void QCBOREncode_AddDateEpoch(QCBOREncodeContext *pCtx, int64_t date);
@@ -1040,15 +1063,15 @@
/**
@brief Add a byte string to the encoded output.
-
+
@param[in] pCtx The context to initialize.
@param[in] Bytes Pointer and length of the input data.
-
+
Simply adds the bytes to the encoded output as CBOR major type 2.
-
+
If called with Bytes.len equal to 0, an empty string will be
added. When Bytes.len is 0, Bytes.ptr may be NULL.
-
+
Error handling is the same as QCBOREncode_AddInt64().
*/
static void QCBOREncode_AddBytes(QCBOREncodeContext *pCtx, UsefulBufC Bytes);
@@ -1061,12 +1084,12 @@
/**
@brief Add a binary UUID to the encoded output.
-
+
@param[in] pCtx The context to initialize.
@param[in] Bytes Pointer and length of the binary UUID.
-
+
A binary UUID as defined in RFC 4122 is added to the ouput.
-
+
It is output as CBOR major type 2, a binary string, with
optional tag 36 indicating the binary string is a UUID.
*/
@@ -1079,17 +1102,17 @@
/**
@brief Add a positive big number to the encoded output.
-
+
@param[in] pCtx The context to initialize.
@param[in] Bytes Pointer and length of the big number.
-
+
Big numbers are integers larger than 64-bits. Their format
is described in RFC 7049.
-
+
It is output as CBOR major type 2, a binary string, with
optional tag 2 indicating the binary string is a positive big
number.
-
+
Often big numbers are used to represent cryptographic keys,
however, COSE which defines representations for keys chose not
to use this particular type.
@@ -1103,17 +1126,17 @@
/**
@brief Add a negative big number to the encoded output.
-
+
@param[in] pCtx The context to initialize.
@param[in] Bytes Pointer and length of the big number.
-
+
Big numbers are integers larger than 64-bits. Their format
is described in RFC 7049.
-
+
It is output as CBOR major type 2, a binary string, with
optional tag 2 indicating the binary string is a negative big
number.
-
+
Often big numbers are used to represent cryptographic keys,
however, COSE which defines representations for keys chose not
to use this particular type.
@@ -1127,12 +1150,12 @@
/**
@brief Add a text URI to the encoded output.
-
+
@param[in] pCtx The context to initialize.
@param[in] URI Pointer and length of the URI.
-
+
The format of URI is RFC 3986.
-
+
It is output as CBOR major type 3, a text string, with
optional tag 32 indicating the text string is a URI.
*/
@@ -1145,12 +1168,12 @@
/**
@brief Add base 64-encoded text to encoded output.
-
+
@param[in] pCtx The context to initialize.
@param[in] B64Text Pointer and length of the base-64 encoded text.
-
+
The text content is base 64 encoded data per RFC 4648.
-
+
It is output as CBOR major type 3, a text string, with
optional tag 34 indicating the text string is a URI.
*/
@@ -1163,12 +1186,12 @@
/**
@brief Add base 64URL -encoded URL to encoded output.
-
+
@param[in] pCtx The context to initialize.
@param[in] B64Text Pointer and length of the base-64 encoded text.
-
+
The text content is base 64 URL format encoded text as per RFC 4648.
-
+
It is output as CBOR major type 3, a text string, with
optional tag 33 indicating the text string is a URI.
*/
@@ -1181,13 +1204,13 @@
/**
@brief Add Perl Compatible Regular Expression
-
+
@param[in] pCtx The context to initialize.
@param[in] Regex Pointer and length of the regular expression.
-
+
The text content is Perl Compatible Regular
Expressions (PCRE) / JavaScript syntax [ECMA262].
-
+
It is output as CBOR major type 3, a text string, with
optional tag 35 indicating the text string is a regular expression.
*/
@@ -1200,12 +1223,12 @@
/**
@brief MIME encoded text to the encoded output.
-
+
@param[in] pCtx The context to initialize.
@param[in] MIMEData Pointer and length of the regular expression.
-
+
The text content is in MIME format per RFC 2045 including the headers.
-
+
It is output as CBOR major type 3, a text string, with
optional tag 36 indicating the text string is MIME data.
*/
@@ -1218,17 +1241,17 @@
/**
@brief Add an RFC 3339 date string
-
+
@param[in] pCtx The encoding context to add the simple value to.
@param[in] szDate Null-terminated string with date to add
The string szDate should be in the form of RFC 3339 as defined by section
3.3 in RFC 4287. This is as described in section 2.4.1 in RFC 7049.
-
+
Note that this function doesn't validate the format of the date string
at all. If you add an incorrect format date string, the generated
CBOR will be incorrect and the receiver may not be able to handle it.
-
+
Error handling is the same as QCBOREncode_AddInt64().
*/
static void QCBOREncode_AddDateString(QCBOREncodeContext *pCtx, const char *szDate);
@@ -1240,12 +1263,12 @@
/**
@brief Add a standard boolean.
-
+
@param[in] pCtx The encoding context to add the simple value to.
@param[in] b true or false from stdbool. Anything will result in an error.
-
+
Adds a boolean value as CBOR major type 7.
-
+
Error handling is the same as QCBOREncode_AddInt64().
*/
static void QCBOREncode_AddBool(QCBOREncodeContext *pCtx, bool b);
@@ -1258,14 +1281,14 @@
/**
@brief Add a NULL to the encoded output.
-
+
@param[in] pCtx The encoding context to add the simple value to.
-
+
Adds the NULL value as CBOR major type 7.
-
+
This NULL doesn't have any special meaning in CBOR such as a terminating
value for a string or an empty value.
-
+
Error handling is the same as QCBOREncode_AddInt64().
*/
static void QCBOREncode_AddNULL(QCBOREncodeContext *pCtx);
@@ -1277,16 +1300,16 @@
/**
@brief Add an "undef" to the encoded output.
-
+
@param[in] pCtx The encoding context to add the simple value to.
-
+
Adds the undef value as CBOR major type 7.
-
+
Note that this value will not translate to JSON.
-
+
This Undef doesn't have any special meaning in CBOR such as a terminating
value for a string or an empty value.
-
+
Error handling is the same as QCBOREncode_AddInt64().
*/
static void QCBOREncode_AddUndef(QCBOREncodeContext *pCtx);
@@ -1298,16 +1321,16 @@
/**
@brief Indicates that the next items added are in an array.
-
+
@param[in] pCtx The encoding context to open the array in.
-
+
Arrays are the basic CBOR aggregate or structure type. Call this
function to start or open an array. Then call the various AddXXX
functions to add the items that go into the array. Then call
QCBOREncode_CloseArray() when all items have been added. The
data items in the array can be of any type and can be of
mixed types.
-
+
Nesting of arrays and maps is allowed and supported just by calling
OpenArray again before calling CloseArray. While CBOR has no limit
on nesting, this implementation does in order to keep it smaller and
@@ -1316,13 +1339,13 @@
QCBOREncode_CloseArray(). QCBOREncode_Finish() will return
QCBOR_ERR_ARRAY_TOO_LONG when it is called as this function just sets
an error state and returns no value when this occurs.
-
+
If you try to add more than 32,767 items to an array or map, incorrect CBOR will
be produced by this encoder.
-
+
An array itself must have a label if it is being added to a map. Note that
array elements do not have labels (but map elements do).
-
+
An array itself may be tagged.
*/
static void QCBOREncode_OpenArray(QCBOREncodeContext *pCtx);
@@ -1334,21 +1357,21 @@
/**
@brief Close an open array.
-
+
@param[in] pCtx The context to add to.
-
+
The closes an array opened by QCBOREncode_OpenArray(). It reduces
nesting level by one. All arrays (and maps) must be closed
before calling QCBOREncode_Finish().
-
+
When an error occurs as a result of this call, the encoder records
the error and enters the error state. The error will be returned when
QCBOREncode_Finish() is called.
-
+
If this has been called more times than QCBOREncode_OpenArray(),
then QCBOR_ERR_TOO_MANY_CLOSES will be returned when
QCBOREncode_Finish() is called.
-
+
If this is called and it is not an array that is currently
open, QCBOR_ERR_CLOSE_MISMATCH will be returned when QCBOREncode_Finish()
is called.
@@ -1358,31 +1381,31 @@
/**
@brief Indicates that the next items added are in a map.
-
+
@param[in] pCtx The context to add to.
-
+
See QCBOREncode_OpenArray() for more information.
-
+
CBOR maps are an aggregate type where each item in the map consists
of a label and a value. They are similar to JSON objects.
-
+
The value can be any CBOR type including another map.
-
+
The label can also be any CBOR type, but in practice they are
typically, integers as this gives the most compact output. They
might also be text strings which gives readability and translation
to JSON.
-
+
Every QCBOREncode_AddXXX() call has once version that is "InMap" for
adding items to maps with string labels and on that is "InMapN" that
is for adding with integer labels.
-
+
RFC 7049 uses the term "key" instead of "label".
-
+
If you wish to use map labels that are neither integer labels or
text strings, then just call the QCBOREncode_AddXXX() function
explicitly to add the label. Then call it again to add the value.
-
+
See the RFC7049 for a lot more information on creating maps.
*/
static void QCBOREncode_OpenMap(QCBOREncodeContext *pCtx);
@@ -1395,20 +1418,20 @@
/**
@brief Close an open map.
-
+
@param[in] pCtx The context to add to.
-
+
The closes a map opened by QCBOREncode_OpenMap(). It reduces
nesting level by one.
-
+
When an error occurs as a result of this call, the encoder records
the error and enters the error state. The error will be returned when
QCBOREncode_Finish() is called.
-
+
If this has been called more times than QCBOREncode_OpenMap(),
then QCBOR_ERR_TOO_MANY_CLOSES will be returned when
QCBOREncode_Finish() is called.
-
+
If this is called and it is not a map that is currently
open, QCBOR_ERR_CLOSE_MISMATCH will be returned when QCBOREncode_Finish()
is called.
@@ -1418,27 +1441,27 @@
/**
@brief Indicate start of encoded CBOR to be wrapped in a bstr.
-
+
@param[in] pCtx The context to add to.
-
+
All added encoded items between this call and a call to
QCBOREncode_CloseBstrWrap() will be wrapped in a bstr. They will
appear in the final output as a byte string. That byte string will
contain encoded CBOR.
-
+
The typical use case is for encoded CBOR that is to be
cryptographically hashed, as part of a COSE (RFC 8152)
implementation. This avoids having to encode the items first in one
buffer (e.g., the COSE payload) and then add that buffer as a bstr to
another encoding (e.g. the COSE to-be-signed bytes, the
Sig_structure) potentially saving a lot of memory.
-
+
When constructing cryptographically signed CBOR objects, maps or arrays, they
typically are encoded
normally and then wrapped as a byte string. The COSE standard for example
does this. The wrapping is simply treating the encoded CBOR map
as a byte string.
-
+
The stated purpose of this wrapping is to prevent code relaying the signed data
but not verifying it from tampering with the signed data thus making
the signature unverifiable. It is also quite beneficial for the
@@ -1456,13 +1479,13 @@
/**
@brief Close a wrapping bstr.
-
+
@param[in] pCtx The context to add to.
@param[out] pWrappedCBOR UsefulBufC containing wrapped bytes
-
+
The closes a wrapping bstr opened by QCBOREncode_BstrWrap(). It reduces
nesting level by one.
-
+
A pointer and length of the enclosed encoded CBOR is returned in
*pWrappedCBOR if it is not NULL. The main purpose of this is so this
data can be hashed (e.g., with SHA-256) as part of a COSE (RFC 8152)
@@ -1470,15 +1493,15 @@
right away before any other calls to QCBOREncode_xxxx() as they will
move data around and the pointer and length will no longer be to the
correct encoded CBOR.
-
+
When an error occurs as a result of this call, the encoder records
the error and enters the error state. The error will be returned when
QCBOREncode_Finish() is called.
-
+
If this has been called more times then QCBOREncode_BstrWrap(),
then QCBOR_ERR_TOO_MANY_CLOSES will be returned when
QCBOREncode_Finish() is called.
-
+
If this is called and it is not a wrapping bstr that is currently
open, QCBOR_ERR_CLOSE_MISMATCH will be returned when QCBOREncode_Finish()
is called.
@@ -1488,19 +1511,19 @@
/**
Add some already-encoded CBOR bytes.
-
+
@param[in] pCtx The context to add to.
@param[in] Encoded The already-encoded CBOR to add to the context.
-
+
The encoded CBOR being added must be fully conforming CBOR. It must
be complete with no arrays or maps that are incomplete. While this
encoder doesn't ever produce indefinite lengths, it is OK for the
raw CBOR added here to have indefinite lengths.
-
+
The raw CBOR added here is not checked in anyway. If it is not
conforming or has open arrays or such, the final encoded CBOR
will probably be wrong or not what was intended.
-
+
If the encoded CBOR being added here contains multiple items, they
must be enclosed in a map or array. At the top level the raw
CBOR must be a single data item.
@@ -1514,28 +1537,28 @@
/**
Get the encoded result.
-
+
@param[in] pCtx The context to finish encoding with.
@param[out] pEncodedCBOR Pointer and length of encoded CBOR.
-
+
@return
One of the CBOR error codes.
-
+
If this returns success QCBOR_SUCCESS the encoding was a success and
the return length is correct and complete.
-
+
If no buffer was passed to QCBOR_Init(), then only the length and
number of items was computed. The length is in
pEncodedCBOR->Bytes.len. pEncodedCBOR->Bytes.ptr is NULL.
-
+
If a buffer was passed, then pEncodedCBOR->Bytes.ptr is the same as
the buffer passed to QCBOR_Init() and contains the encoded CBOR
and the length is filled in.
-
+
If an error is returned, the buffer may have partially encoded
incorrect CBOR in it and it should not be used. Likewise, the length
may be incorrect and should not be used.
-
+
Note that the error could have occurred in one of the many
QCBOR_AddXXX calls long before QCBOREncode_Finish() was called. This
error handling approach reduces the CBOR implementation size, but makes
@@ -1546,24 +1569,24 @@
/**
Get the encoded CBOR and error status.
-
+
@param[in] pCtx The context to finish encoding with.
@param[out] uEncodedLen The length of the encoded or potentially encoded CBOR in bytes.
-
+
@return
One of the CBOR error codes.
-
+
If this returns success QCBOR_SUCCESS the encoding was a success and
the return length is correct and complete.
-
+
If no buffer was passed to QCBOR_Init(), then only the length was
computed. If a buffer was passed, then the encoded CBOR is in the
buffer.
-
+
If an error is returned, the buffer may have partially encoded
incorrect CBOR in it and it should not be used. Likewise, the length
may be incorrect and should not be used.
-
+
Note that the error could have occurred in one of the many
QCBOR_AddXXX calls long before QCBOREncode_Finish() was called. This
error handling reduces the CBOR implementation size, but makes
@@ -1588,90 +1611,100 @@
/**
Initialize the CBOR decoder context.
-
+
@param[in] pCtx The context to initialize.
@param[in] EncodedCBOR The buffer with CBOR encoded bytes to be decoded.
@param[in] nMode One of QCBOR_DECODE_MODE_xxx
-
+
Initialize context for a pre-order travesal of the encoded CBOR tree.
-
+
Most CBOR decoding can be completed by calling this function to start
- and QCBORDecode_GetNext() in a loop. If indefinite length strings
- are to be decoded, then QCBORDecode_SetMemPool() or QCBORDecode_SetUpAllocator()
- must be called. If tags other than built-in tags are to be
- recognized, then QCBORDecode_SetCallerAddedTagMap() must be called.
- The built-in tags are those for which a macro of the form
- CBOR_TAG_XXX is defined.
-
- Three decoding modes are supported. In normal mode, maps are decoded
- and strings and ints are accepted as map labels. If a label is other
- than these, the error QCBOR_ERR_MAP_LABEL_TYPE is returned by
- QCBORDecode_GetNext(). In strings-only mode, only text strings are
- accepted for map labels. This lines up with CBOR that converts to
- JSON. The error QCBOR_ERR_MAP_LABEL_TYPE is returned by
+ and QCBORDecode_GetNext() in a loop.
+
+ If indefinite length strings are to be decoded, then
+ QCBORDecode_SetMemPool() or QCBORDecode_SetUpAllocator() must be
+ called to set up a string allocator.
+
+ If tags other than built-in tags are to be recognized, then
+ QCBORDecode_SetCallerAddedTagMap() must be called. The built-in tags
+ are those for which a macro of the form CBOR_TAG_XXX is defined.
+
+ Three decoding modes are supported. In normal mode,
+ QCBOR_DECODE_MODE_NORMAL, maps are decoded and strings and ints are
+ accepted as map labels. If a label is other than these, the error
+ QCBOR_ERR_MAP_LABEL_TYPE is returned by QCBORDecode_GetNext().
+
+ In strings-only mode, QCBOR_DECODE_MODE_MAP_STRINGS_ONLY, only text
+ strings are accepted for map labels. This lines up with CBOR that
+ converts to JSON. The error QCBOR_ERR_MAP_LABEL_TYPE is returned by
QCBORDecode_GetNext() if anything but a text string label is
- encountered. In array mode, the maps are treated as arrays. This will
- decode any type of label, but the caller must figure out all the map
- decoding.
+ encountered.
+
+ In QCBOR_DECODE_MODE_MAP_AS_ARRAY maps are treated as special arrays.
+ They will be return with special uDataType QCBOR_TYPE_MAP_AS_ARRAY
+ and uCount, the number of items, will be double what it would be
+ for a normal map because the labels are also counted. This mode
+ is useful for decoding CBOR that has labels that are not
+ integers or text strings, but the caller must manage much of
+ the map decoding.
*/
-void QCBORDecode_Init(QCBORDecodeContext *pCtx, UsefulBufC EncodedCBOR, int8_t nMode);
+void QCBORDecode_Init(QCBORDecodeContext *pCtx, UsefulBufC EncodedCBOR, QCBORDecodeMode nMode);
/**
- Set up the MemPool string allocator for indefinite length strings.
-
+ @brief Set up the MemPool string allocator for indefinite length strings.
+
@param[in] pCtx The decode context.
@param[in] MemPool The pointer and length of the memory pool.
@param[in] bAllStrings true means to put even definite length strings in the pool.
-
- @return 0 if the MemPool was at least minimum size, 1 if too small.
-
- Indefinite length strings (text and byte) cannot be decoded unless there is
- a string allocator configured. MemPool is a simple built-in string allocator
- that allocates bytes from a memory pool handed to it by calling
- this function. The memory pool is just a pointer and length for some
- block of memory that is to be used for string allocation. It can
- come from the stack, heap or other.
-
- The memory pool must be large enough to hold some fixed overhead plus the
- space for all the strings allocated. The fixed overhead does vary
- by CPU and compiler, but can roughly be computed as the space for
- seven pointers, 56 bytes for a 64-bit CPU. There is no overhead
- per string allocated
-
- This memory pool is used for all indefinite length strings that are text
- strings or byte strings, including strings used as labels.
-
+
+ @return error if the MemPool was less than QCBOR_DECODE_MIN_MEM_POOL_SIZE.
+
+ Indefinite length strings (text and byte) cannot be decoded unless
+ there is a string allocator configured. MemPool is a simple built-in
+ string allocator that allocates bytes from a memory pool handed to it
+ by calling this function. The memory pool is just a pointer and
+ length for some block of memory that is to be used for string
+ allocation. It can come from the stack, heap or other.
+
+ The memory pool must be QCBOR_DECODE_MIN_MEM_POOL_SIZE plus space for
+ all the strings allocated. There is no overhead per string allocated
+
+ This memory pool is used for all indefinite length strings that are
+ text strings or byte strings, including strings used as labels.
+
The pointers to strings in QCBORItem will point into the memory pool set
here. They do not need to be individually freed. Just discard the buffer
when they are no longer needed.
-
- If bAllStrings is set, then the size will be the overhead plus the space to
- hold **all** strings, definite and indefinite length, value or label. The
- advantage of this is that after the decode is complete, the original memory
- holding the encoded CBOR does not need to remain valid.
-
- If this function is not called because there is no need to support indefinite
- length strings, the MemPool implementation should be dead-stripped by the loader
- and not add to code size.
+
+ If bAllStrings is set, then the size will be the overhead plus the
+ space to hold **all** strings, definite and indefinite length, value
+ or label. The advantage of this is that after the decode is complete,
+ the original memory holding the encoded CBOR does not need to remain
+ valid.
+
+ If this function is never called because there is no need to support
+ indefinite length strings, the MemPool implementation should be
+ dead-stripped by the loader and not add to code size.
*/
QCBORError QCBORDecode_SetMemPool(QCBORDecodeContext *pCtx, UsefulBuf MemPool, bool bAllStrings);
/**
@brief Sets up a custom string allocator for indefinite length strings
-
+
@param[in] pCtx The decoder context to set up an allocator for
@param[in] pAllocator The string allocator "object"
-
+
See QCBORStringAllocator for the requirements of the string allocator.
-
+
Typically, this is used if the simple MemPool allocator isn't desired.
-
+
A malloc based string allocator can be obtained by calling
- QCBORDecode_MakeMallocStringAllocator(). Pass its result to
- this function.
-
+ QCBOR_DMalloc(). This function is supply separately from qcbor
+ to keep qcbor smaller and neater. It is in a separate
+ GitHub repository.
+
You can also write your own allocator. Create the allocate, free,
and destroy functions and put pointers to them in a QCBORStringAllocator.
*/
@@ -1680,45 +1713,25 @@
/**
@brief Configure list of caller selected tags to be recognized
-
+
@param[in] pCtx The decode context.
@param[out] pTagList Structure holding the list of tags to configure
-
+
This is used to tell the decoder about tags beyond those that are
built-in that should be recognized. The built-in tags are those
with macros of the form CBOR_TAG_XXX.
-
+
See description of QCBORTagListIn.
*/
void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pCtx, const QCBORTagListIn *pTagList);
/**
- @brief This returns a string allocator that uses malloc
-
- @return pointer to string allocator or NULL
-
- Call this to get the string allocator and then configure it into
- the decoder by calling QCBORDecode_SetUpAllocator(). If you
- don't call this, there will be no dependency on malloc
- in QCBOR. Some deployments of QCBOR might even exclude
- the implementation of this function if they don't have
- malloc() at all.
-
- If you do set up this malloc-based string allocator, then
- every string marked as allocated in a QCBORItem must
- freed. They are marked by uDataAlloc and uLabelAlloc
- in QCBORItem.
- */
-QCBORStringAllocator *QCBORDecode_MakeMallocStringAllocator(void);
-
-
-/**
@brief Gets the next item (integer, byte string, array...) in pre order traversal of CBOR tree
-
+
@param[in] pCtx The decoder context.
@param[out] pDecodedItem Holds the CBOR item just decoded.
-
+
@return 0 or error. All errors except QCBOR_ERR_TOO_MANY_TAGS
and QCBOR_ERR_STRING_ALLOCATE indicate that the CBOR input
could not be decoded. In most cases
@@ -1731,28 +1744,28 @@
QCBOR_ERR_MAP_LABEL_TYPE is in a way a limitation of
this implementation, but can be avoided by decoding
in QCBOR_DECODE_MODE_MAP_AS_ARRAY mode.
-
+
pDecodedItem is filled in with the value parsed. Generally, the
following data is returned in the structure.
-
+
- The data type in uDataType which indicates which member of the val
union the data is in. This decoder figures out the type based on the
CBOR major type, the CBOR "additionalInfo", the CBOR optional tags
and the value of the integer.
-
+
- The value of the item, which might be an integer, a pointer and a
length, the count of items in an array, a floating-point number or
other.
-
+
- The nesting level for maps and arrays.
-
+
- The label for an item in a map, which may be a text or byte string or an integer.
-
+
- The CBOR optional tag or tags.
-
+
See documentation on in the data type QCBORItem for all the details
on what is returned.
-
+
This function also handles arrays and maps. When first encountered a
QCBORItem will be returned with major type CBOR_MAJOR_TYPE_ARRAY or
CBOR_MAJOR_TYPE_ARRAY_MAP. QCBORItem.val.uCount will indicate the number
@@ -1761,25 +1774,25 @@
indefinite length maps and arrays, QCBORItem.val.uCount is UINT16_MAX
and uNextNestLevel must be used to know when the end of a map
or array is reached.
-
+
Nesting level 0 is the outside top-most nesting level. For example, in
a CBOR structure with two items, an integer and a byte string only,
both would be at nesting level 0. A CBOR structure with an array
open, an integer and a byte string, would have the integer and byte
string as nesting level 1.
-
+
Here is an example of how the nesting level is reported with no arrays
or maps at all
-
+
@verbatim
CBOR Structure Nesting Level
Integer 0
Byte String 0
@endverbatim
-
+
Here is an example of how the nesting level is reported with an a simple
array and some top-level items.
-
+
@verbatim
Integer 0
Array (with 2 items) 0
@@ -1787,11 +1800,11 @@
Byte string 1
Integer 0
@endverbatim
-
-
+
+
Here's a more complex example
@verbatim
-
+
Map with 2 items 0
Text string 1
Array with 3 integers 1
@@ -1801,7 +1814,7 @@
text string 1
byte string 1
@endverbatim
-
+
In QCBORItem, uNextNestLevel is the nesting level for the next call
to QCBORDecode_GetNext(). It indicates if any maps or arrays were closed
out during the processing of the just-fecthed QCBORItem. This processing
@@ -1810,7 +1823,7 @@
hierarchical structure. If uNextNestLevel is not equal to uNestLevel
the end of the current map or array has been encountered. This
works the same for both definite and indefinite length arrays.
-
+
Most uses of this decoder will not need to do anything extra for
tag handling. The built-in tags, those with a macro of the form
CBOR_TAG_XXXX, will be enough.
@@ -1818,14 +1831,14 @@
If tags beyond built-in tags are to be recognized, they must be
configured by calling QCBORDecode_SetCallerConfiguredTags(). If
a tag is not recognized it is silently ignored.
-
+
Several tagged types are automatically recognized and decoded and
returned in their decoded form.
-
+
To find out if a QCBORItem was tagged with a particular tag
call QCBORDecode_IsTagged(). This works only for built-in
tags and caller-configured tags.
-
+
To get the full list of tags on an Item without having to
pre-configure any predetermined list of tags use
QCBORDecode_GetNextWithTags().
@@ -1835,26 +1848,26 @@
/**
@brief Gets the next item including full list of tags for item
-
+
@param[in] pCtx The decoder context.
@param[out] pDecodedItem Holds the CBOR item just decoded.
@param[in,out] pTagList On input array to put tags in; on output the tags on this item.
-
+
@return 0 or error.
-
+
This works the same as QCBORDecode_GetNext() except that it also returns
the full list of tags for the data item. This function should only
be needed when parsing CBOR to print it out or convert it to some other
format. It should not be needed in an actual CBOR protocol implementation.
-
+
Tags will be returned here whether or not they are in the built-in or
caller-configured tag lists.
-
+
CBOR has no upper bound of limit on the number of tags that can be
associated with a data item. In practice the number of tags on an item
will usually be small, perhaps less than five. This will return an error
if the array in pTagList is too small to hold all the tags for an item.
-
+
(This function is separate from QCBORDecode_GetNext() so as to not have to
make QCBORItem large enough to be able to hold a full list of tags. Even a list of
five tags would nearly double its size because tags can be a uint64_t).
@@ -1864,30 +1877,30 @@
/**
@brief Determine if a CBOR item was tagged with a particular tag
-
+
@param[in] pCtx The decoder context.
@param[in] pItem The CBOR item to check
@param[in] uTag The tag to check
@return 1 if it was tagged, 0 if not
-
+
QCBORDecode_GetNext() processes tags by looking them up
in two lists and setting a bit corresponding to the tag
in uTagBits in the QCBORItem. To find out if a
QCBORItem was tagged with a particular tag, call
this function. It handles the mapping between
the two lists of tags and the bits set for it.
-
+
The first tag list is the built-in tags, those
with a macro of the form CBOR_TAG_XXX in this
header file. There are up to 48 of these,
corresponding to the lower 48 tag bits.
-
+
The other optional tag list is the ones
the caller configured using QCBORDecode_SetCallerConfiguredTagList()
There are QCBOR_MAX_CUSTOM_TAGS (16) of these corresponding to the
upper 16 tag bits.
-
+
See also QCBORDecode_GetTags() and QCBORDecode_GetNextWithTags().
*/
int QCBORDecode_IsTagged(QCBORDecodeContext *pCtx, const QCBORItem *pItem, uint64_t uTag);
@@ -1895,11 +1908,11 @@
/**
Check whether all the bytes have been decoded and maps and arrays closed.
-
+
@param[in] pCtx The context to check
-
+
@return QCBOR_SUCCESS or error
-
+
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
@@ -1912,40 +1925,40 @@
/**
Convert int64_t to smaller int's safely
-
+
@param [in] src An int64_t
@param [out] dest A smaller sized int to convert to
-
+
@return 0 on success -1 if not
-
+
When decoding an integer, the CBOR decoder will return the value as an
int64_t unless the integer is in the range of INT64_MAX and
UINT64_MAX. That is, unless the value is so large that it can only be
represented as a uint64_t, it will be an int64_t.
-
+
CBOR itself doesn't size the individual integers it carries at
all. The only limits it puts on the major integer types is that they
are 8 bytes or less in length. Then encoders like this one use the
smallest number of 1, 2, 4 or 8 bytes to represent the integer based
on its value. There is thus no notion that one data item in CBOR is
an 1 byte integer and another is a 4 byte integer.
-
+
The interface to this CBOR encoder only uses 64-bit integers. Some
CBOR protocols or implementations of CBOR protocols may not want to
work with something smaller than a 64-bit integer. Perhaps an array
of 1000 integers needs to be sent and none has a value larger than
50,000 and are represented as uint16_t.
-
+
The sending / encoding side is easy. Integers are temporarily widened
to 64-bits as a parameter passing through QCBOREncode_AddInt64() and
encoded in the smallest way possible for their value, possibly in
less than an uint16_t.
-
+
On the decoding side the integers will be returned at int64_t even if
they are small and were represented by only 1 or 2 bytes in the
encoded CBOR. The functions here will convert integers to a small
representation with an overflow check.
-
+
(The decoder could have support 8 different integer types and
represented the integer with the smallest type automatically, but
this would have made the decoder more complex and code calling the
@@ -2029,23 +2042,23 @@
/* ===========================================================================
BEGINNING OF PRIVATE INLINE IMPLEMENTATION
-
+
=========================================================================== */
/**
@brief Semi-private method to add a buffer full of bytes to encoded output
-
+
@param[in] pCtx The encoding context to add the integer to.
@param[in] uMajorType The CBOR major type of the bytes.
@param[in] Bytes The bytes to add.
-
+
Use QCBOREncode_AddText() or QCBOREncode_AddBytes() or
QCBOREncode_AddEncoded() instead. They are inline functions
that call this and supply the correct major type. This function
is public to make the inline functions work to keep the overall
code size down and because the C language has no way to make
it private.
-
+
If this is called the major type should be CBOR_MAJOR_TYPE_TEXT_STRING,
CBOR_MAJOR_TYPE_BYTE_STRING or CBOR_MAJOR_NONE_TYPE_RAW. The last
one is special for adding already-encoded CBOR.
@@ -2055,10 +2068,10 @@
/**
@brief Semi-private method to open a map, array or bstr wrapped CBOR
-
+
@param[in] pCtx The context to add to.
@param[in] uMajorType The major CBOR type to close
-
+
Call QCBOREncode_OpenArray(), QCBOREncode_OpenMap() or
QCBOREncode_BstrWrap() instead of this.
*/
@@ -2067,11 +2080,11 @@
/**
@brief Semi-private method to close a map, array or bstr wrapped CBOR
-
+
@param[in] pCtx The context to add to.
@param[in] uMajorType The major CBOR type to close
@param[out] pWrappedCBOR UsefulBufC containing wrapped bytes
-
+
Call QCBOREncode_CloseArray(), QCBOREncode_CloseMap() or
QCBOREncode_CloseBstrWrap() instead of this.
*/
@@ -2080,19 +2093,19 @@
/**
@brief Semi-private method to add simple types.
-
+
@param[in] pCtx The encoding context to add the simple value to.
@param[in] uSize Minimum encoding size for uNum. Usually 0.
@param[in] uNum One of CBOR_SIMPLEV_FALSE through _UNDEF or other.
-
+
This is used to add simple types like true and false.
-
+
Call QCBOREncode_AddBool(), QCBOREncode_AddNULL(), QCBOREncode_AddUndef()
instead of this.
-
+
This function can add simple values that are not defined by CBOR yet. This expansion
point in CBOR should not be used unless they are standardized.
-
+
Error handling is the same as QCBOREncode_AddInt64().
*/
void QCBOREncode_AddType7(QCBOREncodeContext *pCtx, size_t uSize, uint64_t uNum);
@@ -2567,7 +2580,7 @@
/* ===========================================================================
END OF PRIVATE INLINE IMPLEMENTATION
-
+
=========================================================================== */
#endif /* defined(__QCBOR__qcbor__) */
diff --git a/min_use_main.c b/min_use_main.c
index fd8328d..7d6f5d9 100644
--- a/min_use_main.c
+++ b/min_use_main.c
@@ -15,7 +15,7 @@
* The name "Laurence Lundblade" may not be used to
endorse or promote products derived from this software without
specific prior written permission.
-
+
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
@@ -40,50 +40,50 @@
that is good as an example and for
checking code size with all the
inlining and dead stripping on.
-
+
*/
int main(int argc, const char * argv[])
{
(void)argc; // Suppress unused warning
(void)argv; // Suppress unused warning
-
+
uint8_t pBuf[300];
// Very simple CBOR, a map with one boolean that is true in it
QCBOREncodeContext EC;
-
+
QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(pBuf));
-
+
QCBOREncode_OpenMap(&EC);
QCBOREncode_AddBoolToMapN(&EC, 66, true);
QCBOREncode_CloseMap(&EC);
-
+
UsefulBufC Encoded;
if(QCBOREncode_Finish(&EC, &Encoded)) {
return -1;
}
-
-
+
+
// Decode it and see that is right
QCBORDecodeContext DC;
QCBORItem Item;
QCBORDecode_Init(&DC, Encoded, QCBOR_DECODE_MODE_NORMAL);
-
+
QCBORDecode_GetNext(&DC, &Item);
if(Item.uDataType != QCBOR_TYPE_MAP) {
return -2;
}
-
+
QCBORDecode_GetNext(&DC, &Item);
if(Item.uDataType != QCBOR_TYPE_TRUE) {
return -3;
}
-
+
if(QCBORDecode_Finish(&DC)) {
return -4;
}
-
-
+
+
// Make another encoded message with the CBOR from the previous put into this one
UsefulBuf_MAKE_STACK_UB(MemoryForEncoded2, 20);
QCBOREncode_Init(&EC, MemoryForEncoded2);
@@ -94,7 +94,7 @@
QCBOREncode_AddEncodedToMapN(&EC, -70000, Encoded);
QCBOREncode_CloseMap(&EC);
QCBOREncode_CloseArray(&EC);
-
+
UsefulBufC Encoded2;
if(QCBOREncode_Finish(&EC, &Encoded2)) {
return -5;
@@ -111,9 +111,9 @@
}
}
]
-
-
-
+
+
+
83 # array(3)
19 01C3 # unsigned(451)
A1 # map(1)
@@ -125,55 +125,55 @@
18 42 # unsigned(66)
F5 # primitive(21)
*/
-
+
// Decode it and see if it is OK
QCBORDecode_Init(&DC, Encoded2, QCBOR_DECODE_MODE_NORMAL);
-
+
// 0 1:3
QCBORDecode_GetNext(&DC, &Item);
if(Item.uDataType != QCBOR_TYPE_ARRAY || Item.val.uCount != 3) {
return -6;
}
-
+
// 1 1:2
QCBORDecode_GetNext(&DC, &Item);
if(Item.uDataType != QCBOR_TYPE_INT64 || Item.val.uint64 != 451) {
return -7;
}
-
+
// 1 1:2 2:1
QCBORDecode_GetNext(&DC, &Item);
if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 1) {
return -8;
}
-
+
// 2 1:1
QCBORDecode_GetNext(&DC, &Item);
if(Item.uDataType != QCBOR_TYPE_TRUE) {
return -9;
}
-
+
// 1 1:1 2:1
QCBORDecode_GetNext(&DC, &Item);
if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 1) {
return -10;
}
-
+
// 2 1:1 2:1 3:1
QCBORDecode_GetNext(&DC, &Item);
if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 1 || Item.uLabelType != QCBOR_TYPE_INT64 || Item.label.int64 != -70000) {
return -11;
}
-
+
// 3 XXXXXX
QCBORDecode_GetNext(&DC, &Item);
if(Item.uDataType != QCBOR_TYPE_TRUE || Item.uLabelType != QCBOR_TYPE_INT64 || Item.label.int64 != 66) {
return -12;
}
-
+
if(QCBORDecode_Finish(&DC)) {
return -13;
}
-
+
return 0;
}
diff --git a/src/UsefulBuf.c b/src/UsefulBuf.c
index 8cb8c49..4213ab2 100644
--- a/src/UsefulBuf.c
+++ b/src/UsefulBuf.c
@@ -2,7 +2,7 @@
Copyright (c) 2016-2018, The Linux Foundation.
Copyright (c) 2018, Laurence Lundblade.
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
@@ -16,7 +16,7 @@
contributors, nor the name "Laurence Lundblade" may be used to
endorse or promote products derived from this software without
specific prior written permission.
-
+
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
@@ -32,17 +32,17 @@
/*===================================================================================
FILE: UsefulBuf.c
-
+
DESCRIPTION: General purpose input and output buffers
-
+
EDIT HISTORY FOR FILE:
-
+
This section contains comments describing changes made to the module.
Notice that changes are listed in reverse chronological order.
-
+
when who what, where, why
-------- ---- ---------------------------------------------------
- 09/07/17 llundbla Fix critical bug in UsefulBuf_Find() -- a read off
+ 09/07/17 llundbla Fix critical bug in UsefulBuf_Find() -- a read off
the end of memory when the bytes to find is longer
than the bytes to search.
06/27/17 llundbla Fix UsefulBuf_Compare() bug. Only affected comparison
@@ -50,7 +50,7 @@
UsefulBuf_Set() function.
05/30/17 llundbla Functions for NULL UsefulBufs and const / unconst
11/13/16 llundbla Initial Version.
-
+
=====================================================================================*/
#include "UsefulBuf.h"
@@ -67,10 +67,10 @@
if(uOffset > Dest.len || Src.len > Dest.len - uOffset) { // uOffset + Src.len > Dest.len
return NULLUsefulBufC;
}
-
+
memcpy((uint8_t *)Dest.ptr + uOffset, Src.ptr, Src.len);
-
- return((UsefulBufC){Dest.ptr, Src.len + uOffset});
+
+ return (UsefulBufC){Dest.ptr, Src.len + uOffset};
}
@@ -86,7 +86,7 @@
} else if (UB1.len > UB2.len) {
return 1;
} // else UB1.len == UB2.len
-
+
return memcmp(UB1.ptr, UB2.ptr, UB1.len);
}
@@ -100,20 +100,20 @@
if(BytesToSearch.len < BytesToFind.len) {
return SIZE_MAX;
}
-
+
for(size_t uPos = 0; uPos <= BytesToSearch.len - BytesToFind.len; uPos++) {
if(!UsefulBuf_Compare((UsefulBufC){((uint8_t *)BytesToSearch.ptr) + uPos, BytesToFind.len}, BytesToFind)) {
return uPos;
}
}
-
+
return SIZE_MAX;
}
/*
Public function -- see UsefulBuf.h
-
+
Code Reviewers: THIS FUNCTION DOES POINTER MATH
*/
void UsefulOutBuf_Init(UsefulOutBuf *me, UsefulBuf Storage)
@@ -121,10 +121,10 @@
me->magic = USEFUL_OUT_BUF_MAGIC;
UsefulOutBuf_Reset(me);
me->UB = Storage;
-
+
#if 0
// This check is off by default.
-
+
// The following check fails on ThreadX
// Sanity check on the pointer and size to be sure we are not
@@ -142,37 +142,37 @@
/*
Public function -- see UsefulBuf.h
-
+
The core of UsefulOutBuf -- put some bytes in the buffer without writing off the end of it.
-
+
Code Reviewers: THIS FUNCTION DOES POINTER MATH
-
+
This function inserts the source buffer, NewData, into the destination buffer, me->UB.ptr.
-
+
Destination is represented as:
me->UB.ptr -- start of the buffer
me->UB.len -- size of the buffer UB.ptr
me->data_len -- length of value data in UB
-
+
Source is data:
NewData.ptr -- start of source buffer
NewData.len -- length of source buffer
-
+
Insertion point:
uInsertionPos.
-
+
Steps:
-
+
0. Corruption checks on UsefulOutBuf
-
+
1. Figure out if the new data will fit or not
-
+
2. Is insertion position in the range of valid data?
-
+
3. If insertion point is not at the end, slide data to the right of the insertion point to the right
-
+
4. Put the new data in at the insertion position.
-
+
*/
void UsefulOutBuf_InsertUsefulBuf(UsefulOutBuf *me, UsefulBufC NewData, size_t uInsertionPos)
{
@@ -180,7 +180,7 @@
// Already in error state.
return;
}
-
+
/* 0. Sanity check the UsefulOutBuf structure */
// A "counter measure". If magic number is not the right number it
// probably means me was not initialized or it was corrupted. Attackers
@@ -198,7 +198,7 @@
me->err = 1;
return; // Offset of valid data is off the end of the UsefulOutBuf due to uninitialization or corruption
}
-
+
/* 1. Will it fit? */
// WillItFit() is the same as: NewData.len <= (me->size - me->data_len)
// Check #1 makes sure subtraction in RoomLeft will not wrap around
@@ -207,7 +207,7 @@
me->err = 1;
return;
}
-
+
/* 2. Check the Insertion Position */
// This, with Check #1, also confirms that uInsertionPos <= me->size
if(uInsertionPos > me->data_len) { // Check #3
@@ -215,17 +215,17 @@
me->err = 1;
return;
}
-
+
/* 3. Slide existing data to the right */
uint8_t *pSourceOfMove = ((uint8_t *)me->UB.ptr) + uInsertionPos; // PtrMath #1
size_t uNumBytesToMove = me->data_len - uInsertionPos; // PtrMath #2
uint8_t *pDestinationOfMove = pSourceOfMove + NewData.len; // PtrMath #3
size_t uRoomInDestination = me->UB.len - (uInsertionPos + NewData.len); // PtrMath #4
-
+
if(uNumBytesToMove && me->UB.ptr) {
memmove(pDestinationOfMove, pSourceOfMove, uNumBytesToMove);
}
-
+
/* 4. Put the new data in */
uint8_t *pInsertionPoint = ((uint8_t *)me->UB.ptr) + uInsertionPos; // PtrMath #5
uRoomInDestination = me->UB.len - uInsertionPos; // PtrMath #6
@@ -238,25 +238,25 @@
/*
Rationale that describes why the above pointer math is safe
-
+
PtrMath #1 will never wrap around over because
Check #0 in UsefulOutBuf_Init makes sure me-UB.ptr + me->size doesn't wrap
Check #1 makes sure me->data_len is less than me->UB.len
Check #3 makes sure uInsertionPos is less than me->data_len
-
+
PtrMath #2 will never wrap around under because
Check #3 makes sure uInsertionPos is less than me->data_len
-
+
PtrMath #3 will never wrap around over because todo
PtrMath #1 is checked resulting in pStartOfDataToMove being between me->UB.ptr and a maximum valid ptr
-
+
PtrMath #4 will never wrap under because
Check #3 makes sure uInsertionPos is less than me->data_len
Check #3 allows Check #2 to be refactored as NewData.Len > (me->size - uInsertionPos)
This algebraically rearranges to me->size > uInsertionPos + NewData.len
-
+
PtrMath #5 is exactly the same as PtrMath #1
-
+
PtrMath #6 will never wrap under because
Check #1 makes sure me->data_len is less than me->size
Check #3 makes sure uInsertionPos is less than me->data_len
@@ -264,31 +264,31 @@
/*
- Public function -- see UsefulBuf.h
+ Public function -- see UsefulBuf.h
*/
UsefulBufC UsefulOutBuf_OutUBuf(UsefulOutBuf *me)
{
if(me->err) {
return NULLUsefulBufC;
}
-
+
if(me->magic != USEFUL_OUT_BUF_MAGIC) {
me->err = 1;
return NULLUsefulBufC;
}
-
- return(UsefulBufC){me->UB.ptr,me->data_len};
+
+ return (UsefulBufC){me->UB.ptr,me->data_len};
}
/*
Public function -- see UsefulBuf.h
-
+
Copy out the data accumulated in to the output buffer.
*/
UsefulBufC UsefulOutBuf_CopyOut(UsefulOutBuf *me, UsefulBuf pDest)
{
- UsefulBufC Tmp = UsefulOutBuf_OutUBuf(me);
+ const UsefulBufC Tmp = UsefulOutBuf_OutUBuf(me);
if(UsefulBuf_IsNULLC(Tmp)) {
return NULLUsefulBufC;
}
@@ -302,7 +302,7 @@
Public function -- see UsefulBuf.h
The core of UsefulInputBuf -- consume some bytes without going off the end of the buffer.
-
+
Code Reviewers: THIS FUNCTION DOES POINTER MATH
*/
const void * UsefulInputBuf_GetBytes(UsefulInputBuf *me, size_t uAmount)
@@ -311,13 +311,13 @@
if(me->err) {
return NULL;
}
-
+
if(!UsefulInputBuf_BytesAvailable(me, uAmount)) {
// The number of bytes asked for at current position are more than available
me->err = 1;
return NULL;
}
-
+
// This is going to succeed
const void * const result = ((uint8_t *)me->UB.ptr) + me->cursor;
me->cursor += uAmount; // this will not overflow because of check using UsefulInputBuf_BytesAvailable()
diff --git a/src/ieee754.c b/src/ieee754.c
index 40d5739..c52f6eb 100644
--- a/src/ieee754.c
+++ b/src/ieee754.c
@@ -1,8 +1,8 @@
/*==============================================================================
-
+
Copyright (c) 2018, Laurence Lundblade.
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
@@ -15,7 +15,7 @@
* The name "Laurence Lundblade" may not be used to
endorse or promote products derived from this software without
specific prior written permission.
-
+
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
@@ -46,14 +46,14 @@
that the optimizer will do a good job. The LLVM optimizer, -Os, does seem to do the
job and the resulting object code is smaller from combining code for the many different
cases (normal, subnormal, infinity, zero...) for the conversions.
-
+
Dead stripping is also really helpful to get code size down when floating point
encoding is not needed.
-
+
This code works solely using shifts and masks and thus has no dependency on
any math libraries. It can even work if the CPU doesn't have any floating
point support, though that isn't the most useful thing to do.
-
+
The memcpy() dependency is only for CopyFloatToUint32() and friends which only
is needed to avoid type punning when converting the actual float bits to
an unsigned value so the bit shifts and masks can work.
@@ -61,11 +61,11 @@
/*
The references used to write this code:
-
+
- IEEE 754-2008, particularly section 3.6 and 6.2.1
-
+
- https://en.wikipedia.org/wiki/IEEE_754 and subordinate pages
-
+
- https://stackoverflow.com/questions/19800415/why-does-ieee-754-reserve-so-many-nan-values
*/
@@ -155,7 +155,7 @@
Convenient functions to avoid type punning, compiler warnings and such
The optimizer reduces them to a simple assignment.
This is a crusty corner of C. It shouldn't be this hard.
-
+
These are also in UsefulBuf.h under a different name. They are copied
here to avoid a dependency on UsefulBuf.h. There is no
object code size impact because these always optimze down to a
@@ -198,8 +198,8 @@
const int32_t nSingleUnbiasedExponent = ((uSingle & SINGLE_EXPONENT_MASK) >> SINGLE_EXPONENT_SHIFT) - SINGLE_EXPONENT_BIAS;
const uint32_t uSingleSign = (uSingle & SINGLE_SIGN_MASK) >> SINGLE_SIGN_SHIFT;
const uint32_t uSingleSignificand = uSingle & SINGLE_SIGNIFICAND_MASK;
-
-
+
+
// Now convert the three parts to half-precision.
uint16_t uHalfSign, uHalfSignificand, uHalfBiasedExponent;
if(nSingleUnbiasedExponent == SINGLE_EXPONENT_INF_OR_NAN) {
@@ -265,7 +265,7 @@
const uint64_t uDoubleSign = (uDouble & DOUBLE_SIGN_MASK) >> DOUBLE_SIGN_SHIFT;
const uint64_t uDoubleSignificand = uDouble & DOUBLE_SIGNIFICAND_MASK;
-
+
// Now convert the three parts to half-precision.
uint16_t uHalfSign, uHalfSignificand, uHalfBiasedExponent;
if(nDoubleUnbiasedExponent == DOUBLE_EXPONENT_INF_OR_NAN) {
@@ -305,7 +305,7 @@
// Also have to shift the significand by the difference in number of bits between a double and a half significand
const int64_t nSignificandBitsDiff = DOUBLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS;
// Add in the 1 that is implied in the significand of a normal number; it needs to be present in a subnormal
- const uint64_t uDoubleSignificandSubnormal = uDoubleSignificand + (0x01L << DOUBLE_NUM_SIGNIFICAND_BITS);
+ const uint64_t uDoubleSignificandSubnormal = uDoubleSignificand + (0x01ULL << DOUBLE_NUM_SIGNIFICAND_BITS);
uHalfSignificand = uDoubleSignificandSubnormal >> (nExpDiff + nSignificandBitsDiff);
} else {
// The normal case
@@ -313,8 +313,8 @@
uHalfSignificand = uDoubleSignificand >> (DOUBLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS);
}
uHalfSign = uDoubleSign;
-
-
+
+
// Put the 3 values in the right place for a half precision
const uint16_t uHalfPrecision = uHalfSignificand |
(uHalfBiasedExponent << HALF_EXPONENT_SHIFT) |
@@ -330,8 +330,8 @@
const uint16_t uHalfSignificand = uHalfPrecision & HALF_SIGNIFICAND_MASK;
const int16_t nHalfUnBiasedExponent = ((uHalfPrecision & HALF_EXPONENT_MASK) >> HALF_EXPONENT_SHIFT) - HALF_EXPONENT_BIAS;
const uint16_t uHalfSign = (uHalfPrecision & HALF_SIGN_MASK) >> HALF_SIGN_SHIFT;
-
-
+
+
// Make the three parts of the single-precision number
uint32_t uSingleSignificand, uSingleSign, uSingleBiasedExponent;
if(nHalfUnBiasedExponent == HALF_EXPONENT_ZERO) {
@@ -374,13 +374,13 @@
uSingleSignificand = uHalfSignificand << (SINGLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS);
}
uSingleSign = uHalfSign;
-
-
+
+
// Shift the three parts of the single precision into place
const uint32_t uSinglePrecision = uSingleSignificand |
(uSingleBiasedExponent << SINGLE_EXPONENT_SHIFT) |
(uSingleSign << SINGLE_SIGN_SHIFT);
-
+
return CopyUint32ToFloat(uSinglePrecision);
}
@@ -392,8 +392,8 @@
const uint16_t uHalfSignificand = uHalfPrecision & HALF_SIGNIFICAND_MASK;
const int16_t nHalfUnBiasedExponent = ((uHalfPrecision & HALF_EXPONENT_MASK) >> HALF_EXPONENT_SHIFT) - HALF_EXPONENT_BIAS;
const uint16_t uHalfSign = (uHalfPrecision & HALF_SIGN_MASK) >> HALF_SIGN_SHIFT;
-
-
+
+
// Make the three parts of hte single-precision number
uint64_t uDoubleSignificand, uDoubleSign, uDoubleBiasedExponent;
if(nHalfUnBiasedExponent == HALF_EXPONENT_ZERO) {
@@ -436,8 +436,8 @@
uDoubleSignificand = (uint64_t)uHalfSignificand << (DOUBLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS);
}
uDoubleSign = uHalfSign;
-
-
+
+
// Shift the 3 parts into place as a double-precision
const uint64_t uDouble = uDoubleSignificand |
(uDoubleBiasedExponent << DOUBLE_EXPONENT_SHIFT) |
@@ -450,12 +450,12 @@
IEEE754_union IEEE754_FloatToSmallest(float f)
{
IEEE754_union result;
-
+
// Pull the neeed two parts out of the single-precision float
const uint32_t uSingle = CopyFloatToUint32(f);
const int32_t nSingleExponent = ((uSingle & SINGLE_EXPONENT_MASK) >> SINGLE_EXPONENT_SHIFT) - SINGLE_EXPONENT_BIAS;
const uint32_t uSingleSignificand = uSingle & SINGLE_SIGNIFICAND_MASK;
-
+
// Bit mask that is the significand bits that would be lost when converting
// from single-precision to half-precision
const uint64_t uDroppedSingleBits = SINGLE_SIGNIFICAND_MASK >> HALF_NUM_SIGNIFICAND_BITS;
@@ -478,7 +478,7 @@
result.uSize = IEEE754_UNION_IS_SINGLE;
result.uValue = uSingle;
}
-
+
return result;
}
@@ -486,16 +486,16 @@
IEEE754_union IEEE754_DoubleToSmallestInternal(double d, int bAllowHalfPrecision)
{
IEEE754_union result;
-
+
// Pull the needed two parts out of the double-precision float
const uint64_t uDouble = CopyDoubleToUint64(d);
const int64_t nDoubleExponent = ((uDouble & DOUBLE_EXPONENT_MASK) >> DOUBLE_EXPONENT_SHIFT) - DOUBLE_EXPONENT_BIAS;
const uint64_t uDoubleSignificand = uDouble & DOUBLE_SIGNIFICAND_MASK;
-
+
// Masks to check whether dropped significand bits are zero or not
const uint64_t uDroppedDoubleBits = DOUBLE_SIGNIFICAND_MASK >> HALF_NUM_SIGNIFICAND_BITS;
const uint64_t uDroppedSingleBits = DOUBLE_SIGNIFICAND_MASK >> SINGLE_NUM_SIGNIFICAND_BITS;
-
+
// The various cases
if(d == 0.0) { // Take care of positive and negative zero
// Value is 0.0000, not a a subnormal
@@ -518,7 +518,7 @@
result.uSize = IEEE754_UNION_IS_DOUBLE;
result.uValue = uDouble;
}
-
+
return result;
}
diff --git a/src/ieee754.h b/src/ieee754.h
index e6570c8..fc94646 100644
--- a/src/ieee754.h
+++ b/src/ieee754.h
@@ -1,5 +1,5 @@
/*==============================================================================
-
+
Copyright (c) 2018, Laurence Lundblade.
All rights reserved.
@@ -15,7 +15,7 @@
* The name "Laurence Lundblade" may not be used to
endorse or promote products derived from this software without
specific prior written permission.
-
+
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
@@ -45,25 +45,25 @@
/*
General comments
-
+
This is a complete in that it handles all conversion cases
including +/- infinity, +/- zero, subnormal numbers, qNaN, sNaN
and NaN payloads.
-
+
This confirms to IEEE 754-2008, but note that this doesn't
specify conversions, just the encodings.
-
+
NaN payloads are preserved with alignment on the LSB. The
qNaN bit is handled differently and explicity copied. It
is always the MSB of the significand. The NaN payload MSBs
(except the qNaN bit) are truncated when going from
double or single to half.
-
+
TODO: what does the C cast do with NaN payloads from
double to single?
-
-
-
+
+
+
*/
/*
@@ -72,26 +72,26 @@
these types and so does qcbor. This encoder also supports
half precision and there's a few ways to use it to encode
floating point numbers in less space.
-
+
Without losing precision, you can encode a single or double
such that the special values of 0, NaN and Infinity encode
as half-precision. This CBOR decodoer and most others
should handle this properly.
-
+
If you don't mind losing precision, then you can use half-precision.
One way to do this is to set up your environment to use
___fp_16. Some compilers and CPUs support it even though it is not
standard C. What is nice about this is that your program
will use less memory and floating point operations like
multiplying, adding and such will be faster.
-
+
Another way to make use of half-precision is to represent
the values in your program as single or double, but encode
them in CBOR as half-precision. This cuts the size
of the encoded messages by 2 or 4, but doesn't reduce
memory needs or speed because you are still using
single or double in your code.
-
+
encode:
- float as float
@@ -101,10 +101,10 @@
- double as half_precision, for environments that don't support a half-precision type
- float with NaN, Infinity and 0 as half
- double with NaN, Infinity and 0 as half
-
-
-
-
+
+
+
+
*/
diff --git a/src/qcbor_decode.c b/src/qcbor_decode.c
index 8eaeb43..8a1df27 100644
--- a/src/qcbor_decode.c
+++ b/src/qcbor_decode.c
@@ -2,7 +2,7 @@
Copyright (c) 2016-2018, The Linux Foundation.
Copyright (c) 2018, Laurence Lundblade.
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
@@ -16,7 +16,7 @@
contributors, nor the name "Laurence Lundblade" may be used to
endorse or promote products derived from this software without
specific prior written permission.
-
+
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
@@ -32,14 +32,14 @@
/*===================================================================================
FILE: qcbor_decode.c
-
+
DESCRIPTION: This file contains the implementation of QCBOR.
-
+
EDIT HISTORY FOR FILE:
-
+
This section contains comments describing changes made to the module.
Notice that changes are listed in reverse chronological order.
-
+
when who what, where, why
-------- ---- ---------------------------------------------------
11/9/18 llundblade Error codes are now enums.
@@ -55,7 +55,7 @@
11/13/16 llundbla Integrate most TZ changes back into github version.
09/30/16 gkanike Porting to TZ.
03/15/16 llundbla Initial Version.
-
+
=====================================================================================*/
#include "qcbor.h"
@@ -98,7 +98,7 @@
if(!DecodeNesting_IsNested(pNesting)) {
return 0;
}
-
+
return CBOR_MAJOR_TYPE_MAP == pNesting->pCurrent->uMajorType;
}
@@ -109,15 +109,15 @@
if(!DecodeNesting_IsNested(pNesting)) {
return QCBOR_ERR_BAD_BREAK;
}
-
+
// breaks can only occur when the map/array is indefinite length
if(!DecodeNesting_IsIndefiniteLength(pNesting)) {
return QCBOR_ERR_BAD_BREAK;
}
-
+
// if all OK, the break reduces the level of nesting
pNesting->pCurrent--;
-
+
return QCBOR_SUCCESS;
}
@@ -128,12 +128,12 @@
// at top level where there is no tracking
return;
}
-
+
if(DecodeNesting_IsIndefiniteLength(pNesting)) {
// There is no count for indefinite length arrays/maps
return;
}
-
+
// Decrement the count of items in this array/map
pNesting->pCurrent->uCount--;
@@ -150,33 +150,33 @@
inline static QCBORError DecodeNesting_Descend(QCBORDecodeNesting *pNesting, QCBORItem *pItem)
{
QCBORError nReturn = QCBOR_SUCCESS;
-
+
if(pItem->val.uCount == 0) {
// Nothing to do for empty definite lenth arrays. They are just are
// effectively the same as an item that is not a map or array
goto Done;
// Empty indefinite length maps and arrays are handled elsewhere
}
-
+
// Error out if arrays is too long to handle
if(pItem->val.uCount != UINT16_MAX && pItem->val.uCount > QCBOR_MAX_ITEMS_IN_ARRAY) {
nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
goto Done;
}
-
+
// Error out if nesting is too deep
if(pNesting->pCurrent >= &(pNesting->pMapsAndArrays[QCBOR_MAX_ARRAY_NESTING])) {
nReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
goto Done;
}
-
+
// The actual descend
pNesting->pCurrent++;
-
+
// Record a few details for this nesting level
pNesting->pCurrent->uMajorType = pItem->uDataType;
pNesting->pCurrent->uCount = pItem->val.uCount;
-
+
Done:
return nReturn;;
}
@@ -250,12 +250,12 @@
// as all the values are known at compile time.
return -1;
}
-
+
if(uTag > UINT16_MAX) {
// This tag map works only on 16-bit tags
return -1;
}
-
+
for(int nTagBitIndex = 0; nTagBitIndex < (int)(sizeof(spBuiltInTagMap)/sizeof(uint16_t)); nTagBitIndex++) {
if(spBuiltInTagMap[nTagBitIndex] == uTag) {
return nTagBitIndex;
@@ -271,15 +271,15 @@
return nTagBitIndex + TAG_MAPPER_CUSTOM_TAGS_BASE_INDEX;
}
}
-
+
return -1; // Indicates no match
}
/*
Find the tag bit index for a given tag value, or error out
-
+
This and the above functions could probably be optimized and made
- clearer and neater.
+ clearer and neater.
*/
static QCBORError TagMapper_Lookup(const QCBORTagListIn *pCallerConfiguredTagMap, uint64_t uTag, uint8_t *puTagBitIndex)
{
@@ -289,7 +289,7 @@
*puTagBitIndex = (uint8_t)nTagBitIndex;
return QCBOR_SUCCESS;
}
-
+
if(pCallerConfiguredTagMap) {
if(pCallerConfiguredTagMap->uNumTags > QCBOR_MAX_CUSTOM_TAGS) {
return QCBOR_ERR_TOO_MANY_TAGS;
@@ -302,7 +302,7 @@
return QCBOR_SUCCESS;
}
}
-
+
return QCBOR_ERR_BAD_OPT_TAG;
}
@@ -312,7 +312,7 @@
/*
Public function, see header file
*/
-void QCBORDecode_Init(QCBORDecodeContext *me, UsefulBufC EncodedCBOR, int8_t nDecodeMode)
+void QCBORDecode_Init(QCBORDecodeContext *me, UsefulBufC EncodedCBOR, QCBORDecodeMode nDecodeMode)
{
memset(me, 0, sizeof(QCBORDecodeContext));
UsefulInputBuf_Init(&(me->InBuf), EncodedCBOR);
@@ -340,52 +340,52 @@
/*
This decodes the fundamental part of a CBOR data item, the type and number
-
+
This is the Counterpart to InsertEncodedTypeAndNumber().
-
+
This does the network->host byte order conversion. The conversion here
also results in the conversion for floats in addition to that for
lengths, tags and integer values.
-
+
This returns:
pnMajorType -- the major type for the item
puNumber -- the "number" which is used a the value for integers, tags and floats and length for strings and arrays
puAdditionalInfo -- Pass this along to know what kind of float or if length is indefinite
-
+
*/
inline static QCBORError DecodeTypeAndNumber(UsefulInputBuf *pUInBuf, int *pnMajorType, uint64_t *puNumber, uint8_t *puAdditionalInfo)
{
// Stack usage: int/ptr 5 -- 40
QCBORError nReturn;
-
+
// Get the initial byte that every CBOR data item has
const uint8_t InitialByte = UsefulInputBuf_GetByte(pUInBuf);
-
+
// Break down the initial byte
const uint8_t uTmpMajorType = InitialByte >> 5;
const uint8_t uAdditionalInfo = InitialByte & 0x1f;
-
+
// Get the integer that follows the major type. Do not know if this is a length, value, float or tag at this point
// Also convert from network byte order.
uint64_t uTmpValue;
switch(uAdditionalInfo) {
-
+
case LEN_IS_ONE_BYTE:
uTmpValue = UsefulInputBuf_GetByte(pUInBuf);
break;
-
+
case LEN_IS_TWO_BYTES:
uTmpValue = UsefulInputBuf_GetUint16(pUInBuf);
break;
-
+
case LEN_IS_FOUR_BYTES:
uTmpValue = UsefulInputBuf_GetUint32(pUInBuf);
break;
-
+
case LEN_IS_EIGHT_BYTES:
uTmpValue = UsefulInputBuf_GetUint64(pUInBuf);
break;
-
+
case ADDINFO_RESERVED1: // reserved by CBOR spec
case ADDINFO_RESERVED2: // reserved by CBOR spec
case ADDINFO_RESERVED3: // reserved by CBOR spec
@@ -397,22 +397,22 @@
uTmpValue = uAdditionalInfo;
break;
}
-
+
// If any of the UsefulInputBuf_Get calls fail we will get here with uTmpValue as 0.
// There is no harm in this. This following check takes care of catching all of
- // these errors.
-
+ // these errors.
+
if(UsefulInputBuf_GetError(pUInBuf)) {
nReturn = QCBOR_ERR_HIT_END;
goto Done;
}
-
+
// All successful if we got here.
nReturn = QCBOR_SUCCESS;
*pnMajorType = uTmpMajorType;
*puNumber = uTmpValue;
*puAdditionalInfo = uAdditionalInfo;
-
+
Done:
return nReturn;
}
@@ -427,7 +427,7 @@
more away from zero than positive.
Stdint, as far as I can tell, uses two's compliment to represent
negative integers.
-
+
See http://www.unix.org/whitepapers/64bit.html for reasons int isn't
used here in any way including in the interface
*/
@@ -435,29 +435,29 @@
{
// Stack usage: int/ptr 1 -- 8
QCBORError nReturn = QCBOR_SUCCESS;
-
+
if(nMajorType == CBOR_MAJOR_TYPE_POSITIVE_INT) {
if (uNumber <= INT64_MAX) {
pDecodedItem->val.int64 = (int64_t)uNumber;
pDecodedItem->uDataType = QCBOR_TYPE_INT64;
-
+
} else {
pDecodedItem->val.uint64 = uNumber;
pDecodedItem->uDataType = QCBOR_TYPE_UINT64;
-
+
}
} else {
if(uNumber <= INT64_MAX) {
pDecodedItem->val.int64 = -uNumber-1;
pDecodedItem->uDataType = QCBOR_TYPE_INT64;
-
+
} else {
// C can't represent a negative integer in this range
// so it is an error. todo -- test this condition
nReturn = QCBOR_ERR_INT_OVERFLOW;
}
}
-
+
return nReturn;
}
@@ -498,18 +498,18 @@
{
// Stack usage: 0
QCBORError nReturn = QCBOR_SUCCESS;
-
+
// uAdditionalInfo is 5 bits from the initial byte
// compile time checks above make sure uAdditionalInfo values line up with uDataType values
pDecodedItem->uDataType = uAdditionalInfo;
-
+
switch(uAdditionalInfo) {
case ADDINFO_RESERVED1: // 28
case ADDINFO_RESERVED2: // 29
case ADDINFO_RESERVED3: // 30
nReturn = QCBOR_ERR_UNSUPPORTED;
break;
-
+
case HALF_PREC_FLOAT:
pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uNumber);
pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
@@ -522,14 +522,14 @@
pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uNumber);
pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
break;
-
+
case CBOR_SIMPLEV_FALSE: // 20
case CBOR_SIMPLEV_TRUE: // 21
case CBOR_SIMPLEV_NULL: // 22
case CBOR_SIMPLEV_UNDEF: // 23
case CBOR_SIMPLE_BREAK: // 31
break; // nothing to do
-
+
case CBOR_SIMPLEV_ONEBYTE: // 24
if(uNumber <= CBOR_SIMPLE_BREAK) {
// This takes out f8 00 ... f8 1f which should be encoded as e0 … f7
@@ -537,7 +537,7 @@
goto Done;
}
// fall through intentionally
-
+
default: // 0-19
pDecodedItem->uDataType = QCBOR_TYPE_UKNOWN_SIMPLE;
// DecodeTypeAndNumber will make uNumber equal to uAdditionalInfo when uAdditionalInfo is < 24
@@ -545,7 +545,7 @@
pDecodedItem->val.uSimple = (uint8_t)uNumber;
break;
}
-
+
Done:
return nReturn;
}
@@ -559,8 +559,8 @@
{
// Stack usage: UsefulBuf 2, int/ptr 1 40
QCBORError nReturn = QCBOR_SUCCESS;
-
- UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(pUInBuf, uStrLen);
+
+ const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(pUInBuf, uStrLen);
if(UsefulBuf_IsNULLC(Bytes)) {
// Failed to get the bytes for this string item
nReturn = QCBOR_ERR_HIT_END;
@@ -580,7 +580,7 @@
pDecodedItem->val.string = Bytes;
}
pDecodedItem->uDataType = (nMajorType == CBOR_MAJOR_TYPE_BYTE_STRING) ? QCBOR_TYPE_BYTE_STRING : QCBOR_TYPE_TEXT_STRING;
-
+
Done:
return nReturn;
}
@@ -595,8 +595,8 @@
if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
return QCBOR_ERR_BAD_OPT_TAG;
}
-
- UsefulBufC Temp = pDecodedItem->val.string;
+
+ const UsefulBufC Temp = pDecodedItem->val.string;
pDecodedItem->val.dateString = Temp;
pDecodedItem->uDataType = QCBOR_TYPE_DATE_STRING;
return QCBOR_SUCCESS;
@@ -612,7 +612,7 @@
if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
return QCBOR_ERR_BAD_OPT_TAG;
}
- UsefulBufC Temp = pDecodedItem->val.string;
+ const UsefulBufC Temp = pDecodedItem->val.string;
pDecodedItem->val.bigNum = Temp;
pDecodedItem->uDataType = pDecodedItem->uTagBits & QCBOR_TAGFLAG_POS_BIGNUM ? QCBOR_TYPE_POSBIGNUM : QCBOR_TYPE_NEGBIGNUM;
return QCBOR_SUCCESS;
@@ -626,15 +626,15 @@
{
// Stack usage: 1
QCBORError nReturn = QCBOR_SUCCESS;
-
+
pDecodedItem->val.epochDate.fSecondsFraction = 0;
-
+
switch (pDecodedItem->uDataType) {
-
+
case QCBOR_TYPE_INT64:
pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.int64;
break;
-
+
case QCBOR_TYPE_UINT64:
if(pDecodedItem->val.uint64 > INT64_MAX) {
nReturn = QCBOR_ERR_DATE_OVERFLOW;
@@ -642,7 +642,7 @@
}
pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.uint64;
break;
-
+
case QCBOR_TYPE_DOUBLE:
{
const double d = pDecodedItem->val.dfnum;
@@ -654,13 +654,13 @@
pDecodedItem->val.epochDate.fSecondsFraction = d - pDecodedItem->val.epochDate.nSeconds;
}
break;
-
+
default:
nReturn = QCBOR_ERR_BAD_OPT_TAG;
goto Done;
}
pDecodedItem->uDataType = QCBOR_TYPE_DATE_EPOCH;
-
+
Done:
return nReturn;
}
@@ -680,7 +680,7 @@
This gets a single data item and decodes it including preceding optional tagging. This does not
deal with arrays and maps and nesting except to decode the data item introducing them. Arrays and
maps are handled at the next level up in GetNext().
-
+
Errors detected here include: an array that is too long to decode, hit end of buffer unexpectedly,
a few forms of invalid encoded CBOR
*/
@@ -688,22 +688,22 @@
{
// Stack usage: int/ptr 3 -- 24
QCBORError nReturn;
-
+
// Get the major type and the number. Number could be length of more bytes or the value depending on the major type
// nAdditionalInfo is an encoding of the length of the uNumber and is needed to decode floats and doubles
int uMajorType;
uint64_t uNumber;
uint8_t uAdditionalInfo;
-
+
nReturn = DecodeTypeAndNumber(pUInBuf, &uMajorType, &uNumber, &uAdditionalInfo);
-
+
// Error out here if we got into trouble on the type and number.
// The code after this will not work if the type and number is not good.
if(nReturn)
goto Done;
-
+
memset(pDecodedItem, 0, sizeof(QCBORItem));
-
+
// At this point the major type and the value are valid. We've got the type and the number that
// starts every CBOR data item.
switch (uMajorType) {
@@ -711,7 +711,7 @@
case CBOR_MAJOR_TYPE_NEGATIVE_INT: // Major type 1
nReturn = DecodeInteger(uMajorType, uNumber, pDecodedItem);
break;
-
+
case CBOR_MAJOR_TYPE_BYTE_STRING: // Major type 2
case CBOR_MAJOR_TYPE_TEXT_STRING: // Major type 3
if(uAdditionalInfo == LEN_IS_INDEFINITE) {
@@ -721,7 +721,7 @@
nReturn = DecodeBytes(pAlloc, uMajorType, uNumber, pUInBuf, pDecodedItem);
}
break;
-
+
case CBOR_MAJOR_TYPE_ARRAY: // Major type 4
case CBOR_MAJOR_TYPE_MAP: // Major type 5
// Record the number of items in the array or map
@@ -736,21 +736,21 @@
}
pDecodedItem->uDataType = uMajorType; // C preproc #if above makes sure constants align
break;
-
+
case CBOR_MAJOR_TYPE_OPTIONAL: // Major type 6, optional prepended tags
pDecodedItem->val.uTagV = uNumber;
pDecodedItem->uDataType = QCBOR_TYPE_OPTTAG;
break;
-
+
case CBOR_MAJOR_TYPE_SIMPLE: // Major type 7, float, double, true, false, null...
nReturn = DecodeSimple(uAdditionalInfo, uNumber, pDecodedItem);
break;
-
+
default: // Should never happen because DecodeTypeAndNumber() should never return > 7
nReturn = QCBOR_ERR_UNSUPPORTED;
break;
}
-
+
Done:
return nReturn;
}
@@ -761,7 +761,7 @@
This layer deals with indefinite length strings. It pulls all the
individual chunk items together into one QCBORItem using the
string allocator.
-
+
Code Reviewers: THIS FUNCTION DOES A LITTLE POINTER MATH
*/
static inline QCBORError GetNext_FullItem(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
@@ -770,36 +770,36 @@
QCBORError nReturn;
QCBORStringAllocator *pAlloc = (QCBORStringAllocator *)me->pStringAllocator;
UsefulBufC FullString = NULLUsefulBufC;
-
+
nReturn = GetNext_Item(&(me->InBuf), pDecodedItem, me->bStringAllocateAll ? pAlloc: NULL);
if(nReturn) {
goto Done;
}
-
+
// To reduce code size by removing support for indefinite length strings, the
// code in this function from here down can be eliminated. Run tests, except
// indefinite length string tests, to be sure all is OK if this is removed.
-
+
// Only do indefinite length processing on strings
if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING && pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
goto Done; // no need to do any work here on non-string types
}
-
+
// Is this a string with an indefinite length?
if(pDecodedItem->val.string.len != SIZE_MAX) {
goto Done; // length is not indefinite, so no work to do here
}
-
+
// Can't do indefinite length strings without a string allocator
if(pAlloc == NULL) {
nReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
goto Done;
}
-
+
// There is an indefinite length string to work on...
// Track which type of string it is
const uint8_t uStringType = pDecodedItem->uDataType;
-
+
// Loop getting chunk of indefinite string
for(;;) {
// Get item for next chunk
@@ -809,7 +809,7 @@
if(nReturn) {
break; // Error getting the next chunk
}
-
+
// See if it is a marker at end of indefinite length string
if(StringChunkItem.uDataType == QCBOR_TYPE_BREAK) {
// String is complete
@@ -817,14 +817,14 @@
pDecodedItem->uDataAlloc = 1;
break;
}
-
+
// Match data type of chunk to type at beginning.
// Also catches error of other non-string types that don't belong.
if(StringChunkItem.uDataType != uStringType) {
nReturn = QCBOR_ERR_INDEFINITE_STRING_CHUNK;
break;
}
-
+
// Alloc new buffer or expand previously allocated buffer so it can fit
UsefulBuf NewMem = (*pAlloc->fAllocate)(pAlloc->pAllocaterContext,
UNCONST_POINTER(FullString.ptr),
@@ -834,17 +834,17 @@
nReturn = QCBOR_ERR_STRING_ALLOCATE;
break;
}
-
+
// Copy new string chunk at the end of string so far.
FullString = UsefulBuf_CopyOffset(NewMem, FullString.len, StringChunkItem.val.string);
}
-
+
Done:
if(pAlloc && nReturn && !UsefulBuf_IsNULLC(FullString)) {
// Getting item failed, clean up the allocated memory
(pAlloc->fFree)(pAlloc->pAllocaterContext, UNCONST_POINTER(FullString.ptr));
}
-
+
return nReturn;
}
@@ -867,31 +867,31 @@
if(nReturn) {
goto Done; // Error out of the loop
}
-
+
if(pDecodedItem->uDataType != QCBOR_TYPE_OPTTAG) {
// Successful exit from loop; maybe got some tags, maybe not
pDecodedItem->uTagBits = uTagBits;
break;
}
-
+
uint8_t uTagBitIndex;
// Tag was mapped, tag was not mapped, error with tag list
switch(TagMapper_Lookup(me->pCallerConfiguredTagList, pDecodedItem->val.uTagV, &uTagBitIndex)) {
-
+
case QCBOR_SUCCESS:
// Successfully mapped the tag
uTagBits |= 0x01ULL << uTagBitIndex;
break;
-
+
case QCBOR_ERR_BAD_OPT_TAG:
// Tag is not recognized. Do nothing
break;
-
+
default:
// Error Condition
goto Done;
}
-
+
if(pTags) {
// Caller wants all tags recorded in the provided buffer
if(pTags->uNumUsed >= pTags->uNumAllocated) {
@@ -902,33 +902,33 @@
pTags->uNumUsed++;
}
}
-
+
switch(pDecodedItem->uTagBits & TAG_MAPPER_FIRST_FOUR) {
case 0:
// No tags at all or none we know about. Nothing to do.
// This is part of the pass-through path of this function
// that will mostly be taken when decoding any item.
break;
-
+
case QCBOR_TAGFLAG_DATE_STRING:
nReturn = DecodeDateString(pDecodedItem);
break;
-
+
case QCBOR_TAGFLAG_DATE_EPOCH:
nReturn = DecodeDateEpoch(pDecodedItem);
break;
-
+
case QCBOR_TAGFLAG_POS_BIGNUM:
case QCBOR_TAGFLAG_NEG_BIGNUM:
nReturn = DecodeBigNum(pDecodedItem);
break;
-
+
default:
// Encountering some mixed up CBOR like something that
// is tagged as both a string and integer date.
nReturn = QCBOR_ERR_BAD_OPT_TAG;
}
-
+
Done:
return nReturn;
}
@@ -943,51 +943,60 @@
QCBORError nReturn = GetNext_TaggedItem(me, pDecodedItem, pTags);
if(nReturn)
goto Done;
-
+
if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
// Break can't be a map entry
goto Done;
}
-
- // If in a map and the right decoding mode, get the label
- if(DecodeNesting_TypeIsMap(&(me->nesting)) && me->uDecodeMode != QCBOR_DECODE_MODE_MAP_AS_ARRAY) {
- // In a map and caller wants maps decoded, not treated as arrays
-
- // Get the next item which will be the real data; Item will be the label
- QCBORItem LabelItem = *pDecodedItem;
- nReturn = GetNext_TaggedItem(me, pDecodedItem, pTags);
- if(nReturn)
- goto Done;
-
- pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
- if(LabelItem.uDataType == QCBOR_TYPE_TEXT_STRING) {
- // strings are always good labels
- pDecodedItem->label.string = LabelItem.val.string;
- pDecodedItem->uLabelType = QCBOR_TYPE_TEXT_STRING;
- } else if (QCBOR_DECODE_MODE_MAP_STRINGS_ONLY == me->uDecodeMode) {
- // It's not a string and we only want strings, probably for easy translation to JSON
- nReturn = QCBOR_ERR_MAP_LABEL_TYPE;
- goto Done;
- } else if(LabelItem.uDataType == QCBOR_TYPE_INT64) {
- pDecodedItem->label.int64 = LabelItem.val.int64;
- pDecodedItem->uLabelType = QCBOR_TYPE_INT64;
- } else if(LabelItem.uDataType == QCBOR_TYPE_UINT64) {
- pDecodedItem->label.uint64 = LabelItem.val.uint64;
- pDecodedItem->uLabelType = QCBOR_TYPE_UINT64;
- } else if(LabelItem.uDataType == QCBOR_TYPE_BYTE_STRING) {
- pDecodedItem->label.string = LabelItem.val.string;
+ if(me->uDecodeMode != QCBOR_DECODE_MODE_MAP_AS_ARRAY) {
+ // In a map and caller wants maps decoded, not treated as arrays
+
+ if(DecodeNesting_TypeIsMap(&(me->nesting))) {
+ // If in a map and the right decoding mode, get the label
+
+ // Get the next item which will be the real data; Item will be the label
+ QCBORItem LabelItem = *pDecodedItem;
+ nReturn = GetNext_TaggedItem(me, pDecodedItem, pTags);
+ if(nReturn)
+ goto Done;
+
pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
- pDecodedItem->uLabelType = QCBOR_TYPE_BYTE_STRING;
- } else {
- // label is not an int or a string. It is an arrray
- // or a float or such and this implementation doesn't handle that.
- // Also, tags on labels are ignored.
- nReturn = QCBOR_ERR_MAP_LABEL_TYPE;
- goto Done;
+
+ if(LabelItem.uDataType == QCBOR_TYPE_TEXT_STRING) {
+ // strings are always good labels
+ pDecodedItem->label.string = LabelItem.val.string;
+ pDecodedItem->uLabelType = QCBOR_TYPE_TEXT_STRING;
+ } else if (QCBOR_DECODE_MODE_MAP_STRINGS_ONLY == me->uDecodeMode) {
+ // It's not a string and we only want strings, probably for easy translation to JSON
+ nReturn = QCBOR_ERR_MAP_LABEL_TYPE;
+ goto Done;
+ } else if(LabelItem.uDataType == QCBOR_TYPE_INT64) {
+ pDecodedItem->label.int64 = LabelItem.val.int64;
+ pDecodedItem->uLabelType = QCBOR_TYPE_INT64;
+ } else if(LabelItem.uDataType == QCBOR_TYPE_UINT64) {
+ pDecodedItem->label.uint64 = LabelItem.val.uint64;
+ pDecodedItem->uLabelType = QCBOR_TYPE_UINT64;
+ } else if(LabelItem.uDataType == QCBOR_TYPE_BYTE_STRING) {
+ pDecodedItem->label.string = LabelItem.val.string;
+ pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
+ pDecodedItem->uLabelType = QCBOR_TYPE_BYTE_STRING;
+ } else {
+ // label is not an int or a string. It is an arrray
+ // or a float or such and this implementation doesn't handle that.
+ // Also, tags on labels are ignored.
+ nReturn = QCBOR_ERR_MAP_LABEL_TYPE;
+ goto Done;
+ }
+ }
+ } else {
+ if(pDecodedItem->uDataType == QCBOR_TYPE_MAP) {
+ // Decoding a map as an array
+ pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY;
+ pDecodedItem->val.uCount *= 2;
}
}
-
+
Done:
return nReturn;
}
@@ -1003,7 +1012,7 @@
// The public entry point for fetching and parsing the next QCBORItem.
// All the CBOR parsing work is here and in subordinate calls.
QCBORError nReturn;
-
+
nReturn = GetNext_MapEntry(me, pDecodedItem, pTags);
if(nReturn) {
goto Done;
@@ -1015,11 +1024,11 @@
nReturn = QCBOR_ERR_BAD_BREAK;
goto Done;
}
-
+
// Record the nesting level for this data item before processing any of
// decrementing and descending.
pDecodedItem->uNestingLevel = DecodeNesting_GetLevel(&(me->nesting));
-
+
// Process the item just received for descent or decrement, and
// ascent if decrements are enough to close out a definite length array/map
if(IsMapOrArray(pDecodedItem->uDataType)) {
@@ -1039,7 +1048,7 @@
if(nReturn) {
goto Done;
}
-
+
// For indefinite length maps/arrays, looking at any and
// all breaks that might terminate them. The equivalent
// for definite length maps/arrays happens in
@@ -1067,12 +1076,12 @@
}
}
}
-
+
// Tell the caller what level is next. This tells them what maps/arrays
// were closed out and makes it possible for them to reconstruct
// the tree with just the information returned by GetNext
pDecodedItem->uNextNestLevel = DecodeNesting_GetLevel(&(me->nesting));
-
+
Done:
return nReturn;
}
@@ -1088,34 +1097,34 @@
Decoding items is done in 5 layered functions, one calling the
next one down. If a layer has no work to do for a particular item
it returns quickly.
-
+
- QCBORDecode_GetNext -- The top layer manages the beginnings and
ends of maps and arrays. It tracks descending into and ascending
out of maps/arrays. It processes all breaks that terminate
maps and arrays.
-
+
- GetNext_MapEntry -- This handles the combining of two
items, the label and the data, that make up a map entry.
It only does work on maps. It combines the label and data
items into one labeled item.
-
+
- GetNext_TaggedItem -- This handles the type 6 tagged items.
It accumulates all the tags and combines them with the following
non-tagged item. If the tagged item is something that is understood
like a date, the decoding of that item is invoked.
-
+
- GetNext_FullItem -- This assembles the sub items that make up
an indefinte length string into one string item. It uses the
string allocater to create contiguous space for the item. It
processes all breaks that are part of indefinite length strings.
-
+
- GetNext_Item -- This gets and decodes the most atomic
item in CBOR, the thing with an initial byte containing
the major type.
-
+
Roughly this takes 300 bytes of stack for vars. Need to
evaluate this more carefully and correctly.
-
+
*/
@@ -1125,14 +1134,14 @@
int QCBORDecode_IsTagged(QCBORDecodeContext *me, const QCBORItem *pItem, uint64_t uTag)
{
const QCBORTagListIn *pCallerConfiguredTagMap = me->pCallerConfiguredTagList;
-
+
uint8_t uTagBitIndex;
// Do not care about errors in pCallerConfiguredTagMap here. They are
// caught during GetNext() before this is called.
if(TagMapper_Lookup(pCallerConfiguredTagMap, uTag, &uTagBitIndex)) {
return 0;
}
-
+
const uint64_t uTagBit = 0x01ULL << uTagBitIndex;
return (uTagBit & pItem->uTagBits) != 0;
}
@@ -1144,7 +1153,7 @@
QCBORError QCBORDecode_Finish(QCBORDecodeContext *me)
{
int nReturn = QCBOR_SUCCESS;
-
+
// Error out if all the maps/arrays are not closed out
if(DecodeNesting_IsNested(&(me->nesting))) {
nReturn = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
@@ -1155,7 +1164,7 @@
if(UsefulInputBuf_BytesUnconsumed(&(me->InBuf))) {
nReturn = QCBOR_ERR_EXTRA_BYTES;
}
-
+
Done:
// Call the destructor for the string allocator if there is one.
// Always called, even if there are errors; always have to clean up
@@ -1165,34 +1174,34 @@
(pAllocator->fDestructor)(pAllocator->pAllocaterContext);
}
}
-
+
return nReturn;
}
-/*
-
+/*
+
Decoder errors handled in this file
-
+
- Hit end of input before it was expected while decoding type and number QCBOR_ERR_HIT_END
-
+
- negative integer that is too large for C QCBOR_ERR_INT_OVERFLOW
-
+
- Hit end of input while decoding a text or byte string QCBOR_ERR_HIT_END
-
+
- Encountered conflicting tags -- e.g., an item is tagged both a date string and an epoch date QCBOR_ERR_UNSUPPORTED
-
+
- Encontered an array or mapp that has too many items QCBOR_ERR_ARRAY_TOO_LONG
-
+
- Encountered array/map nesting that is too deep QCBOR_ERR_ARRAY_NESTING_TOO_DEEP
-
+
- An epoch date > INT64_MAX or < INT64_MIN was encountered QCBOR_ERR_DATE_OVERFLOW
-
+
- The type of a map label is not a string or int QCBOR_ERR_MAP_LABEL_TYPE
-
+
- Hit end with arrays or maps still open -- QCBOR_ERR_EXTRA_BYTES
-
+
*/
@@ -1202,7 +1211,7 @@
This is a very primitive memory allocator. It does not track individual
allocations, only a high-water mark. A free or reallotcation must be of
the last chunk allocated.
-
+
All of this following code will get dead-stripped if QCBORDecode_SetMemPool()
is not called.
*/
@@ -1217,14 +1226,14 @@
/*
Internal function for an allocation
-
+
Code Reviewers: THIS FUNCTION DOES POINTER MATH
*/
static UsefulBuf MemPool_Alloc(void *ctx, void *pMem, size_t uNewSize)
{
MemPool *me = (MemPool *)ctx;
void *pReturn = NULL;
-
+
if(pMem) {
// Realloc case
// This check will work even if uNewSize is a super-large value like UINT64_MAX
@@ -1240,7 +1249,7 @@
me->pFree += uNewSize;
}
}
-
+
return (UsefulBuf){pReturn, uNewSize};
}
@@ -1258,32 +1267,48 @@
*/
QCBORError QCBORDecode_SetMemPool(QCBORDecodeContext *me, UsefulBuf Pool, bool bAllStrings)
{
+ // The idea behind QCBOR_MIN_MEM_POOL_SIZE is
+ // that the caller knows exactly what size to
+ // allocate and that the tests can run conclusively
+ // no matter what size MemPool is
+ // even though it wastes some memory. MemPool
+ // will vary depending on pointer size of the
+ // the machine. QCBOR_MIN_MEM_POOL_SIZE is
+ // set for pointers up to 64-bits. This
+ // wastes about 50 bytes on a 32-bit machine.
+ // This check makes sure things don't go
+ // horribly wrong. It should optimize out
+ // when there is no problem as the sizes are
+ // known at compile time.
+ if(sizeof(MemPool) > QCBOR_DECODE_MIN_MEM_POOL_SIZE) {
+ return QCBOR_ERR_MEM_POOL_INTERNAL;
+ }
+
// The first bytes of the Pool passed in are used
// as the context (vtable of sorts) for the memory pool
// allocator.
- if(Pool.len < sizeof(MemPool)+1) {
+ if(Pool.len < QCBOR_DECODE_MIN_MEM_POOL_SIZE) {
return QCBOR_ERR_BUFFER_TOO_SMALL;
}
-
MemPool *pMP = (MemPool *)Pool.ptr;
-
+
// Fill in the "vtable"
pMP->StringAllocator.fAllocate = MemPool_Alloc;
pMP->StringAllocator.fFree = MemPool_Free;
pMP->StringAllocator.fDestructor = NULL;
-
+
// Set up the pointers to the memory to be allocated
- pMP->pStart = (uint8_t *)Pool.ptr + sizeof(MemPool);
+ pMP->pStart = (uint8_t *)Pool.ptr + QCBOR_DECODE_MIN_MEM_POOL_SIZE;
pMP->pFree = pMP->pStart;
pMP->pEnd = (uint8_t *)Pool.ptr + Pool.len;
-
+
// More book keeping of context
pMP->StringAllocator.pAllocaterContext = pMP;
me->pStringAllocator = pMP;
-
+
// The flag indicating when to use the allocator
me->bStringAllocateAll = bAllStrings;
-
+
return QCBOR_SUCCESS;
}
@@ -1292,13 +1317,13 @@
Extra little hook to make MemPool testing work right
without adding any code size or overhead to non-test
uses. This will get dead-stripped for non-test use.
-
- This is not a public function.
+
+ This is not a public function.
*/
size_t MemPoolTestHook_GetPoolSize(void *ctx)
{
MemPool *me = (MemPool *)ctx;
-
+
return me->pEnd - me->pStart;
}
diff --git a/src/qcbor_decode_malloc.c b/src/qcbor_decode_malloc.c
deleted file mode 100644
index 33b5d6c..0000000
--- a/src/qcbor_decode_malloc.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/*==============================================================================
-
- Copyright (c) 2018, Laurence Lundblade.
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- Copyright (c) 2018, Laurence Lundblade.
- All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the following
- disclaimer in the documentation and/or other materials provided
- with the distribution.
- * The name "Laurence Lundblade" may not be used to
- endorse or promote products derived from this software without
- specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
-WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
-BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
-OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
-IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==============================================================================*/
-
-#include "qcbor.h"
-#include <stdlib.h> // for realloc and free
-
-static UsefulBuf MemMallocAlloc(void *ctx, void *pOldMem, size_t uNewSize)
-{
- (void)ctx;
- void *pNewMem = realloc(pOldMem, uNewSize);
- return (UsefulBuf){pNewMem, uNewSize};
-}
-
-static void MemMallocFree(void *ctx, void *old)
-{
- (void)ctx;
- free(old);
-}
-
-static void MemMallocDestructor(void *ctx)
-{
- free(ctx);
-}
-/*
- Public function. See qcbor.h
- */
-QCBORStringAllocator *QCBORDecode_MakeMallocStringAllocator()
-{
- QCBORStringAllocator *pAllocaterContext = malloc(sizeof(QCBORStringAllocator));
- if(pAllocaterContext) {
- pAllocaterContext->fAllocate = MemMallocAlloc;
- pAllocaterContext->fFree = MemMallocFree;
- pAllocaterContext->fDestructor = MemMallocDestructor;
- pAllocaterContext->pAllocaterContext = pAllocaterContext; // So that destructor can work.
- }
-
- return pAllocaterContext;
-}
-
-
-
-
diff --git a/src/qcbor_encode.c b/src/qcbor_encode.c
index a23fda3..05e376b 100644
--- a/src/qcbor_encode.c
+++ b/src/qcbor_encode.c
@@ -2,7 +2,7 @@
Copyright (c) 2016-2018, The Linux Foundation.
Copyright (c) 2018, Laurence Lundblade.
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
@@ -16,7 +16,7 @@
contributors, nor the name "Laurence Lundblade" may be used to
endorse or promote products derived from this software without
specific prior written permission.
-
+
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
@@ -32,14 +32,14 @@
/*===================================================================================
FILE: qcbor_encode.c
-
+
DESCRIPTION: This file contains the implementation of QCBOR.
-
+
EDIT HISTORY FOR FILE:
-
+
This section contains comments describing changes made to the module.
Notice that changes are listed in reverse chronological order.
-
+
when who what, where, why
-------- ---- ---------------------------------------------------
12/30/18 llundblade Small efficient clever encode of type & argument.
@@ -48,14 +48,14 @@
11/1/18 llundblade Floating support.
10/31/18 llundblade Switch to one license that is almost BSD-3.
09/28/18 llundblade Added bstr wrapping feature for COSE implementation.
- 02/05/18 llundbla Works on CPUs which require integer alignment.
+ 02/05/18 llundbla Works on CPUs which require integer alignment.
Requires new version of UsefulBuf.
07/05/17 llundbla Add bstr wrapping of maps/arrays for COSE
03/01/17 llundbla More data types
11/13/16 llundbla Integrate most TZ changes back into github version.
09/30/16 gkanike Porting to TZ.
03/15/16 llundbla Initial Version.
-
+
=====================================================================================*/
#include "qcbor.h"
@@ -70,13 +70,13 @@
limit of QCBOR_MAX_ARRAY_NESTING to the number of arrays and maps
that can be nested in one encoding so the encoding context stays
small enough to fit on the stack.
-
+
When an array / map is opened, pCurrentNesting points to the element
in pArrays that records the type, start position and accumluates a
count of the number of items added. When closed the start position is
used to go back and fill in the type and number of items in the array
/ map.
-
+
Encoded output be just items like ints and strings that are
not part of any array / map. That is, the first thing encoded
does not have to be an array or a map.
@@ -93,7 +93,7 @@
inline static QCBORError Nesting_Increase(QCBORTrackNesting *pNesting, uint8_t uMajorType, uint32_t uPos)
{
QCBORError nReturn = QCBOR_SUCCESS;
-
+
if(pNesting->pCurrentNesting == &pNesting->pArrays[QCBOR_MAX_ARRAY_NESTING]) {
// trying to open one too many
nReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
@@ -116,8 +116,9 @@
if(1 >= QCBOR_MAX_ITEMS_IN_ARRAY - pNesting->pCurrentNesting->uCount) {
return QCBOR_ERR_ARRAY_TOO_LONG;
}
-
+
pNesting->pCurrentNesting->uCount += 1;
+
return QCBOR_SUCCESS;
}
@@ -158,23 +159,23 @@
context. Once either of these errors is set they are never
cleared. Only Init() resets them. Or said another way, they must
never be cleared or we'll tell the caller all is good when it is not.
-
+
Only one error code is reported by Finish() even if there are
multiple errors. The last one set wins. The caller might have to fix
one error to reveal the next one they have to fix. This is OK.
-
+
The buffer full error tracked by UsefulBuf is only pulled out of
UsefulBuf in Finish() so it is the one that usually wins. UsefulBuf
will never go off the end of the buffer even if it is called again
and again when full.
-
+
It is really tempting to not check for overflow on the count in the
number of items in an array. It would save a lot of code, it is
extremely unlikely that any one will every put 65,000 items in an
array, and the only bad thing that would happen is the CBOR would be
bogus. Once we prove that is the only consequence, then we can make
the change.
-
+
Since this does not parse any input, you could in theory remove all
error checks in this code if you knew the caller called it
correctly. Maybe someday CDDL or some such language will be able to
@@ -182,24 +183,24 @@
correct. This could also automatically size some of the data
structures like array/map nesting resulting in some good memory
savings.
-
+
Errors returned here fall into three categories:
-
+
Sizes
QCBOR_ERR_BUFFER_TOO_LARGE -- A buffer passed in > UINT32_MAX
QCBOR_ERR_BUFFER_TOO_SMALL -- output buffer too small
-
+
QCBOR_ERR_ARRAY_NESTING_TOO_DEEP -- Too many opens without closes
QCBOR_ERR_ARRAY_TOO_LONG -- Too many things added to an array/map
-
+
Nesting constructed incorrectly
QCBOR_ERR_TOO_MANY_CLOSES -- more close calls than opens
QCBOR_ERR_CLOSE_MISMATCH -- Type of close does not match open
QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN -- Finish called without enough closes
-
+
Bad data
QCBOR_ERR_BAD_SIMPLE -- Simple value integer not valid
-
+
*/
@@ -229,12 +230,13 @@
used.
Every encoding of the type and argument has at least one byte, the
+>>>>>>> origin/smallinsert
"initial byte".
-
+
The top three bits of the initial byte are the major type for the
CBOR data item. The eight major types defined by the standard are
defined as CBOR_MAJOR_TYPE_xxxx in qcbor.h.
-
+
The remaining five bits, known as "additional information", and
possibly more bytes encode the argument. If the argument is less than
24, then it is encoded entirely in the five bits. This is neat
@@ -251,13 +253,14 @@
This function inserts them into the output buffer at the specified
position. AppendEncodedTypeAndNumber() appends to the end.
-
- This function takes care of converting to network byte order.
-
+
+ This function takes care of converting to network byte order.
+
This function is also used to insert floats and doubles. Before this
function is called the float or double must be copied into a
uint64_t. That is how they are passed in. They are then converted to
network byte order correctly. The uMinLen param makes sure that even
+
if all the digits of a half, float or double are 0 it is still
correctly encoded in 2, 4 or 8 bytes.
*/
@@ -338,7 +341,7 @@
/*
Append the type and number info to the end of the buffer.
-
+
See InsertEncodedTypeAndNumber() function above for details
*/
inline static void AppendEncodedTypeAndNumber(QCBOREncodeContext *me, uint8_t uMajorType, uint64_t uNumber)
@@ -369,7 +372,7 @@
if(me->uError == QCBOR_SUCCESS) {
uint8_t uMajorType;
uint64_t uValue;
-
+
if(nNum < 0) {
uValue = (uint64_t)(-nNum - 1); // This is the way negative ints work in CBOR. -1 encodes as 0x00 with major type negative int.
uMajorType = CBOR_MAJOR_TYPE_NEGATIVE_INT;
@@ -377,7 +380,7 @@
uValue = (uint64_t)nNum;
uMajorType = CBOR_MAJOR_TYPE_POSITIVE_INT;
}
-
+
AppendEncodedTypeAndNumber(me, uMajorType, uValue);
me->uError = Nesting_Increment(&(me->nesting));
}
@@ -387,9 +390,9 @@
/*
Semi-private function. It is exposed to user of the interface,
but they will usually call one of the inline wrappers rather than this.
-
+
See header qcbor.h
-
+
Does the work of adding some bytes to the CBOR output. Works for a
byte and text strings, which are the same in in CBOR though they have
different major types. This is also used to insert raw
@@ -401,9 +404,6 @@
// If it is not Raw CBOR, add the type and the length
if(uMajorType != CBOR_MAJOR_NONE_TYPE_RAW) {
AppendEncodedTypeAndNumber(me, uMajorType, Bytes.len);
- // The increment in uPos is to account for bytes added for
- // type and number so the buffer being added goes to the
- // right place
}
// Actually add the bytes
@@ -429,7 +429,7 @@
/*
Semi-private function. It is exposed to user of the interface,
but they will usually call one of the inline wrappers rather than this.
-
+
See header qcbor.h
*/
void QCBOREncode_AddType7(QCBOREncodeContext *me, size_t uSize, uint64_t uNum)
@@ -456,7 +456,7 @@
void QCBOREncode_AddDouble(QCBOREncodeContext *me, double dNum)
{
const IEEE754_union uNum = IEEE754_DoubleToSmallest(dNum);
-
+
QCBOREncode_AddType7(me, uNum.uSize, uNum.uValue);
}
@@ -464,7 +464,7 @@
/*
Semi-public function. It is exposed to user of the interface,
but they will usually call one of the inline wrappers rather than this.
-
+
See header qcbor.h
*/
void QCBOREncode_OpenMapOrArray(QCBOREncodeContext *me, uint8_t uMajorType)
@@ -508,26 +508,26 @@
// and never shrinks. UsefulOutBut itself also has defenses such that
// it won't write were it should not even if given hostile input lengths
const size_t uLenOfEncodedMapOrArray = uEndPosition - uInsertPosition;
-
+
// Length is number of bytes for a bstr and number of items a for map & array
const size_t uLength = uMajorType == CBOR_MAJOR_TYPE_BYTE_STRING ?
uLenOfEncodedMapOrArray : Nesting_GetCount(&(me->nesting));
-
+
// Actually insert
InsertEncodedTypeAndNumber(me,
uMajorType, // major type bstr, array or map
0, // no minimum length for encoding
uLength, // either len of bstr or num items in array or map
uInsertPosition); // position in out buffer
-
+
// Return pointer and length to the enclosed encoded CBOR. The intended
// use is for it to be hashed (e.g., SHA-256) in a COSE implementation.
// This must be used right away, as the pointer and length go invalid
// on any subsequent calls to this function because of the
// InsertEncodedTypeAndNumber() call that slides data to the right.
if(pWrappedCBOR) {
- UsefulBufC PartialResult = UsefulOutBuf_OutUBuf(&(me->OutBuf));
- size_t uBstrLen = UsefulOutBuf_GetEndPosition(&(me->OutBuf)) - uEndPosition;
+ const UsefulBufC PartialResult = UsefulOutBuf_OutUBuf(&(me->OutBuf));
+ const size_t uBstrLen = UsefulOutBuf_GetEndPosition(&(me->OutBuf)) - uEndPosition;
*pWrappedCBOR = UsefulBuf_Tail(PartialResult, uInsertPosition+uBstrLen);
}
Nesting_Decrease(&(me->nesting));
@@ -543,16 +543,16 @@
QCBORError QCBOREncode_Finish(QCBOREncodeContext *me, UsefulBufC *pEncodedCBOR)
{
QCBORError uReturn = me->uError;
-
+
if(uReturn != QCBOR_SUCCESS) {
goto Done;
}
-
+
if (Nesting_IsInNest(&(me->nesting))) {
uReturn = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
goto Done;
}
-
+
if(UsefulOutBuf_GetError(&(me->OutBuf))) {
// Stuff didn't fit in the buffer.
// This check catches this condition for all the appends and inserts
@@ -565,7 +565,7 @@
}
*pEncodedCBOR = UsefulOutBuf_OutUBuf(&(me->OutBuf));
-
+
Done:
return uReturn;
}
@@ -577,13 +577,13 @@
QCBORError QCBOREncode_FinishGetSize(QCBOREncodeContext *me, size_t *puEncodedLen)
{
UsefulBufC Enc;
-
+
QCBORError nReturn = QCBOREncode_Finish(me, &Enc);
-
+
if(nReturn == QCBOR_SUCCESS) {
*puEncodedLen = Enc.len;
}
-
+
return nReturn;
}
@@ -592,7 +592,7 @@
/*
Notes on the code
-
+
CBOR Major Type Public Function
0 QCBOREncode_AddUInt64
0, 1 QCBOREncode_AddUInt64, QCBOREncode_AddInt64
@@ -621,14 +621,11 @@
_QCBOREncode_CloseMapOrArray is larger because it has a lot
of nesting tracking to do and much of Nesting_ inlines
into it. It probably can't be reduced much.
-
+
If the error returned by Nesting_Increment() can be ignored
because the limit is so high and the consequence of exceeding
is proved to be inconsequential, then a lot of if(me->uError)
instance can be removed, saving some code.
-
+
*/
-
-
-
diff --git a/test/UsefulBuf_Tests.c b/test/UsefulBuf_Tests.c
index fc99ee6..3ec2529 100644
--- a/test/UsefulBuf_Tests.c
+++ b/test/UsefulBuf_Tests.c
@@ -2,7 +2,7 @@
Copyright (c) 2016-2018, The Linux Foundation.
Copyright (c) 2018, Laurence Lundblade.
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
@@ -16,7 +16,7 @@
contributors, nor the name "Laurence Lundblade" may be used to
endorse or promote products derived from this software without
specific prior written permission.
-
+
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
@@ -34,11 +34,11 @@
/* Basic exercise...
-
+
Call all the main public functions.
-
+
Binary compare the result to the expected.
-
+
There is nothing adversarial in this test
*/
const char * UOBTest_NonAdversarial()
@@ -46,16 +46,16 @@
const char *szReturn = NULL;
UsefulBuf_MAKE_STACK_UB(outbuf,50);
-
+
UsefulOutBuf UOB;
-
+
UsefulOutBuf_Init(&UOB, outbuf);
-
+
if(!UsefulOutBuf_AtStart(&UOB)) {
szReturn = "Not at start";
goto Done;
}
-
+
// Put 7 bytes at beginning of buf
UsefulOutBuf_AppendData(&UOB, "bluster", 7);
@@ -63,41 +63,41 @@
szReturn = "At start";
goto Done;
}
-
+
// add a space to end
UsefulOutBuf_AppendByte(&UOB, ' ');
-
+
// Add 5 bytes to the end
UsefulBufC UBC = {"hunny", 5};
UsefulOutBuf_AppendUsefulBuf(&UOB, UBC);
-
+
// Insert 9 bytes at the beginning, slide the previous stuff right
UsefulOutBuf_InsertData(&UOB, "heffalump", 9, 0);
UsefulOutBuf_InsertByte(&UOB, ' ', 9);
-
+
// Put 9 bytes in at position 10 -- just after "heffalump "
UsefulBufC UBC2 = {"unbounce ", 9};
UsefulOutBuf_InsertUsefulBuf(&UOB, UBC2, 10);
-
+
// Make it a null terminated string (because all the appends and inserts above not strcpy !)
UsefulOutBuf_AppendByte(&UOB, '\0');
-
-
+
+
UsefulBufC U = UsefulOutBuf_OutUBuf(&UOB);
-
+
const char *expected = "heffalump unbounce bluster hunny";
-
+
if(UsefulBuf_IsNULLC(U) || U.len-1 != strlen(expected) || strcmp(expected, U.ptr) || UsefulOutBuf_GetError(&UOB)) {
szReturn = "OutUBuf";
}
-
+
UsefulBuf_MAKE_STACK_UB(buf, 50);
UsefulBufC Out = UsefulOutBuf_CopyOut(&UOB, buf);
-
+
if(UsefulBuf_IsNULLC(Out) || Out.len-1 != strlen(expected) || strcmp(expected, Out.ptr)) {
szReturn = "CopyOut";
}
-
+
Done:
return szReturn;
}
@@ -108,26 +108,26 @@
pUOB is the buffer to append too
num is the amount to append
expected is the expected return code, 0 or 1
-
+
returns 0 if test passed
-
+
*/
static int AppendTest(UsefulOutBuf *pUOB, size_t num, int expected)
{
//reset
UsefulOutBuf_Reset(pUOB);
-
+
// check status first
if(UsefulOutBuf_GetError(pUOB))
return 1;
-
+
// append the bytes
UsefulOutBuf_AppendData(pUOB, (const uint8_t *)"bluster", num);
-
+
// check error status after
if(UsefulOutBuf_GetError(pUOB) != expected)
return 1;
-
+
return 0;
}
@@ -139,16 +139,16 @@
{
// reset
UsefulOutBuf_Reset(pUOB);
-
+
// check
if(UsefulOutBuf_GetError(pUOB))
return 1;
-
+
UsefulOutBuf_InsertData(pUOB, (const uint8_t *)"bluster", num, pos);
-
+
if(UsefulOutBuf_GetError(pUOB) != expected)
return 1;
-
+
return 0;
}
@@ -158,28 +158,28 @@
- around 0
- around the buffer size
- around MAX size_t
-
-
+
+
Test these for the buffer size and the cursor, the insert amount, the append amount and the insert position
-
+
*/
const char *UOBTest_BoundaryConditionsTest()
{
UsefulBuf_MAKE_STACK_UB(outbuf,2);
-
+
UsefulOutBuf UOB;
-
+
UsefulOutBuf_Init(&UOB, outbuf);
// append 0 byte to a 2 byte buffer --> success
if(AppendTest(&UOB, 0, 0))
return "Append 0 bytes failed";
-
+
// append 1 byte to a 2 byte buffer --> success
if(AppendTest(&UOB, 1, 0))
return "Append of 1 byte failed";
-
+
// append 2 byte to a 2 byte buffer --> success
if(AppendTest(&UOB, 2, 0))
return "Append to fill buffer failed";
@@ -191,53 +191,53 @@
// append max size_t to a 2 byte buffer --> failure
if(AppendTest(&UOB, SIZE_MAX, 1))
return "Append of SIZE_MAX error not caught";
-
+
if(InsertTest(&UOB, 1, 0, 0))
return "Insert 1 byte at start failed";
if(InsertTest(&UOB, 2, 0, 0))
return "Insert 2 bytes at start failed";
-
+
if(InsertTest(&UOB, 3, 0, 1))
return "Insert overflow not caught";
-
+
if(InsertTest(&UOB, 1, 1, 1))
return "Bad insertion point not caught";
-
-
+
+
UsefulBuf_MAKE_STACK_UB(outBuf2,10);
-
+
UsefulOutBuf_Init(&UOB, outBuf2);
-
+
UsefulOutBuf_Reset(&UOB);
// put data in the buffer
UsefulOutBuf_AppendString(&UOB, "abc123");
-
+
UsefulOutBuf_InsertString(&UOB, "xyz*&^", 0);
-
+
if(!UsefulOutBuf_GetError(&UOB)) {
return "insert with data should have failed";
}
-
+
UsefulOutBuf_Init(&UOB, (UsefulBuf){NULL, SIZE_MAX - 5});
UsefulOutBuf_AppendData(&UOB, "123456789", SIZE_MAX -6);
if(UsefulOutBuf_GetError(&UOB)) {
return "insert in huge should have succeeded";
}
-
+
UsefulOutBuf_Init(&UOB, (UsefulBuf){NULL, SIZE_MAX - 5});
UsefulOutBuf_AppendData(&UOB, "123456789", SIZE_MAX -5);
if(UsefulOutBuf_GetError(&UOB)) {
return "insert in huge should have succeeded";
}
-
+
UsefulOutBuf_Init(&UOB, (UsefulBuf){NULL, SIZE_MAX - 5});
UsefulOutBuf_AppendData(&UOB, "123456789", SIZE_MAX - 4);
if(!UsefulOutBuf_GetError(&UOB)) {
return "lengths near max size";
}
-
+
return NULL;
}
@@ -250,15 +250,15 @@
const char *TestBasicSanity()
{
UsefulBuf_MAKE_STACK_UB(outbuf,10);
-
+
UsefulOutBuf UOB;
-
+
// First -- make sure that the room left function returns the right amount
UsefulOutBuf_Init(&UOB, outbuf);
-
+
if(UsefulOutBuf_RoomLeft(&UOB) != 10)
return "room left failed";
-
+
if(!UsefulOutBuf_WillItFit(&UOB, 9)) {
return "it did not fit";
}
@@ -266,27 +266,27 @@
if(UsefulOutBuf_WillItFit(&UOB, 11)) {
return "it should have not fit";
}
-
-
+
+
// Next -- make sure that the magic number checking is working right
UOB.magic = 8888; // make magic bogus
-
+
UsefulOutBuf_AppendData(&UOB, (const uint8_t *)"bluster", 7);
-
+
if(!UsefulOutBuf_GetError(&UOB))
return "magic corruption check failed";
-
-
-
+
+
+
// Next make sure that the valid data length check is working right
UsefulOutBuf_Init(&UOB, outbuf);
-
+
UOB.data_len = UOB.UB.len+1; // make size bogus
-
+
UsefulOutBuf_AppendData(&UOB, (const uint8_t *)"bluster", 7);
if(!UsefulOutBuf_GetError(&UOB))
return "valid data check failed";
-
+
return NULL;
}
@@ -295,11 +295,11 @@
const char *UBMacroConversionsTest()
{
char *szFoo = "foo";
-
+
UsefulBufC Foo = UsefulBuf_FromSZ(szFoo);
if(Foo.len != 3 || strncmp(Foo.ptr, szFoo, 3))
return "SZToUsefulBufC failed";
-
+
UsefulBufC Too = UsefulBuf_FROM_SZ_LITERAL("Toooo");
if(Too.len != 5 || strncmp(Too.ptr, "Toooo", 5))
return "UsefulBuf_FROM_SZ_LITERAL failed";
@@ -308,13 +308,13 @@
UsefulBufC Boo = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pB);
if(Boo.len != 3 || strncmp(Boo.ptr, "Boo", 3))
return "UsefulBuf_FROM_BYTE_ARRAY_LITERAL failed";
-
+
char *sz = "not const"; // some data for the test
UsefulBuf B = (UsefulBuf){sz, sizeof(sz)};
UsefulBufC BC = UsefulBuf_Const(B);
if(BC.len != sizeof(sz) || BC.ptr != sz)
return "UsefulBufConst failed";
-
+
return NULL;
}
@@ -322,7 +322,7 @@
const char *UBUtilTests()
{
UsefulBuf UB = NULLUsefulBuf;
-
+
if(!UsefulBuf_IsNULL(UB)){
return "IsNull failed";
}
@@ -330,64 +330,64 @@
if(!UsefulBuf_IsEmpty(UB)){
return "IsEmpty failed";
}
-
+
if(!UsefulBuf_IsNULLOrEmpty(UB)) {
return "IsNULLOrEmpty failed";
}
-
- UsefulBufC UBC = UsefulBuf_Const(UB);
-
+
+ const UsefulBufC UBC = UsefulBuf_Const(UB);
+
if(!UsefulBuf_IsNULLC(UBC)){
return "IsNull const failed";
}
-
+
if(!UsefulBuf_IsEmptyC(UBC)){
return "IsEmptyC failed";
}
-
+
if(!UsefulBuf_IsNULLOrEmptyC(UBC)){
return "IsNULLOrEmptyC failed";
}
-
- UsefulBuf UB2 = UsefulBuf_Unconst(UBC);
+
+ const UsefulBuf UB2 = UsefulBuf_Unconst(UBC);
if(!UsefulBuf_IsEmpty(UB2)) {
return "Back to UB is Empty failed";
}
-
+
UB.ptr = "x"; // just some valid pointer
-
+
if(UsefulBuf_IsNULL(UB)){
return "IsNull failed";
}
-
+
if(!UsefulBuf_IsEmptyC(UBC)){
return "IsEmpty failed";
}
-
+
// test the Unconst.
if(UsefulBuf_Unconst(UBC).ptr != NULL) {
return "Unconst failed";
}
-
+
// Set 100 bytes of '+'; validated a few tests later
UsefulBuf_MAKE_STACK_UB(Temp, 100);
- UsefulBufC TempC = UsefulBuf_Set(Temp, '+');
-
+ const UsefulBufC TempC = UsefulBuf_Set(Temp, '+');
+
// Try to copy into a buf that is too small and see failure
UsefulBuf_MAKE_STACK_UB(Temp2, 99);
if(!UsefulBuf_IsNULLC(UsefulBuf_Copy(Temp2, TempC))) {
return "Copy should have failed";
}
-
+
if(UsefulBuf_IsNULLC(UsefulBuf_CopyPtr(Temp2, "xx", 2))) {
return "CopyPtr failed";
}
-
+
UsefulBufC xxyy = UsefulBuf_CopyOffset(Temp2, 2, UsefulBuf_FROM_SZ_LITERAL("yy"));
if(UsefulBuf_IsNULLC(xxyy)) {
return "CopyOffset Failed";
}
-
+
if(UsefulBuf_Compare(UsefulBuf_Head(xxyy, 3), UsefulBuf_FROM_SZ_LITERAL("xxy"))) {
return "head failed";
}
@@ -395,7 +395,7 @@
if(UsefulBuf_Compare(UsefulBuf_Tail(xxyy, 1), UsefulBuf_FROM_SZ_LITERAL("xyy"))) {
return "tail failed";
}
-
+
if(!UsefulBuf_IsNULLC(UsefulBuf_Head(xxyy, 5))) {
return "head should have failed";
}
@@ -403,27 +403,27 @@
if(!UsefulBuf_IsNULLC(UsefulBuf_Tail(xxyy, 5))) {
return "tail should have failed";
}
-
+
if(!UsefulBuf_IsNULLC(UsefulBuf_CopyOffset(Temp2, 100, UsefulBuf_FROM_SZ_LITERAL("yy")))) {
return "Copy Offset should have failed";
}
-
+
// Try to copy into a NULL/empty buf and see failure
- UsefulBuf UBNull = NULLUsefulBuf;
+ const UsefulBuf UBNull = NULLUsefulBuf;
if(!UsefulBuf_IsNULLC(UsefulBuf_Copy(UBNull, TempC))) {
return "Copy to NULL should have failed";
}
-
-
+
+
// Try to set a NULL/empty buf; nothing should happen
UsefulBuf_Set(UBNull, '+'); // This will crash on failure
-
+
// Copy successfully to a buffer
UsefulBuf_MAKE_STACK_UB(Temp3, 101);
if(UsefulBuf_IsNULLC(UsefulBuf_Copy(Temp3, TempC))) {
return "Copy should not have failed";
}
-
+
static const uint8_t pExpected[] = {
'+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
'+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
@@ -441,12 +441,12 @@
if(UsefulBuf_Compare(Expected, TempC)) {
return "Set / Copy / Compare failed";
}
-
+
// Compare two empties and expect success
if(UsefulBuf_Compare(NULLUsefulBufC, NULLUsefulBufC)){
return "Compare Empties failed";
}
-
+
// Compare with empty and expect the first to be larger
if(UsefulBuf_Compare(Expected, NULLUsefulBufC) <= 0){
return "Compare with empty failed";
@@ -465,14 +465,14 @@
'+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
'+', '+', '+', '+', '+', '+', '+', '+', '+', ',',
};
- UsefulBufC ExpectedBigger = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pExpectedBigger);
-
+ const UsefulBufC ExpectedBigger = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pExpectedBigger);
+
// Expect -1 when the first arg is smaller
if(UsefulBuf_Compare(Expected, ExpectedBigger) >= 0){
return "Compare with bigger";
}
-
+
static const uint8_t pExpectedSmaller[] = {
'+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
'+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
@@ -485,13 +485,13 @@
'+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
'+', '+', '+', '+', '+', '+', '+', '+', '+', '*',
};
- UsefulBufC ExpectedSmaller = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pExpectedSmaller);
+ const UsefulBufC ExpectedSmaller = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pExpectedSmaller);
// Expect +1 when the first arg is larger
if(UsefulBuf_Compare(Expected, ExpectedSmaller) <= 0){
return "Compare with smaller";
}
-
-
+
+
static const uint8_t pExpectedLonger[] = {
'+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
'+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
@@ -504,14 +504,14 @@
'+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
'+', '+', '+', '+', '+', '+', '+', '+', '+', '+', '+'
};
- UsefulBufC ExpectedLonger = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pExpectedLonger);
-
+ const UsefulBufC ExpectedLonger = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pExpectedLonger);
+
// Expect -1 when the first arg is smaller
if(UsefulBuf_Compare(Expected, ExpectedLonger) >= 0){
return "Compare with longer";
}
-
+
static const uint8_t pExpectedShorter[] = {
'+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
'+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
@@ -524,26 +524,26 @@
'+', '+', '+', '+', '+', '+', '+', '+', '+', '+',
'+', '+', '+', '+', '+', '+', '+', '+', '+',
};
- UsefulBufC ExpectedShorter = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pExpectedShorter);
+ const UsefulBufC ExpectedShorter = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pExpectedShorter);
// Expect +1 with the first arg is larger
if(UsefulBuf_Compare(Expected, ExpectedShorter) <= 0){
return "Compare with shorter";
}
-
-
+
+
if(UsefulBuf_IsNULLC(UsefulBuf_Copy(Temp, NULLUsefulBufC))) {
return "Copy null/empty failed";
}
-
+
// Look for +++++... in +++++... and find it at the beginning
if(0 != UsefulBuf_FindBytes(ExpectedLonger, ExpectedShorter)){
return "Failed to find";
}
-
+
// look for ++* in ....++* and find it at the end
static const uint8_t pToFind[] = {'+', '+', '*'};
- UsefulBufC ToBeFound = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pToFind);
-
+ const UsefulBufC ToBeFound = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pToFind);
+
if(97 != UsefulBuf_FindBytes(ExpectedSmaller, ToBeFound)){
return "Failed to find 2";
}
@@ -552,12 +552,12 @@
if(SIZE_MAX != UsefulBuf_FindBytes(ExpectedBigger, ToBeFound)){
return "Failed to not find";
}
-
+
// Look for the whole buffer in itself and succeed.
if(0 != UsefulBuf_FindBytes(ExpectedLonger, ExpectedLonger)){
return "Failed to find 3";
}
-
+
return NULL;
}
@@ -565,40 +565,40 @@
const char * UIBTest_IntegerFormat()
{
UsefulOutBuf_MakeOnStack(UOB,100);
-
+
const uint32_t u32 = 0x0A0B0C0D; // from https://en.wikipedia.org/wiki/Endianness
const uint64_t u64 = 1984738472938472;
const uint16_t u16 = 40000;
const uint8_t u8 = 9;
const float f = (float)314.15;
const double d = 2.1e10;
-
-
+
+
UsefulOutBuf_AppendUint32(&UOB, u32); // Also tests UsefulOutBuf_InsertUint64 and UsefulOutBuf_GetEndPosition
UsefulOutBuf_AppendUint64(&UOB, u64); // Also tests UsefulOutBuf_InsertUint32
UsefulOutBuf_AppendUint16(&UOB, u16); // Also tests UsefulOutBuf_InsertUint16
UsefulOutBuf_AppendByte(&UOB, u8);
UsefulOutBuf_AppendFloat(&UOB, f); // Also tests UsefulOutBuf_InsertFloat
UsefulOutBuf_AppendDouble(&UOB, d); // Also tests UsefulOutBuf_InsertDouble
-
- UsefulBufC O = UsefulOutBuf_OutUBuf(&UOB);
+
+ const UsefulBufC O = UsefulOutBuf_OutUBuf(&UOB);
if(UsefulBuf_IsNULLC(O))
return "Couldn't output integers";
-
+
// from https://en.wikipedia.org/wiki/Endianness
const uint8_t pExpectedNetworkOrder[4] = {0x0A, 0x0B, 0x0C, 0x0D};
if(memcmp(O.ptr, pExpectedNetworkOrder, 4)) {
return "not in network order";
}
-
+
UsefulInputBuf UIB;
-
+
UsefulInputBuf_Init(&UIB, O);
-
+
if(UsefulInputBuf_Tell(&UIB) != 0) {
return "UsefulInputBuf_Tell failed";
}
-
+
if(UsefulInputBuf_GetUint32(&UIB) != u32) {
return "u32 out then in failed";
}
@@ -620,15 +620,15 @@
// Reset and go again for a few more tests
UsefulInputBuf_Init(&UIB, O);
-
- UsefulBufC Four = UsefulInputBuf_GetUsefulBuf(&UIB, 4);
+
+ const UsefulBufC Four = UsefulInputBuf_GetUsefulBuf(&UIB, 4);
if(UsefulBuf_IsNULLC(Four)) {
return "Four is NULL";
}
if(UsefulBuf_Compare(Four, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pExpectedNetworkOrder))) {
return "Four compare failed";
}
-
+
if(UsefulInputBuf_BytesUnconsumed(&UIB) != 23){
return "Wrong number of unconsumed bytes";
}
@@ -640,28 +640,28 @@
if(UsefulInputBuf_BytesAvailable(&UIB, 24)){
return "Wrong number of bytes available II";
}
-
+
UsefulInputBuf_Seek(&UIB, 0);
-
+
if(UsefulInputBuf_GetError(&UIB)) {
return "unexpected error after seek";
}
-
+
const uint8_t *pGetBytes = (const uint8_t *)UsefulInputBuf_GetBytes(&UIB, 4);
if(pGetBytes == NULL) {
return "GetBytes returns NULL";
}
-
+
if(memcmp(pGetBytes, pExpectedNetworkOrder, 4)) {
return "Got wrong bytes";
}
-
+
UsefulInputBuf_Seek(&UIB, 28);
if(!UsefulInputBuf_GetError(&UIB)) {
return "expected error after seek";
}
-
+
return NULL;
}
@@ -675,15 +675,15 @@
if(UsefulBufUtil_CopyDoubleToUint64(4e-40F) != 0X37C16C2800000000ULL) {
return "CopyDoubleToUint64 failed";
}
-
+
if(UsefulBufUtil_CopyUint64ToDouble(0X37C16C2800000000ULL) != 4e-40F) {
return "CopyUint64ToDouble failed";
}
-
+
if(UsefulBufUtil_CopyUint32ToFloat(0x47800000) != 65536.0F) {
return "CopyUint32ToFloat failed";
}
-
+
return NULL;
}
diff --git a/test/UsefulBuf_Tests.h b/test/UsefulBuf_Tests.h
index 649d6a8..976de62 100644
--- a/test/UsefulBuf_Tests.h
+++ b/test/UsefulBuf_Tests.h
@@ -2,7 +2,7 @@
Copyright (c) 2016-2018, The Linux Foundation.
Copyright (c) 2018, Laurence Lundblade.
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
@@ -16,7 +16,7 @@
contributors, nor the name "Laurence Lundblade" may be used to
endorse or promote products derived from this software without
specific prior written permission.
-
+
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
diff --git a/test/float_tests.c b/test/float_tests.c
index 2b472f3..7bc23aa 100644
--- a/test/float_tests.c
+++ b/test/float_tests.c
@@ -3,7 +3,7 @@
Copyright (c) 2018, Laurence Lundblade.
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
@@ -16,7 +16,7 @@
* The name "Laurence Lundblade" may not be used to
endorse or promote products derived from this software without
specific prior written permission.
-
+
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
@@ -86,17 +86,17 @@
0xF9, 0x7E, 0x0F, // qNaN with payload 0x0f
0x07,
0xF9, 0x7C, 0x0F, // sNaN with payload 0x0f
-
+
};
int HalfPrecisionDecodeBasicTests()
{
UsefulBufC HalfPrecision = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedHalf);
-
+
QCBORDecodeContext DC;
QCBORDecode_Init(&DC, HalfPrecision, 0);
-
+
QCBORItem Item;
QCBORDecode_GetNext(&DC, &Item);
@@ -108,7 +108,7 @@
if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.0F) {
return -2;
}
-
+
QCBORDecode_GetNext(&DC, &Item);
if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != INFINITY) {
return -3;
@@ -128,7 +128,7 @@
if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 1.0F) {
return -6;
}
-
+
QCBORDecode_GetNext(&DC, &Item);
if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.333251953125F) {
return -7;
@@ -143,7 +143,7 @@
if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != INFINITY) {
return -9;
}
-
+
QCBORDecode_GetNext(&DC, &Item); // TODO: check this
if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.0000000596046448F) {
return -10;
@@ -158,17 +158,17 @@
if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.0000610351563F) {
return -12;
}
-
- QCBORDecode_GetNext(&DC, &Item);
+
+ QCBORDecode_GetNext(&DC, &Item);
if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0) {
return -13;
}
-
+
QCBORDecode_GetNext(&DC, &Item);
if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != -2.0F) {
return -14;
}
-
+
// TODO: double check these four tests
QCBORDecode_GetNext(&DC, &Item); // qNaN
if(Item.uDataType != QCBOR_TYPE_DOUBLE || UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum) != 0x7ff8000000000000ULL) {
@@ -190,7 +190,7 @@
if(QCBORDecode_Finish(&DC)) {
return -19;
}
-
+
return 0;
}
@@ -204,12 +204,12 @@
x[1] = uHalfP & 0xff;
x[0] = uHalfP >> 8;
double d = decode_half(x);
-
+
// Contruct the CBOR for the half-precision float by hand
UsefulBuf_MAKE_STACK_UB(__xx, 3);
UsefulOutBuf UOB;
UsefulOutBuf_Init(&UOB, __xx);
-
+
const uint8_t uHalfPrecInitialByte = HALF_PREC_FLOAT + (CBOR_MAJOR_TYPE_SIMPLE << 5); // 0xf9
UsefulOutBuf_AppendByte(&UOB, uHalfPrecInitialByte); // The initial byte for a half-precision float
UsefulOutBuf_AppendUint16(&UOB, (uint16_t)uHalfP);
@@ -217,16 +217,16 @@
// Now parse the hand-constructed CBOR. This will invoke the conversion to a float
QCBORDecodeContext DC;
QCBORDecode_Init(&DC, UsefulOutBuf_OutUBuf(&UOB), 0);
-
+
QCBORItem Item;
-
+
QCBORDecode_GetNext(&DC, &Item);
if(Item.uDataType != QCBOR_TYPE_DOUBLE) {
return -1;
}
-
+
//printf("%04x QCBOR:%15.15f RFC: %15.15f (%8x)\n", uHalfP,Item.val.fnum, d , UsefulBufUtil_CopyFloatToUint32(d));
-
+
if(isnan(d)) {
// The RFC code uses the native instructions which may or may not
// handle sNaN, qNaN and NaN payloads correctly. This test just
@@ -315,11 +315,11 @@
int DoubleAsSmallestTest()
{
UsefulBuf_MAKE_STACK_UB(EncodedHalfsMem, 420);
-
+
#define QCBOREncode_AddDoubleAsSmallestToMap QCBOREncode_AddDoubleToMap
#define QCBOREncode_AddDoubleAsSmallestToMapN QCBOREncode_AddDoubleToMapN
-
+
QCBOREncodeContext EC;
QCBOREncode_Init(&EC, EncodedHalfsMem);
// These are mostly from https://en.wikipedia.org/wiki/Half-precision_floating-point_format
@@ -333,34 +333,34 @@
// 7A65726F # "negative zero"
// F9 8000 # primitive(0)
QCBOREncode_AddDoubleAsSmallestToMap(&EC, "negative zero", -0.00);
-
+
// 6A # text(10)
// 696E66696E6974697479 # "infinitity"
// F9 7C00 # primitive(31744)
QCBOREncode_AddDoubleAsSmallestToMap(&EC, "infinitity", INFINITY);
-
+
// 73 # text(19)
// 6E6567617469766520696E66696E6974697479 # "negative infinitity"
// F9 FC00 # primitive(64512)
QCBOREncode_AddDoubleAsSmallestToMap(&EC, "negative infinitity", -INFINITY);
-
+
// 63 # text(3)
// 4E614E # "NaN"
// F9 7E00 # primitive(32256)
QCBOREncode_AddDoubleAsSmallestToMap(&EC, "NaN", NAN);
-
+
// TODO: test a few NaN variants
-
+
// 63 # text(3)
// 6F6E65 # "one"
// F9 3C00 # primitive(15360)
QCBOREncode_AddDoubleAsSmallestToMap(&EC, "one", 1.0);
-
+
// 69 # text(9)
// 6F6E65207468697264 # "one third"
// F9 3555 # primitive(13653)
QCBOREncode_AddDoubleAsSmallestToMap(&EC, "one third", 0.333251953125);
-
+
// 76 # text(22)
// 6C6172676573742068616C662D707265636973696F6E # "largest half-precision"
// F9 7BFF # primitive(31743)
@@ -370,20 +370,20 @@
// 6C6172676573742068616C662D707265636973696F6E # "largest half-precision"
// F9 7BFF # primitive(31743)
QCBOREncode_AddDoubleAsSmallestToMap(&EC, "largest half-precision point one",65504.1);
-
+
// Float 65536.0F is 0x47800000 in hex. It has an exponent of 16, which is larger than 15, the largest half-precision exponent
// 78 18 # text(24)
// 746F6F2D6C617267652068616C662D707265636973696F6E # "too-large half-precision"
// FA 47800000 # primitive(31743)
QCBOREncode_AddDoubleAsSmallestToMap(&EC, "too-large half-precision", 65536.0);
-
+
// The smallest possible half-precision subnormal, but digitis are lost converting
// to half, so this turns into a double
// 72 # text(18)
// 736D616C6C657374207375626E6F726D616C # "smallest subnormal"
// FB 3E700000001C5F68 # primitive(4499096027744984936)
QCBOREncode_AddDoubleAsSmallestToMap(&EC, "smallest subnormal", 0.0000000596046448);
-
+
// The smallest possible half-precision snormal, but digitis are lost converting
// to half, so this turns into a single TODO: confirm this is right
// 6F # text(15)
@@ -391,22 +391,22 @@
// FA 387FFFFF # primitive(947912703)
// in hex single is 0x387fffff, exponent -15, significand 7fffff
QCBOREncode_AddDoubleAsSmallestToMap(&EC, "smallest normal", 0.0000610351526F);
-
+
// 71 # text(17)
// 62696767657374207375626E6F726D616C # "biggest subnormal"
// F9 0400 # primitive(1024)
// in hex single is 0x38800000, exponent -14, significand 0
QCBOREncode_AddDoubleAsSmallestToMap(&EC, "biggest subnormal", 0.0000610351563F);
-
+
// 70 # text(16)
// 7375626E6F726D616C2073696E676C65 # "subnormal single"
// FB 37C16C2800000000 # primitive(4017611261645684736)
QCBOREncode_AddDoubleAsSmallestToMap(&EC, "subnormal single", 4e-40F);
-
+
// 03 # unsigned(3)
// F9 C000 # primitive(49152)
QCBOREncode_AddDoubleAsSmallestToMapN(&EC, 3, -2.0);
-
+
// 70 # text(16)
// 6C617267652073696E676C6520657870 # "large single exp"
// FA 7F400000 # primitive(2134900736)
@@ -423,27 +423,27 @@
// 646664666465 # "dfdfde"
// FA 4B800000 # primitive(1266679808)
QCBOREncode_AddDoubleAsSmallestToMap(&EC, "biggest single with prec",16777216); // Single with no precision loss
-
+
// 78 18 # text(24)
// 626967676573742073696E676C6520776974682070726563 # "biggest single with prec"
// FA 4B800000 # primitive(1266679808)
QCBOREncode_AddDoubleAsSmallestToMap(&EC, "first single with prec loss",16777217); // Double becuase of precision loss
-
+
// Just a convenient marker when cutting and pasting encoded CBOR
QCBOREncode_AddSZStringToMapN(&EC, 1, "fin");
QCBOREncode_CloseMap(&EC);
-
+
UsefulBufC EncodedHalfs;
int nReturn = QCBOREncode_Finish(&EC, &EncodedHalfs);
if(nReturn) {
return -1;
}
-
+
if(UsefulBuf_Compare(EncodedHalfs, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedSmallest))) {
return -3;
}
-
+
return 0;
}
@@ -474,20 +474,20 @@
double dqNaN = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | DOUBLE_QUIET_NAN_BIT);
double dsNaN = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | 0x01);
double dqNaNPayload = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | DOUBLE_QUIET_NAN_BIT | 0xf00f);
-
+
float f1 = (float)dqNaN;
float f2 = (float)dsNaN;
float f3 = (float)dqNaNPayload;
-
-
+
+
uint32_t uqNaN = UsefulBufUtil_CopyFloatToUint32((float)dqNaN);
uint32_t usNaN = UsefulBufUtil_CopyFloatToUint32((float)dsNaN);
uint32_t uqNaNPayload = UsefulBufUtil_CopyFloatToUint32((float)dqNaNPayload);
-
+
// Result of this on x86 is that every NaN is a qNaN. The intel
// CVTSD2SS instruction ignores the NaN payload and even converts
// a sNaN to a qNaN.
-
+
return 0;
}
#endif
diff --git a/test/float_tests.h b/test/float_tests.h
index 6bc0af1..ffd8aac 100644
--- a/test/float_tests.h
+++ b/test/float_tests.h
@@ -3,7 +3,7 @@
Copyright (c) 2018, Laurence Lundblade.
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
@@ -16,7 +16,7 @@
* The name "Laurence Lundblade" may not be used to
endorse or promote products derived from this software without
specific prior written permission.
-
+
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
diff --git a/test/half_to_double_from_rfc7049.c b/test/half_to_double_from_rfc7049.c
index 68d03cb..6380e51 100644
--- a/test/half_to_double_from_rfc7049.c
+++ b/test/half_to_double_from_rfc7049.c
@@ -1,8 +1,8 @@
/*
-
+
Copyright (c) 2013 IETF Trust and the persons identified as the
document authors. All rights reserved.
-
+
This document is subject to BCP 78 and the IETF Trust's Legal
Provisions Relating to IETF Documents
(http://trustee.ietf.org/license-info) in effect on the date of
@@ -12,7 +12,7 @@
include Simplified BSD License text as described in Section 4.e of
the Trust Legal Provisions and are provided without warranty as
described in the Simplified BSD License.
-
+
*/
/*
@@ -20,13 +20,13 @@
because:
a) it adds a dependency on <math.h> and ldexp().
b) the license may be an issue
-
+
QCBOR does support half-precision, but rather than using
floating point math like this, it does it with bit shifting
and masking.
-
+
This code is here to test that code.
-
+
*/
#include "half_to_double_from_rfc7049.h"
diff --git a/test/half_to_double_from_rfc7049.h b/test/half_to_double_from_rfc7049.h
index c8b2a06..a971c6c 100644
--- a/test/half_to_double_from_rfc7049.h
+++ b/test/half_to_double_from_rfc7049.h
@@ -1,11 +1,11 @@
/*==============================================================================
-
+
Copyright (c) 2018, Laurence Lundblade.
All rights reserved.
-
+
Copyright (c) 2018, Laurence Lundblade.
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
@@ -18,7 +18,7 @@
* The name "Laurence Lundblade" may not be used to
endorse or promote products derived from this software without
specific prior written permission.
-
+
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
diff --git a/test/qcbor_decode_malloc_tests.c b/test/qcbor_decode_malloc_tests.c
deleted file mode 100644
index ea6be04..0000000
--- a/test/qcbor_decode_malloc_tests.c
+++ /dev/null
@@ -1,126 +0,0 @@
-/*==============================================================================
-
- Copyright (c) 2018, Laurence Lundblade.
- All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the following
- disclaimer in the documentation and/or other materials provided
- with the distribution.
- * The name "Laurence Lundblade" may not be used to
- endorse or promote products derived from this software without
- specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
-WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
-BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
-OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
-IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- ==============================================================================*/
-
-#include "qcbor_decode_malloc_tests.h"
-#include "qcbor.h"
-#include <stdlib.h>
-
-
-/*
- {"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"}
- }
- */
-
-static uint8_t pValidMapEncoded[] = {
- 0xa3, 0x6d, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x18, 0x2a,
- 0x77, 0x61, 0x6e, 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x6f, 0x66, 0x20, 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 } ;
-
-
-#define UNCONST_POINTER(ptr) ((void *)(ptr))
-
-
-int MallocAllStringsTest()
-{
- QCBORDecodeContext DC;
-
- // Next parse, save pointers to a few strings, destroy original and see all is OK.
- UsefulBuf_MAKE_STACK_UB(CopyOfStorage, 160);
- UsefulBufC CopyOf = UsefulBuf_Copy(CopyOfStorage, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded));
-
- QCBORDecode_Init(&DC, CopyOf, QCBOR_DECODE_MODE_NORMAL);
- QCBORStringAllocator *pAlloc = QCBORDecode_MakeMallocStringAllocator();
- QCBORDecode_SetUpAllocator(&DC, pAlloc, true);
-
-
- int nCBORError;
- QCBORItem Item1, Item2, Item3, Item4;
- if((nCBORError = QCBORDecode_GetNext(&DC, &Item1)))
- return nCBORError;
- if(Item1.uDataType != QCBOR_TYPE_MAP ||
- Item1.val.uCount != 3)
- return -1;
- if((nCBORError = QCBORDecode_GetNext(&DC, &Item1)))
- return nCBORError;
- if((nCBORError = QCBORDecode_GetNext(&DC, &Item2)))
- return nCBORError;
- if((nCBORError = QCBORDecode_GetNext(&DC, &Item3)))
- return nCBORError;
- if((nCBORError = QCBORDecode_GetNext(&DC, &Item4)))
- return nCBORError;
-
- UsefulBuf_Set(CopyOfStorage, '_');
-
- if(Item1.uLabelType != QCBOR_TYPE_TEXT_STRING ||
- Item1.label.string.len != 13 ||
- Item1.uDataType != QCBOR_TYPE_INT64 ||
- Item1.val.int64 != 42 ||
- memcmp(Item1.label.string.ptr, "first integer", 13))
- return -1;
-
- if(Item2.uLabelType != QCBOR_TYPE_TEXT_STRING ||
- Item2.label.string.len != 23 ||
- memcmp(Item2.label.string.ptr, "an array of two strings", 23) ||
- Item2.uDataType != QCBOR_TYPE_ARRAY ||
- Item2.val.uCount != 2)
- return -1;
-
- if(Item3.uDataType != QCBOR_TYPE_TEXT_STRING ||
- Item3.val.string.len != 7 ||
- memcmp(Item3.val.string.ptr, "string1", 7))
- return -1;
-
- if(Item4.uDataType != QCBOR_TYPE_TEXT_STRING ||
- Item4.val.string.len != 7 ||
- memcmp(Item4.val.string.ptr, "string2", 7))
- return -1;
-
- (void)QCBORDecode_Finish(&DC);
-
- free(UNCONST_POINTER(Item1.label.string.ptr));
- free(UNCONST_POINTER(Item2.label.string.ptr));
- free(UNCONST_POINTER(Item3.val.string.ptr));
- free(UNCONST_POINTER(Item4.val.string.ptr));
-
- return 0;
-}
diff --git a/test/qcbor_decode_malloc_tests.h b/test/qcbor_decode_malloc_tests.h
deleted file mode 100644
index 9682f26..0000000
--- a/test/qcbor_decode_malloc_tests.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*==============================================================================
-
- Copyright (c) 2018, Laurence Lundblade.
- All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the following
- disclaimer in the documentation and/or other materials provided
- with the distribution.
- * The name "Laurence Lundblade" may not be used to
- endorse or promote products derived from this software without
- specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
-WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
-BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
-OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
-IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- ==============================================================================*/
-#ifndef qcbor_decode_malloc_tests_h
-#define qcbor_decode_malloc_tests_h
-
-int MallocAllStringsTest(void);
-
-#endif /* qcbor_decode_malloc_tests_h */
diff --git a/test/qcbor_decode_tests.c b/test/qcbor_decode_tests.c
index f1b5dbf..3fe705c 100644
--- a/test/qcbor_decode_tests.c
+++ b/test/qcbor_decode_tests.c
@@ -2,7 +2,7 @@
Copyright (c) 2016-2018, The Linux Foundation.
Copyright (c) 2018, Laurence Lundblade.
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
@@ -16,7 +16,7 @@
contributors, nor the name "Laurence Lundblade" may be used to
endorse or promote products derived from this software without
specific prior written permission.
-
+
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
@@ -32,32 +32,34 @@
#include "qcbor.h"
#include "qcbor_decode_tests.h"
-#include <stdio.h>
-#include <strings.h>
+#include <string.h>
#include <math.h> // for fabs()
#include <stdlib.h>
+#ifdef PRINT_FUNCTIONS_FOR_DEBUGGING
+#include <stdio.h>
-// TODO: test other than the normal decoder mode
-
-static void printencoded(const char *szLabel, const uint8_t *pEncoded, size_t nLen)
+static void PrintUsefulBufC(const char *szLabel, UsefulBufC Buf)
{
if(szLabel) {
printf("%s ", szLabel);
}
size_t i;
- for(i = 0; i < nLen; i++) {
- uint8_t Z = pEncoded[i];
+ for(i = 0; i < Buf.len; i++) {
+ uint8_t Z = ((uint8_t *)Buf.ptr)[i];
printf("%02x ", Z);
}
printf("\n");
-
+
fflush(stdout);
}
-
-// TODO: -- add a test for counting the top level items and adding it back in with AddRaw()
+/*static void printencoded(const char *szLabel, const uint8_t *pEncoded, size_t nLen)
+{
+ PrintUsefulBufC(szLabel, (UsefulBufC){pEncoded, nLen});
+}*/
+#endif
static const uint8_t spExpectedEncodedInts[] = {
@@ -93,7 +95,7 @@
{
QCBORItem Item;
int nCBORError;
-
+
if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_ARRAY)
@@ -110,165 +112,165 @@
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != -4294967297)
return -1;
-
+
if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != -4294967296)
return -1;
-
+
if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != -4294967295)
return -1;
-
+
if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != -4294967294)
return -1;
-
-
+
+
if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != -2147483648)
return -1;
-
+
if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != -2147483647)
return -1;
-
+
if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != -65538)
return -1;
-
+
if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != -65537)
return -1;
-
+
if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != -65536)
return -1;
-
+
if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != -65535)
return -1;
-
+
if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != -65534)
return -1;
-
+
if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != -257)
return -1;
-
+
if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != -256)
return -1;
-
+
if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != -255)
return -1;
-
+
if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != -254)
return -1;
-
-
+
+
if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != -25)
return -1;
-
+
if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != -24)
return -1;
-
+
if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != -23)
return -1;
-
+
if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != -1)
return -1;
-
+
if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != 0)
return -1;
-
+
if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != 0)
return -1;
-
+
if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != 1)
return -1;
-
+
if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != 22)
return -1;
-
+
if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != 23)
return -1;
-
+
if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != 24)
return -1;
-
+
if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
@@ -281,143 +283,143 @@
Item.val.int64 != 26)
return -1;
-
+
if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != 254)
return -1;
-
-
+
+
if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != 255)
return -1;
-
-
+
+
if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != 256)
return -1;
-
+
if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != 257)
return -1;
-
+
if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != 65534)
return -1;
-
+
if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != 65535)
return -1;
-
+
if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != 65536)
return -1;
-
+
if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != 65537)
return -1;
-
+
if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != 65538)
return -1;
-
+
if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != 2147483647)
return -1;
-
+
if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != 2147483647)
return -1;
-
+
if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != 2147483648)
return -1;
-
+
if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != 2147483649)
return -1;
-
+
if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != 4294967294)
return -1;
-
-
+
+
if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != 4294967295)
return -1;
-
-
+
+
if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != 4294967296)
return -1;
-
-
+
+
if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != 4294967297)
return -1;
-
-
+
+
if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != 9223372036854775807LL)
return -1;
-
-
+
+
if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_UINT64 ||
Item.val.uint64 != 18446744073709551615ULL)
return -1;
-
-
+
+
if(QCBORDecode_Finish(pDCtx) != QCBOR_SUCCESS) {
return -1;
}
-
+
return 0;
}
-/*
- Tests the decoding of lots of different integers sizes
+/*
+ Tests the decoding of lots of different integers sizes
and values.
*/
@@ -425,31 +427,31 @@
{
int n;
QCBORDecodeContext DCtx;
-
+
QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedEncodedInts), QCBOR_DECODE_MODE_NORMAL);
-
+
n = IntegerValuesParseTestInternal(&DCtx);
-
+
return(n);
}
/*
Creates a simple CBOR array and returns it in *pEncoded. The array is malloced
- and needs to be freed. This is used by several tests.
-
+ and needs to be freed. This is used by several tests.
+
Two of the inputs can be set. Two other items in the array are fixed.
-
+
*/
static int CreateSimpleArray(int nInt1, int nInt2, uint8_t **pEncoded, size_t *pEncodedLen)
{
QCBOREncodeContext ECtx;
int nReturn = -1;
-
+
*pEncoded = NULL;
*pEncodedLen = INT32_MAX;
-
+
// loop runs CBOR encoding twice. First with no buffer to
// calucate the length so buffer can be allocated correctly,
// and last with the buffer to do the actual encoding
@@ -461,7 +463,7 @@
QCBOREncode_AddBytes(&ECtx, ((UsefulBufC) {"galactic", 8}));
QCBOREncode_AddBytes(&ECtx, ((UsefulBufC) {"haven token", 11}));
QCBOREncode_CloseArray(&ECtx);
-
+
UsefulBufC Encoded;
if(QCBOREncode_Finish(&ECtx, &Encoded))
goto Done;
@@ -476,22 +478,25 @@
nReturn = -1;
goto Done;
}
-
+
} while(1);
Done:
return (nReturn);
-
+
}
/*
{"first integer": 42,
- "an array of two strings": ["string1", "string2"],
+ "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"}
+ "another int": 98,
+ "text 2": "lies, damn lies and statistics"
+ }
}
*/
@@ -518,37 +523,37 @@
QCBORDecodeContext DCtx;
QCBORItem Item;
int nReturn = -1; // assume error until success
-
+
QCBORDecode_Init(&DCtx, (UsefulBufC){pEncoded, nLen}, QCBOR_DECODE_MODE_NORMAL);
-
+
// Make sure the first thing is a map
if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || Item.uDataType != QCBOR_TYPE_ARRAY)
goto Done;
-
+
// First integer
- if(QCBORDecode_GetNext(&DCtx, &Item) != 0 | Item.uDataType != QCBOR_TYPE_INT64)
+ if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || Item.uDataType != QCBOR_TYPE_INT64)
goto Done;
*pInt1 = Item.val.int64;
-
+
// Second integer
if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || Item.uDataType != QCBOR_TYPE_INT64)
goto Done;
*pInt2 = Item.val.int64;
-
+
// First string
if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || Item.uDataType != QCBOR_TYPE_BYTE_STRING)
goto Done;
*pBuf3 = Item.val.string.ptr;
*pBuf3Len = Item.val.string.len;
-
+
// Second string
if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || Item.uDataType != QCBOR_TYPE_BYTE_STRING)
goto Done;
*pBuf4 = Item.val.string.ptr;
*pBuf4Len = Item.val.string.len;
-
+
nReturn = 0;
-
+
Done:
return(nReturn);
}
@@ -560,28 +565,27 @@
{
uint8_t *pEncoded;
size_t nEncodedLen;
-
+
int64_t i1, i2;
size_t i3, i4;
const uint8_t *s3, *s4;
-
-
+
+
if(CreateSimpleArray(23, 6000, &pEncoded, &nEncodedLen) < 0) {
return(-1);
}
-
+
ParseOrderedArray(pEncoded, nEncodedLen, &i1, &i2, &s3, &i3, &s4, &i4);
-
+
if(i1 != 23 ||
i2 != 6000 ||
i3 != 8 ||
i4 != 11 ||
memcmp("galactic", s3, 8) !=0 ||
memcmp("haven token", s4, 11) !=0) {
- printf("SimpleArraryTest Failed\n");
return(-1);
}
-
+
return(0);
}
@@ -594,12 +598,12 @@
QCBORDecodeContext DCtx;
int nReturn = 0;
int i;
-
+
QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spDeepArrays), QCBOR_DECODE_MODE_NORMAL);
-
+
for(i = 0; i < 10; i++) {
QCBORItem Item;
-
+
if(QCBORDecode_GetNext(&DCtx, &Item) != 0 ||
Item.uDataType != QCBOR_TYPE_ARRAY ||
Item.uNestingLevel != i) {
@@ -607,7 +611,7 @@
break;
}
}
-
+
return(nReturn);
}
@@ -623,12 +627,12 @@
int nReturn = 0;
int i;
QCBORItem Item;
-
-
+
+
QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTooDeepArrays), QCBOR_DECODE_MODE_NORMAL);
-
+
for(i = 0; i < QCBOR_MAX_ARRAY_NESTING1; i++) {
-
+
if(QCBORDecode_GetNext(&DCtx, &Item) != 0 ||
Item.uDataType != QCBOR_TYPE_ARRAY ||
Item.uNestingLevel != i) {
@@ -636,10 +640,10 @@
break;
}
}
-
+
if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_ARRAY_NESTING_TOO_DEEP)
nReturn = -1;
-
+
return(nReturn);
}
@@ -651,16 +655,16 @@
int nResult = 0;
QCBORDecodeContext DCtx;
int num;
-
+
for(num = sizeof(spExpectedEncodedInts)-1; num; num--) {
int n;
-
+
QCBORDecode_Init(&DCtx, (UsefulBufC){spExpectedEncodedInts, num}, QCBOR_DECODE_MODE_NORMAL);
-
+
n = IntegerValuesParseTestInternal(&DCtx);
-
+
//printf("Len %d, result: %d\n", num, n);
-
+
if(n != QCBOR_ERR_HIT_END) {
nResult = -1;
goto Done;
@@ -677,26 +681,24 @@
uint8_t *pEncoded;
int nReturn;
size_t nEncodedLen;
-
+
int64_t i1, i2;
size_t i3, i4;
const uint8_t *s3, *s4;
-
+
nReturn = 0;
-
+
if(CreateSimpleArray(23, 6000, &pEncoded, &nEncodedLen) < 0) {
return(-1);
}
-
- //printencoded(pEncoded, nEncodedLen);
-
+
for(nEncodedLen--; nEncodedLen; nEncodedLen--) {
int nResult = ParseOrderedArray(pEncoded, (uint32_t)nEncodedLen, &i1, &i2, &s3, &i3, &s4, &i4);
if(nResult == 0) {
nReturn = -1;
}
}
-
+
return(nReturn);
}
@@ -704,131 +706,334 @@
Decode and thoroughly check a moderately complex
set of maps
*/
-static int ParseMapTest1()
+static int ParseMapTest1(QCBORDecodeMode nMode)
{
QCBORDecodeContext DCtx;
QCBORItem Item;
int nCBORError;
-
- QCBORDecode_Init(&DCtx, (UsefulBufC){pValidMapEncoded, sizeof(pValidMapEncoded)}, QCBOR_DECODE_MODE_NORMAL);
-
- if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+
+ QCBORDecode_Init(&DCtx, (UsefulBufC){pValidMapEncoded, sizeof(pValidMapEncoded)}, nMode);
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
return nCBORError;
+ }
if(Item.uDataType != QCBOR_TYPE_MAP ||
Item.val.uCount != 3)
return -1;
-
- if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
return nCBORError;
+ }
if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
- Item.label.string.len != 13 ||
Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != 42 ||
Item.uDataAlloc ||
Item.uLabelAlloc ||
- memcmp(Item.label.string.ptr, "first integer", 13))
+ UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("first integer"))) {
return -1;
-
- if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+ }
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
return nCBORError;
+ }
if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
- Item.label.string.len != 23 ||
Item.uDataAlloc ||
Item.uLabelAlloc ||
- memcmp(Item.label.string.ptr, "an array of two strings", 23) ||
+ UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("an array of two strings")) ||
Item.uDataType != QCBOR_TYPE_ARRAY ||
Item.val.uCount != 2)
return -1;
-
- if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
return nCBORError;
+ }
if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
- Item.val.string.len != 7 ||
Item.uDataAlloc ||
Item.uLabelAlloc ||
- memcmp(Item.val.string.ptr, "string1", 7))
+ UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("string1"))) {
return -1;
-
- if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+ }
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
return nCBORError;
+ }
if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
- Item.val.string.len != 7 ||
Item.uDataAlloc ||
Item.uLabelAlloc ||
- memcmp(Item.val.string.ptr, "string2", 7))
+ UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("string2"))) {
return -1;
-
- if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+ }
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
return nCBORError;
+ }
if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
- Item.label.string.len != 12 ||
Item.uDataAlloc ||
Item.uLabelAlloc ||
- memcmp(Item.label.string.ptr, "map in a map", 12) ||
+ UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("map in a map")) ||
Item.uDataType != QCBOR_TYPE_MAP ||
- Item.val.uCount != 4)
+ Item.val.uCount != 4) {
return -1;
-
- if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+ }
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
return nCBORError;
+ }
if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
- Item.label.string.len != 7 ||
- memcmp(Item.label.string.ptr, "bytes 1", 7)||
+ UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("bytes 1"))||
Item.uDataType != QCBOR_TYPE_BYTE_STRING ||
- Item.val.string.len != 4 ||
Item.uDataAlloc ||
Item.uLabelAlloc ||
- memcmp(Item.val.string.ptr, "xxxx", 4))
+ UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("xxxx"))) {
return -1;
-
- if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+ }
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
return nCBORError;
+ }
if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
- Item.label.string.len != 7 ||
- memcmp(Item.label.string.ptr, "bytes 2", 7) ||
+ UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("bytes 2")) ||
Item.uDataType != QCBOR_TYPE_BYTE_STRING ||
- Item.val.string.len != 4 ||
Item.uDataAlloc ||
Item.uLabelAlloc ||
- memcmp(Item.val.string.ptr, "yyyy", 4))
+ UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("yyyy"))) {
return -1;
-
- if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+ }
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
return nCBORError;
+ }
if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
- Item.label.string.len != 11 ||
Item.uDataAlloc ||
Item.uLabelAlloc ||
- memcmp(Item.label.string.ptr, "another int", 11) ||
+ UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("another int")) ||
Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != 98)
return -1;
-
- if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
return nCBORError;
+ }
if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
- Item.label.string.len != 6 ||
- memcmp(Item.label.string.ptr, "text 2", 6)||
+ UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("text 2"))||
Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
- Item.val.string.len != 30 ||
Item.uDataAlloc ||
Item.uLabelAlloc ||
- memcmp(Item.val.string.ptr, "lies, damn lies and statistics", 30))
+ UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("lies, damn lies and statistics"))) {
return -1;
-
+ }
+
return 0;
}
+/*
+ Decode and thoroughly check a moderately complex
+ set of maps
+ */
+int ParseMapAsArrayTest()
+{
+ QCBORDecodeContext DCtx;
+ QCBORItem Item;
+ int nCBORError;
+
+ QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), QCBOR_DECODE_MODE_MAP_AS_ARRAY);
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return nCBORError;
+ }
+ if(Item.uDataType != QCBOR_TYPE_MAP_AS_ARRAY ||
+ Item.val.uCount != 6) {
+ return -1;
+ }
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return nCBORError;
+ }
+ if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+ Item.uDataAlloc ||
+ Item.uLabelAlloc ||
+ Item.uLabelType != QCBOR_TYPE_NONE ||
+ UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("first integer"))) {
+ return -2;
+ }
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return nCBORError;
+ }
+ if(Item.uLabelType != QCBOR_TYPE_NONE ||
+ Item.uDataType != QCBOR_TYPE_INT64 ||
+ Item.val.int64 != 42 ||
+ Item.uDataAlloc ||
+ Item.uLabelAlloc) {
+ return -3;
+ }
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return nCBORError;
+ }
+ if(Item.uLabelType != QCBOR_TYPE_NONE ||
+ Item.uDataAlloc ||
+ Item.uLabelAlloc ||
+ UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("an array of two strings")) ||
+ Item.uDataType != QCBOR_TYPE_TEXT_STRING) {
+ return -4;
+ }
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return nCBORError;
+ }
+ if(Item.uLabelType != QCBOR_TYPE_NONE ||
+ Item.uDataAlloc ||
+ Item.uLabelAlloc ||
+ Item.uDataType != QCBOR_TYPE_ARRAY ||
+ Item.val.uCount != 2) {
+ return -5;
+ }
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return nCBORError;
+ }
+ if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+ Item.val.string.len != 7 ||
+ Item.uDataAlloc ||
+ Item.uLabelAlloc ||
+ UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("string1"))) {
+ return -6;
+ }
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return nCBORError;
+ }
+ if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+ Item.uDataAlloc ||
+ Item.uLabelAlloc ||
+ UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("string2"))) {
+ return -7;
+ }
+
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return nCBORError;
+ }
+ if(Item.uLabelType != QCBOR_TYPE_NONE ||
+ Item.uDataAlloc ||
+ Item.uLabelAlloc ||
+ UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("map in a map"))) {
+ return -8;
+ }
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return nCBORError;
+ }
+ if(Item.uLabelType != QCBOR_TYPE_NONE ||
+ Item.uDataAlloc ||
+ Item.uLabelAlloc ||
+ Item.uDataType != QCBOR_TYPE_MAP_AS_ARRAY ||
+ Item.val.uCount != 8) {
+ return -9;
+ }
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return nCBORError;
+ }
+ if(Item.uLabelType != QCBOR_TYPE_NONE ||
+ UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("bytes 1"))||
+ Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+ Item.uDataAlloc ||
+ Item.uLabelAlloc) {
+ return -10;
+ }
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return nCBORError;
+ }
+ if(Item.uLabelType != QCBOR_TYPE_NONE ||
+ Item.uDataType != QCBOR_TYPE_BYTE_STRING ||
+ Item.uDataAlloc ||
+ Item.uLabelAlloc ||
+ UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("xxxx"))) {
+ return -11;
+ }
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return nCBORError;
+ }
+ if(Item.uLabelType != QCBOR_TYPE_NONE ||
+ UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("bytes 2")) ||
+ Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+ Item.uDataAlloc ||
+ Item.uLabelAlloc) {
+ return -12;
+ }
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return nCBORError;
+ }
+ if(Item.uLabelType != QCBOR_TYPE_NONE ||
+ Item.uDataType != QCBOR_TYPE_BYTE_STRING ||
+ Item.uDataAlloc ||
+ Item.uLabelAlloc ||
+ UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("yyyy"))) {
+ return -13;
+ }
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return nCBORError;
+ }
+ if(Item.uLabelType != QCBOR_TYPE_NONE ||
+ Item.uDataAlloc ||
+ Item.uLabelAlloc ||
+ UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("another int")) ||
+ Item.uDataType != QCBOR_TYPE_TEXT_STRING) {
+ return -14;
+ }
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return nCBORError;
+ }
+ if(Item.uLabelType != QCBOR_TYPE_NONE ||
+ Item.uDataAlloc ||
+ Item.uLabelAlloc ||
+ Item.uDataType != QCBOR_TYPE_INT64 ||
+ Item.val.int64 != 98) {
+ return -15;
+ }
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return nCBORError;
+ }
+ if(Item.uLabelType != QCBOR_TYPE_NONE ||
+ UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("text 2"))||
+ Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+ Item.uDataAlloc ||
+ Item.uLabelAlloc) {
+ return -16;
+ }
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
+ return nCBORError;
+ }
+ if(Item.uLabelType != QCBOR_TYPE_NONE ||
+ Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
+ Item.uDataAlloc ||
+ Item.uLabelAlloc ||
+ UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("lies, damn lies and statistics"))) {
+ return -17;
+ }
+
+ return 0;
+}
+
/*
Fully or partially decode pValidMapEncoded. When
partially decoding check for the right error code.
How much partial decoding depends on nLevel.
-
+
The partial decodes test error conditions of
incomplete encoded input.
-
+
This could be combined with the above test
and made prettier and maybe a little more
thorough.
@@ -838,9 +1043,9 @@
QCBORDecodeContext DCtx;
QCBORItem Item;
int nCBORError;
-
+
QCBORDecode_Init(&DCtx, (UsefulBufC){pValidMapEncoded, sizeof(pValidMapEncoded)}, QCBOR_DECODE_MODE_NORMAL);
-
+
if(nLevel < 1) {
if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_EXTRA_BYTES) {
return -1;
@@ -849,9 +1054,10 @@
}
}
-
- if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
return nCBORError;
+ }
if(Item.uDataType != QCBOR_TYPE_MAP ||
Item.val.uCount != 3)
return -1;
@@ -863,17 +1069,18 @@
return 0;
}
}
-
-
- if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
return nCBORError;
+ }
if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
- Item.label.string.len != 13 ||
Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.uCount != 42 ||
- memcmp(Item.label.string.ptr, "first integer", 13))
+ UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("first integer"))) {
return -1;
-
+ }
+
if(nLevel < 3) {
if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) {
return -1;
@@ -881,17 +1088,18 @@
return 0;
}
}
-
- if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
return nCBORError;
+ }
if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
- Item.label.string.len != 23 ||
- memcmp(Item.label.string.ptr, "an array of two strings", 23) ||
+ UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("an array of two strings")) ||
Item.uDataType != QCBOR_TYPE_ARRAY ||
- Item.val.uCount != 2)
+ Item.val.uCount != 2) {
return -1;
-
-
+ }
+
+
if(nLevel < 4) {
if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) {
return -1;
@@ -899,15 +1107,16 @@
return 0;
}
}
-
-
- if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
return nCBORError;
+ }
if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
- Item.val.string.len != 7 ||
- memcmp(Item.val.string.ptr, "string1", 7))
+ UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("string1"))) {
return -1;
-
+ }
+
if(nLevel < 5) {
if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) {
return -1;
@@ -915,14 +1124,15 @@
return 0;
}
}
-
- if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
return nCBORError;
+ }
if(Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
- Item.val.string.len != 7 ||
- memcmp(Item.val.string.ptr, "string2", 7))
+ UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("string2"))) {
return -1;
-
+ }
+
if(nLevel < 6) {
if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) {
return -1;
@@ -930,16 +1140,16 @@
return 0;
}
}
-
- if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
return nCBORError;
+ }
if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
- Item.label.string.len != 12 ||
- memcmp(Item.label.string.ptr, "map in a map", 12) ||
+ UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("map in a map")) ||
Item.uDataType != QCBOR_TYPE_MAP ||
Item.val.uCount != 4)
return -1;
-
+
if(nLevel < 7) {
if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) {
return -1;
@@ -947,17 +1157,17 @@
return 0;
}
}
-
- if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
return nCBORError;
+ }
if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
- Item.label.string.len != 7 ||
- memcmp(Item.label.string.ptr, "bytes 1", 7)||
+ UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("bytes 1")) ||
Item.uDataType != QCBOR_TYPE_BYTE_STRING ||
- Item.val.string.len != 4 ||
- memcmp(Item.val.string.ptr, "xxxx", 4))
+ UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("xxxx"))) {
return -1;
-
+ }
+
if(nLevel < 8) {
if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) {
return -1;
@@ -965,17 +1175,17 @@
return 0;
}
}
-
- if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
return nCBORError;
+ }
if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
- Item.label.string.len != 7 ||
- memcmp(Item.label.string.ptr, "bytes 2", 7) ||
+ UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("bytes 2")) ||
Item.uDataType != QCBOR_TYPE_BYTE_STRING ||
- Item.val.string.len != 4 ||
- memcmp(Item.val.string.ptr, "yyyy", 4))
+ UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("yyyy"))) {
return -1;
-
+ }
+
if(nLevel < 9) {
if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) {
return -1;
@@ -983,16 +1193,16 @@
return 0;
}
}
-
- if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
return nCBORError;
+ }
if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
- Item.label.string.len != 11 ||
- memcmp(Item.label.string.ptr, "another int", 11) ||
+ UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("another int")) ||
Item.uDataType != QCBOR_TYPE_INT64 ||
Item.val.int64 != 98)
return -1;
-
+
if(nLevel < 10) {
if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) {
return -1;
@@ -1000,21 +1210,21 @@
return 0;
}
}
-
- if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
+
+ if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) {
return nCBORError;
+ }
if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING ||
- Item.label.string.len != 6 ||
- memcmp(Item.label.string.ptr, "text 2", 6)||
+ UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("text 2"))||
Item.uDataType != QCBOR_TYPE_TEXT_STRING ||
- Item.val.string.len != 30 ||
- memcmp(Item.val.string.ptr, "lies, damn lies and statistics", 30))
+ UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("lies, damn lies and statistics"))) {
return -1;
-
+ }
+
if(QCBORDecode_Finish(&DCtx)) {
return -1;
}
-
+
return 0;
}
@@ -1024,8 +1234,10 @@
int ParseMapTest()
{
// Parse a moderatly complex map structure very thoroughl
- int n = ParseMapTest1();
-
+ int n = ParseMapTest1(QCBOR_DECODE_MODE_NORMAL);
+
+ n = ParseMapTest1(QCBOR_DECODE_MODE_MAP_STRINGS_ONLY);
+
if(!n) {
for(int i = 0; i < 10; i++) {
n = ExtraBytesTest(i);
@@ -1034,7 +1246,7 @@
}
}
}
-
+
return(n);
}
@@ -1046,17 +1258,17 @@
QCBORDecodeContext DCtx;
QCBORItem Item;
int nCBORError;
-
-
+
+
QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSimpleValues), QCBOR_DECODE_MODE_NORMAL);
-
-
+
+
if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_ARRAY ||
Item.val.uCount != 10)
return -1;
-
+
if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_FALSE)
@@ -1066,12 +1278,12 @@
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_TRUE)
return -1;
-
+
if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_NULL)
return -1;
-
+
if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_UNDEF)
@@ -1093,25 +1305,25 @@
if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_INVALID_CBOR)
return -1;
-
+
if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_INVALID_CBOR)
return -1;
if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_INVALID_CBOR)
return -1;
-
+
if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_UKNOWN_SIMPLE || Item.val.uSimple != 32)
return -1;
-
+
if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
return nCBORError;
if(Item.uDataType != QCBOR_TYPE_UKNOWN_SIMPLE || Item.val.uSimple != 255)
return -1;
-
+
return 0;
-
+
}
@@ -1148,29 +1360,19 @@
};
-void Dump(UsefulBufC Input, int x)
-{
- char label[10];
-
- sprintf(label, "%d", x);
-
- printencoded(label, Input.ptr, Input.len);
-}
-
-
int FailureTests()
{
int nResult = 0;
-
+
struct FailInput *pFEnd = &Failures[0] + sizeof(Failures)/sizeof(struct FailInput);
-
+
for(struct FailInput *pF = &Failures[0]; pF < pFEnd ;pF++) {
QCBORDecodeContext DCtx;
QCBORItem Item;
int nCBORError;
-
+
QCBORDecode_Init(&DCtx, pF->Input, QCBOR_DECODE_MODE_NORMAL);
-
+
while(1) {
nCBORError = QCBORDecode_GetNext(&DCtx, &Item);
if(QCBOR_ERR_HIT_END == nCBORError) {
@@ -1178,17 +1380,16 @@
}
if(nCBORError != pF->nError) {
nResult = 1;
- // Dump(pF->Input, nCBORError);
break;
}
}
}
-
+
{
QCBORDecodeContext DCtx;
QCBORItem Item;
int nCBORError;
-
+
QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSimpleValues), QCBOR_DECODE_MODE_NORMAL);
if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
@@ -1196,80 +1397,92 @@
if(Item.uDataType != QCBOR_TYPE_ARRAY ||
Item.val.uCount != 10)
return -1;
-
+
DCtx.InBuf.magic = 0; // Corrupt the UsefulInputBuf
-
+
nCBORError = QCBORDecode_GetNext(&DCtx, &Item);
if(nCBORError != QCBOR_ERR_HIT_END)
return -1;
}
-
-
+
+
return nResult;
}
-
-
-static void Recurser(uint8_t *pBuf, int nLen, int nLenMax)
+/* Try all 256 values of the byte at nLen including recursing for
+ each of the values to try values at nLen+1 ... up to nLenMax
+ */
+static void ComprehensiveInputRecurser(uint8_t *pBuf, int nLen, int nLenMax)
{
-
if(nLen >= nLenMax) {
return;
}
-
- //printf("__%d__%d__\n", nLen, nLenMax);
- for(int i = 0; i < 256; i++) {
- pBuf[nLen] = i;
+ for(int inputByte = 0; inputByte < 256; inputByte++) {
+ // Set up the input
+ pBuf[nLen] = inputByte;
+ const UsefulBufC Input = {pBuf, nLen+1};
+ // Get ready to parse
QCBORDecodeContext DCtx;
- QCBORItem Item;
- int nCBORError;
-
- UsefulBufC Input = {pBuf, nLen+1};
-
QCBORDecode_Init(&DCtx, Input, QCBOR_DECODE_MODE_NORMAL);
-
+
+ // Parse by getting the next item until an error occurs
+ // Just about every possible decoder error can occur here
+ // The goal of this test is not to check for the correct
+ // error since that is not really possible. It is to
+ // see that there is no crash on hostile input.
while(1) {
- nCBORError = QCBORDecode_GetNext(&DCtx, &Item);
- if(QCBOR_ERR_HIT_END == nCBORError) {
- break;
- }
+ QCBORItem Item;
+ QCBORError nCBORError = QCBORDecode_GetNext(&DCtx, &Item);
if(nCBORError != QCBOR_SUCCESS) {
- if(nCBORError != QCBOR_ERR_UNSUPPORTED && nCBORError != QCBOR_ERR_HIT_END && nCBORError != QCBOR_ERR_INVALID_CBOR) {
- //Dump(Input, nCBORError);
- }
break;
}
}
- //Dump(Input, -1);
-
- Recurser(pBuf, nLen+1, nLenMax);
+ ComprehensiveInputRecurser(pBuf, nLen+1, nLenMax);
}
}
/*
- Runs all possible input strings of a given length. This is set to 3 to make the test
- run in reasonable time.
- Main point of this test is to not crash.
+ Public function for initialization. See header qcbor.h
*/
-
int ComprehensiveInputTest()
{
- uint8_t pBuf[3]; // 3 keeps it running in reasonable time. 4 takes tens of minutes.
+ // Size 2 tests 64K inputs and runs quickly
+ uint8_t pBuf[2];
+
+ ComprehensiveInputRecurser(pBuf, 0, sizeof(pBuf));
+
+ return 0;
+}
+
+
+/*
+ Public function for initialization. See header qcbor.h
+ */
+int BigComprehensiveInputTest()
+{
+ // size 3 tests 16 million inputs and runs OK
+ // in seconds on fast machines. Size 4 takes
+ // 10+ minutes and 5 half a day on fast
+ // machines. This test is kept separate from
+ // the others so as to no slow down the use
+ // of them as a very frequent regression.
+ uint8_t pBuf[3]; //
- Recurser(pBuf, 0, sizeof(pBuf));
+ ComprehensiveInputRecurser(pBuf, 0, sizeof(pBuf));
return 0;
}
+
static uint8_t spDateTestInput[] = {
0xc0, // tag for string date
0x6a, '1','9','8','5','-','0','4','-','1','2', // Date string
-
+
0xc1, // tag for epoch date
0x1a, 0x53, 0x72, 0x4E, 0x00, // Epoch date 1400000000; Tue, 13 May 2014 16:53:20 GMT
@@ -1279,10 +1492,10 @@
0xc1, // tag for epoch date
0x1b, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // Too large integer
-
+
0xc1, // tag for epoch date
0xfa, 0x3f, 0x8c, 0xcc, 0xcd, // double with value 1.1
-
+
0xc1, // tag for epoch date
0xfa, 0x7f, 0x7f, 0xff, 0xff // 3.4028234663852886e+38 too large
@@ -1291,11 +1504,11 @@
// have to check float expected only to within an epsilon
int CHECK_EXPECTED_DOUBLE(double val, double expected) {
-
+
double diff = val - expected;
-
+
diff = fabs(diff);
-
+
return diff > 0.0000001;
}
@@ -1305,14 +1518,14 @@
QCBORDecodeContext DCtx;
QCBORItem Item;
int nCBORError;
-
+
QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spDateTestInput), QCBOR_DECODE_MODE_NORMAL);
-
+
const uint64_t uTags[] = {15};
QCBORTagListIn TagList = {1, uTags};
-
+
QCBORDecode_SetCallerConfiguredTagList(&DCtx, &TagList);
-
+
// String date
if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
return -1;
@@ -1329,7 +1542,7 @@
Item.val.epochDate.fSecondsFraction != 0 ) {
return -4;
}
-
+
// Epoch date with extra CBOR_TAG_B64 tag that doesn't really mean anything
// but want to be sure extra tag doesn't cause a problem
if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
@@ -1340,12 +1553,12 @@
!QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_B64)) {
return -6;
}
-
+
// Epoch date that is too large for our representation
if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_DATE_OVERFLOW) {
return -7;
}
-
+
// Epoch date in float format with fractional seconds
if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
return -8;
@@ -1354,12 +1567,12 @@
CHECK_EXPECTED_DOUBLE(Item.val.epochDate.fSecondsFraction, 0.1 )) {
return -9;
}
-
+
// Epoch date float that is too large for our representation
if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_DATE_OVERFLOW) {
return -10;
}
-
+
// TODO: could use a few more tests with float, double, and half precsion and negative (but coverage is still pretty good)
return 0;
@@ -1427,9 +1640,9 @@
{
QCBORDecodeContext DCtx;
QCBORItem Item;
-
+
QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spOptTestInput), QCBOR_DECODE_MODE_NORMAL);
-
+
//-------------------------
// This text matches the magic number tag and the fraction tag
if(QCBORDecode_GetNext(&DCtx, &Item)) {
@@ -1439,7 +1652,7 @@
!QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_CBOR_MAGIC)) {
return -3;
}
-
+
if(QCBORDecode_GetNext(&DCtx, &Item)) {
return -4;
}
@@ -1448,7 +1661,7 @@
Item.val.uCount != 2) {
return -5;
}
-
+
// --------------------------------
// This test decodes the very large tag, but it is not in
// any list so it is ignored.
@@ -1459,14 +1672,14 @@
if(Item.uTagBits) {
return -7;
}
-
+
// ----------------------------------
// This test sets up a caller-config list that includes the very large tage and then matches it.
QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spEncodedLargeTag), QCBOR_DECODE_MODE_NORMAL);
const uint64_t puList[] = {0x9192939495969798, 257};
const QCBORTagListIn TL = {2, puList};
QCBORDecode_SetCallerConfiguredTagList(&DCtx, &TL);
-
+
if(QCBORDecode_GetNext(&DCtx, &Item)) {
return -8;
}
@@ -1477,7 +1690,7 @@
Item.val.uCount != 0) {
return -9;
}
-
+
//------------------------
// This test sets up a caller-configured list, and looks up something not in it
const uint64_t puLongList[17] = {1,2,1};
@@ -1487,7 +1700,7 @@
if(QCBORDecode_GetNext(&DCtx, &Item)) {
return -11;
}
-
+
// -----------------------
// This tests retrievel of the full tag list
QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spLotsOfTags), QCBOR_DECODE_MODE_NORMAL);
@@ -1502,7 +1715,7 @@
puTags[3] != 0x04) {
return -13;
}
-
+
// ----------------------
// This text if too small of an out list
QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spLotsOfTags), QCBOR_DECODE_MODE_NORMAL);
@@ -1510,7 +1723,7 @@
if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &OutSmall) != QCBOR_ERR_TOO_MANY_TAGS) {
return -14;
}
-
+
// ---------------
// Parse a version of the "CSR" that has had a ton of tags randomly inserted
QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRWithTags), QCBOR_DECODE_MODE_NORMAL);
@@ -1518,15 +1731,15 @@
if(n) {
return n-2000;
}
-
+
Out = (QCBORTagListOut){0,16, puTags};
QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRWithTags), QCBOR_DECODE_MODE_NORMAL);
-
+
const uint64_t puTagList[] = {773, 1, 90599561};
const QCBORTagListIn TagList = {3, puTagList};
QCBORDecode_SetCallerConfiguredTagList(&DCtx, &TagList);
-
-
+
+
if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) {
return -100;
}
@@ -1541,7 +1754,7 @@
Out.uNumUsed != 3) {
return -101;
}
-
+
if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) {
return -102;
}
@@ -1555,7 +1768,7 @@
Out.uNumUsed != 2) {
return -103;
}
-
+
if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) {
return -104;
}
@@ -1566,7 +1779,7 @@
Out.uNumUsed != 1) {
return -105;
}
-
+
if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) {
return -106;
}
@@ -1579,7 +1792,7 @@
Out.uNumUsed != 3) {
return -105;
}
-
+
if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) {
return -107;
}
@@ -1590,7 +1803,7 @@
Out.uNumUsed != 1) {
return -108;
}
-
+
if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) {
return -109;
}
@@ -1602,7 +1815,7 @@
Out.uNumUsed != 12) {
return -110;
}
-
+
if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) {
return -111;
}
@@ -1613,7 +1826,7 @@
Out.uNumUsed != 1) {
return -112;
}
-
+
if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) {
return -111;
}
@@ -1635,7 +1848,7 @@
Out.uNumUsed != 1) {
return -114;
}
-
+
if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) {
return -115;
}
@@ -1668,7 +1881,7 @@
Out.uNumUsed != 1) {
return -119;
}
-
+
if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) {
return -120;
}
@@ -1679,7 +1892,7 @@
Out.uNumUsed != 1) {
return -121;
}
-
+
if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) {
return -122;
}
@@ -1690,17 +1903,17 @@
Out.uNumUsed != 1) {
return -123;
}
-
+
if(QCBORDecode_Finish(&DCtx)) {
return -124;
}
-
+
return 0;
}
-
+
static uint8_t spBigNumInput[] = {
0x83,
0xC2, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -1724,18 +1937,18 @@
QCBORDecodeContext DCtx;
QCBORItem Item;
int nCBORError;
-
+
QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNumInput), QCBOR_DECODE_MODE_NORMAL);
-
-
+
+
//
if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
return -1;
if(Item.uDataType != QCBOR_TYPE_ARRAY) {
return -1;
}
-
- //
+
+ //
if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
return -1;
if(Item.uDataType != QCBOR_TYPE_POSBIGNUM ||
@@ -1750,14 +1963,14 @@
UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){
return -1;
}
-
+
//
if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
return -1;
if(Item.uDataType != QCBOR_TYPE_MAP) {
return -1;
}
-
+
if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
return -1;
if(Item.uDataType != QCBOR_TYPE_POSBIGNUM ||
@@ -1774,7 +1987,7 @@
UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){
return -1;
}
-
+
if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
return -1;
if(Item.uDataType != QCBOR_TYPE_NEGBIGNUM ||
@@ -1782,7 +1995,7 @@
UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){
return -1;
}
-
+
if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
return -1;
if(Item.uDataType != QCBOR_TYPE_NEGBIGNUM ||
@@ -1791,7 +2004,7 @@
UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){
return -1;
}
-
+
return 0;
}
@@ -1801,7 +2014,7 @@
{
QCBORItem Item;
int nCBORError;
-
+
if((nCBORError = QCBORDecode_GetNext(pCtx, &Item))) return -1;
if(Item.uDataType != uDataType) return -1;
if(uNestingLevel > 0) {
@@ -1814,7 +2027,7 @@
}
if(Item.uNestingLevel != uNestingLevel) return -1;
if(Item.uNextNestLevel != uNextNest) return -1;
-
+
if(pItem) {
*pItem = Item;
}
@@ -1826,28 +2039,28 @@
static int CheckCSRMaps(QCBORDecodeContext *pDC)
{
if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 0, 1, 0, NULL)) return -1;
-
+
if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 1, 2, -23, NULL)) return -1;
-
+
if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 2, 3, -20, NULL)) return -1;
-
+
if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 3, -18, NULL)) return -1;
if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 3, -17, NULL)) return -1;
if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 3, -15, NULL)) return -1;
if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 3, -16, NULL)) return -1;
if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 2, -14, NULL)) return -1;
-
+
if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 2, 3, -19, NULL)) return -1;
if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 3, 4, -11, NULL)) return -1;
-
+
if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_INT64, 4, 3, -9, NULL)) return -1;
if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_BYTE_STRING, 3, 1, -10, NULL)) return -1;
-
+
if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 1, 2, -22, NULL)) return -1;
if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_INT64, 2, 0, -5, NULL)) return -1;
-
+
if(QCBORDecode_Finish(pDC)) return -2;
-
+
return 0;
}
@@ -1891,12 +2104,39 @@
int NestedMapTest()
{
QCBORDecodeContext DCtx;
-
+
QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInput), QCBOR_DECODE_MODE_NORMAL);
-
+
return CheckCSRMaps(&DCtx);
}
+
+
+int StringDecoderModeFailTest()
+{
+ QCBORDecodeContext DCtx;
+
+ QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInput), QCBOR_DECODE_MODE_MAP_STRINGS_ONLY);
+
+ QCBORItem Item;
+ QCBORError nCBORError;
+
+ if(QCBORDecode_GetNext(&DCtx, &Item)) {
+ return -1;
+ }
+ if(Item.uDataType != QCBOR_TYPE_MAP) {
+ return -2;
+ }
+
+ nCBORError = QCBORDecode_GetNext(&DCtx, &Item);
+ if(nCBORError != QCBOR_ERR_MAP_LABEL_TYPE) {
+ return -3;
+ }
+
+ return 0;
+}
+
+
// Same map as above, but using indefinite lengths
static uint8_t spCSRInputIndefLen[] = {
0xbf, 0x36, 0xbf, 0x33, 0xbf, 0x31, 0x6c, 0x4f,
@@ -1913,9 +2153,9 @@
int NestedMapTestIndefLen()
{
QCBORDecodeContext DCtx;
-
+
QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInputIndefLen), QCBOR_DECODE_MODE_NORMAL);
-
+
return CheckCSRMaps(&DCtx);
}
@@ -1925,7 +2165,7 @@
{
UsefulOutBuf UOB;
UsefulOutBuf_Init(&UOB, Storage);
-
+
int i;
for(i = 0; i < n; i++) {
UsefulOutBuf_AppendByte(&UOB, 0x9f);
@@ -1942,7 +2182,7 @@
{
QCBORDecodeContext DC;
QCBORDecode_Init(&DC, Nested, 0);
-
+
int j;
for(j = 0; j < nNestLevel; j++) {
QCBORItem Item;
@@ -1976,8 +2216,8 @@
{
UsefulBuf_MAKE_STACK_UB(Storage, 50);
int i;
- for(i=1; i < QCBOR_MAX_ARRAY_NESTING+4; i++) {
- UsefulBufC Nested = make_nested_indefinite_arrays(i, Storage);
+ for(i=1; i < QCBOR_MAX_ARRAY_NESTING+4; i++) {
+ const UsefulBufC Nested = make_nested_indefinite_arrays(i, Storage);
int nReturn = parse_indeflen_nested(Nested, i);
if(nReturn) {
return nReturn;
@@ -2000,15 +2240,15 @@
int nResult;
// --- first test -----
UsefulBufC IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArray);
-
+
// Decode it and see if it is OK
UsefulBuf_MAKE_STACK_UB(MemPool, 150);
QCBORDecodeContext DC;
QCBORItem Item;
QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL);
-
+
QCBORDecode_SetMemPool(&DC, MemPool, false);
-
+
QCBORDecode_GetNext(&DC, &Item);
if(Item.uDataType != QCBOR_TYPE_ARRAY ||
@@ -2016,64 +2256,64 @@
Item.uNextNestLevel != 1) {
return -111;
}
-
+
QCBORDecode_GetNext(&DC, &Item);
if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.uNestingLevel != 1 ||
Item.uNextNestLevel != 1) {
return -2;
}
-
+
QCBORDecode_GetNext(&DC, &Item);
if(Item.uDataType != QCBOR_TYPE_ARRAY ||
Item.uNestingLevel != 1 ||
Item.uNextNestLevel != 2) {
return -3;
}
-
+
QCBORDecode_GetNext(&DC, &Item);
- if(Item.uDataType != QCBOR_TYPE_INT64 |
+ if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.uNestingLevel != 2 ||
Item.uNextNestLevel != 2) {
return -4;
}
-
+
QCBORDecode_GetNext(&DC, &Item);
- if(Item.uDataType != QCBOR_TYPE_INT64 |
+ if(Item.uDataType != QCBOR_TYPE_INT64 ||
Item.uNestingLevel != 2 ||
Item.uNextNestLevel != 0) {
return -5;
}
-
+
if(QCBORDecode_Finish(&DC)) {
return -6;
}
-
+
// --- next test -----
IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad1);
-
+
QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL);
-
+
QCBORDecode_SetMemPool(&DC, MemPool, false);
-
+
nResult = QCBORDecode_GetNext(&DC, &Item);
if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) {
return -7;
}
-
+
nResult = QCBORDecode_Finish(&DC);
if(nResult != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) {
return -8;
}
-
+
// --- next test -----
IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad2);
-
+
QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL);
-
+
QCBORDecode_SetMemPool(&DC, MemPool, false);
-
+
nResult = QCBORDecode_GetNext(&DC, &Item);
if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) {
return -9;
@@ -2083,75 +2323,75 @@
if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) {
return -10;
}
-
+
nResult = QCBORDecode_GetNext(&DC, &Item);
if(nResult || Item.uDataType != QCBOR_TYPE_INT64) {
return -11;
}
-
+
nResult = QCBORDecode_Finish(&DC);
if(nResult != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) {
return -12;
}
-
-
+
+
// --- next test -----
IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad3);
-
+
QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL);
-
+
QCBORDecode_SetMemPool(&DC, MemPool, false);
-
+
nResult = QCBORDecode_GetNext(&DC, &Item);
if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) {
return -13;
}
-
+
nResult = QCBORDecode_GetNext(&DC, &Item);
if(nResult != QCBOR_ERR_BAD_BREAK) {
return -14;
}
-
+
// --- next test -----
IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad4);
-
+
QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL);
-
+
QCBORDecode_SetMemPool(&DC, MemPool, false);
-
+
nResult = QCBORDecode_GetNext(&DC, &Item);
if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) {
return -15;
}
-
+
nResult = QCBORDecode_GetNext(&DC, &Item);
if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) {
return -16;
}
-
+
nResult = QCBORDecode_Finish(&DC);
if(nResult != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) {
return -17;
}
-
+
// --- next test -----
IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad5);
-
+
QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL);
-
+
QCBORDecode_SetMemPool(&DC, MemPool, false);
-
+
nResult = QCBORDecode_GetNext(&DC, &Item);
if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) {
return -18;
}
-
+
nResult = QCBORDecode_GetNext(&DC, &Item);
if(nResult != QCBOR_ERR_BAD_BREAK) {
return -19;
}
-
+
return 0;
}
@@ -2196,14 +2436,14 @@
0x01 // integer being labeled.
};
-static UsefulBufC MakeIndefiniteBigBstr(UsefulBuf Storage)
+static UsefulBufC MakeIndefiniteBigBstr(UsefulBuf Storage) // TODO: size this
{
UsefulOutBuf UOB;
-
+
UsefulOutBuf_Init(&UOB, Storage);
UsefulOutBuf_AppendByte(&UOB, 0x81);
UsefulOutBuf_AppendByte(&UOB, 0x5f);
-
+
int i = 0;
for(int nChunkSize = 1; nChunkSize <= 128; nChunkSize *= 2) {
UsefulOutBuf_AppendByte(&UOB, 0x58);
@@ -2223,7 +2463,7 @@
if(BigString.len != 255) {
return 1;
}
-
+
for(uint8_t i = 0; i < 255; i++){
if(((const uint8_t *)BigString.ptr)[i] != i) {
return 1;
@@ -2238,23 +2478,23 @@
QCBORDecodeContext DC;
QCBORItem Item;
// big enough for MakeIndefiniteBigBstr() + MemPool overhead
- UsefulBuf_MAKE_STACK_UB(MemPool, 320);
-
+ UsefulBuf_MAKE_STACK_UB(MemPool, 350);
+
// --- Simple normal indefinite length string ------
UsefulBufC IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenString);
QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL);
-
+
if(QCBORDecode_SetMemPool(&DC, MemPool, false)) {
return -1;
}
-
+
if(QCBORDecode_GetNext(&DC, &Item)) {
return -2;
}
if(Item.uDataType != QCBOR_TYPE_ARRAY || Item.uDataAlloc) {
return -3;
}
-
+
if(QCBORDecode_GetNext(&DC, &Item)) {
return -4;
}
@@ -2267,70 +2507,70 @@
// ----- types mismatch ---
QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringBad2), QCBOR_DECODE_MODE_NORMAL);
-
+
if(QCBORDecode_SetMemPool(&DC, MemPool, false)) {
return -7;
}
-
+
if(QCBORDecode_GetNext(&DC, &Item)) {
return -8;
}
if(Item.uDataType != QCBOR_TYPE_ARRAY) {
return -9;
}
-
+
if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_INDEFINITE_STRING_CHUNK) {
return -10;
}
// ----- not a string ---
QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringBad3), QCBOR_DECODE_MODE_NORMAL);
-
+
if(QCBORDecode_SetMemPool(&DC, MemPool, false)) {
return -11;
}
-
+
if(QCBORDecode_GetNext(&DC, &Item)) {
return -12;
}
if(Item.uDataType != QCBOR_TYPE_ARRAY) {
return -13;
}
-
+
if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_INDEFINITE_STRING_CHUNK) {
return -14;
}
// ----- no end -----
QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringBad4), QCBOR_DECODE_MODE_NORMAL);
-
+
if(QCBORDecode_SetMemPool(&DC, MemPool, false)) {
return -15;
}
-
+
if(QCBORDecode_GetNext(&DC, &Item)) {
return -16;
}
if(Item.uDataType != QCBOR_TYPE_ARRAY) {
return -17;
}
-
+
if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_HIT_END) {
return -18;
}
-
+
// ------ Don't set a string allocator and see an error -----
QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL);
-
+
QCBORDecode_GetNext(&DC, &Item);
if(Item.uDataType != QCBOR_TYPE_ARRAY) {
return -19;
}
-
+
if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_NO_STRING_ALLOCATOR) {
return -20;
}
-
+
// ----- Mempool is way too small -----
UsefulBuf_MAKE_STACK_UB(MemPoolTooSmall, 20); // 20 is too small no matter what
@@ -2338,18 +2578,18 @@
if(!QCBORDecode_SetMemPool(&DC, MemPoolTooSmall, false)) {
return -21;
}
-
+
// ----- Mempool is way too small -----
UsefulBuf_MAKE_STACK_UB(BigIndefBStrStorage, 290);
- UsefulBufC BigIndefBStr = MakeIndefiniteBigBstr(BigIndefBStrStorage);
-
+ const UsefulBufC BigIndefBStr = MakeIndefiniteBigBstr(BigIndefBStrStorage);
+
UsefulBuf_MAKE_STACK_UB(MemPoolSmall, 80); // 80 is big enough for MemPool overhead, but not BigIndefBStr
-
+
QCBORDecode_Init(&DC, BigIndefBStr, QCBOR_DECODE_MODE_NORMAL);
if(QCBORDecode_SetMemPool(&DC, MemPoolSmall, false)) {
return -22;
}
-
+
QCBORDecode_GetNext(&DC, &Item);
if(Item.uDataType != QCBOR_TYPE_ARRAY) {
return -23;
@@ -2357,21 +2597,21 @@
if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_STRING_ALLOCATE) {
return -24;
}
-
+
// ---- big bstr -----
QCBORDecode_Init(&DC, BigIndefBStr, QCBOR_DECODE_MODE_NORMAL);
-
+
if(QCBORDecode_SetMemPool(&DC, MemPool, false)) {
return -25;
}
-
+
if(QCBORDecode_GetNext(&DC, &Item)) {
return -26;
}
if(Item.uDataType != QCBOR_TYPE_ARRAY || Item.uDataAlloc) {
return -26;
}
-
+
if(QCBORDecode_GetNext(&DC, &Item)) {
return -27;
}
@@ -2384,19 +2624,19 @@
if(QCBORDecode_Finish(&DC)) {
return -29;
}
-
+
// --- label is an indefinite length string ------
QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringLabel), QCBOR_DECODE_MODE_NORMAL);
-
+
if(QCBORDecode_SetMemPool(&DC, MemPool, false)) {
return -30;
}
-
+
QCBORDecode_GetNext(&DC, &Item);
if(Item.uDataType != QCBOR_TYPE_MAP) {
return -31;
}
-
+
if(QCBORDecode_GetNext(&DC, &Item)){
return -32;
}
@@ -2405,11 +2645,11 @@
UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("struuming"))) {
return -33;
}
-
+
if(QCBORDecode_Finish(&DC)) {
return -34;
}
-
+
return 0;
}
@@ -2417,32 +2657,37 @@
int AllocAllStringsTest()
{
QCBORDecodeContext DC;
-
+ QCBORError nCBORError;
+
+
// First test, use the "CSRMap" as easy input and checking
QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInput), QCBOR_DECODE_MODE_NORMAL);
-
- UsefulBuf_MAKE_STACK_UB(Pool, 300);
-
- QCBORDecode_SetMemPool(&DC, Pool, 1); // Turn on copying.
-
- if(CheckCSRMaps(&DC)) {
+
+ UsefulBuf_MAKE_STACK_UB(Pool, sizeof(spCSRInput) + QCBOR_DECODE_MIN_MEM_POOL_SIZE);
+
+ nCBORError = QCBORDecode_SetMemPool(&DC, Pool, 1); // Turn on copying.
+ if(nCBORError) {
return -1;
}
-
+
+ if(CheckCSRMaps(&DC)) {
+ return -2;
+ }
+
// Next parse, save pointers to a few strings, destroy original and see all is OK.
- UsefulBuf_MAKE_STACK_UB(CopyOfStorage, 160);
- UsefulBufC CopyOf = UsefulBuf_Copy(CopyOfStorage, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded));
+ UsefulBuf_MAKE_STACK_UB(CopyOfStorage, sizeof(pValidMapEncoded) + QCBOR_DECODE_MIN_MEM_POOL_SIZE);
+ const UsefulBufC CopyOf = UsefulBuf_Copy(CopyOfStorage, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded));
QCBORDecode_Init(&DC, CopyOf, QCBOR_DECODE_MODE_NORMAL);
+ UsefulBuf_Set(Pool, '/');
QCBORDecode_SetMemPool(&DC, Pool, 1); // Turn on copying.
-
- int nCBORError;
+
QCBORItem Item1, Item2, Item3, Item4;
if((nCBORError = QCBORDecode_GetNext(&DC, &Item1)))
return nCBORError;
if(Item1.uDataType != QCBOR_TYPE_MAP ||
Item1.val.uCount != 3)
- return -1;
+ return -3;
if((nCBORError = QCBORDecode_GetNext(&DC, &Item1)))
return nCBORError;
if((nCBORError = QCBORDecode_GetNext(&DC, &Item2)))
@@ -2451,43 +2696,43 @@
return nCBORError;
if((nCBORError = QCBORDecode_GetNext(&DC, &Item4)))
return nCBORError;
-
+
UsefulBuf_Set(CopyOfStorage, '_');
-
+
if(Item1.uLabelType != QCBOR_TYPE_TEXT_STRING ||
- Item1.label.string.len != 13 ||
Item1.uDataType != QCBOR_TYPE_INT64 ||
Item1.val.int64 != 42 ||
- memcmp(Item1.label.string.ptr, "first integer", 13))
- return -1;
-
+ UsefulBuf_Compare(Item1.label.string, UsefulBuf_FromSZ("first integer"))) {
+ return -4;
+ }
+
if(Item2.uLabelType != QCBOR_TYPE_TEXT_STRING ||
- Item2.label.string.len != 23 ||
- memcmp(Item2.label.string.ptr, "an array of two strings", 23) ||
+ UsefulBuf_Compare(Item2.label.string, UsefulBuf_FromSZ("an array of two strings")) ||
Item2.uDataType != QCBOR_TYPE_ARRAY ||
Item2.val.uCount != 2)
- return -1;
-
+ return -5;
+
if(Item3.uDataType != QCBOR_TYPE_TEXT_STRING ||
- Item3.val.string.len != 7 ||
- memcmp(Item3.val.string.ptr, "string1", 7))
- return -1;
-
+ UsefulBuf_Compare(Item3.val.string, UsefulBuf_FromSZ("string1"))) {
+ return -6;
+ }
+
if(Item4.uDataType != QCBOR_TYPE_TEXT_STRING ||
- Item4.val.string.len != 7 ||
- memcmp(Item4.val.string.ptr, "string2", 7))
- return -1;
-
+ UsefulBuf_Compare(Item4.val.string, UsefulBuf_FromSZ("string2"))) {
+ return -7;
+ }
+
// Next parse with a pool that is too small
- UsefulBuf_MAKE_STACK_UB(SmallPool, 80);
+ UsefulBuf_MAKE_STACK_UB(SmallPool, QCBOR_DECODE_MIN_MEM_POOL_SIZE + 1);
QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), QCBOR_DECODE_MODE_NORMAL);
QCBORDecode_SetMemPool(&DC, SmallPool, 1); // Turn on copying.
if((nCBORError = QCBORDecode_GetNext(&DC, &Item1)))
- return nCBORError;
+ return -8;
if(Item1.uDataType != QCBOR_TYPE_MAP ||
- Item1.val.uCount != 3)
- return -1;
+ Item1.val.uCount != 3) {
+ return -9;
+ }
if(!(nCBORError = QCBORDecode_GetNext(&DC, &Item1))){
if(!(nCBORError = QCBORDecode_GetNext(&DC, &Item2))) {
if(!(nCBORError = QCBORDecode_GetNext(&DC, &Item3))) {
@@ -2496,7 +2741,7 @@
}
}
if(nCBORError != QCBOR_ERR_STRING_ALLOCATE) {
- return -5;
+ return -10;
}
return 0;
@@ -2512,15 +2757,18 @@
QCBORDecodeContext DC;
const uint8_t pMinimalCBOR[] = {0xa0}; // One empty map
QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pMinimalCBOR),0);
-
+
// Set up an memory pool of 100 bytes
UsefulBuf_MAKE_STACK_UB(Pool, 100);
- QCBORDecode_SetMemPool(&DC, Pool, 0);
-
+ QCBORError nError = QCBORDecode_SetMemPool(&DC, Pool, 0);
+ if(nError) {
+ return -9;
+ }
+
// Cheat a little to get to the string allocator object
// so we can call it directly to test it
QCBORStringAllocator *pAlloc = (QCBORStringAllocator *)DC.pStringAllocator;
- // Cheat some more to know exactly the
+ // Cheat some more to know exactly the
size_t uAvailPool = MemPoolTestHook_GetPoolSize(pAlloc);
// First test -- ask for too much in one go
@@ -2528,21 +2776,21 @@
if(!UsefulBuf_IsNULL(Allocated)) {
return -1;
}
-
-
+
+
// Re do the set up for the next test that will do a successful alloc,
// a fail, a free and then success
// This test should work on 32 and 64-bit machines if the compiler
// does the expected thing with pointer sizes for the internal
// MemPool implementation leaving 44 or 72 bytes of pool memory.
QCBORDecode_SetMemPool(&DC, Pool, 0);
-
+
// Cheat a little to get to the string allocator object
// so we can call it directly to test it
pAlloc = (QCBORStringAllocator *)DC.pStringAllocator;
// Cheat some more to know exactly the
uAvailPool = MemPoolTestHook_GetPoolSize(pAlloc);
-
+
Allocated = (*pAlloc->fAllocate)(pAlloc->pAllocaterContext, NULL, uAvailPool-1);
if(UsefulBuf_IsNULL(Allocated)) { // expected to succeed
return -2;
@@ -2556,12 +2804,12 @@
if(UsefulBuf_IsNULL(Allocated)) { // succeed because of the free
return -4;
}
-
-
+
+
// Re do set up for next test that involves a successful alloc,
// and a successful realloc and a failed realloc
QCBORDecode_SetMemPool(&DC, Pool, 0);
-
+
// Cheat a little to get to the string allocator object
// so we can call it directly to test it
pAlloc = (QCBORStringAllocator *)DC.pStringAllocator;
@@ -2580,7 +2828,7 @@
if(!UsefulBuf_IsNULL(Allocated3)) { // expected to fail
return -8;
}
-
+
return 0;
}
diff --git a/test/qcbor_decode_tests.h b/test/qcbor_decode_tests.h
index 55b1bf5..6ba71b4 100644
--- a/test/qcbor_decode_tests.h
+++ b/test/qcbor_decode_tests.h
@@ -2,7 +2,7 @@
Copyright (c) 2016-2018, The Linux Foundation.
Copyright (c) 2018, Laurence Lundblade.
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
@@ -16,7 +16,7 @@
contributors, nor the name "Laurence Lundblade" may be used to
endorse or promote products derived from this software without
specific prior written permission.
-
+
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
@@ -36,16 +36,16 @@
#include "qcbor.h"
-/*
+/*
Notes:
-
+
- All the functions in qcbor.h are called once in the aggregation of all the tests below.
-
+
- All the types that are supported are given as input and parsed by these tests
-
+
- There is some hostile input such as invalid lengths and CBOR too complex
and types this parser doesn't handle
-
+
*/
@@ -90,7 +90,7 @@
int UnsupportedCBORDecodeTest(void);
-/*
+/*
This takes the encoded CBOR integers used in the above test and parses
it over and over with one more byte less each time. It should fail
every time on incorrect CBOR input. This is a hostile input decode test.
@@ -98,7 +98,7 @@
int ShortBufferParseTest(void);
-/*
+/*
Same as ShortBufferParseTest, but with a different encoded CBOR input.
It is another hostile input test
*/
@@ -120,6 +120,12 @@
int SimpleValuesTest1(void);
+/*
+
+ */
+int ParseMapAsArrayTest(void);
+
+
int ParseSimpleTest(void);
@@ -132,12 +138,27 @@
/*
- Generate all possible input strings up to length x and tries to parse them completely
+ Parses all possible inputs that are two bytes long. Main point
+ is that the test doesn't crash as it doesn't evaluate the
+ input for correctness in any way.
+
+ (Parsing all possible 3 byte strings takes too long on all but
+ very fast machines).
*/
int ComprehensiveInputTest(void);
/*
+ Parses all possible inputs that are four bytes long. Main point
+ is that the test doesn't crash as it doesn't evaluate the
+ input for correctness in any way. This runs very slow, so it
+ is only practical as a once-in-a-while regression test on
+ fast machines.
+ */
+int BigComprehensiveInputTest(void);
+
+
+/*
Thest the date types -- epoch and strings
*/
int DateParseTest(void);
@@ -155,6 +176,9 @@
int BignumParseTest(void);
+int StringDecoderModeFailTest(void);
+
+
/*
Parse some nested maps
*/
diff --git a/test/qcbor_encode_tests.c b/test/qcbor_encode_tests.c
index 4bb2cab..fcded50 100644
--- a/test/qcbor_encode_tests.c
+++ b/test/qcbor_encode_tests.c
@@ -2,7 +2,7 @@
Copyright (c) 2016-2018, The Linux Foundation.
Copyright (c) 2018, Laurence Lundblade.
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
@@ -16,7 +16,7 @@
contributors, nor the name "Laurence Lundblade" may be used to
endorse or promote products derived from this software without
specific prior written permission.
-
+
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
@@ -36,15 +36,15 @@
/*
This is the test set for CBOR encoding.
-
+
This is largely complete for the implemented.
-
+
A few more things to do include:
- Add a test for counting the top level items and adding it back in with AddRaw()
- Run on some different CPUs like 32-bit and maybe even 16-bit
- Test the large array count limit
- Add the CBOR diagnostic output for every expected
-
+
*/
//#define PRINT_FUNCTIONS_FOR_DEBUGGINGXX
@@ -76,7 +76,7 @@
}
}
return 0;
-
+
}
#define CheckResults(Enc, Expected) \
@@ -105,39 +105,39 @@
{
// Very simple CBOR, a map with one boolean that is true in it
QCBOREncodeContext EC;
-
+
QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
QCBOREncode_OpenMap(&EC);
QCBOREncode_AddBoolToMapN(&EC, 66, true);
QCBOREncode_CloseMap(&EC);
-
+
UsefulBufC Encoded;
if(QCBOREncode_Finish(&EC, &Encoded)) {
return -1;
}
-
-
+
+
// Decode it and see that is right
QCBORDecodeContext DC;
QCBORItem Item;
QCBORDecode_Init(&DC, Encoded, QCBOR_DECODE_MODE_NORMAL);
-
+
QCBORDecode_GetNext(&DC, &Item);
if(Item.uDataType != QCBOR_TYPE_MAP) {
return -2;
}
-
+
QCBORDecode_GetNext(&DC, &Item);
if(Item.uDataType != QCBOR_TYPE_TRUE) {
return -3;
}
-
+
if(QCBORDecode_Finish(&DC)) {
return -4;
}
-
-
+
+
// Make another encoded message with the CBOR from the previous put into this one
UsefulBuf_MAKE_STACK_UB(MemoryForEncoded2, 20);
QCBOREncode_Init(&EC, MemoryForEncoded2);
@@ -148,7 +148,7 @@
QCBOREncode_AddEncodedToMapN(&EC, -70000, Encoded);
QCBOREncode_CloseMap(&EC);
QCBOREncode_CloseArray(&EC);
-
+
UsefulBufC Encoded2;
if(QCBOREncode_Finish(&EC, &Encoded2)) {
return -5;
@@ -165,9 +165,9 @@
}
}
]
-
-
-
+
+
+
83 # array(3)
19 01C3 # unsigned(451)
A1 # map(1)
@@ -179,56 +179,56 @@
18 42 # unsigned(66)
F5 # primitive(21)
*/
-
+
// Decode it and see if it is OK
QCBORDecode_Init(&DC, Encoded2, QCBOR_DECODE_MODE_NORMAL);
-
+
// 0 1:3
QCBORDecode_GetNext(&DC, &Item);
if(Item.uDataType != QCBOR_TYPE_ARRAY || Item.val.uCount != 3) {
return -6;
}
-
+
// 1 1:2
QCBORDecode_GetNext(&DC, &Item);
if(Item.uDataType != QCBOR_TYPE_INT64 || Item.val.uint64 != 451) {
return -7;
}
-
+
// 1 1:2 2:1
QCBORDecode_GetNext(&DC, &Item);
if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 1) {
return -8;
}
-
+
// 2 1:1
QCBORDecode_GetNext(&DC, &Item);
if(Item.uDataType != QCBOR_TYPE_TRUE) {
return -9;
}
-
+
// 1 1:1 2:1
QCBORDecode_GetNext(&DC, &Item);
if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 1) {
return -10;
}
-
+
// 2 1:1 2:1 3:1
QCBORDecode_GetNext(&DC, &Item);
if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 1 || Item.uLabelType != QCBOR_TYPE_INT64 || Item.label.int64 != -70000) {
return -11;
}
-
+
// 3 XXXXXX
QCBORDecode_GetNext(&DC, &Item);
if(Item.uDataType != QCBOR_TYPE_TRUE || Item.uLabelType != QCBOR_TYPE_INT64 || Item.label.int64 != 66) {
return -12;
}
-
+
if(QCBORDecode_Finish(&DC)) {
return -13;
}
-
+
return 0;
}
@@ -471,9 +471,9 @@
// TODO: this test should be broken down into several so it is more managable. Tags and labels could be more sensible
QCBOREncodeContext ECtx;
int nReturn = 0;
-
+
QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
-
+
QCBOREncode_OpenArray(&ECtx);
// Some ints that are tagged and have strings preceeding them (not labels becase it is not a map)
@@ -493,17 +493,17 @@
QCBOREncode_AddInt64ToMap(&ECtx, "NEGLBLTHAT IS KIND OF LONG", -2394893489238);
QCBOREncode_AddInt64ToMapN(&ECtx, -100000000, -800000000);
QCBOREncode_CloseMap(&ECtx);
-
+
// Epoch Date
QCBOREncode_AddDateEpoch(&ECtx, 2383748234);
-
+
// Epoch date with labels
QCBOREncode_OpenMap(&ECtx);
QCBOREncode_AddDateEpochToMap(&ECtx, "LongLiveDenisRitchie", 1400000000);
QCBOREncode_AddDateEpochToMap(&ECtx, "time()", 1477263730);
QCBOREncode_AddDateEpochToMapN(&ECtx, -1969, 1477263222);
QCBOREncode_CloseMap(&ECtx);
-
+
// Binary blobs
QCBOREncode_AddBytes(&ECtx, ((UsefulBufC) {(uint8_t []){0xff, 0x00}, 2}));
@@ -515,7 +515,7 @@
QCBOREncode_AddBytesToMap(&ECtx, "blabel", ((UsefulBufC) {(uint8_t []){0x01, 0x02, 0x03}, 3}));
QCBOREncode_AddBytesToMapN(&ECtx, 0, ((UsefulBufC){(uint8_t []){0x04, 0x02, 0x03, 0xfe}, 4}));
QCBOREncode_CloseMap(&ECtx);
-
+
// text blobs
QCBOREncode_AddText(&ECtx, UsefulBuf_FROM_SZ_LITERAL("bar bar foo bar"));
QCBOREncode_AddSZString(&ECtx, "oof\n");
@@ -523,7 +523,7 @@
QCBOREncode_AddB64Text(&ECtx, UsefulBuf_FROM_SZ_LITERAL("YW55IGNhcm5hbCBwbGVhc3VyZQ=="));
QCBOREncode_AddRegex(&ECtx, UsefulBuf_FROM_SZ_LITERAL("[^abc]+"));
QCBOREncode_AddMIMEData(&ECtx, UsefulBuf_FromSZ(szMIME));
-
+
// text blobs in maps
QCBOREncode_OpenMap(&ECtx);
QCBOREncode_AddTextToMap(&ECtx, "#####", UsefulBuf_FROM_SZ_LITERAL("foo bar foo foo"));
@@ -550,7 +550,7 @@
QCBOREncode_AddDateStringToMap(&ECtx, "Bed time", "2003-12-13T18:30:02.25+01:00");
QCBOREncode_AddDateStringToMapN(&ECtx, 88, "2003-12-13T18:30:02.25+01:00");
QCBOREncode_CloseMap(&ECtx);
-
+
// true / false ...
QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_UNDEF);
QCBOREncode_OpenMap(&ECtx);
@@ -560,7 +560,7 @@
QCBOREncode_AddBoolToMap(&ECtx, "uu", false);
QCBOREncode_AddSimpleToMapN(&ECtx, 737634, CBOR_SIMPLEV_NULL);
QCBOREncode_CloseMap(&ECtx);
-
+
// opening an array
QCBOREncode_OpenArray(&ECtx);
QCBOREncode_CloseArray(&ECtx);
@@ -574,9 +574,9 @@
QCBOREncode_OpenArrayInMap(&ECtx, "alabl");
QCBOREncode_CloseArray(&ECtx);
QCBOREncode_OpenArrayInMapN(&ECtx, 42);
- QCBOREncode_CloseArray(&ECtx);
+ QCBOREncode_CloseArray(&ECtx);
QCBOREncode_CloseMap(&ECtx);
-
+
// opening maps with labels and tagging
QCBOREncode_OpenMap(&ECtx);
QCBOREncode_OpenMapInMap(&ECtx, "in a map");
@@ -588,7 +588,7 @@
QCBOREncode_CloseMap(&ECtx);
QCBOREncode_CloseMap(&ECtx);
QCBOREncode_CloseMap(&ECtx);
-
+
// Extended simple values (these are not standard...)
QCBOREncode_OpenMap(&ECtx);
@@ -606,16 +606,16 @@
QCBOREncode_AddTag(&ECtx, 88);
QCBOREncode_AddSimple(&ECtx, 19);
QCBOREncode_CloseMap(&ECtx);
-
+
// UUIDs
static const uint8_t ppppUUID[] = {0x53, 0x4D, 0x41, 0x52, 0x54, 0x43, 0x53, 0x4C, 0x54, 0x54, 0x43, 0x46, 0x49, 0x43, 0x41, 0x32};
- UsefulBufC XXUUID = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(ppppUUID);
+ const UsefulBufC XXUUID = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(ppppUUID);
QCBOREncode_AddBinaryUUID(&ECtx, XXUUID);
QCBOREncode_OpenMap(&ECtx);
QCBOREncode_AddBinaryUUIDToMap(&ECtx, "UUUU", XXUUID);
QCBOREncode_AddBinaryUUIDToMapN(&ECtx, 99, XXUUID);
QCBOREncode_CloseMap(&ECtx);
-
+
// Bool
QCBOREncode_AddBool(&ECtx, true);
QCBOREncode_AddBool(&ECtx, false);
@@ -626,7 +626,7 @@
static const uint8_t pBignum[] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
- UsefulBufC BIGNUM = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pBignum);
+ const UsefulBufC BIGNUM = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pBignum);
QCBOREncode_AddPositiveBignum(&ECtx, BIGNUM);
QCBOREncode_AddNegativeBignum(&ECtx, BIGNUM);
QCBOREncode_OpenMap(&ECtx);
@@ -635,19 +635,19 @@
QCBOREncode_AddNegativeBignumToMap(&ECtx, "BN-", BIGNUM);
QCBOREncode_AddNegativeBignumToMapN(&ECtx, -64, BIGNUM);
QCBOREncode_CloseMap(&ECtx);
-
+
QCBOREncode_CloseArray(&ECtx);
UsefulBufC Enc;
-
+
if(QCBOREncode_Finish(&ECtx, &Enc)) {
nReturn = -1;
goto Done;
}
-
+
if(CheckResults(Enc, spExpectedEncodedAll))
nReturn = -2;
-
+
Done:
return nReturn;
}
@@ -729,19 +729,19 @@
0xff, 0xff};
/*
-
+
Test the generation of integers. This also ends up testing
encoding of all the different lengths. It encodes integers
of many lengths and values, especially around the boundaries
for different types of integers. It compares the output
to expected values generated from http://cbor.me.
-
+
*/
int IntegerValuesTest1()
{
QCBOREncodeContext ECtx;
int nReturn = 0;
-
+
QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
QCBOREncode_OpenArray(&ECtx);
@@ -792,17 +792,17 @@
QCBOREncode_AddInt64(&ECtx, 4294967297);
QCBOREncode_AddInt64(&ECtx, 9223372036854775807LL);
QCBOREncode_AddUInt64(&ECtx, 18446744073709551615ULL);
-
+
QCBOREncode_CloseArray(&ECtx);
-
+
UsefulBufC Enc;
if(QCBOREncode_Finish(&ECtx, &Enc)) {
nReturn = -1;
}
-
+
if(CheckResults(Enc, spExpectedEncodedInts))
return -2;
-
+
return(nReturn);
}
@@ -825,7 +825,7 @@
{
QCBOREncodeContext ECtx;
int nReturn = 0;
-
+
QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
QCBOREncode_OpenArray(&ECtx);
@@ -833,22 +833,22 @@
QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_FALSE);
QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_NULL);
QCBOREncode_AddSimple(&ECtx, CBOR_SIMPLEV_UNDEF);
-
+
QCBOREncode_OpenMap(&ECtx);
QCBOREncode_AddSimpleToMap(&ECtx, "UNDef", CBOR_SIMPLEV_UNDEF);
QCBOREncode_CloseMap(&ECtx);
QCBOREncode_CloseArray(&ECtx);
-
+
UsefulBufC ECBOR;
if(QCBOREncode_Finish(&ECtx, &ECBOR)) {
nReturn = -1;
}
-
+
if(CheckResults(ECBOR, spExpectedEncodedSimple))
return -2;
-
+
return(nReturn);
}
@@ -887,24 +887,24 @@
{
QCBOREncodeContext ECtx;
int nReturn = 0;
-
+
QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
-
+
QCBOREncode_OpenArray(&ECtx);
-
+
QCBOREncode_AddDateString(&ECtx, "2013-03-21T20:04:00Z"); // from CBOR RFC
QCBOREncode_AddDateEpoch(&ECtx, 1363896240); // from CBOR RFC
-
+
QCBOREncode_OpenMap(&ECtx);
QCBOREncode_AddDateStringToMap(&ECtx, "Sample Date from RFC 3339", "1985-04-12T23:20:50.52Z");
-
+
QCBOREncode_AddDateEpochToMap(&ECtx, "SD", 999);
-
+
QCBOREncode_CloseMap(&ECtx);
-
+
QCBOREncode_CloseArray(&ECtx);
UsefulBufC ECBOR;
@@ -912,10 +912,10 @@
if(QCBOREncode_Finish(&ECtx, &ECBOR)) {
nReturn = -1;
}
-
+
if(CheckResults(ECBOR, spExpectedEncodedDates))
return -2;
-
+
return(nReturn);
}
@@ -925,7 +925,7 @@
QCBOREncodeContext ECtx;
int i;
int nReturn = 0;
-
+
QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
for(i = QCBOR_MAX_ARRAY_NESTING; i; i--) {
QCBOREncode_OpenArray(&ECtx);
@@ -948,7 +948,7 @@
QCBOREncodeContext ECtx;
int i;
int nReturn = 0;
-
+
QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
for(i = QCBOR_MAX_ARRAY_NESTING+1; i; i--) {
QCBOREncode_OpenArray(&ECtx);
@@ -956,12 +956,12 @@
for(i = QCBOR_MAX_ARRAY_NESTING; i; i--) {
QCBOREncode_CloseArray(&ECtx);
}
-
+
UsefulBufC Encoded;
if(QCBOREncode_Finish(&ECtx, &Encoded) != QCBOR_ERR_ARRAY_NESTING_TOO_DEEP) {
nReturn = -1;
}
-
+
return(nReturn);
}
@@ -972,7 +972,7 @@
QCBOREncodeContext ECtx;
int i;
int nReturn = 0;
-
+
QCBOREncode_Init(&ECtx, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
for(i = QCBOR_MAX_ARRAY_NESTING; i; i--) {
QCBOREncode_OpenArray(&ECtx);
@@ -984,7 +984,7 @@
if(QCBOREncode_Finish(&ECtx, &Encoded) != QCBOR_ERR_TOO_MANY_CLOSES) {
nReturn = -1;
}
-
+
return(nReturn);
}
@@ -1091,17 +1091,17 @@
QCBOREncode_AddEncoded(&ECtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spFiveArrarys));
QCBOREncode_AddEncoded(&ECtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedEncodedInts));
QCBOREncode_CloseArray(&ECtx);
-
+
UsefulBufC EncodedRawTest;
-
+
if(QCBOREncode_Finish(&ECtx, &EncodedRawTest)) {
return -4;
}
-
+
if(CheckResults(EncodedRawTest, spEncodeRawExpected)) {
return -5;
}
-
+
return 0;
}
@@ -1112,11 +1112,11 @@
{
QCBOREncodeContext ECtx;
int nReturn = -1;
-
+
*pEncoded = NULL;
*pEncodedLen = INT32_MAX;
size_t uFirstSizeEstimate = 0;
-
+
// loop runs CBOR encoding twice. First with no buffer to
// calucate the length so buffer can be allocated correctly,
// and last with the buffer to do the actual encoding
@@ -1135,7 +1135,7 @@
QCBOREncode_AddTextToMap(&ECtx, "text 2", ((UsefulBufC) {"lies, damn lies and statistics", 30}));
QCBOREncode_CloseMap(&ECtx);
QCBOREncode_CloseMap(&ECtx);
-
+
if(QCBOREncode_FinishGetSize(&ECtx, pEncodedLen))
goto Done;
if(*pEncoded != NULL) {
@@ -1148,9 +1148,9 @@
}
*pEncoded = spBigBuf;
uFirstSizeEstimate = *pEncodedLen;
-
+
} while(1);
-
+
Done:
return(nReturn);
}
@@ -1209,38 +1209,38 @@
{
uint8_t *pEncodedMaps;
size_t nEncodedMapLen;
-
+
if(CreateMap(&pEncodedMaps, &nEncodedMapLen)) {
return -1;
}
-
+
int nReturn = 0;
if(memcmp(spValidMapEncoded, pEncodedMaps, sizeof(spValidMapEncoded)))
nReturn = 2;
-
+
return(nReturn);
}
/*
@brief Encode the RTIC results
-
+
@param[in] nRResult CBOR_SIMPLEV_TRUE, CBOR_SIMPLEV_FALSE or CBOR_SIMPLEV_NULL
@param[in] time Time stamp in UNIX epoch time or 0 for no time stamp
@param[in] szAlexString Diagnostic code.
@param[in[ pOut Buffer to put the result in
@param[in/out] pnLen Size of pOut buffer when called; length of data output in buffer on return
-
+
@return
One of the CBOR encoder errors. QCBOR_SUCCESS, which is has value 0, if no error.
-
+
The size of pOut should be 30 bytes plus the length of pnLen. If you make it too
- short an error will be returned. This function will never write off the end
+ short an error will be returned. This function will never write off the end
of the buffer passed to it.
-
+
If the result is 0, then the correct encoded CBOR is in pOut and *pnLen is the
length of the encoded CBOR.
-
+
*/
static UsefulBufC FormatRTICResults(int nRResult, uint64_t time, const char *szType, const char *szAlexString, UsefulBuf Storage)
@@ -1248,17 +1248,17 @@
// Buffer that the result will be written in to
// It is fixed size and small that a stack variable will be fine
// QCBOREncode will never write off the end of this buffer. If it won't fit QCBOREncode_Finish will return an error.
-
+
// Context for the encoder
QCBOREncodeContext ECtx;
QCBOREncode_Init(&ECtx, Storage);
-
+
// All the RTIC results are grouped in a CBOR Map which will get turned into a JSON Object
// Contents are label / value pairs
QCBOREncode_OpenMap(&ECtx);
-
+
{ // Brace / indention just to show CBOR encoding nesting
-
+
// The result: 0 if scan happened and found nothing; 1 if it happened and found something wrong; 2 if it didn't happen
QCBOREncode_AddSimpleToMap(&ECtx, "integrity", nRResult);
@@ -1277,7 +1277,7 @@
QCBOREncode_OpenMapInMap(&ECtx, "telemetry");
{ // Brace / indention just to show CBOR encoding nesting
-
+
// Add a few fake integers and buffers for now.
QCBOREncode_AddInt64ToMap(&ECtx, "Shoe Size", 12);
@@ -1286,22 +1286,22 @@
// Add a few fake integers and buffers for now.
static const uint8_t pPV[] = {0x66, 0x67, 0x00, 0x56, 0xaa, 0xbb, 0x01, 0x01};
- UsefulBufC WSPV = {pPV, sizeof(pPV)};
-
+ const UsefulBufC WSPV = {pPV, sizeof(pPV)};
+
QCBOREncode_AddBytesToMap(&ECtx, "WhaleSharkPatternVector", WSPV);
}
}
-
+
// Close the telemetry map
QCBOREncode_CloseMap(&ECtx);
-
+
// Close the map
QCBOREncode_CloseMap(&ECtx);
-
+
UsefulBufC Result;
-
+
QCBOREncode_Finish(&ECtx, &Result);
-
+
return Result;
}
@@ -1354,18 +1354,18 @@
int RTICResultsTest()
{
- UsefulBufC Encoded = FormatRTICResults(CBOR_SIMPLEV_FALSE, 1477263730,
+ const UsefulBufC Encoded = FormatRTICResults(CBOR_SIMPLEV_FALSE, 1477263730,
"recent", "0xA1eC5001",
UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
if(UsefulBuf_IsNULLC(Encoded)) {
return -1;
}
-
+
if(CheckResults(Encoded, spExpectedRTIC)) {
return -2;
}
-
- return 0;
+
+ return 0;
}
@@ -1383,29 +1383,29 @@
int BstrWrapTest()
{
QCBOREncodeContext EC;
-
+
QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
-
+
QCBOREncode_OpenArray(&EC);
QCBOREncode_AddUInt64(&EC, 451);
-
+
QCBOREncode_BstrWrap(&EC);
QCBOREncode_AddUInt64(&EC, 466);
-
+
UsefulBufC Wrapped;
QCBOREncode_CloseBstrWrap(&EC, &Wrapped);
-
+
QCBOREncode_CloseArray(&EC);
-
+
UsefulBufC Encoded;
if(QCBOREncode_Finish(&EC, &Encoded)) {
return -1;
}
-
+
if(CheckResults(Encoded, spExpectedBstrWrap)) {
return -2;
}
-
+
return 0;
}
@@ -1415,48 +1415,48 @@
{
// -------------- Test closing a bstrwrap when it is an array that is open -----------
QCBOREncodeContext EC;
-
+
QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
-
+
QCBOREncode_OpenArray(&EC);
QCBOREncode_AddUInt64(&EC, 451);
-
+
QCBOREncode_BstrWrap(&EC);
QCBOREncode_AddUInt64(&EC, 466);
QCBOREncode_OpenArray(&EC);
-
+
UsefulBufC Wrapped;
QCBOREncode_CloseBstrWrap(&EC, &Wrapped);
-
+
QCBOREncode_CloseArray(&EC);
-
+
UsefulBufC Encoded2;
if(QCBOREncode_Finish(&EC, &Encoded2) != QCBOR_ERR_CLOSE_MISMATCH) {
return -1;
}
-
+
// ----------- test closing a bstrwrap when nothing is open ---------------------
QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
QCBOREncode_CloseBstrWrap(&EC, &Wrapped);
if(QCBOREncode_Finish(&EC, &Encoded2) != QCBOR_ERR_TOO_MANY_CLOSES) {
return -2;
}
-
+
// --------------- test nesting too deep ----------------------------------
QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
for(int i = 1; i < 18; i++) {
QCBOREncode_BstrWrap(&EC);
}
QCBOREncode_AddBool(&EC, true);
-
+
for(int i = 1; i < 18; i++) {
QCBOREncode_CloseBstrWrap(&EC, &Wrapped);
}
-
+
if(QCBOREncode_Finish(&EC, &Encoded2) != QCBOR_ERR_ARRAY_NESTING_TOO_DEEP) {
return -3;
}
-
+
return 0;
}
@@ -1502,8 +1502,8 @@
18 31 integer value 31
18 41 integer label 41
65 68 65 6C 6C 6F text string hello
-
-
+
+
*/
@@ -1538,7 +1538,7 @@
int nReturn;
QCBORDecodeContext DC;
QCBORDecode_Init(&DC, Wrapped, QCBOR_DECODE_MODE_NORMAL);
-
+
QCBORItem Item;
nReturn = QCBORDecode_GetNext(&DC, &Item);
if(nReturn) {
@@ -1547,7 +1547,7 @@
if(Item.uDataType != QCBOR_TYPE_INT64) {
return -12;
}
-
+
nReturn = QCBORDecode_GetNext(&DC, &Item);
if(nReturn == QCBOR_ERR_HIT_END) {
return 0;
@@ -1559,7 +1559,7 @@
if(nReturn) {
return nReturn;
}
-
+
nReturn = QCBORDecode_GetNext(&DC, &Item);
if(nReturn) {
return -14;
@@ -1567,11 +1567,11 @@
if(Item.uDataType != QCBOR_TYPE_INT64) {
return -15;
}
-
+
if(QCBORDecode_Finish(&DC)) {
return -16;
}
-
+
return 0;
}
@@ -1581,7 +1581,7 @@
int nReturn;
QCBORDecodeContext DC;
QCBORDecode_Init(&DC, Wrapped, QCBOR_DECODE_MODE_NORMAL);
-
+
QCBORItem Item;
nReturn = QCBORDecode_GetNext(&DC, &Item);
if(nReturn) {
@@ -1590,7 +1590,7 @@
if(Item.uDataType != QCBOR_TYPE_ARRAY) {
return -12;
}
-
+
nReturn = QCBORDecode_GetNext(&DC, &Item);
if(nReturn) {
return -11;
@@ -1598,7 +1598,7 @@
if(Item.uDataType != QCBOR_TYPE_INT64) {
return -12;
}
-
+
nReturn = QCBORDecode_GetNext(&DC, &Item);
if(nReturn) {
return -11;
@@ -1606,7 +1606,7 @@
if(Item.uDataType != QCBOR_TYPE_MAP) {
return 0;
}
-
+
nReturn = QCBORDecode_GetNext(&DC, &Item);
if(nReturn) {
return -11;
@@ -1618,7 +1618,7 @@
if(nReturn) {
return nReturn;
}
-
+
nReturn = QCBORDecode_GetNext(&DC, &Item);
if(nReturn) {
return -11;
@@ -1633,11 +1633,11 @@
if(Item.uDataType != QCBOR_TYPE_INT64) {
return -12;
}
-
+
if(QCBORDecode_Finish(&DC)) {
return -16;
}
-
+
return 0;
}
@@ -1646,29 +1646,29 @@
{
QCBOREncodeContext EC;
QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
-
+
// ---- Make a complicated nested CBOR structure ---
#define BSTR_TEST_DEPTH 10
-
+
QCBOREncode_OpenArray(&EC);
for(int i = 0; i < BSTR_TEST_DEPTH-2; i++) {
QCBOREncode_BstrWrap(&EC);
QCBOREncode_AddUInt64(&EC, i);
}
-
+
for(int i = 0; i < BSTR_TEST_DEPTH-2; i++) {
QCBOREncode_CloseBstrWrap(&EC, NULL);
QCBOREncode_AddUInt64(&EC, i);
}
-
+
for(int i = 0; i < (BSTR_TEST_DEPTH-2)/3; i++) {
QCBOREncode_OpenMap(&EC);
QCBOREncode_BstrWrapInMapN(&EC, i+0x20);
QCBOREncode_OpenArray(&EC);
QCBOREncode_AddUInt64(&EC, i+0x10);
}
-
+
for(int i = 0; i < (BSTR_TEST_DEPTH-2)/3; i++) {
QCBOREncode_CloseArray(&EC);
QCBOREncode_AddUInt64(&EC, i+0x30);
@@ -1677,38 +1677,38 @@
QCBOREncode_CloseMap(&EC);
}
QCBOREncode_CloseArray(&EC);
-
+
UsefulBufC Encoded;
if(QCBOREncode_Finish(&EC, &Encoded)) {
return -1;
}
-
+
// ---Compare it to expected. Expected was hand checked with use of CBOR playground ----
if(UsefulBuf_Compare(UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedDeepBstr), Encoded)) {
return -25;
}
-
-
+
+
// ---- Decode it and see if it is OK ------
QCBORDecodeContext DC;
QCBORDecode_Init(&DC, Encoded, QCBOR_DECODE_MODE_NORMAL);
-
+
QCBORItem Item;
QCBORDecode_GetNext(&DC, &Item);
if(Item.uDataType != QCBOR_TYPE_ARRAY || Item.val.uCount != 3) {
return -2;
}
-
+
QCBORDecode_GetNext(&DC, &Item);
if(Item.uDataType != QCBOR_TYPE_BYTE_STRING) {
return -3;
}
-
+
int nReturn = DecodeNextNested(Item.val.string);
if(nReturn) {
return nReturn;
}
-
+
nReturn = QCBORDecode_GetNext(&DC, &Item);
if(nReturn) {
return -11;
@@ -1716,12 +1716,12 @@
if(Item.uDataType != QCBOR_TYPE_INT64) {
return -12;
}
-
+
QCBORDecode_GetNext(&DC, &Item);
if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 2) {
return -2;
}
-
+
QCBORDecode_GetNext(&DC, &Item);
if(Item.uDataType != QCBOR_TYPE_BYTE_STRING) {
return -3;
@@ -1730,7 +1730,7 @@
if(nReturn) {
return nReturn;
}
-
+
nReturn = QCBORDecode_GetNext(&DC, &Item);
if(nReturn) {
return -11;
@@ -1738,11 +1738,11 @@
if(Item.uDataType != QCBOR_TYPE_TEXT_STRING) {
return -12;
}
-
+
if(QCBORDecode_Finish(&DC)) {
return -16;
}
-
+
return 0;
}
@@ -1793,62 +1793,62 @@
{
// All of this is from RFC 8152 C.2.1
const char *szKid = "11";
- UsefulBufC Kid = UsefulBuf_FromSZ(szKid);
+ const UsefulBufC Kid = UsefulBuf_FromSZ(szKid);
const char *szPayload = "This is the content.";
- UsefulBufC Payload = UsefulBuf_FromSZ(szPayload);
+ const UsefulBufC Payload = UsefulBuf_FromSZ(szPayload);
static const uint8_t pProtectedHeaders[] = {0xa1, 0x01, 0x26};
- UsefulBufC ProtectedHeaders = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pProtectedHeaders);
+ const UsefulBufC ProtectedHeaders = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pProtectedHeaders);
// It would be good to compare this to the output from
// a COSE implementation like COSE-C. It has been checked
// against the CBOR playground.
- UsefulBufC Signature = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSignature);
-
+ const UsefulBufC Signature = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSignature);
+
QCBOREncodeContext EC;
QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(spBigBuf));
-
+
// top level array for cose sign1, 18 is the tag for COSE sign
QCBOREncode_AddTag(&EC, CBOR_TAG_COSE_SIGN1);
QCBOREncode_OpenArray(&EC);
-
+
// Add protected headers
QCBOREncode_AddBytes(&EC, ProtectedHeaders);
-
+
// Empty map with unprotected headers
QCBOREncode_OpenMap(&EC);
QCBOREncode_AddBytesToMapN(&EC, 4, Kid);
QCBOREncode_CloseMap(&EC);
-
+
// The payload
UsefulBufC WrappedPayload;
QCBOREncode_BstrWrap(&EC);
QCBOREncode_AddEncoded(&EC, Payload); // Payload is not actually CBOR in example C.2.1
QCBOREncode_CloseBstrWrap(&EC, &WrappedPayload);
-
+
// Check we got back the actual payload expected
if(UsefulBuf_Compare(WrappedPayload, Payload)) {
return -1;
}
-
+
// The signature
QCBOREncode_AddBytes(&EC, Signature);
QCBOREncode_CloseArray(&EC);
-
+
// Finish and check the results
UsefulBufC COSE_Sign1;
if(QCBOREncode_Finish(&EC, &COSE_Sign1)) {
return -2;
}
-
+
// 98 is the size from RFC 8152 C.2.1
if(COSE_Sign1.len != 98) {
return -3;
}
-
+
if(CheckResults(COSE_Sign1, spExpected)) {
return -4;
}
-
+
return 0;
}
diff --git a/test/qcbor_encode_tests.h b/test/qcbor_encode_tests.h
index b0674d9..32f9570 100644
--- a/test/qcbor_encode_tests.h
+++ b/test/qcbor_encode_tests.h
@@ -2,7 +2,7 @@
Copyright (c) 2016-2018, The Linux Foundation.
Copyright (c) 2018, Laurence Lundblade.
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
@@ -16,7 +16,7 @@
contributors, nor the name "Laurence Lundblade" may be used to
endorse or promote products derived from this software without
specific prior written permission.
-
+
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
@@ -36,16 +36,16 @@
#include "qcbor.h"
-/*
+/*
Notes:
-
+
- All the functions in qcbor.h are called once in the aggregation of all the tests below.
-
+
- All the types that are supported are given as input and parsed by these tests
-
+
- There is some hostile input such as invalid lengths and CBOR too complex
and types this parser doesn't handle
-
+
*/
diff --git a/test/run_tests.c b/test/run_tests.c
index 3fba941..ef5a16f 100644
--- a/test/run_tests.c
+++ b/test/run_tests.c
@@ -1,10 +1,10 @@
/*==============================================================================
run_tests.c -- test aggregator and results reporting
-
+
Copyright (c) 2018, Laurence Lundblade.
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
@@ -17,7 +17,7 @@
* The name "Laurence Lundblade" may not be used to
endorse or promote products derived from this software without
specific prior written permission.
-
+
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
@@ -41,7 +41,6 @@
#include "qcbor_decode_tests.h"
#include "qcbor_encode_tests.h"
#include "UsefulBuf_Tests.h"
-#include "qcbor_decode_malloc_tests.h"
// Used to test the test runner
int fail_test()
@@ -57,10 +56,10 @@
const char *NumToString(int32_t nNum, UsefulBuf StringMem)
{
const int32_t nMax = 1000000000;
-
+
UsefulOutBuf OutBuf;
UsefulOutBuf_Init(&OutBuf, StringMem);
-
+
if(nNum < 0) {
UsefulOutBuf_AppendByte(&OutBuf, '-');
nNum = -nNum;
@@ -68,7 +67,7 @@
if(nNum > nMax-1) {
return "XXX";
}
-
+
bool bDidSomeOutput = false;
for(int n = nMax; n > 0; n/=10) {
int x = nNum/n;
@@ -82,7 +81,7 @@
UsefulOutBuf_AppendByte(&OutBuf, '0');
}
UsefulOutBuf_AppendByte(&OutBuf, '\0');
-
+
return UsefulOutBuf_GetError(&OutBuf) ? "" : StringMem.ptr;
}
@@ -92,15 +91,19 @@
typedef const char * (test_fun2_t)(void);
-#define TEST_ENTRY(test_name) {#test_name, test_name}
+#define TEST_ENTRY(test_name) {#test_name, test_name, true}
+#define TEST_ENTRY_DISABLED(test_name) {#test_name, test_name, false}
+
typedef struct {
- const char *szTestName;
+ const char *szTestName;
test_fun_t *test_fun;
+ bool bEnabled;
} test_entry;
typedef struct {
const char *szTestName;
test_fun2_t *test_fun;
+ bool bEnabled;
} test_entry2;
test_entry2 s_tests2[] = {
@@ -115,7 +118,7 @@
test_entry s_tests[] = {
- TEST_ENTRY(MallocAllStringsTest),
+ TEST_ENTRY(ParseMapAsArrayTest),
TEST_ENTRY(AllocAllStringsTest),
TEST_ENTRY(IndefiniteLengthNestTest),
TEST_ENTRY(NestedMapTestIndefLen),
@@ -153,6 +156,8 @@
TEST_ENTRY(BstrWrapErrorTest),
TEST_ENTRY(BstrWrapNestTest),
TEST_ENTRY(CoseSign1TBSTest),
+ TEST_ENTRY(StringDecoderModeFailTest),
+ TEST_ENTRY_DISABLED(BigComprehensiveInputTest),
TEST_ENTRY(EncodeErrorTests),
//TEST_ENTRY(fail_test),
};
@@ -166,21 +171,26 @@
test_entry2 *t2;
const test_entry2 *s_tests2_end = s_tests2 + sizeof(s_tests2)/sizeof(test_entry2);
-
+
for(t2 = s_tests2; t2 < s_tests2_end; t2++) {
+ if(!t2->bEnabled && !szTestName) {
+ // Don't run disabled tests when all tests are being run
+ // as indicated by no specific test name being given
+ continue;
+ }
if(szTestName && strcmp(szTestName, t2->szTestName)) {
continue;
}
- const char * x = (t2->test_fun)();
+ const char * szTestResult = (t2->test_fun)();
nTestsRun++;
if(output) {
(*output)(t2->szTestName, poutCtx);
}
-
- if(x) {
+
+ if(szTestResult) {
if(output) {
(*output)(" FAILED (returned ", poutCtx);
- (*output)(x, poutCtx);
+ (*output)(szTestResult, poutCtx);
(*output)(")\n", poutCtx);
}
nTestsFailed++;
@@ -190,25 +200,30 @@
}
}
}
-
-
+
+
test_entry *t;
const test_entry *s_tests_end = s_tests + sizeof(s_tests)/sizeof(test_entry);
-
+
for(t = s_tests; t < s_tests_end; t++) {
+ if(!t->bEnabled && !szTestName) {
+ // Don't run disabled tests when all tests are being run
+ // as indicated by no specific test name being given
+ continue;
+ }
if(szTestName && strcmp(szTestName, t->szTestName)) {
continue;
}
- int x = (t->test_fun)();
+ int nTestResult = (t->test_fun)();
nTestsRun++;
if(output) {
(*output)(t->szTestName, poutCtx);
}
-
- if(x) {
+
+ if(nTestResult) {
if(output) {
(*output)(" FAILED (returned ", poutCtx);
- (*output)(NumToString(x, StringStorage), poutCtx);
+ (*output)(NumToString(nTestResult, StringStorage), poutCtx);
(*output)(")\n", poutCtx);
}
nTestsFailed++;
@@ -218,11 +233,11 @@
}
}
}
-
+
if(pNumTestsRun) {
*pNumTestsRun = nTestsRun;
}
-
+
if(output) {
(*output)( "SUMMARY: ", poutCtx);
(*output)( NumToString(nTestsRun, StringStorage), poutCtx);
@@ -230,6 +245,6 @@
(*output)( NumToString(nTestsFailed, StringStorage), poutCtx);
(*output)( " tests failed\n", poutCtx);
}
-
+
return nTestsFailed;
}
diff --git a/test/run_tests.h b/test/run_tests.h
index 498554e..431ef22 100644
--- a/test/run_tests.h
+++ b/test/run_tests.h
@@ -1,10 +1,10 @@
/*==============================================================================
run_tests.c -- test aggregator and results reporting
-
+
Copyright (c) 2018, Laurence Lundblade.
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
@@ -17,7 +17,7 @@
* The name "Laurence Lundblade" may not be used to
endorse or promote products derived from this software without
specific prior written permission.
-
+
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT