blob: b1617523d74b42308a1ba893118385d5a7a952c2 [file] [log] [blame]
/*==============================================================================
Copyright (c) 2016-2018, The Linux Foundation.
Copyright (c) 2018-2020, 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.
* Neither the name of The Linux Foundation nor the names of its
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
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_private_h
#define qcbor_private_h
#include <stdint.h>
#include "UsefulBuf.h"
#ifdef __cplusplus
extern "C" {
#if 0
} // Keep editor indention formatting happy
#endif
#endif
/*
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
/* The largest offset to the start of an array or map. It is slightly
less than UINT32_MAX so the error condition can be tested on 32-bit machines.
UINT32_MAX comes from uStart in QCBORTrackNesting being a uin32_t.
This will cause trouble on a machine where size_t is less than 32-bits.
*/
#define QCBOR_MAX_ARRAY_OFFSET (UINT32_MAX - 100)
/* The number of tags that are 16-bit or larger that can be handled
in a decode.
*/
#define QCBOR_NUM_MAPPED_TAGS 4
/* The number of tags (of any size) recorded for an individual item. */
#define QCBOR_MAX_TAGS_PER_ITEM1 4
/*
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
*/
typedef struct __QCBORTrackNesting {
// PRIVATE DATA STRUCTURE
struct {
// See function QCBOREncode_OpenMapOrArray() for details 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
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
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
*/
struct _QCBOREncodeContext {
// PRIVATE DATA STRUCTURE
UsefulOutBuf OutBuf; // Pointer to output buffer, its length and
// position in it
uint8_t uError; // Error state, always from QCBORError enum
QCBORTrackNesting nesting; // Keep track of array and map nesting
};
/*
PRIVATE DATA STRUCTURE
Holds the data for array and map nesting for decoding work. This
structure and the DecodeNesting_Xxx() functions in qcbor_decode.c
form an "object" that does the work for arrays and maps. All access
to this structure is through DecodeNesting_Xxx() functions.
64-bit machine size
128 = 16 * 8 for the two unions
64 = 16 * 4 for the uLevelType, 1 byte padded to 4 bytes for alignment
16 = 16 bytes for two pointers
208 TOTAL
32-bit machine size is 200 bytes
*/
typedef struct __QCBORDecodeNesting {
// PRIVATE DATA STRUCTURE
struct nesting_decode_level {
/*
This keeps tracking info for each nesting level. There are two
main types of levels:
1) Byte count tracking. This is for the top level input CBOR
which might be a single item or a CBOR sequence and byte
string wrapped encoded CBOR.
2) Item tracking. This is for maps and arrays.
uLevelType has value QCBOR_TYPE_BYTE_STRING for 1) and
QCBOR_TYPE_MAP or QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP_AS_ARRAY
for 2).
Item tracking is either be for definite or indefinite length
maps/arrays. For definite lengths, the total count and items
unconsumed are tracked. For indefinite length, uTotalCount is
QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH (UINT16_MAX) and there
is no per-item count of members. For indefinite length maps and
arrays, uCountCursor is UINT16_MAX if not consumed and zero if
it is consumed in the pre-order traversal. Additionally, if
entered in bounded mode, uCountCursor is
QCBOR_COUNT_INDICATES_ZERO_LENGTH to indicate it is empty.
This also records whether a level is bounded or not. All
byte-count tracked levels (the top-level sequence and
bstr-wrapped CBOR) are bounded. Maps and arrays may or may not
be bounded. They are bounded if they were Entered() and not if
they were traversed with GetNext(). They are marked as bounded
by uStartOffset not being UINT32_MAX.
*/
/*
If uLevelType can put in a separately indexed array, the union/
struct will be 8 bytes rather than 9 and a lot of wasted
padding for alignment will be saved.
*/
uint8_t uLevelType;
union {
struct {
#define QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH UINT16_MAX
#define QCBOR_COUNT_INDICATES_ZERO_LENGTH UINT16_MAX-1
uint16_t uCountTotal;
uint16_t uCountCursor;
#define QCBOR_NON_BOUNDED_OFFSET UINT32_MAX
uint32_t uStartOffset;
} ma; /* for maps and arrays */
struct {
uint32_t uEndOfBstr;
uint32_t uPreviousEndOffset;
} bs; /* for top-level sequence and bstr wrapped CBOR */
} u;
} pLevels[QCBOR_MAX_ARRAY_NESTING1+1],
*pCurrent,
*pCurrentBounded;
/*
pCurrent is for item-by-item pre-order traversal.
pCurrentBounded points to the current bounding level or is NULL if
there isn't one.
pCurrent must always be below pCurrentBounded as the pre-order
traversal is always bounded by the bounding level.
When a bounded level is entered, the pre-order traversal is set to
the first item in the bounded level. When a bounded level is
exited, the pre-order traversl is set to the next item after the
map, array or bstr. This may be more than one level up, or even
the end of the input CBOR.
*/
} QCBORDecodeNesting;
typedef struct {
// PRIVATE DATA STRUCTURE
void *pAllocateCxt;
UsefulBuf (* pfAllocator)(void *pAllocateCxt, void *pOldMem, size_t uNewSize);
} QCORInternalAllocator;
/*
PRIVATE DATA STRUCTURE
The decode context. This data structure plus the public QCBORDecode_xxx
functions form an "object" that does CBOR decoding.
Size approximation (varies with CPU/compiler):
64-bit machine: 32 + 1 + 1 + 6 bytes padding + 72 + 16 + 8 + 8 = 144 bytes
32-bit machine: 16 + 1 + 1 + 2 bytes padding + 68 + 8 + 8 + 4 = 108 bytes
*/
struct _QCBORDecodeContext {
// PRIVATE DATA STRUCTURE
UsefulInputBuf InBuf;
QCBORDecodeNesting nesting;
// If a string allocator is configured for indefinite-length
// strings, it is configured here.
QCORInternalAllocator StringAllocator;
// These are special for the internal MemPool allocator.
// They are not used otherwise. We tried packing these
// in the MemPool itself, but there are issues
// with memory alignment.
uint32_t uMemPoolSize;
uint32_t uMemPoolFreeOffset;
// A cached offset to the end of the current map
// 0 if no value is cached.
#define QCBOR_MAP_OFFSET_CACHE_INVALID UINT32_MAX
uint32_t uMapEndOffsetCache;
uint8_t uDecodeMode;
uint8_t bStringAllocateAll;
uint8_t uLastError; // QCBORError stuffed into a uint8_t
uint64_t auMappedTags[QCBOR_NUM_MAPPED_TAGS];
uint16_t uLastTags[QCBOR_MAX_TAGS_PER_ITEM1];
};
// Used internally in the impementation here
// Must not conflict with any of the official CBOR types
#define CBOR_MAJOR_NONE_TYPE_RAW 9
#define CBOR_MAJOR_NONE_TAG_LABEL_REORDER 10
#define CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY 11
// Add this to types to indicate they are to be encoded as indefinite lengths
#define QCBOR_INDEFINITE_LEN_TYPE_MODIFIER 0x80
#define CBOR_MAJOR_NONE_TYPE_ARRAY_INDEFINITE_LEN \
CBOR_MAJOR_TYPE_ARRAY + QCBOR_INDEFINITE_LEN_TYPE_MODIFIER
#define CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN \
CBOR_MAJOR_TYPE_MAP + QCBOR_INDEFINITE_LEN_TYPE_MODIFIER
#define CBOR_MAJOR_NONE_TYPE_SIMPLE_BREAK \
CBOR_MAJOR_TYPE_SIMPLE + QCBOR_INDEFINITE_LEN_TYPE_MODIFIER
#ifdef __cplusplus
}
#endif
#endif /* qcbor_private_h */