remove all trailing tabs and spaces
diff --git a/src/UsefulBuf.c b/src/UsefulBuf.c
index 282b6ad..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,9 +67,9 @@
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};
}
@@ -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,26 +264,26 @@
/*
- 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};
}
/*
Public function -- see UsefulBuf.h
-
+
Copy out the data accumulated in to the output buffer.
*/
UsefulBufC UsefulOutBuf_CopyOut(UsefulOutBuf *me, UsefulBuf pDest)
@@ -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/UsefulBuf.o b/src/UsefulBuf.o
new file mode 100644
index 0000000..8974c1f
--- /dev/null
+++ b/src/UsefulBuf.o
Binary files differ
diff --git a/src/ieee754.c b/src/ieee754.c
index b7cf7c8..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) {
@@ -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/ieee754.o b/src/ieee754.o
new file mode 100644
index 0000000..17c315e
--- /dev/null
+++ b/src/ieee754.o
Binary files differ
diff --git a/src/qcbor_decode.c b/src/qcbor_decode.c
index 8a1b151..b015dd8 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;
}
@@ -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,7 +559,7 @@
{
// Stack usage: UsefulBuf 2, int/ptr 1 40
QCBORError nReturn = QCBOR_SUCCESS;
-
+
const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(pUInBuf, uStrLen);
if(UsefulBuf_IsNULLC(Bytes)) {
// Failed to get the bytes for this string item
@@ -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,7 +595,7 @@
if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
return QCBOR_ERR_BAD_OPT_TAG;
}
-
+
const UsefulBufC Temp = pDecodedItem->val.string;
pDecodedItem->val.dateString = Temp;
pDecodedItem->uDataType = QCBOR_TYPE_DATE_STRING;
@@ -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,12 +943,12 @@
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(me->uDecodeMode != QCBOR_DECODE_MODE_MAP_AS_ARRAY) {
// In a map and caller wants maps decoded, not treated as arrays
@@ -960,7 +960,7 @@
nReturn = GetNext_TaggedItem(me, pDecodedItem, pTags);
if(nReturn)
goto Done;
-
+
pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
if(LabelItem.uDataType == QCBOR_TYPE_TEXT_STRING) {
@@ -996,7 +996,7 @@
pDecodedItem->val.uCount *= 2;
}
}
-
+
Done:
return nReturn;
}
@@ -1012,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;
@@ -1024,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)) {
@@ -1048,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
@@ -1076,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;
}
@@ -1097,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.
-
+
*/
@@ -1134,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;
}
@@ -1153,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;
@@ -1164,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
@@ -1174,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
-
+
*/
@@ -1211,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.
*/
@@ -1226,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
@@ -1249,7 +1249,7 @@
me->pFree += uNewSize;
}
}
-
+
return (UsefulBuf){pReturn, uNewSize};
}
@@ -1273,26 +1273,26 @@
if(Pool.len < sizeof(MemPool)+1) {
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->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;
}
@@ -1301,13 +1301,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.o b/src/qcbor_decode.o
new file mode 100644
index 0000000..5db18c0
--- /dev/null
+++ b/src/qcbor_decode.o
Binary files differ
diff --git a/src/qcbor_decode_malloc.c b/src/qcbor_decode_malloc.c
index 33b5d6c..fae095a 100644
--- a/src/qcbor_decode_malloc.c
+++ b/src/qcbor_decode_malloc.c
@@ -1,12 +1,12 @@
/*==============================================================================
-
+
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:
@@ -19,7 +19,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
@@ -64,7 +64,7 @@
pAllocaterContext->fDestructor = MemMallocDestructor;
pAllocaterContext->pAllocaterContext = pAllocaterContext; // So that destructor can work.
}
-
+
return pAllocaterContext;
}
diff --git a/src/qcbor_decode_malloc.o b/src/qcbor_decode_malloc.o
new file mode 100644
index 0000000..cee53c1
--- /dev/null
+++ b/src/qcbor_decode_malloc.o
Binary files differ
diff --git a/src/qcbor_encode.c b/src/qcbor_encode.c
index a99da1f..f660d7c 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
-------- ---- ---------------------------------------------------
11/29/18 llundblade Rework to simpler handling of tags and labels.
@@ -47,14 +47,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"
@@ -69,13 +69,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.
@@ -92,7 +92,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;
@@ -115,7 +115,7 @@
if(uAmount >= QCBOR_MAX_ITEMS_IN_ARRAY - pNesting->pCurrentNesting->uCount) {
return QCBOR_ERR_ARRAY_TOO_LONG;
}
-
+
pNesting->pCurrentNesting->uCount += uAmount;
return QCBOR_SUCCESS;
}
@@ -157,23 +157,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
@@ -181,24 +181,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
-
+
*/
@@ -221,50 +221,50 @@
-/*
+/*
All CBOR data items have a type and a number. The number is either
the value of the item for integer types, the length of the content
for string, byte, array and map types, a tag for major type 6, and
has serveral uses for major type 7.
-
+
This function encodes the type and the number. There are several
encodings for the number depending on how large it is and how it is
used.
-
- Every encoding of the type and number has at least one byte, the
+
+ Every encoding of the type and number has at least one byte, the
"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 number. If the number is less than 24,
then it is encoded entirely in the five bits. This is neat because it
allows you to encode an entire CBOR data item in 1 byte for many
values and types (integers 0-23, true, false, and tags).
-
+
If the number is larger than 24, then it is encoded in 1,2,4 or 8
additional bytes, with the number of these bytes indicated by the
values of the 5 bits 24, 25, 25 and 27.
-
+
It is possible to encode a particular number in many ways with this
representation. This implementation always uses the smallest
possible representation. This is also the suggestion made in the RFC
for cannonical CBOR.
-
+
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 halft, float or double are 0 it is still correctly
encoded in 2, 4 or 8 bytes.
-
+
*/
static void InsertEncodedTypeAndNumber(QCBOREncodeContext *me, uint8_t uMajorType, size_t uMinLen, uint64_t uNumber, size_t uPos)
{
@@ -273,20 +273,20 @@
// _generation_, not parsing c) a mistake will result in bad CBOR generation,
// not a security vulnerability.
uMajorType <<= 5;
-
+
if(uNumber > 0xffffffff || uMinLen >= 8) {
UsefulOutBuf_InsertByte(&(me->OutBuf), uMajorType + LEN_IS_EIGHT_BYTES, uPos);
UsefulOutBuf_InsertUint64(&(me->OutBuf), (uint64_t)uNumber, uPos+1);
-
+
} else if(uNumber > 0xffff || uMinLen >= 4) {
UsefulOutBuf_InsertByte(&(me->OutBuf), uMajorType + LEN_IS_FOUR_BYTES, uPos);
UsefulOutBuf_InsertUint32(&(me->OutBuf), (uint32_t)uNumber, uPos+1);
-
+
} else if (uNumber > 0xff || uMinLen>= 2) {
// Between 0 and 65535
UsefulOutBuf_InsertByte(&(me->OutBuf), uMajorType + LEN_IS_TWO_BYTES, uPos);
UsefulOutBuf_InsertUint16(&(me->OutBuf), (uint16_t)uNumber, uPos+1);
-
+
} else if(uNumber >= 24) {
// Between 0 and 255, but only between 24 and 255 is ever encoded here
UsefulOutBuf_InsertByte(&(me->OutBuf), uMajorType + LEN_IS_ONE_BYTE, uPos);
@@ -301,7 +301,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)
@@ -332,7 +332,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;
@@ -340,7 +340,7 @@
uValue = (uint64_t)nNum;
uMajorType = CBOR_MAJOR_TYPE_POSITIVE_INT;
}
-
+
AppendEncodedTypeAndNumber(me, uMajorType, uValue);
me->uError = Nesting_Increment(&(me->nesting), 1);
}
@@ -350,9 +350,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
@@ -367,7 +367,7 @@
// it is entirely impractical to create tokens bigger than 4GB in
// contiguous RAM
me->uError = QCBOR_ERR_BUFFER_TOO_LARGE;
-
+
} else {
if(!me->uError) {
// If it is not Raw CBOR, add the type and the length
@@ -377,10 +377,10 @@
// type and number so the buffer being added goes to the
// right place
}
-
+
// Actually add the bytes
UsefulOutBuf_AppendUsefulBuf(&(me->OutBuf), Bytes);
-
+
// Update the array counting if there is any nesting at all
me->uError = Nesting_Increment(&(me->nesting), 1);
}
@@ -402,7 +402,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)
@@ -417,7 +417,7 @@
uNum, // Bytes of the floating
// point number as a uint
UsefulOutBuf_GetEndPosition(&(me->OutBuf))); // end position for append
-
+
me->uError = Nesting_Increment(&(me->nesting), 1);
}
}
@@ -429,7 +429,7 @@
void QCBOREncode_AddDouble(QCBOREncodeContext *me, double dNum)
{
const IEEE754_union uNum = IEEE754_DoubleToSmallest(dNum);
-
+
QCBOREncode_AddType7(me, uNum.uSize, uNum.uValue);
}
@@ -437,7 +437,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)
@@ -477,18 +477,18 @@
// 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
@@ -512,16 +512,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
@@ -534,7 +534,7 @@
}
*pEncodedCBOR = UsefulOutBuf_OutUBuf(&(me->OutBuf));
-
+
Done:
return uReturn;
}
@@ -546,13 +546,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;
}
@@ -561,7 +561,7 @@
/*
Notes on the code
-
+
CBOR Major Type Public Function
0 QCBOREncode_AddUInt64
0, 1 QCBOREncode_AddUInt64, QCBOREncode_AddInt64
@@ -569,9 +569,9 @@
4, 5 QCBOREncode_OpenMapOrArray
6 QCBOREncode_AddTag
7 QCBOREncode_AddDouble, QCBOREncode_AddSimple
-
+
Object code sizes on X86 with LLVM compiler and -Os (Nov 27, 2018)
-
+
_QCBOREncode_Init 84
_QCBOREncode_AddUInt64 76
_QCBOREncode_AddInt64 87
@@ -582,23 +582,23 @@
_QCBOREncode_CloseMapOrArray 181
_InsertEncodedTypeAndNumber 480
_QCBOREncode_Finish 72
-
+
Total is about 1.4KB (including FinishGetSize and AddTag and AddDouble)
-
+
_InsertEncodedTypeAndNumber is large because a lot of UsefulBuf
code inlines into it including the conversion to network byte
order. This could be optimized to at least half the size, but
code would probably not be quite as clean.
-
+
_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/src/qcbor_encode.o b/src/qcbor_encode.o
new file mode 100644
index 0000000..32117c3
--- /dev/null
+++ b/src/qcbor_encode.o
Binary files differ