Clear distinction between UsefulBuf and UsefulBufC and convention for using them. Remove EncodedCBOR structure. AddRaw is now AddedEncoded. Can only add fully completed maps and arrays, not parts of maps and arrays now
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..1eeb20d
--- /dev/null
+++ b/README.md
@@ -0,0 +1,37 @@
+# QCBOR
+
+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.
+
+**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 used. The encode context is 128 bytes, decode context is 168 bytes and the description of decoded data item is 56 bytes. Stack use is very 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 and it is 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) (indefinite length support is planned, but not ready yet).
+
+**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.
+
+**Small Code Size** – When optimized for size using the compiler -Os option, x86 code is less than 5KB (~2KB encode, 2KB decode, 1KB common).
+
+**Clear documented public interface** – The public interface is separated from the implementation. It can be put to use without reading the source.
+
+## Code Status
+This 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.
+
+The following modifications are planned as of September 2018:
+* Floating point support
+* Indefinite length support
+* Improve design for handling multiple tags
+
+These changes may result in some interface changes.
+
+
+
+
diff --git a/code_size_check.c b/code_size_check.c
new file mode 100644
index 0000000..977eac3
--- /dev/null
+++ b/code_size_check.c
@@ -0,0 +1,9 @@
+//
+// code_size_check.c
+// QCBOR
+//
+// Created by Laurence Lundblade on 9/15/18.
+// Copyright © 2018 Laurence Lundblade. All rights reserved.
+//
+
+#include "code_size_check.h"
diff --git a/code_size_check.h b/code_size_check.h
new file mode 100644
index 0000000..8dc4174
--- /dev/null
+++ b/code_size_check.h
@@ -0,0 +1,14 @@
+//
+// code_size_check.h
+// QCBOR
+//
+// Created by Laurence Lundblade on 9/15/18.
+// Copyright © 2018 Laurence Lundblade. All rights reserved.
+//
+
+#ifndef code_size_check_h
+#define code_size_check_h
+
+#include <stdio.h>
+
+#endif /* code_size_check_h */
diff --git a/inc/UsefulBuf.h b/inc/UsefulBuf.h
index aa160ba..69b2665 100644
--- a/inc/UsefulBuf.h
+++ b/inc/UsefulBuf.h
@@ -63,45 +63,43 @@
@file UsefulBuf.h
The goal of this code is to make buffer and pointer manipulation
- easier and safer.
+ easier and safer when working with binary data.
- The idea is that you use the UsefulBuf, UsefulOutBuf and UsefulInputBuf
+ 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 formating data. For example
- the QCBOR encoder was rewritten using these and only one simple function
- remains that does any pointer manipulation.
+ 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 must use cases. For
+ not by that much or enough to have an affect for most use cases. For
security-oriented code this is highly worthwhile. Clarity, simplicity,
- reviwability and certainty are more important.
+ reviewability and are more important.
There are some extra sanity and double checks in this code to help catch
coding errors and simple memory corruption. They are helpful, but not a
substitute for proper code review, input validation and such.
This code has a lot of simple small functions to hopefully create clarity
- about what it does so it is easier to review. UsefulOutBuf and UsefulInBuf
+ about what it does so it is easier to review. UsefulOutBuf and UsefulInputBuf
are also objects in a form (a largely private data structure and accessor
- functions). Most of the code is marked inline and presumably compilers
- will do a good job on optimizing all this. (In theory they should, though
- this has not been verified yet).
+ functions). This code will benefit enormously from aggressive optimization
+ such as the -Os or -O3 options.
*/
/**
-
- UsefulBuf is a simple data structure to hold a pointer and length for
+ UsefulBufC and UsefulBuf are simple data structures to hold a pointer and 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 the pointer and the convention for handling a
+ 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
@@ -124,43 +122,130 @@
A UsefulBuf is NULL, it has no value, when the ptr in it is NULL.
There are only a few utility functions and macros associated with
- UsefulBuf.
+ UsefulBuf including the equivalent of memxxx() functions.
See also UsefulOutBuf. It is a richer structure that has both the
size of the valid data and the size of the buffer.
- Struct is 16 or 8 bytes on a 64 or 32 bit machine so it can go on the
+ UsefulBufC 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 ballon fits beautifully, "it goes in and out like
+ birthday. Eeyore's balloon fits beautifully, "it goes in and out like
anything".
*/
+typedef struct {
+ const void *ptr;
+ const size_t len;
+} UsefulBufC;
+
+/**
+ The non-const UsefulBuf typically used for some allocated memory
+ that is to be filled in. The len is the amount of memory,
+ not the length of the valid data in the buffer.
+ */
typedef struct {
void *ptr;
const size_t len;
} UsefulBuf;
-typedef struct {
- const void *ptr;
- const size_t len;
-} UsefulBufC;
+/**
+ A "NULL" UsefulBufC is one that has no value in the same way a NULL pointer has no value.
+ A UsefulBuf is NULL when the ptr field is NULL. It doesn't matter what len is.
+ See UsefulBuf_IsEmpty() for the distinction between NULL and empty.
+ */
+#define NULLUsefulBufC ((UsefulBufC) {NULL, 0})
+
+/** A NULL UsefulBuf is one that has no memory associated the say way
+ NULL points to nothing. It does not matter what len is.
+ */
+#define NULLUsefulBuf ((UsefulBuf) {NULL, 0})
/**
- A "NULL" UsefulBuf is one that has no value in the same way a NULL pointer has no value.
- A UsefulBuf is NULL when the ptr field is NULL. It doesn't matter what len is.
+ @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.
*/
-#define UsefulBuf_IsNULL(UB) (!(UB).ptr)
+static inline int UsefulBuf_IsNULL(UsefulBuf UB) {
+ return !UB.ptr;
+}
-#define NULLUsefulBufC ((UsefulBufC) {NULL, 0})
-#define NULLUsefulBuf ((UsefulBuf) {NULL, 0})
+/**
+ @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) {
+ return !UB.ptr;
+}
+/**
+ @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
+ not be NULL when the UsefulBuf is considered empty, but not NULL.
+
+ */
+static inline int UsefulBuf_IsEmpty(UsefulBuf UB) {
+ return !UB.len;
+}
+
+
+/**
+ @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) {
+ return !UB.len;
+}
+
+
+/**
+ @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) {
+ return UsefulBuf_IsEmpty(UB) || UsefulBuf_IsNULL(UB);
+}
+
+
+/**
+ @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_IsNULLOrEmptyXC(UsefulBufC UB) {
+ return UsefulBuf_IsEmptyC(UB) || UsefulBuf_IsNULLC(UB);
+}
+
/**
@brief Convert a non const UsefulBuf to a const UsefulBufC
@@ -183,28 +268,23 @@
Returns: a non const UsefulBuf struct
*/
-static inline UsefulBuf UsefulBufC_Unconst(const UsefulBufC UBC)
+static inline UsefulBuf UsefulBuf_Unconst(const UsefulBufC UBC)
{
return (UsefulBuf){(void *)UBC.ptr, UBC.len};
}
-
-
/**
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 SZToUsefulBufC
+ 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 SZLiteralToUsefulBufC(szString) \
- ((UsefulBufC) {(szString), sizeof(szString)-1})
-
#define UsefulBuf_FromSZLiteral(szString) \
((UsefulBufC) {(szString), sizeof(szString)-1})
@@ -213,48 +293,22 @@
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 strings.
+ It will not work on non-literal arrays.
*/
-#define ByteArrayLiteralToUsefulBufC(pBytes) \
- ((UsefulBufC) {(pBytes), sizeof(pBytes)})
-
#define UsefulBuf_FromByteArrayLiteral(pBytes) \
((UsefulBufC) {(pBytes), sizeof(pBytes)})
-// Make an automatic variable with name of type UsefulBuf and point it to a stack
-// variable of the give size
-#define MakeUsefulBufOnStack(name, size) \
- uint8_t __pBuf##name[(size)];\
- UsefulBuf name = {__pBuf##name , sizeof( __pBuf##name )}
-
+/**
+ Make an automatic variable with name of type UsefulBuf and point it to a stack
+ variable of the give size
+ */
#define UsefulBuf_MakeStackUB(name, size) \
uint8_t __pBuf##name[(size)];\
UsefulBuf name = {__pBuf##name , sizeof( __pBuf##name )}
-/*
- 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
- not be NULL when the UsefulBuf is considered empty, but not NULL.
- */
-
-#define UsefulBuf_IsEmpty(UB) (!(UB).len)
-
-#define UsefulBuf_IsNULLOrEmpty(UB) (UsefulBuf_IsNULL(UB) || UsefulBuf_IsEmpty(UB))
-
-static inline int UsefulBuf_IsEmptyX(UsefulBufC UB) {
- return !UB.len;
-}
-
-
-
/**
@brief Convert a NULL terminated string to a UsefulBufC.
@@ -287,11 +341,12 @@
this will crash, rather than return NULLUsefulBufC if
they are NULL or invalid.
+ Results are undefined if Dest and Src overlap.
+
*/
UsefulBufC UsefulBuf_Copy(UsefulBuf Dest, const UsefulBufC Src);
-
/**
@brief Set all bytes in a UsefulBuf to a value, for example 0
@@ -302,8 +357,10 @@
this will crash if NULL or invalid.
*/
-void UsefulBuf_Set(UsefulBuf *pDest, uint8_t value);
-
+static inline void UsefulBuf_Set(UsefulBuf *pDest, uint8_t value)
+{
+ memset(pDest->ptr, value, pDest->len);
+}
/**
@@ -315,7 +372,7 @@
@return 0 on success, 1 on failure
- This fails and returns 1 if Src.len is greater than
+ This fails and returns NULLUsefulBufC if len is greater than
pDest->len.
Note that like memcpy, the pointers are not checked and
@@ -330,7 +387,43 @@
/**
- @brief Compare two UsefulBufs
+ @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)
+{
+ if(uAmount > UB.len) {
+ return NULLUsefulBufC;
+ }
+ return (UsefulBufC){UB.ptr, uAmount};
+}
+
+
+/**
+ @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)
+{
+ if(uAmount > UB.len) {
+ return NULLUsefulBufC;
+ }
+ return (UsefulBufC){UB.ptr + uAmount, UB.len - uAmount};
+}
+
+
+/**
+ @brief Compare two UsefulBufCs
@param[in] UB1 The destination buffer to copy into
@param[in] UB2 The source to copy from
@@ -353,7 +446,7 @@
int UsefulBuf_Compare(const UsefulBufC UB1, const UsefulBufC UB2);
-/*
+/**
@brief Find one UsefulBuf in another
@param[in] BytesToSearch UsefulBuf to search through
@@ -367,6 +460,26 @@
+#if NOT_DEPRECATED
+/** Deprecated macro; use UsefulBuf_FromSZLiteral instead */
+#define SZLiteralToUsefulBufC(szString) \
+ ((UsefulBufC) {(szString), sizeof(szString)-1})
+
+/** Deprecated macro; use UsefulBuf_MakeStackUB instead */
+#define MakeUsefulBufOnStack(name, size) \
+ uint8_t __pBuf##name[(size)];\
+ UsefulBuf name = {__pBuf##name , sizeof( __pBuf##name )}
+
+/** Deprecated macro; use UsefulBuf_FromByteArrayLiteral instead */
+#define ByteArrayLiteralToUsefulBufC(pBytes) \
+ ((UsefulBufC) {(pBytes), sizeof(pBytes)})
+
+/** Deprecated function; use UsefulBuf_Unconst() instead */
+static inline UsefulBuf UsefulBufC_Unconst(const UsefulBufC UBC)
+{
+ return (UsefulBuf){(void *)UBC.ptr, UBC.len};
+}
+#endif
@@ -393,7 +506,7 @@
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 callers
+ 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
@@ -401,7 +514,7 @@
left and see if some data will fit too, but their use is generally
not necessary.
- The generall calling flow is like this:
+ 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
@@ -421,23 +534,23 @@
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 callint Init, if you want
+ 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
- addtion to gaurd against use of an uninitialized or corrupted
+ 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
+ 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.
*/
typedef struct {
- UsefulBuf UB;
+ UsefulBuf UB; // Memory that is being output to
size_t data_len; // length of the data
uint16_t magic; // Used to detect corruption and lack of initialization
uint8_t err;
@@ -965,17 +1078,17 @@
/**
- UsefulInBuf is the counterpart to UsefulOutBuf and is for parsing
+ UsefulInputBuf is the counterpart to UsefulOutBuf and is for parsing
data read or received. The idea is that you initialize with the data
you got off the network and its length. Then you use the functions
here to get the various data types out of it. It maintains a position
for getting the next item. This means you don't have to track a
- pointer as you get each object. UsefulInBuf does that for you and
- makes sure it never goes off the end of the buffer. The qcbor
+ pointer as you get each object. UsefulInputBuf does that for you and
+ 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.
- UsefulInBuf also maintains an intenal error state so you do not have
+ 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
but they will either return 0 or NULL. As long as you don't
diff --git a/inc/qcbor.h b/inc/qcbor.h
index 1036e1a..9566fae 100644
--- a/inc/qcbor.h
+++ b/inc/qcbor.h
@@ -472,39 +472,7 @@
*/
-
/**
- This holds some encoded CBOR. It is primarily the pointer and length
- of the encoded CBOR.
-
- It also includes a count of the number of items at the top level of
- the encoded CBOR. When the top level of CBOR is a map or an array
- the item count will be 1 because there is one map or array. It is
- only greater than 1 if the top level is not a map or an array.
-
- For the most part the item count can be ignored. It is only needed
- when piecing together separately encoded chunks using QCBOREncode_AddRaw().
- (In this case it saves the parsing the encoded CBOR that is being
- added to get the item count).
-
- The item count is the actual number of individual items. In array
- it is the same as the CBOR count. For a map it is double because
- the CBOR count is label/data pairs while this count the label
- and the data separately
- */
-
-typedef struct __EncodedCBORC {
- UsefulBufC Bytes;
- uint16_t uItems;
-} EncodedCBORC;
-
-typedef struct __EncodedCBOR {
- UsefulBufC Bytes;
- uint16_t uItems;
-} EncodedCBOR;
-
-
-/**
The maximum number of items in a single array or map when encoding of decoding.
*/
#define QCBOR_MAX_ITEMS_IN_ARRAY (UINT16_MAX) // This value is 65,535 a lot of items for an array
@@ -712,20 +680,6 @@
*/
#define QCBOR_NO_INT_LABEL INT64_MAX
-
-/**
- Convert a non const EncodedCBOR to a const EncodedCBORC
-
- @param[in] ECBOR The EncodedCBOR to convert
-
- Returns: a EncodedCBORC struct
- */
-static inline EncodedCBORC EncodedCBORConst(const EncodedCBOR ECBOR)
-{
- return (EncodedCBORC){ECBOR.Bytes, ECBOR.uItems};
-}
-
-
/**
QCBOREncodeContext is the data type that holds context for all the
encoding functions. It is a little over 100 bytes so it can go on
@@ -741,8 +695,7 @@
Initialize the the encoder to prepare to encode some CBOR.
@param[in,out] pCtx The encoder context to initialize.
- @param[out] pBuf The buffer into which this encoded result will be placed.
- @param[in] uBufLen The length of pBuf.
+ @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
@@ -1297,30 +1250,36 @@
Add some already-encoded CBOR bytes
@param[in] pCtx The context to add to.
+ @param[in] szLabel A NULL-terminated string label for the map. May be a NULL pointer.
+ @param[in] nLabel An integer label for the whole map. QCBOR_NO_INT_LABEL for no integer label.
+ @param[in] uTag A tag for the whole map or CBOR_TAG_NONE.
@param[in] Encoded The already-encoded CBOR to add to the context.
- The CBOR added here must be self-consistent and not have any arrays
- or maps open. Specifically, if an array or map with N encoded items is
- added all N items must be present in pEncodedCBOR. This is because
- the bytes added here are not examined in any way for correct CBOR
- formatting or to figure out if all the arrays and maps are closed or
- not.
+ 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 every produce indefinite lengths, it is OK for the
+ raw CBOR added here to have indefinite lengths.
- If what you are adding is one array or map at the top level, then
- pass 1 for nItems. This is really the main intended use for this
- function.
+ 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.
- Otherwise you must provide the correct count for the number of items,
- particularly if you have a map or array open so the correct count can
- be added when it is closed.
+ 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 have a single item.
- It is a good idea to use http://cbor.me, the CBOR playground to validate
- CBOR generated when you use this function.
*/
-void QCBOREncode_AddRaw(QCBOREncodeContext *pCtx, EncodedCBORC Encoded);
+void QCBOREncode_AddEncodedToMap_3(QCBOREncodeContext *pCtx, const char *szLabel, uint64_t nLabel, uint64_t uTag, UsefulBufC Encoded);
+#define QCBOREncode_AddEncodedToMapN(pCtx, nLabel, Encoded) \
+ QCBOREncode_AddEncodedToMap_3((pCtx), NULL, (nLabel), CBOR_TAG_NONE, Encoded)
+#define QCBOREncode_AddEncoded(pCtx, Encoded) \
+ QCBOREncode_AddEncodedToMap_3((pCtx), NULL, QCBOR_NO_INT_LABEL, CBOR_TAG_NONE, (Encoded))
+
+#define QCBOREncode_AddEncodedToMap(pCtx, szLabel, Encoded) \
+ QCBOREncode_AddEncodedToMap_3((pCtx), (szLabel), QCBOR_NO_INT_LABEL, CBOR_TAG_NONE, (Encoded))
/**
@@ -1391,7 +1350,7 @@
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. The number of items is in
- pEncodedCBOR->nItems. pEncodedCBOR->Bytes.ptr is NULL.
+ pEncodedCBOR->nItems. pEncodedCBOR->Bytes.ptr is NULL. TODO: fix documentation
If a buffer was passed, then pEncodedCBOR->Bytes.ptr is the same as
the buffer passed to QCBOR_Init() and contains the encoded CBOR.
@@ -1407,7 +1366,7 @@
*/
-int QCBOREncode_Finish2(QCBOREncodeContext *pCtx, EncodedCBOR *pEncodedCBOR);
+int QCBOREncode_Finish2(QCBOREncodeContext *pCtx, UsefulBufC *pEncodedCBOR);
diff --git a/src/UsefulBuf.c b/src/UsefulBuf.c
index d98ebd5..ea6978c 100644
--- a/src/UsefulBuf.c
+++ b/src/UsefulBuf.c
@@ -84,13 +84,7 @@
}
-/*
- Public function -- see UsefulBuf.h
- */
-void UsefulBuf_Set(UsefulBuf *pDest, uint8_t value)
-{
- memset(pDest->ptr, value, pDest->len);
-}
+
/*
@@ -307,7 +301,7 @@
UsefulBufC UsefulOutBuf_CopyOut2(UsefulOutBuf *me, UsefulBuf pDest)
{
UsefulBufC Tmp = UsefulOutBuf_OutUBuf(me);
- if(UsefulBuf_IsNULL(Tmp)) {
+ if(UsefulBuf_IsNULLC(Tmp)) {
return NULLUsefulBufC;
}
@@ -324,7 +318,7 @@
int UsefulOutBuf_CopyOut(UsefulOutBuf *me, void *pBuf, size_t uBufSize, size_t *puCopied)
{
UsefulBufC B = UsefulOutBuf_CopyOut2(me, (UsefulBuf){pBuf, uBufSize});
- if(UsefulBuf_IsNULL(B)) {
+ if(UsefulBuf_IsNULLC(B)) {
return 1; // was in error state or was corrupted or pBuf too small
}
diff --git a/src/qcbor_encode.c b/src/qcbor_encode.c
index b40db6c..64a6b33 100644
--- a/src/qcbor_encode.c
+++ b/src/qcbor_encode.c
@@ -297,7 +297,7 @@
}
-static void AddBytesInternal(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, UsefulBufC Bytes, uint8_t uMajorType, uint16_t uItems);
+static void AddBytesInternal(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, UsefulBufC Bytes, uint8_t uMajorType);
/*
@@ -307,7 +307,7 @@
{
if(szLabel) {
UsefulBufC SZText = {szLabel, strlen(szLabel)};
- AddBytesInternal(me, NULL, nLabel, CBOR_TAG_NONE, SZText, CBOR_MAJOR_TYPE_TEXT_STRING, 0);
+ AddBytesInternal(me, NULL, nLabel, CBOR_TAG_NONE, SZText, CBOR_MAJOR_TYPE_TEXT_STRING);
} else if (QCBOR_NO_INT_LABEL != nLabel) {
// Add an integer label. This is just adding an integer at this point
// This will result in a call right back to here, but the call won't do anything
@@ -323,10 +323,10 @@
/*
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 or
- pre-formatted CBOR.
+ different major types. This is also used to insert raw
+ pre-encoded CBOR.
*/
-static void AddBytesInternal(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, UsefulBufC Bytes, uint8_t uMajorType, uint16_t uItems)
+static void AddBytesInternal(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, UsefulBufC Bytes, uint8_t uMajorType)
{
if(Bytes.len >= UINT32_MAX) {
// This implementation doesn't allow buffers larger than UINT32_MAX. This is
@@ -350,7 +350,7 @@
UsefulOutBuf_AppendUsefulBuf(&(me->OutBuf), Bytes);
// Update the array counting if there is any nesting at all
- me->uError = Nesting_Increment(&(me->nesting), uMajorType == CBOR_MAJOR_NONE_TYPE_RAW ? uItems : 1);
+ me->uError = Nesting_Increment(&(me->nesting), 1);
}
}
}
@@ -363,22 +363,21 @@
*/
void QCBOREncode_AddBytes_3(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, UsefulBufC Bytes)
{
- AddBytesInternal(me, szLabel, nLabel, uTag, Bytes, CBOR_MAJOR_TYPE_BYTE_STRING, 0);
+ AddBytesInternal(me, szLabel, nLabel, uTag, Bytes, CBOR_MAJOR_TYPE_BYTE_STRING);
}
void QCBOREncode_AddText_3(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, UsefulBufC Bytes)
{
- AddBytesInternal(me, szLabel, nLabel, uTag, Bytes, CBOR_MAJOR_TYPE_TEXT_STRING, 0);
+ AddBytesInternal(me, szLabel, nLabel, uTag, Bytes, CBOR_MAJOR_TYPE_TEXT_STRING);
}
-void QCBOREncode_AddRaw(QCBOREncodeContext *me, EncodedCBORC Raw)
+void QCBOREncode_AddEncodedToMap_3(QCBOREncodeContext *me, const char *szLabel, uint64_t nLabel, uint64_t uTag, UsefulBufC Encoded)
{
- AddBytesInternal(me, NULL, QCBOR_NO_INT_LABEL, CBOR_TAG_NONE, Raw.Bytes, CBOR_MAJOR_NONE_TYPE_RAW, Raw.uItems);
+ AddBytesInternal(me, szLabel, nLabel, uTag, Encoded, CBOR_MAJOR_NONE_TYPE_RAW);
}
-
/*
Internal function common to opening an array or a map
@@ -585,7 +584,7 @@
/*
Public functions to finish and get the encoded result. See header qcbor.h
*/
-int QCBOREncode_Finish2(QCBOREncodeContext *me, EncodedCBOR *pEncodedCBOR)
+int QCBOREncode_Finish2(QCBOREncodeContext *me, UsefulBufC *pEncodedCBOR)
{
if(me->uError)
goto Done;
@@ -605,9 +604,7 @@
goto Done;
}
- pEncodedCBOR->Bytes = UsefulOutBuf_OutUBuf(&(me->OutBuf));
-
- pEncodedCBOR->uItems = Nesting_GetCount(&(me->nesting));
+ *pEncodedCBOR = UsefulOutBuf_OutUBuf(&(me->OutBuf));
Done:
return me->uError;
@@ -615,12 +612,12 @@
int QCBOREncode_Finish(QCBOREncodeContext *me, size_t *puEncodedLen)
{
- EncodedCBOR Enc;
+ UsefulBufC Enc;
int nReturn = QCBOREncode_Finish2(me, &Enc);
if(nReturn == QCBOR_SUCCESS) {
- *puEncodedLen = Enc.Bytes.len;
+ *puEncodedLen = Enc.len;
}
return nReturn;
diff --git a/test/basic_test.c b/test/basic_test.c
index e5f510c..905ad1a 100644
--- a/test/basic_test.c
+++ b/test/basic_test.c
@@ -7,31 +7,42 @@
//
#include "basic_test.h"
-
#include "qcbor.h"
+/*
+ Some very minimal tests until the full test suite is open sourced and available.
+ Return codes here don't mean much (yet).
+ */
int basic_test_one()
{
- MakeUsefulBufOnStack(Storage, 512);
+ // Very simple CBOR, a map with one boolean that is true in it
+ UsefulBuf_MakeStackUB(MemoryForEncoded, 100);
QCBOREncodeContext EC;
- QCBOREncode_Init(&EC, Storage);
+ QCBOREncode_Init(&EC, MemoryForEncoded);
- QCBOREncode_AddBool(&EC, true);
+ QCBOREncode_OpenMap(&EC);
+ QCBOREncode_AddBoolToMapN(&EC, 66, true);
+ QCBOREncode_CloseMap(&EC);
- EncodedCBOR Encoded;
+ UsefulBufC Encoded;
if(QCBOREncode_Finish2(&EC, &Encoded)) {
return -3;
}
-
+ // Decode it and see that is right
QCBORDecodeContext DC;
QCBORItem Item;
- QCBORDecode_Init(&DC, Encoded.Bytes, QCBOR_DECODE_MODE_NORMAL);
+ QCBORDecode_Init(&DC, Encoded, QCBOR_DECODE_MODE_NORMAL);
QCBORDecode_GetNext(&DC, &Item);
+ if(Item.uDataType != QCBOR_TYPE_MAP) {
+ return -1;
+ }
+
+ QCBORDecode_GetNext(&DC, &Item);
if(Item.uDataType != QCBOR_TYPE_TRUE) {
return -1;
}
@@ -40,5 +51,69 @@
return -2;
}
+
+ // Make another encoded message with the CBOR from the previous put into this one
+ UsefulBuf_MakeStackUB(MemoryForEncoded2, 100);
+ QCBOREncode_Init(&EC, MemoryForEncoded2);
+ QCBOREncode_OpenArray(&EC);
+ QCBOREncode_AddUInt64(&EC, 451);
+ QCBOREncode_AddEncoded(&EC, Encoded);
+ QCBOREncode_OpenMap(&EC);
+ QCBOREncode_AddEncodedToMapN(&EC, -70000, Encoded);
+ QCBOREncode_CloseMap(&EC);
+ QCBOREncode_CloseArray(&EC);
+
+ UsefulBufC Encoded2;
+ if(QCBOREncode_Finish2(&EC, &Encoded2)) {
+ return -3;
+ }
+
+
+ // Decode it and see if it is OK
+ QCBORDecode_Init(&DC, Encoded2, QCBOR_DECODE_MODE_NORMAL);
+
+ QCBORDecode_GetNext(&DC, &Item);
+ if(Item.uDataType != QCBOR_TYPE_ARRAY || Item.val.uCount != 3) {
+ return -1;
+ }
+
+ QCBORDecode_GetNext(&DC, &Item);
+ if(Item.uDataType != QCBOR_TYPE_INT64 || Item.val.uint64 != 451) {
+ return -1;
+ }
+
+ QCBORDecode_GetNext(&DC, &Item);
+ if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 1) {
+ return -1;
+ }
+
+ QCBORDecode_GetNext(&DC, &Item);
+ if(Item.uDataType != QCBOR_TYPE_TRUE) {
+ return -1;
+ }
+
+ QCBORDecode_GetNext(&DC, &Item);
+ if(Item.uDataType != QCBOR_TYPE_MAP || Item.val.uCount != 1) {
+ return -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 -1;
+ }
+
+ QCBORDecode_GetNext(&DC, &Item);
+ if(Item.uDataType != QCBOR_TYPE_TRUE || Item.uLabelType != QCBOR_TYPE_INT64 || Item.label.int64 != 66) {
+ return -1;
+ }
+
+ if(QCBORDecode_Finish(&DC)) {
+ return -2;
+ }
+
+
+
+
+
return 0;
}