blob: cb6670db48ba55e8b567c760da0155c50f3c4333 [file] [log] [blame]
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001/*==============================================================================
Laurence Lundbladed92a6162018-11-01 11:38:35 +07002 Copyright (c) 2016-2018, The Linux Foundation.
Laurence Lundbladeee851742020-01-08 08:37:05 -08003 Copyright (c) 2018-2020, Laurence Lundblade.
Laurence Lundbladed92a6162018-11-01 11:38:35 +07004 All rights reserved.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08005
Laurence Lundblade0dbc9172018-11-01 14:17:21 +07006Redistribution and use in source and binary forms, with or without
7modification, are permitted provided that the following conditions are
8met:
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of The Linux Foundation nor the names of its
16 contributors, nor the name "Laurence Lundblade" may be used to
17 endorse or promote products derived from this software without
18 specific prior written permission.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080019
Laurence Lundblade0dbc9172018-11-01 14:17:21 +070020THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
21WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
23ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
24BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
27BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
29OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
30IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Laurence Lundbladeee851742020-01-08 08:37:05 -080031 =============================================================================*/
Laurence Lundblade624405d2018-09-18 20:10:47 -070032
Laurence Lundbladeee851742020-01-08 08:37:05 -080033/*=============================================================================
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070034 FILE: qcbor_encode.c
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080035
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070036 DESCRIPTION: This file contains the implementation of QCBOR.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080037
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070038 EDIT HISTORY FOR FILE:
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080039
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070040 This section contains comments describing changes made to the module.
41 Notice that changes are listed in reverse chronological order.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080042
Laurence Lundbladeee851742020-01-08 08:37:05 -080043 when who what, where, why
44 -------- ---- ---------------------------------------------------
45 01/08/2020 llundblade Documentation corrections & improved code formatting.
46 12/30/19 llundblade Add support for decimal fractions and bigfloats.
47 8/7/19 llundblade Prevent encoding simple type reserved values 24..31
48 7/25/19 janjongboom Add indefinite length encoding for maps and arrays
49 4/6/19 llundblade Wrapped bstr returned now includes the wrapping bstr
50 12/30/18 llundblade Small efficient clever encode of type & argument.
51 11/29/18 llundblade Rework to simpler handling of tags and labels.
52 11/9/18 llundblade Error codes are now enums.
53 11/1/18 llundblade Floating support.
54 10/31/18 llundblade Switch to one license that is almost BSD-3.
55 09/28/18 llundblade Added bstr wrapping feature for COSE implementation.
56 02/05/18 llundbla Works on CPUs which require integer alignment.
57 Requires new version of UsefulBuf.
58 07/05/17 llundbla Add bstr wrapping of maps/arrays for COSE
59 03/01/17 llundbla More data types
60 11/13/16 llundbla Integrate most TZ changes back into github version.
61 09/30/16 gkanike Porting to TZ.
62 03/15/16 llundbla Initial Version.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080063
Laurence Lundbladeee851742020-01-08 08:37:05 -080064 =============================================================================*/
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070065
66#include "qcbor.h"
Laurence Lundblade12d32c52018-09-19 11:25:27 -070067#include "ieee754.h"
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070068
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070069
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070070
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070071/*
Laurence Lundbladeee851742020-01-08 08:37:05 -080072 Nesting -- This tracks the nesting of maps and arrays.
73
74 The following functions and data type QCBORTrackNesting implement the
75 nesting management for encoding.
76
77 CBOR's two nesting types, arrays and maps, are tracked here. There is
78 a limit of QCBOR_MAX_ARRAY_NESTING to the number of arrays and maps
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070079 that can be nested in one encoding so the encoding context stays
80 small enough to fit on the stack.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080081
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070082 When an array / map is opened, pCurrentNesting points to the element
Laurence Lundbladeee851742020-01-08 08:37:05 -080083 in pArrays that records the type, start position and accumulates a
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070084 count of the number of items added. When closed the start position is
85 used to go back and fill in the type and number of items in the array
86 / map.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080087
Laurence Lundbladeee851742020-01-08 08:37:05 -080088 Encoded output can be just items like ints and strings that are not
89 part of any array / map. That is, the first thing encoded does not
90 have to be an array or a map.
91
92 QCBOR has a special feature to allow constructing bstr-wrapped CBOR
93 directly into the output buffer, so an extra buffer for it is not
94 needed. This is implemented as nesting with type
95 CBOR_MAJOR_TYPE_BYTE_STRING and uses this code. Bstr-wrapped CBOR is
96 used by COSE for data that is to be hashed.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070097 */
98inline static void Nesting_Init(QCBORTrackNesting *pNesting)
99{
Laurence Lundbladeee851742020-01-08 08:37:05 -0800100 // Assumes pNesting has been zeroed
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700101 pNesting->pCurrentNesting = &pNesting->pArrays[0];
102 // Implied CBOR array at the top nesting level. This is never returned,
103 // but makes the item count work correctly.
104 pNesting->pCurrentNesting->uMajorType = CBOR_MAJOR_TYPE_ARRAY;
105}
106
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800107inline static QCBORError Nesting_Increase(QCBORTrackNesting *pNesting,
108 uint8_t uMajorType,
109 uint32_t uPos)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700110{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700111 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800112
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700113 if(pNesting->pCurrentNesting == &pNesting->pArrays[QCBOR_MAX_ARRAY_NESTING]) {
Laurence Lundbladeee851742020-01-08 08:37:05 -0800114 // Trying to open one too many
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700115 nReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
116 } else {
117 pNesting->pCurrentNesting++;
118 pNesting->pCurrentNesting->uCount = 0;
119 pNesting->pCurrentNesting->uStart = uPos;
120 pNesting->pCurrentNesting->uMajorType = uMajorType;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700121 }
122 return nReturn;
123}
124
125inline static void Nesting_Decrease(QCBORTrackNesting *pNesting)
126{
127 pNesting->pCurrentNesting--;
128}
129
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800130inline static QCBORError Nesting_Increment(QCBORTrackNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700131{
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800132 if(1 >= QCBOR_MAX_ITEMS_IN_ARRAY - pNesting->pCurrentNesting->uCount) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700133 return QCBOR_ERR_ARRAY_TOO_LONG;
134 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800135
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800136 pNesting->pCurrentNesting->uCount += 1;
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800137
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700138 return QCBOR_SUCCESS;
139}
140
141inline static uint16_t Nesting_GetCount(QCBORTrackNesting *pNesting)
142{
143 // The nesting count recorded is always the actual number of individiual
144 // data items in the array or map. For arrays CBOR uses the actual item
145 // count. For maps, CBOR uses the number of pairs. This function returns
146 // the number needed for the CBOR encoding, so it divides the number of
147 // items by two for maps to get the number of pairs. This implementation
148 // takes advantage of the map major type being one larger the array major
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800149 // type, hence uDivisor is either 1 or 2.
150 const uint16_t uDivisor = pNesting->pCurrentNesting->uMajorType - CBOR_MAJOR_TYPE_ARRAY+1;
151
152 return pNesting->pCurrentNesting->uCount / uDivisor;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700153}
154
155inline static uint32_t Nesting_GetStartPos(QCBORTrackNesting *pNesting)
156{
157 return pNesting->pCurrentNesting->uStart;
158}
159
160inline static uint8_t Nesting_GetMajorType(QCBORTrackNesting *pNesting)
161{
162 return pNesting->pCurrentNesting->uMajorType;
163}
164
Laurence Lundbladeee851742020-01-08 08:37:05 -0800165inline static bool Nesting_IsInNest(QCBORTrackNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700166{
Laurence Lundbladeee851742020-01-08 08:37:05 -0800167 return pNesting->pCurrentNesting == &pNesting->pArrays[0] ? false : true;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700168}
169
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700170
171
172
173/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800174 Encoding of the major CBOR types is by these functions:
175
176 CBOR Major Type Public Function
177 0 QCBOREncode_AddUInt64()
178 0, 1 QCBOREncode_AddUInt64(), QCBOREncode_AddInt64()
179 2, 3 QCBOREncode_AddBuffer(), Also QCBOREncode_OpenMapOrArray(),
180 QCBOREncode_CloseMapOrArray()
181 4, 5 QCBOREncode_OpenMapOrArray(), QCBOREncode_CloseMapOrArray(),
182 QCBOREncode_OpenMapOrArrayIndefiniteLength(),
183 QCBOREncode_CloseMapOrArrayIndefiniteLength()
184 6 QCBOREncode_AddTag()
185 7 QCBOREncode_AddDouble(), QCBOREncode_AddType7()
186
187 Additionally, encoding of decimal fractions and bigfloats is by
188 QCBOREncode_AddExponentAndMantissa()
189*/
190
191/*
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700192 Error tracking plan -- Errors are tracked internally and not returned
Laurence Lundbladeee851742020-01-08 08:37:05 -0800193 until QCBOREncode_Finish is called. The CBOR errors are in me->uError.
Laurence Lundblade067035b2018-11-28 17:35:25 -0800194 UsefulOutBuf also tracks whether the buffer is full or not in its
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700195 context. Once either of these errors is set they are never
Laurence Lundblade241705e2018-12-30 18:56:14 -0800196 cleared. Only QCBOREncode_Init() resets them. Or said another way, they must
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700197 never be cleared or we'll tell the caller all is good when it is not.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800198
Laurence Lundblade241705e2018-12-30 18:56:14 -0800199 Only one error code is reported by QCBOREncode_Finish() even if there are
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700200 multiple errors. The last one set wins. The caller might have to fix
201 one error to reveal the next one they have to fix. This is OK.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800202
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700203 The buffer full error tracked by UsefulBuf is only pulled out of
204 UsefulBuf in Finish() so it is the one that usually wins. UsefulBuf
205 will never go off the end of the buffer even if it is called again
206 and again when full.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800207
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700208 It is really tempting to not check for overflow on the count in the
209 number of items in an array. It would save a lot of code, it is
210 extremely unlikely that any one will every put 65,000 items in an
211 array, and the only bad thing that would happen is the CBOR would be
Laurence Lundblade241705e2018-12-30 18:56:14 -0800212 bogus.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800213
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700214 Since this does not parse any input, you could in theory remove all
215 error checks in this code if you knew the caller called it
216 correctly. Maybe someday CDDL or some such language will be able to
217 generate the code to call this and the calling code would always be
Laurence Lundblade56230d12018-11-01 11:14:51 +0700218 correct. This could also automatically size some of the data
Laurence Lundblade241705e2018-12-30 18:56:14 -0800219 structures like array/map nesting resulting in some stack memory
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700220 savings.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800221
Laurence Lundbladeee851742020-01-08 08:37:05 -0800222 The 8 errors returned here fall into three categories:
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800223
Laurence Lundblade067035b2018-11-28 17:35:25 -0800224 Sizes
Laurence Lundbladeee851742020-01-08 08:37:05 -0800225 QCBOR_ERR_BUFFER_TOO_LARGE -- Encoded output exceeded UINT32_MAX
226 QCBOR_ERR_BUFFER_TOO_SMALL -- Output buffer too small
227 QCBOR_ERR_ARRAY_NESTING_TOO_DEEP -- Nesting > QCBOR_MAX_ARRAY_NESTING1
228 QCBOR_ERR_ARRAY_TOO_LONG -- Too many things added to an array/map
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800229
Laurence Lundblade067035b2018-11-28 17:35:25 -0800230 Nesting constructed incorrectly
Laurence Lundbladeee851742020-01-08 08:37:05 -0800231 QCBOR_ERR_TOO_MANY_CLOSES -- More close calls than opens
232 QCBOR_ERR_CLOSE_MISMATCH -- Type of close does not match open
Laurence Lundblade067035b2018-11-28 17:35:25 -0800233 QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN -- Finish called without enough closes
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700234
235 Would generate not-well-formed CBOR
Laurence Lundbladeee851742020-01-08 08:37:05 -0800236 QCBOR_ERR_UNSUPPORTED -- Simple type between 24 and 31
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700237 */
238
239
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700240/*
241 Public function for initialization. See header qcbor.h
242 */
Laurence Lundblade2296db52018-09-14 18:08:39 -0700243void QCBOREncode_Init(QCBOREncodeContext *me, UsefulBuf Storage)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700244{
245 memset(me, 0, sizeof(QCBOREncodeContext));
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800246 UsefulOutBuf_Init(&(me->OutBuf), Storage);
247 Nesting_Init(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700248}
249
250
Laurence Lundbladeee851742020-01-08 08:37:05 -0800251/**
252 @brief Encode a data item, the most atomic part of CBOR
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700253
Laurence Lundbladeee851742020-01-08 08:37:05 -0800254 @param[in,out] me Encoding context including output buffer
255 @param[in] uMajorType One of CBOR_MAJOR_TYPE_XX
256 @param[in] nMinLen Include zero bytes up to this length. If 0 include
257 no zero bytes. Non-zero to encode floats and doubles.
258 @param[in] uNumber The number to encode, the argument.
259 @param[in] uPos The position in the output buffer (which is inside
260 the encoding context) to insert the result. This is
261 usually at the end, an append.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700262
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800263 All CBOR data items have a type and an "argument". The argument is
264 either the value of the item for integer types, the length of the
265 content for string, byte, array and map types, a tag for major type
266 6, and has several uses for major type 7.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800267
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800268 This function encodes the type and the argument. There are several
269 encodings for the argument depending on how large it is and how it is
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700270 used.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800271
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800272 Every encoding of the type and argument has at least one byte, the
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700273 "initial byte".
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800274
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700275 The top three bits of the initial byte are the major type for the
276 CBOR data item. The eight major types defined by the standard are
277 defined as CBOR_MAJOR_TYPE_xxxx in qcbor.h.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800278
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700279 The remaining five bits, known as "additional information", and
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800280 possibly more bytes encode the argument. If the argument is less than
281 24, then it is encoded entirely in the five bits. This is neat
282 because it allows you to encode an entire CBOR data item in 1 byte
283 for many values and types (integers 0-23, true, false, and tags).
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800284
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800285 If the argument is larger than 24, then it is encoded in 1,2,4 or 8
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700286 additional bytes, with the number of these bytes indicated by the
287 values of the 5 bits 24, 25, 25 and 27.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800288
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800289 It is possible to encode a particular argument in many ways with this
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700290 representation. This implementation always uses the smallest
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800291 possible representation. This conforms with CBOR preferred encoding.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800292
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700293 This function inserts them into the output buffer at the specified
Laurence Lundblade067035b2018-11-28 17:35:25 -0800294 position. AppendEncodedTypeAndNumber() appends to the end.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800295
296 This function takes care of converting to network byte order.
297
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700298 This function is also used to insert floats and doubles. Before this
299 function is called the float or double must be copied into a
300 uint64_t. That is how they are passed in. They are then converted to
Laurence Lundbladeee851742020-01-08 08:37:05 -0800301 network byte order correctly. The uMinLen parameter makes sure that
302 even if all the digits of a half, float or double are 0 it is still
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800303 correctly encoded in 2, 4 or 8 bytes.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700304 */
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800305static void InsertEncodedTypeAndNumber(QCBOREncodeContext *me,
Laurence Lundbladeee851742020-01-08 08:37:05 -0800306 uint8_t uMajorType,
307 int nMinLen,
308 uint64_t uNumber,
309 size_t uPos)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700310{
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800311 /*
312 This code does endian conversion without hton or knowing the
Laurence Lundblade241705e2018-12-30 18:56:14 -0800313 endianness of the machine using masks and shifts. This avoids the
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800314 dependency on hton and the mess of figuring out how to find the
315 machine's endianness.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800316
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800317 This is a good efficient implementation on little-endian machines.
318 A faster and small implementation is possible on big-endian
319 machines because CBOR/network byte order is big endian. However
320 big endian machines are uncommon.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800321
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800322 On x86, it is about 200 bytes instead of 500 bytes for the more
323 formal unoptimized code.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800324
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800325 This also does the CBOR preferred shortest encoding for integers
326 and is called to do endian conversion for floats.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800327
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800328 It works backwards from the LSB to the MSB as needed.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800329
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800330 Code Reviewers: THIS FUNCTION DOES POINTER MATH
331 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800332
333 // Holds up to 9 bytes of type and argument plus one extra so pointer
334 // always points to valid bytes.
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800335 uint8_t bytes[sizeof(uint64_t)+2];
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800336 // Point to the last bytes and work backwards
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800337 uint8_t *pByte = &bytes[sizeof(bytes)-1];
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800338 // This is the 5 bits in the initial byte that is not the major type
339 uint8_t uAdditionalInfo;
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800340
Jan Jongboom5d827882019-08-07 12:51:15 +0200341 if (uMajorType == CBOR_MAJOR_NONE_TYPE_ARRAY_INDEFINITE_LEN) {
342 uMajorType = CBOR_MAJOR_TYPE_ARRAY;
343 uAdditionalInfo = LEN_IS_INDEFINITE;
344 } else if (uMajorType == CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN) {
345 uMajorType = CBOR_MAJOR_TYPE_MAP;
346 uAdditionalInfo = LEN_IS_INDEFINITE;
347 } else if (uNumber < CBOR_TWENTY_FOUR && nMinLen == 0) {
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800348 // Simple case where argument is < 24
349 uAdditionalInfo = uNumber;
Jan Jongboom4a93a662019-07-25 08:44:58 +0200350 } else if (uMajorType == CBOR_MAJOR_TYPE_SIMPLE && uNumber == CBOR_SIMPLE_BREAK) {
351 // Break statement can be encoded in single byte too (0xff)
352 uAdditionalInfo = uNumber;
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800353 } else {
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800354 /*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800355 Encode argument in 1,2,4 or 8 bytes. Outer loop runs once for 1
356 byte and 4 times for 8 bytes. Inner loop runs 1, 2 or 4 times
357 depending on outer loop counter. This works backwards taking 8
358 bits off the argument being encoded at a time until all bits
359 from uNumber have been encoded and the minimum encoding size is
360 reached. Minimum encoding size is for floating-point numbers
361 with zero bytes.
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800362 */
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800363 static const uint8_t aIterate[] = {1,1,2,4};
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800364 uint8_t i;
365 for(i = 0; uNumber || nMinLen > 0; i++) {
366 const uint8_t uIterations = aIterate[i];
367 for(int j = 0; j < uIterations; j++) {
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800368 *--pByte = uNumber & 0xff;
369 uNumber = uNumber >> 8;
370 }
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800371 nMinLen -= uIterations;
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800372 }
Laurence Lundbladeee851742020-01-08 08:37:05 -0800373 // Additional info is the encoding of the number of additional
374 // bytes to encode argument.
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800375 uAdditionalInfo = LEN_IS_ONE_BYTE-1 + i;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700376 }
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800377 *--pByte = (uMajorType << 5) + uAdditionalInfo;
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800378
379 UsefulOutBuf_InsertData(&(me->OutBuf), pByte, &bytes[sizeof(bytes)-1] - pByte, uPos);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700380}
381
382
383/*
384 Append the type and number info to the end of the buffer.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800385
Laurence Lundbladeee851742020-01-08 08:37:05 -0800386 See InsertEncodedTypeAndNumber() function above for details.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700387*/
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800388inline static void AppendEncodedTypeAndNumber(QCBOREncodeContext *me,
389 uint8_t uMajorType,
390 uint64_t uNumber)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700391{
392 // An append is an insert at the end.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800393 InsertEncodedTypeAndNumber(me,
394 uMajorType,
395 0,
396 uNumber,
397 UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700398}
399
400
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700401
Laurence Lundblade241705e2018-12-30 18:56:14 -0800402
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700403/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800404 Public functions for closing arrays and maps. See qcbor.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700405 */
Laurence Lundblade067035b2018-11-28 17:35:25 -0800406void QCBOREncode_AddUInt64(QCBOREncodeContext *me, uint64_t uValue)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700407{
Laurence Lundblade067035b2018-11-28 17:35:25 -0800408 if(me->uError == QCBOR_SUCCESS) {
409 AppendEncodedTypeAndNumber(me, CBOR_MAJOR_TYPE_POSITIVE_INT, uValue);
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800410 me->uError = Nesting_Increment(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700411 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700412}
413
Laurence Lundblade56230d12018-11-01 11:14:51 +0700414
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700415/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800416 Public functions for closing arrays and maps. See qcbor.h
Laurence Lundblade067035b2018-11-28 17:35:25 -0800417 */
418void QCBOREncode_AddInt64(QCBOREncodeContext *me, int64_t nNum)
419{
420 if(me->uError == QCBOR_SUCCESS) {
421 uint8_t uMajorType;
422 uint64_t uValue;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800423
Laurence Lundblade067035b2018-11-28 17:35:25 -0800424 if(nNum < 0) {
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800425 // In CBOR -1 encodes as 0x00 with major type negative int.
426 uValue = (uint64_t)(-nNum - 1);
Laurence Lundblade067035b2018-11-28 17:35:25 -0800427 uMajorType = CBOR_MAJOR_TYPE_NEGATIVE_INT;
428 } else {
429 uValue = (uint64_t)nNum;
430 uMajorType = CBOR_MAJOR_TYPE_POSITIVE_INT;
431 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800432
Laurence Lundblade067035b2018-11-28 17:35:25 -0800433 AppendEncodedTypeAndNumber(me, uMajorType, uValue);
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800434 me->uError = Nesting_Increment(&(me->nesting));
Laurence Lundblade067035b2018-11-28 17:35:25 -0800435 }
436}
437
438
439/*
Laurence Lundbladeda532272019-04-07 11:40:17 -0700440 Semi-private function. It is exposed to user of the interface, but
441 they will usually call one of the inline wrappers rather than this.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800442
Laurence Lundbladeee851742020-01-08 08:37:05 -0800443 See qcbor.h
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800444
Laurence Lundbladeda532272019-04-07 11:40:17 -0700445 Does the work of adding actual strings bytes to the CBOR output (as
446 opposed to numbers and opening / closing aggregate types).
447
448 There are four use cases:
449 CBOR_MAJOR_TYPE_BYTE_STRING -- Byte strings
450 CBOR_MAJOR_TYPE_TEXT_STRING -- Text strings
451 CBOR_MAJOR_NONE_TYPE_RAW -- Already-encoded CBOR
452 CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY -- Special case
453
454 The first two add the type and length plus the actual bytes. The
455 third just adds the bytes as the type and length are presumed to be
456 in the bytes. The fourth just adds the type and length for the very
457 special case of QCBOREncode_AddBytesLenOnly().
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700458 */
Laurence Lundblade067035b2018-11-28 17:35:25 -0800459void QCBOREncode_AddBuffer(QCBOREncodeContext *me, uint8_t uMajorType, UsefulBufC Bytes)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700460{
Laurence Lundblade241705e2018-12-30 18:56:14 -0800461 if(me->uError == QCBOR_SUCCESS) {
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800462 // If it is not Raw CBOR, add the type and the length
463 if(uMajorType != CBOR_MAJOR_NONE_TYPE_RAW) {
Laurence Lundbladeda532272019-04-07 11:40:17 -0700464 uint8_t uRealMajorType = uMajorType;
465 if(uRealMajorType == CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY) {
466 uRealMajorType = CBOR_MAJOR_TYPE_BYTE_STRING;
467 }
468 AppendEncodedTypeAndNumber(me, uRealMajorType, Bytes.len);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700469 }
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800470
Laurence Lundbladeda532272019-04-07 11:40:17 -0700471 if(uMajorType != CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY) {
472 // Actually add the bytes
473 UsefulOutBuf_AppendUsefulBuf(&(me->OutBuf), Bytes);
474 }
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800475
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800476 // Update the array counting if there is any nesting at all
477 me->uError = Nesting_Increment(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700478 }
479}
480
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700481
Laurence Lundblade55a24832018-10-30 04:35:08 +0700482/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800483 Public functions for closing arrays and maps. See qcbor.h
Laurence Lundblade55a24832018-10-30 04:35:08 +0700484 */
485void QCBOREncode_AddTag(QCBOREncodeContext *me, uint64_t uTag)
486{
Laurence Lundblade55a24832018-10-30 04:35:08 +0700487 AppendEncodedTypeAndNumber(me, CBOR_MAJOR_TYPE_OPTIONAL, uTag);
488}
489
490
Laurence Lundblade56230d12018-11-01 11:14:51 +0700491/*
Laurence Lundblade487930f2018-11-30 11:01:45 -0800492 Semi-private function. It is exposed to user of the interface,
493 but they will usually call one of the inline wrappers rather than this.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800494
Laurence Lundblade487930f2018-11-30 11:01:45 -0800495 See header qcbor.h
Laurence Lundblade56230d12018-11-01 11:14:51 +0700496 */
Laurence Lundblade487930f2018-11-30 11:01:45 -0800497void QCBOREncode_AddType7(QCBOREncodeContext *me, size_t uSize, uint64_t uNum)
Laurence Lundblade55a24832018-10-30 04:35:08 +0700498{
Laurence Lundblade487930f2018-11-30 11:01:45 -0800499 if(me->uError == QCBOR_SUCCESS) {
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700500 if(uNum >= CBOR_SIMPLEV_RESERVED_START && uNum <= CBOR_SIMPLEV_RESERVED_END) {
501 me->uError = QCBOR_ERR_UNSUPPORTED;
502 } else {
Laurence Lundbladeee851742020-01-08 08:37:05 -0800503 // This call takes care of endian swapping for the float / double
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700504 InsertEncodedTypeAndNumber(me,
505 // The major type for floats and doubles
506 CBOR_MAJOR_TYPE_SIMPLE,
Laurence Lundbladeee851742020-01-08 08:37:05 -0800507 // Must pass size to ensure floats
508 // with zero bytes encode correctly
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700509 (int)uSize,
Laurence Lundbladeee851742020-01-08 08:37:05 -0800510 // The floating-point number as a uint
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700511 uNum,
512 // end position because this is append
513 UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800514
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700515 me->uError = Nesting_Increment(&(me->nesting));
516 }
Laurence Lundblade487930f2018-11-30 11:01:45 -0800517 }
Laurence Lundblade55a24832018-10-30 04:35:08 +0700518}
519
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700520
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700521/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800522 Public functions for closing arrays and maps. See qcbor.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700523 */
Laurence Lundblade067035b2018-11-28 17:35:25 -0800524void QCBOREncode_AddDouble(QCBOREncodeContext *me, double dNum)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700525{
Laurence Lundblade067035b2018-11-28 17:35:25 -0800526 const IEEE754_union uNum = IEEE754_DoubleToSmallest(dNum);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800527
Laurence Lundblade487930f2018-11-30 11:01:45 -0800528 QCBOREncode_AddType7(me, uNum.uSize, uNum.uValue);
Laurence Lundblade067035b2018-11-28 17:35:25 -0800529}
530
531
Laurence Lundblade59289e52019-12-30 13:44:37 -0800532#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
533/*
534 Semi-public function. It is exposed to the user of the interface, but
535 one of the inline wrappers will usually be called rather than this.
536
537 See qcbor.h
538 */
539void QCBOREncode_AddExponentAndMantissa(QCBOREncodeContext *pMe,
540 uint64_t uTag,
541 UsefulBufC BigNumMantissa,
542 bool bBigNumIsNegative,
543 int64_t nMantissa,
544 int64_t nExponent)
545{
Laurence Lundbladeee851742020-01-08 08:37:05 -0800546 /*
547 This is for encoding either a big float or a decimal fraction,
548 both of which are an array of two items, an exponent and a
549 mantissa. The difference between the two is that the exponent is
550 base-2 for big floats and base-10 for decimal fractions, but that
551 has no effect on the code here.
552 */
Laurence Lundblade59289e52019-12-30 13:44:37 -0800553 QCBOREncode_AddTag(pMe, uTag);
554 QCBOREncode_OpenArray(pMe);
555 QCBOREncode_AddInt64(pMe, nExponent);
556 if(!UsefulBuf_IsNULLC(BigNumMantissa)) {
557 if(bBigNumIsNegative) {
558 QCBOREncode_AddNegativeBignum(pMe, BigNumMantissa);
559 } else {
560 QCBOREncode_AddPositiveBignum(pMe, BigNumMantissa);
561 }
562 } else {
563 QCBOREncode_AddInt64(pMe, nMantissa);
564 }
565 QCBOREncode_CloseArray(pMe);
566}
567#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
568
569
Laurence Lundblade067035b2018-11-28 17:35:25 -0800570/*
571 Semi-public function. It is exposed to user of the interface,
572 but they will usually call one of the inline wrappers rather than this.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800573
Laurence Lundblade067035b2018-11-28 17:35:25 -0800574 See header qcbor.h
575*/
576void QCBOREncode_OpenMapOrArray(QCBOREncodeContext *me, uint8_t uMajorType)
577{
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800578 // Add one item to the nesting level we are in for the new map or array
579 me->uError = Nesting_Increment(&(me->nesting));
Laurence Lundblade241705e2018-12-30 18:56:14 -0800580 if(me->uError == QCBOR_SUCCESS) {
Laurence Lundbladeee851742020-01-08 08:37:05 -0800581 /*
582 The offset where the length of an array or map will get written
583 is stored in a uint32_t, not a size_t to keep stack usage
584 smaller. This checks to be sure there is no wrap around when
585 recording the offset. Note that on 64-bit machines CBOR larger
586 than 4GB can be encoded as long as no array / map offsets occur
587 past the 4GB mark, but the public interface says that the
588 maximum is 4GB to keep the discussion simpler.
589 */
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800590 size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf));
Laurence Lundbladed39cd392019-01-11 18:17:38 -0800591
Laurence Lundbladeee851742020-01-08 08:37:05 -0800592 /*
593 QCBOR_MAX_ARRAY_OFFSET is slightly less than UINT32_MAX so this
594 code can run on a 32-bit machine and tests can pass on a 32-bit
595 machine. If it was exactly UINT32_MAX, then this code would not
596 compile or run on a 32-bit machine and an #ifdef or some
597 machine size detection would be needed reducing portability.
598 */
Laurence Lundbladed39cd392019-01-11 18:17:38 -0800599 if(uEndPosition >= QCBOR_MAX_ARRAY_OFFSET) {
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800600 me->uError = QCBOR_ERR_BUFFER_TOO_LARGE;
Laurence Lundbladed39cd392019-01-11 18:17:38 -0800601
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800602 } else {
Laurence Lundbladeee851742020-01-08 08:37:05 -0800603 // Increase nesting level because this is a map or array. Cast
604 // from size_t to uin32_t is safe because of check above
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800605 me->uError = Nesting_Increase(&(me->nesting), uMajorType, (uint32_t)uEndPosition);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700606 }
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800607 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700608}
609
Laurence Lundblade59289e52019-12-30 13:44:37 -0800610
Jan Jongboom4a93a662019-07-25 08:44:58 +0200611/*
612 Semi-public function. It is exposed to user of the interface,
613 but they will usually call one of the inline wrappers rather than this.
614
Laurence Lundbladeee851742020-01-08 08:37:05 -0800615 See qcbor.h
Jan Jongboom4a93a662019-07-25 08:44:58 +0200616*/
617void QCBOREncode_OpenMapOrArrayIndefiniteLength(QCBOREncodeContext *me, uint8_t uMajorType)
618{
619 // insert the indefinite length marker (0x9f for arrays, 0xbf for maps)
Jan Jongboom5d827882019-08-07 12:51:15 +0200620 InsertEncodedTypeAndNumber(me, uMajorType, 0, 0, UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
Jan Jongboom4a93a662019-07-25 08:44:58 +0200621
622 QCBOREncode_OpenMapOrArray(me, uMajorType);
623}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700624
Laurence Lundbladeee851742020-01-08 08:37:05 -0800625
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700626/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800627 Public functions for closing arrays and maps. See qcbor.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700628 */
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800629void QCBOREncode_CloseMapOrArray(QCBOREncodeContext *me,
630 uint8_t uMajorType,
631 UsefulBufC *pWrappedCBOR)
Laurence Lundbladea954db92018-09-28 19:27:31 -0700632{
Laurence Lundblade241705e2018-12-30 18:56:14 -0800633 if(me->uError == QCBOR_SUCCESS) {
Laurence Lundbladea954db92018-09-28 19:27:31 -0700634 if(!Nesting_IsInNest(&(me->nesting))) {
635 me->uError = QCBOR_ERR_TOO_MANY_CLOSES;
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800636 } else if(Nesting_GetMajorType(&(me->nesting)) != uMajorType) {
Laurence Lundblade067035b2018-11-28 17:35:25 -0800637 me->uError = QCBOR_ERR_CLOSE_MISMATCH;
Laurence Lundbladea954db92018-09-28 19:27:31 -0700638 } else {
Laurence Lundbladeee851742020-01-08 08:37:05 -0800639 /*
640 When the array, map or bstr wrap was started, nothing was
641 gone except note the position of the start of it. This code
642 goes back and inserts the actual CBOR array, map or bstr and
643 its length. That means all the data that is in the array,
644 map or wrapped needs to be slid to the right. This is done
645 by UsefulOutBuf's insert function that is called from inside
646 InsertEncodedTypeAndNumber()
647 */
648 const size_t uInsertPosition = Nesting_GetStartPos(&(me->nesting));
649 const size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf));
650 /*
651 This can't go negative because the UsefulOutBuf always only
652 grows and never shrinks. UsefulOutBut itself also has
653 defenses such that it won't write were it should not even if
654 given hostile input lengths
655 */
Laurence Lundblade56230d12018-11-01 11:14:51 +0700656 const size_t uLenOfEncodedMapOrArray = uEndPosition - uInsertPosition;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800657
Laurence Lundbladeee851742020-01-08 08:37:05 -0800658 // Number of bytes for a bstr or number of items a for map & array
659 const bool bIsBstr = uMajorType == CBOR_MAJOR_TYPE_BYTE_STRING;
660 const size_t uLength = bIsBstr ? uLenOfEncodedMapOrArray
661 : Nesting_GetCount(&(me->nesting));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800662
Laurence Lundbladea954db92018-09-28 19:27:31 -0700663 // Actually insert
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700664 InsertEncodedTypeAndNumber(me,
Laurence Lundbladeee851742020-01-08 08:37:05 -0800665 uMajorType, // bstr, array or map
666 0, // no minimum length
667 uLength, // either len of bstr or
668 // num map / array items
Laurence Lundbladea954db92018-09-28 19:27:31 -0700669 uInsertPosition); // position in out buffer
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800670
Laurence Lundbladeee851742020-01-08 08:37:05 -0800671 /*
672 Return pointer and length to the enclosed encoded CBOR. The
673 intended use is for it to be hashed (e.g., SHA-256) in a
674 COSE implementation. This must be used right away, as the
675 pointer and length go invalid on any subsequent calls to
676 this function because there might be calls to
677 InsertEncodedTypeAndNumber() that slides data to the right.
678 */
Laurence Lundbladea954db92018-09-28 19:27:31 -0700679 if(pWrappedCBOR) {
Laurence Lundblade25c6c0a2018-12-17 13:21:59 -0800680 const UsefulBufC PartialResult = UsefulOutBuf_OutUBuf(&(me->OutBuf));
Laurence Lundblade83f5b7f2019-04-06 11:22:37 -0700681 *pWrappedCBOR = UsefulBuf_Tail(PartialResult, uInsertPosition);
Laurence Lundbladea954db92018-09-28 19:27:31 -0700682 }
683 Nesting_Decrease(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700684 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700685 }
686}
687
Laurence Lundbladeee851742020-01-08 08:37:05 -0800688
Jan Jongboom4a93a662019-07-25 08:44:58 +0200689/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800690 Public functions for closing arrays and maps. See qcbor.h
Jan Jongboom4a93a662019-07-25 08:44:58 +0200691 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800692void QCBOREncode_CloseMapOrArrayIndefiniteLength(QCBOREncodeContext *me,
693 uint8_t uMajorType,
694 UsefulBufC *pWrappedCBOR)
Jan Jongboom4a93a662019-07-25 08:44:58 +0200695{
696 if(me->uError == QCBOR_SUCCESS) {
697 if(!Nesting_IsInNest(&(me->nesting))) {
698 me->uError = QCBOR_ERR_TOO_MANY_CLOSES;
699 } else if(Nesting_GetMajorType(&(me->nesting)) != uMajorType) {
700 me->uError = QCBOR_ERR_CLOSE_MISMATCH;
701 } else {
702 // insert the break marker (0xff for both arrays and maps)
Laurence Lundbladeee851742020-01-08 08:37:05 -0800703 InsertEncodedTypeAndNumber(me,
704 CBOR_MAJOR_TYPE_SIMPLE,
705 0,
706 CBOR_SIMPLE_BREAK,
707 UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
Jan Jongboom4a93a662019-07-25 08:44:58 +0200708
Laurence Lundbladeee851742020-01-08 08:37:05 -0800709 /*
710 Return pointer and length to the enclosed encoded CBOR. The
711 intended use is for it to be hashed (e.g., SHA-256) in a
712 COSE implementation. This must be used right away, as the
713 pointer and length go invalid on any subsequent calls to
714 this function because there might be calls to
715 InsertEncodedTypeAndNumber() that slides data to the right.
716 */
Jan Jongboom4a93a662019-07-25 08:44:58 +0200717 if(pWrappedCBOR) {
718 const UsefulBufC PartialResult = UsefulOutBuf_OutUBuf(&(me->OutBuf));
719 *pWrappedCBOR = UsefulBuf_Tail(PartialResult, UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
720 }
721
722 // Decrease nesting level
723 Nesting_Decrease(&(me->nesting));
724 }
725 }
726}
727
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700728
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700729/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800730 Public functions to finish and get the encoded result. See qcbor.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700731 */
Laurence Lundblade30816f22018-11-10 13:40:22 +0700732QCBORError QCBOREncode_Finish(QCBOREncodeContext *me, UsefulBufC *pEncodedCBOR)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700733{
Laurence Lundbladef607a2a2019-07-05 21:25:25 -0700734 QCBORError uReturn = QCBOREncode_GetErrorState(me);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800735
Laurence Lundblade067035b2018-11-28 17:35:25 -0800736 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700737 goto Done;
Laurence Lundblade067035b2018-11-28 17:35:25 -0800738 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800739
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700740 if (Nesting_IsInNest(&(me->nesting))) {
Laurence Lundblade067035b2018-11-28 17:35:25 -0800741 uReturn = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700742 goto Done;
743 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800744
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700745 *pEncodedCBOR = UsefulOutBuf_OutUBuf(&(me->OutBuf));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800746
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700747Done:
Laurence Lundblade067035b2018-11-28 17:35:25 -0800748 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700749}
750
Laurence Lundblade0595e932018-11-02 22:22:47 +0700751
Laurence Lundbladef607a2a2019-07-05 21:25:25 -0700752
Laurence Lundblade067035b2018-11-28 17:35:25 -0800753/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800754 Public functions to finish and get the encoded result. See qcbor.h
Laurence Lundblade067035b2018-11-28 17:35:25 -0800755 */
Laurence Lundblade30816f22018-11-10 13:40:22 +0700756QCBORError QCBOREncode_FinishGetSize(QCBOREncodeContext *me, size_t *puEncodedLen)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700757{
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700758 UsefulBufC Enc;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800759
Laurence Lundblade30816f22018-11-10 13:40:22 +0700760 QCBORError nReturn = QCBOREncode_Finish(me, &Enc);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800761
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700762 if(nReturn == QCBOR_SUCCESS) {
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700763 *puEncodedLen = Enc.len;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700764 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800765
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700766 return nReturn;
767}
768
769
Laurence Lundblade067035b2018-11-28 17:35:25 -0800770
771
772/*
Laurence Lundblade241705e2018-12-30 18:56:14 -0800773 Object code sizes on X86 with LLVM compiler and -Os (Dec 30, 2018)
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800774
Laurence Lundblade9c097392018-12-30 13:52:24 -0800775 _QCBOREncode_Init 69
Laurence Lundblade067035b2018-11-28 17:35:25 -0800776 _QCBOREncode_AddUInt64 76
777 _QCBOREncode_AddInt64 87
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800778 _QCBOREncode_AddBuffer 113
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800779 _QCBOREncode_AddTag 27
Laurence Lundblade9c097392018-12-30 13:52:24 -0800780 _QCBOREncode_AddType7 87
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800781 _QCBOREncode_AddDouble 36
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800782 _QCBOREncode_OpenMapOrArray 103
Laurence Lundblade067035b2018-11-28 17:35:25 -0800783 _QCBOREncode_CloseMapOrArray 181
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800784 _InsertEncodedTypeAndNumber 190
Laurence Lundblade067035b2018-11-28 17:35:25 -0800785 _QCBOREncode_Finish 72
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800786 _QCBOREncode_FinishGetSize 70
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800787
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800788 Total is about 1.1KB
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800789
Laurence Lundblade067035b2018-11-28 17:35:25 -0800790 _QCBOREncode_CloseMapOrArray is larger because it has a lot
791 of nesting tracking to do and much of Nesting_ inlines
792 into it. It probably can't be reduced much.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800793
Laurence Lundblade067035b2018-11-28 17:35:25 -0800794 If the error returned by Nesting_Increment() can be ignored
795 because the limit is so high and the consequence of exceeding
796 is proved to be inconsequential, then a lot of if(me->uError)
797 instance can be removed, saving some code.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800798
Laurence Lundblade067035b2018-11-28 17:35:25 -0800799 */