blob: 56114e1cce01304d39e5413ea5c2fd03dbcc8592 [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 Lundbladed39cd392019-01-11 18:17:38 -08003 Copyright (c) 2018-2019, 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 Lundblade624405d2018-09-18 20:10:47 -070031 ==============================================================================*/
32
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070033/*===================================================================================
34 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 Lundbladeb69cad72018-09-13 11:09:01 -070043 when who what, where, why
44 -------- ---- ---------------------------------------------------
Laurence Lundblade59289e52019-12-30 13:44:37 -080045 12/30/19 llundblade Add support for decimal fractions and bigfloats.
Laurence Lundbladebb1062e2019-08-12 23:28:54 -070046 8/7/19 llundblade Prevent encoding simple type reserved values 24..31
Jan Jongboom4a93a662019-07-25 08:44:58 +020047 7/25/19 janjongboom Add indefinite length encoding for maps and arrays
Laurence Lundblade83f5b7f2019-04-06 11:22:37 -070048 4/6/19 llundblade Wrapped bstr returned now includes the wrapping bstr
Laurence Lundblade9c097392018-12-30 13:52:24 -080049 12/30/18 llundblade Small efficient clever encode of type & argument.
Laurence Lundblade067035b2018-11-28 17:35:25 -080050 11/29/18 llundblade Rework to simpler handling of tags and labels.
51 11/9/18 llundblade Error codes are now enums.
52 11/1/18 llundblade Floating support.
53 10/31/18 llundblade Switch to one license that is almost BSD-3.
54 09/28/18 llundblade Added bstr wrapping feature for COSE implementation.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080055 02/05/18 llundbla Works on CPUs which require integer alignment.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070056 Requires new version of UsefulBuf.
57 07/05/17 llundbla Add bstr wrapping of maps/arrays for COSE
58 03/01/17 llundbla More data types
59 11/13/16 llundbla Integrate most TZ changes back into github version.
60 09/30/16 gkanike Porting to TZ.
61 03/15/16 llundbla Initial Version.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080062
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070063 =====================================================================================*/
64
65#include "qcbor.h"
Laurence Lundblade12d32c52018-09-19 11:25:27 -070066#include "ieee754.h"
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070067
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070068
69/*...... This is a ruler that is 80 characters long...........................*/
70
71
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070072/*
73 CBOR's two nesting types, arrays and maps, are tracked here. There is a
74 limit of QCBOR_MAX_ARRAY_NESTING to the number of arrays and maps
75 that can be nested in one encoding so the encoding context stays
76 small enough to fit on the stack.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080077
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070078 When an array / map is opened, pCurrentNesting points to the element
79 in pArrays that records the type, start position and accumluates a
80 count of the number of items added. When closed the start position is
81 used to go back and fill in the type and number of items in the array
82 / map.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080083
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070084 Encoded output be just items like ints and strings that are
85 not part of any array / map. That is, the first thing encoded
86 does not have to be an array or a map.
87 */
88inline static void Nesting_Init(QCBORTrackNesting *pNesting)
89{
90 // assumes pNesting has been zeroed
91 pNesting->pCurrentNesting = &pNesting->pArrays[0];
92 // Implied CBOR array at the top nesting level. This is never returned,
93 // but makes the item count work correctly.
94 pNesting->pCurrentNesting->uMajorType = CBOR_MAJOR_TYPE_ARRAY;
95}
96
Laurence Lundblade2c40ab82018-12-30 14:20:29 -080097inline static QCBORError Nesting_Increase(QCBORTrackNesting *pNesting,
98 uint8_t uMajorType,
99 uint32_t uPos)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700100{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700101 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800102
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700103 if(pNesting->pCurrentNesting == &pNesting->pArrays[QCBOR_MAX_ARRAY_NESTING]) {
104 // trying to open one too many
105 nReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
106 } else {
107 pNesting->pCurrentNesting++;
108 pNesting->pCurrentNesting->uCount = 0;
109 pNesting->pCurrentNesting->uStart = uPos;
110 pNesting->pCurrentNesting->uMajorType = uMajorType;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700111 }
112 return nReturn;
113}
114
115inline static void Nesting_Decrease(QCBORTrackNesting *pNesting)
116{
117 pNesting->pCurrentNesting--;
118}
119
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800120inline static QCBORError Nesting_Increment(QCBORTrackNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700121{
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800122 if(1 >= QCBOR_MAX_ITEMS_IN_ARRAY - pNesting->pCurrentNesting->uCount) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700123 return QCBOR_ERR_ARRAY_TOO_LONG;
124 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800125
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800126 pNesting->pCurrentNesting->uCount += 1;
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800127
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700128 return QCBOR_SUCCESS;
129}
130
131inline static uint16_t Nesting_GetCount(QCBORTrackNesting *pNesting)
132{
133 // The nesting count recorded is always the actual number of individiual
134 // data items in the array or map. For arrays CBOR uses the actual item
135 // count. For maps, CBOR uses the number of pairs. This function returns
136 // the number needed for the CBOR encoding, so it divides the number of
137 // items by two for maps to get the number of pairs. This implementation
138 // takes advantage of the map major type being one larger the array major
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800139 // type, hence uDivisor is either 1 or 2.
140 const uint16_t uDivisor = pNesting->pCurrentNesting->uMajorType - CBOR_MAJOR_TYPE_ARRAY+1;
141
142 return pNesting->pCurrentNesting->uCount / uDivisor;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700143}
144
145inline static uint32_t Nesting_GetStartPos(QCBORTrackNesting *pNesting)
146{
147 return pNesting->pCurrentNesting->uStart;
148}
149
150inline static uint8_t Nesting_GetMajorType(QCBORTrackNesting *pNesting)
151{
152 return pNesting->pCurrentNesting->uMajorType;
153}
154
155inline static int Nesting_IsInNest(QCBORTrackNesting *pNesting)
156{
157 return pNesting->pCurrentNesting == &pNesting->pArrays[0] ? 0 : 1;
158}
159
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700160
161
162
163/*
164 Error tracking plan -- Errors are tracked internally and not returned
165 until Finish is called. The CBOR errors are in me->uError.
Laurence Lundblade067035b2018-11-28 17:35:25 -0800166 UsefulOutBuf also tracks whether the buffer is full or not in its
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700167 context. Once either of these errors is set they are never
Laurence Lundblade241705e2018-12-30 18:56:14 -0800168 cleared. Only QCBOREncode_Init() resets them. Or said another way, they must
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700169 never be cleared or we'll tell the caller all is good when it is not.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800170
Laurence Lundblade241705e2018-12-30 18:56:14 -0800171 Only one error code is reported by QCBOREncode_Finish() even if there are
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700172 multiple errors. The last one set wins. The caller might have to fix
173 one error to reveal the next one they have to fix. This is OK.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800174
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700175 The buffer full error tracked by UsefulBuf is only pulled out of
176 UsefulBuf in Finish() so it is the one that usually wins. UsefulBuf
177 will never go off the end of the buffer even if it is called again
178 and again when full.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800179
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700180 It is really tempting to not check for overflow on the count in the
181 number of items in an array. It would save a lot of code, it is
182 extremely unlikely that any one will every put 65,000 items in an
183 array, and the only bad thing that would happen is the CBOR would be
Laurence Lundblade241705e2018-12-30 18:56:14 -0800184 bogus.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800185
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700186 Since this does not parse any input, you could in theory remove all
187 error checks in this code if you knew the caller called it
188 correctly. Maybe someday CDDL or some such language will be able to
189 generate the code to call this and the calling code would always be
Laurence Lundblade56230d12018-11-01 11:14:51 +0700190 correct. This could also automatically size some of the data
Laurence Lundblade241705e2018-12-30 18:56:14 -0800191 structures like array/map nesting resulting in some stack memory
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700192 savings.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800193
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700194 Errors returned here fall into three categories:
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800195
Laurence Lundblade067035b2018-11-28 17:35:25 -0800196 Sizes
Laurence Lundblade241705e2018-12-30 18:56:14 -0800197 QCBOR_ERR_BUFFER_TOO_LARGE -- Encoded output exceeded UINT32_MAX
Laurence Lundblade067035b2018-11-28 17:35:25 -0800198 QCBOR_ERR_BUFFER_TOO_SMALL -- output buffer too small
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800199
Laurence Lundblade241705e2018-12-30 18:56:14 -0800200 QCBOR_ERR_ARRAY_NESTING_TOO_DEEP -- Array/map nesting > QCBOR_MAX_ARRAY_NESTING1
Laurence Lundblade067035b2018-11-28 17:35:25 -0800201 QCBOR_ERR_ARRAY_TOO_LONG -- Too many things added to an array/map
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800202
Laurence Lundblade067035b2018-11-28 17:35:25 -0800203 Nesting constructed incorrectly
204 QCBOR_ERR_TOO_MANY_CLOSES -- more close calls than opens
205 QCBOR_ERR_CLOSE_MISMATCH -- Type of close does not match open
206 QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN -- Finish called without enough closes
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700207
208 Would generate not-well-formed CBOR
209 QCBOR_ERR_UNSUPPORTED -- Simple type between 24 and 31
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700210 */
211
212
213
214
215/*
216 Public function for initialization. See header qcbor.h
217 */
Laurence Lundblade2296db52018-09-14 18:08:39 -0700218void QCBOREncode_Init(QCBOREncodeContext *me, UsefulBuf Storage)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700219{
220 memset(me, 0, sizeof(QCBOREncodeContext));
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800221 UsefulOutBuf_Init(&(me->OutBuf), Storage);
222 Nesting_Init(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700223}
224
225
226
227
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800228/*
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800229 All CBOR data items have a type and an "argument". The argument is
230 either the value of the item for integer types, the length of the
231 content for string, byte, array and map types, a tag for major type
232 6, and has several uses for major type 7.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800233
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800234 This function encodes the type and the argument. There are several
235 encodings for the argument depending on how large it is and how it is
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700236 used.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800237
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800238 Every encoding of the type and argument has at least one byte, the
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700239 "initial byte".
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800240
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700241 The top three bits of the initial byte are the major type for the
242 CBOR data item. The eight major types defined by the standard are
243 defined as CBOR_MAJOR_TYPE_xxxx in qcbor.h.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800244
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700245 The remaining five bits, known as "additional information", and
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800246 possibly more bytes encode the argument. If the argument is less than
247 24, then it is encoded entirely in the five bits. This is neat
248 because it allows you to encode an entire CBOR data item in 1 byte
249 for many values and types (integers 0-23, true, false, and tags).
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800250
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800251 If the argument is larger than 24, then it is encoded in 1,2,4 or 8
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700252 additional bytes, with the number of these bytes indicated by the
253 values of the 5 bits 24, 25, 25 and 27.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800254
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800255 It is possible to encode a particular argument in many ways with this
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700256 representation. This implementation always uses the smallest
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800257 possible representation. This conforms with CBOR preferred encoding.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800258
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700259 This function inserts them into the output buffer at the specified
Laurence Lundblade067035b2018-11-28 17:35:25 -0800260 position. AppendEncodedTypeAndNumber() appends to the end.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800261
262 This function takes care of converting to network byte order.
263
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700264 This function is also used to insert floats and doubles. Before this
265 function is called the float or double must be copied into a
266 uint64_t. That is how they are passed in. They are then converted to
267 network byte order correctly. The uMinLen param makes sure that even
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800268
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800269 if all the digits of a half, float or double are 0 it is still
270 correctly encoded in 2, 4 or 8 bytes.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700271 */
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800272
273static void InsertEncodedTypeAndNumber(QCBOREncodeContext *me,
274 uint8_t uMajorType,
275 int nMinLen,
276 uint64_t uNumber,
277 size_t uPos)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700278{
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800279 /*
280 This code does endian conversion without hton or knowing the
Laurence Lundblade241705e2018-12-30 18:56:14 -0800281 endianness of the machine using masks and shifts. This avoids the
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800282 dependency on hton and the mess of figuring out how to find the
283 machine's endianness.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800284
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800285 This is a good efficient implementation on little-endian machines.
286 A faster and small implementation is possible on big-endian
287 machines because CBOR/network byte order is big endian. However
288 big endian machines are uncommon.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800289
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800290 On x86, it is about 200 bytes instead of 500 bytes for the more
291 formal unoptimized code.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800292
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800293 This also does the CBOR preferred shortest encoding for integers
294 and is called to do endian conversion for floats.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800295
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800296 It works backwards from the LSB to the MSB as needed.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800297
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800298 Code Reviewers: THIS FUNCTION DOES POINTER MATH
299 */
300 // Holds up to 9 bytes of type and argument
301 // plus one extra so pointer always points to
302 // valid bytes.
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800303 uint8_t bytes[sizeof(uint64_t)+2];
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800304 // Point to the last bytes and work backwards
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800305 uint8_t *pByte = &bytes[sizeof(bytes)-1];
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800306 // This is the 5 bits in the initial byte that is not the major type
307 uint8_t uAdditionalInfo;
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800308
Jan Jongboom5d827882019-08-07 12:51:15 +0200309 if (uMajorType == CBOR_MAJOR_NONE_TYPE_ARRAY_INDEFINITE_LEN) {
310 uMajorType = CBOR_MAJOR_TYPE_ARRAY;
311 uAdditionalInfo = LEN_IS_INDEFINITE;
312 } else if (uMajorType == CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN) {
313 uMajorType = CBOR_MAJOR_TYPE_MAP;
314 uAdditionalInfo = LEN_IS_INDEFINITE;
315 } else if (uNumber < CBOR_TWENTY_FOUR && nMinLen == 0) {
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800316 // Simple case where argument is < 24
317 uAdditionalInfo = uNumber;
Jan Jongboom4a93a662019-07-25 08:44:58 +0200318 } else if (uMajorType == CBOR_MAJOR_TYPE_SIMPLE && uNumber == CBOR_SIMPLE_BREAK) {
319 // Break statement can be encoded in single byte too (0xff)
320 uAdditionalInfo = uNumber;
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800321 } else {
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800322 /*
323 Encode argument in 1,2,4 or 8 bytes. Outer loop
324 runs once for 1 byte and 4 times for 8 bytes.
325 Inner loop runs 1, 2 or 4 times depending on
326 outer loop counter. This works backwards taking
327 8 bits off the argument being encoded at a time
328 until all bits from uNumber have been encoded
329 and the minimum encoding size is reached.
330 Minimum encoding size is for floating point
Laurence Lundblade241705e2018-12-30 18:56:14 -0800331 numbers with zero bytes.
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800332 */
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800333 static const uint8_t aIterate[] = {1,1,2,4};
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800334 uint8_t i;
335 for(i = 0; uNumber || nMinLen > 0; i++) {
336 const uint8_t uIterations = aIterate[i];
337 for(int j = 0; j < uIterations; j++) {
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800338 *--pByte = uNumber & 0xff;
339 uNumber = uNumber >> 8;
340 }
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800341 nMinLen -= uIterations;
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800342 }
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800343 // Additional info is the encoding of the
344 // number of additional bytes to encode
345 // argument.
346 uAdditionalInfo = LEN_IS_ONE_BYTE-1 + i;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700347 }
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800348 *--pByte = (uMajorType << 5) + uAdditionalInfo;
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800349
350 UsefulOutBuf_InsertData(&(me->OutBuf), pByte, &bytes[sizeof(bytes)-1] - pByte, uPos);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700351}
352
353
354/*
355 Append the type and number info to the end of the buffer.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800356
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700357 See InsertEncodedTypeAndNumber() function above for details
358*/
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800359inline static void AppendEncodedTypeAndNumber(QCBOREncodeContext *me,
360 uint8_t uMajorType,
361 uint64_t uNumber)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700362{
363 // An append is an insert at the end.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800364 InsertEncodedTypeAndNumber(me,
365 uMajorType,
366 0,
367 uNumber,
368 UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700369}
370
371
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700372
Laurence Lundblade241705e2018-12-30 18:56:14 -0800373
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700374/*
Laurence Lundblade067035b2018-11-28 17:35:25 -0800375 Public functions for closing arrays and maps. See header qcbor.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700376 */
Laurence Lundblade067035b2018-11-28 17:35:25 -0800377void QCBOREncode_AddUInt64(QCBOREncodeContext *me, uint64_t uValue)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700378{
Laurence Lundblade067035b2018-11-28 17:35:25 -0800379 if(me->uError == QCBOR_SUCCESS) {
380 AppendEncodedTypeAndNumber(me, CBOR_MAJOR_TYPE_POSITIVE_INT, uValue);
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800381 me->uError = Nesting_Increment(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700382 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700383}
384
Laurence Lundblade56230d12018-11-01 11:14:51 +0700385
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700386/*
Laurence Lundblade067035b2018-11-28 17:35:25 -0800387 Public functions for closing arrays and maps. See header qcbor.h
388 */
389void QCBOREncode_AddInt64(QCBOREncodeContext *me, int64_t nNum)
390{
391 if(me->uError == QCBOR_SUCCESS) {
392 uint8_t uMajorType;
393 uint64_t uValue;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800394
Laurence Lundblade067035b2018-11-28 17:35:25 -0800395 if(nNum < 0) {
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800396 // In CBOR -1 encodes as 0x00 with major type negative int.
397 uValue = (uint64_t)(-nNum - 1);
Laurence Lundblade067035b2018-11-28 17:35:25 -0800398 uMajorType = CBOR_MAJOR_TYPE_NEGATIVE_INT;
399 } else {
400 uValue = (uint64_t)nNum;
401 uMajorType = CBOR_MAJOR_TYPE_POSITIVE_INT;
402 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800403
Laurence Lundblade067035b2018-11-28 17:35:25 -0800404 AppendEncodedTypeAndNumber(me, uMajorType, uValue);
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800405 me->uError = Nesting_Increment(&(me->nesting));
Laurence Lundblade067035b2018-11-28 17:35:25 -0800406 }
407}
408
409
410/*
Laurence Lundbladeda532272019-04-07 11:40:17 -0700411 Semi-private function. It is exposed to user of the interface, but
412 they will usually call one of the inline wrappers rather than this.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800413
Laurence Lundblade067035b2018-11-28 17:35:25 -0800414 See header qcbor.h
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800415
Laurence Lundbladeda532272019-04-07 11:40:17 -0700416 Does the work of adding actual strings bytes to the CBOR output (as
417 opposed to numbers and opening / closing aggregate types).
418
419 There are four use cases:
420 CBOR_MAJOR_TYPE_BYTE_STRING -- Byte strings
421 CBOR_MAJOR_TYPE_TEXT_STRING -- Text strings
422 CBOR_MAJOR_NONE_TYPE_RAW -- Already-encoded CBOR
423 CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY -- Special case
424
425 The first two add the type and length plus the actual bytes. The
426 third just adds the bytes as the type and length are presumed to be
427 in the bytes. The fourth just adds the type and length for the very
428 special case of QCBOREncode_AddBytesLenOnly().
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700429 */
Laurence Lundblade067035b2018-11-28 17:35:25 -0800430void QCBOREncode_AddBuffer(QCBOREncodeContext *me, uint8_t uMajorType, UsefulBufC Bytes)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700431{
Laurence Lundblade241705e2018-12-30 18:56:14 -0800432 if(me->uError == QCBOR_SUCCESS) {
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800433 // If it is not Raw CBOR, add the type and the length
434 if(uMajorType != CBOR_MAJOR_NONE_TYPE_RAW) {
Laurence Lundbladeda532272019-04-07 11:40:17 -0700435 uint8_t uRealMajorType = uMajorType;
436 if(uRealMajorType == CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY) {
437 uRealMajorType = CBOR_MAJOR_TYPE_BYTE_STRING;
438 }
439 AppendEncodedTypeAndNumber(me, uRealMajorType, Bytes.len);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700440 }
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800441
Laurence Lundbladeda532272019-04-07 11:40:17 -0700442 if(uMajorType != CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY) {
443 // Actually add the bytes
444 UsefulOutBuf_AppendUsefulBuf(&(me->OutBuf), Bytes);
445 }
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800446
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800447 // Update the array counting if there is any nesting at all
448 me->uError = Nesting_Increment(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700449 }
450}
451
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700452
Laurence Lundblade55a24832018-10-30 04:35:08 +0700453/*
Laurence Lundblade067035b2018-11-28 17:35:25 -0800454 Public functions for closing arrays and maps. See header qcbor.h
Laurence Lundblade55a24832018-10-30 04:35:08 +0700455 */
456void QCBOREncode_AddTag(QCBOREncodeContext *me, uint64_t uTag)
457{
Laurence Lundblade55a24832018-10-30 04:35:08 +0700458 AppendEncodedTypeAndNumber(me, CBOR_MAJOR_TYPE_OPTIONAL, uTag);
459}
460
461
Laurence Lundblade56230d12018-11-01 11:14:51 +0700462/*
Laurence Lundblade487930f2018-11-30 11:01:45 -0800463 Semi-private function. It is exposed to user of the interface,
464 but they will usually call one of the inline wrappers rather than this.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800465
Laurence Lundblade487930f2018-11-30 11:01:45 -0800466 See header qcbor.h
Laurence Lundblade56230d12018-11-01 11:14:51 +0700467 */
Laurence Lundblade487930f2018-11-30 11:01:45 -0800468void QCBOREncode_AddType7(QCBOREncodeContext *me, size_t uSize, uint64_t uNum)
Laurence Lundblade55a24832018-10-30 04:35:08 +0700469{
Laurence Lundblade487930f2018-11-30 11:01:45 -0800470 if(me->uError == QCBOR_SUCCESS) {
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700471 if(uNum >= CBOR_SIMPLEV_RESERVED_START && uNum <= CBOR_SIMPLEV_RESERVED_END) {
472 me->uError = QCBOR_ERR_UNSUPPORTED;
473 } else {
474 // This function call takes care of endian swapping for the float / double
475 InsertEncodedTypeAndNumber(me,
476 // The major type for floats and doubles
477 CBOR_MAJOR_TYPE_SIMPLE,
478 // size makes sure floats with zeros encode correctly
479 (int)uSize,
480 // Bytes of the floating point number as a uint
481 uNum,
482 // end position because this is append
483 UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800484
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700485 me->uError = Nesting_Increment(&(me->nesting));
486 }
Laurence Lundblade487930f2018-11-30 11:01:45 -0800487 }
Laurence Lundblade55a24832018-10-30 04:35:08 +0700488}
489
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700490
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700491/*
Laurence Lundblade067035b2018-11-28 17:35:25 -0800492 Public functions for closing arrays and maps. See header qcbor.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700493 */
Laurence Lundblade067035b2018-11-28 17:35:25 -0800494void QCBOREncode_AddDouble(QCBOREncodeContext *me, double dNum)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700495{
Laurence Lundblade067035b2018-11-28 17:35:25 -0800496 const IEEE754_union uNum = IEEE754_DoubleToSmallest(dNum);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800497
Laurence Lundblade487930f2018-11-30 11:01:45 -0800498 QCBOREncode_AddType7(me, uNum.uSize, uNum.uValue);
Laurence Lundblade067035b2018-11-28 17:35:25 -0800499}
500
501
Laurence Lundblade59289e52019-12-30 13:44:37 -0800502#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
503/*
504 Semi-public function. It is exposed to the user of the interface, but
505 one of the inline wrappers will usually be called rather than this.
506
507 See qcbor.h
508 */
509void QCBOREncode_AddExponentAndMantissa(QCBOREncodeContext *pMe,
510 uint64_t uTag,
511 UsefulBufC BigNumMantissa,
512 bool bBigNumIsNegative,
513 int64_t nMantissa,
514 int64_t nExponent)
515{
516
517 // This is for encoding either a big float or a decimal fraction,
518 // both of which are an array of two items, an exponent and a
519 // mantissa. The difference between the two is that the exponent is
520 // base-2 for big floats and base-10 for decimal fractions, but that
521 // has no effect on the code here.
522 QCBOREncode_AddTag(pMe, uTag);
523 QCBOREncode_OpenArray(pMe);
524 QCBOREncode_AddInt64(pMe, nExponent);
525 if(!UsefulBuf_IsNULLC(BigNumMantissa)) {
526 if(bBigNumIsNegative) {
527 QCBOREncode_AddNegativeBignum(pMe, BigNumMantissa);
528 } else {
529 QCBOREncode_AddPositiveBignum(pMe, BigNumMantissa);
530 }
531 } else {
532 QCBOREncode_AddInt64(pMe, nMantissa);
533 }
534 QCBOREncode_CloseArray(pMe);
535}
536#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
537
538
Laurence Lundblade067035b2018-11-28 17:35:25 -0800539/*
540 Semi-public function. It is exposed to user of the interface,
541 but they will usually call one of the inline wrappers rather than this.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800542
Laurence Lundblade067035b2018-11-28 17:35:25 -0800543 See header qcbor.h
544*/
545void QCBOREncode_OpenMapOrArray(QCBOREncodeContext *me, uint8_t uMajorType)
546{
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800547 // Add one item to the nesting level we are in for the new map or array
548 me->uError = Nesting_Increment(&(me->nesting));
Laurence Lundblade241705e2018-12-30 18:56:14 -0800549 if(me->uError == QCBOR_SUCCESS) {
Laurence Lundbladed39cd392019-01-11 18:17:38 -0800550 // The offset where the length of an array or map will get written
551 // is stored in a uint32_t, not a size_t to keep stack usage smaller. This
552 // checks to be sure there is no wrap around when recording the offset.
553 // Note that on 64-bit machines CBOR larger than 4GB can be encoded as long as no
554 // array / map offsets occur past the 4GB mark, but the public interface
555 // says that the maximum is 4GB to keep the discussion simpler.
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800556 size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf));
Laurence Lundbladed39cd392019-01-11 18:17:38 -0800557
558 // QCBOR_MAX_ARRAY_OFFSET is slightly less than UINT32_MAX so this
559 // code can run on a 32-bit machine and tests can pass on a 32-bit
560 // machine. If it was exactly UINT32_MAX, then this code would
561 // not compile or run on a 32-bit machine and an #ifdef or some
562 // machine size detection would be needed reducing portability.
563 if(uEndPosition >= QCBOR_MAX_ARRAY_OFFSET) {
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800564 me->uError = QCBOR_ERR_BUFFER_TOO_LARGE;
Laurence Lundbladed39cd392019-01-11 18:17:38 -0800565
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800566 } else {
Laurence Lundbladed39cd392019-01-11 18:17:38 -0800567 // Increase nesting level because this is a map or array.
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800568 // Cast from size_t to uin32_t is safe because of check above
569 me->uError = Nesting_Increase(&(me->nesting), uMajorType, (uint32_t)uEndPosition);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700570 }
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800571 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700572}
573
Laurence Lundblade59289e52019-12-30 13:44:37 -0800574
Jan Jongboom4a93a662019-07-25 08:44:58 +0200575/*
576 Semi-public function. It is exposed to user of the interface,
577 but they will usually call one of the inline wrappers rather than this.
578
579 See header qcbor.h
580*/
581void QCBOREncode_OpenMapOrArrayIndefiniteLength(QCBOREncodeContext *me, uint8_t uMajorType)
582{
583 // insert the indefinite length marker (0x9f for arrays, 0xbf for maps)
Jan Jongboom5d827882019-08-07 12:51:15 +0200584 InsertEncodedTypeAndNumber(me, uMajorType, 0, 0, UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
Jan Jongboom4a93a662019-07-25 08:44:58 +0200585
586 QCBOREncode_OpenMapOrArray(me, uMajorType);
587}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700588
589/*
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700590 Public functions for closing arrays and maps. See header qcbor.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700591 */
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800592void QCBOREncode_CloseMapOrArray(QCBOREncodeContext *me,
593 uint8_t uMajorType,
594 UsefulBufC *pWrappedCBOR)
Laurence Lundbladea954db92018-09-28 19:27:31 -0700595{
Laurence Lundblade241705e2018-12-30 18:56:14 -0800596 if(me->uError == QCBOR_SUCCESS) {
Laurence Lundbladea954db92018-09-28 19:27:31 -0700597 if(!Nesting_IsInNest(&(me->nesting))) {
598 me->uError = QCBOR_ERR_TOO_MANY_CLOSES;
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800599 } else if(Nesting_GetMajorType(&(me->nesting)) != uMajorType) {
Laurence Lundblade067035b2018-11-28 17:35:25 -0800600 me->uError = QCBOR_ERR_CLOSE_MISMATCH;
Laurence Lundbladea954db92018-09-28 19:27:31 -0700601 } else {
Laurence Lundblade56230d12018-11-01 11:14:51 +0700602 // When the array, map or bstr wrap was started, nothing was done
603 // except note the position of the start of it. This code goes back
604 // and inserts the actual CBOR array, map or bstr and its length.
605 // That means all the data that is in the array, map or wrapped
606 // needs to be slid to the right. This is done by UsefulOutBuf's
607 // insert function that is called from inside
608 // InsertEncodedTypeAndNumber()
609 const size_t uInsertPosition = Nesting_GetStartPos(&(me->nesting));
610 const size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf));
611 // This can't go negative because the UsefulOutBuf always only grows
612 // and never shrinks. UsefulOutBut itself also has defenses such that
613 // it won't write were it should not even if given hostile input lengths
614 const size_t uLenOfEncodedMapOrArray = uEndPosition - uInsertPosition;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800615
Laurence Lundblade56230d12018-11-01 11:14:51 +0700616 // Length is number of bytes for a bstr and number of items a for map & array
617 const size_t uLength = uMajorType == CBOR_MAJOR_TYPE_BYTE_STRING ?
Laurence Lundbladea954db92018-09-28 19:27:31 -0700618 uLenOfEncodedMapOrArray : Nesting_GetCount(&(me->nesting));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800619
Laurence Lundbladea954db92018-09-28 19:27:31 -0700620 // Actually insert
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700621 InsertEncodedTypeAndNumber(me,
Laurence Lundbladea954db92018-09-28 19:27:31 -0700622 uMajorType, // major type bstr, array or map
623 0, // no minimum length for encoding
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800624 uLength, // either len of bstr or num map / array items
Laurence Lundbladea954db92018-09-28 19:27:31 -0700625 uInsertPosition); // position in out buffer
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800626
Laurence Lundbladea954db92018-09-28 19:27:31 -0700627 // Return pointer and length to the enclosed encoded CBOR. The intended
628 // use is for it to be hashed (e.g., SHA-256) in a COSE implementation.
629 // This must be used right away, as the pointer and length go invalid
Laurence Lundblade83f5b7f2019-04-06 11:22:37 -0700630 // on any subsequent calls to this function because there might be calls to
631 // InsertEncodedTypeAndNumber() that slides data to the right.
Laurence Lundbladea954db92018-09-28 19:27:31 -0700632 if(pWrappedCBOR) {
Laurence Lundblade25c6c0a2018-12-17 13:21:59 -0800633 const UsefulBufC PartialResult = UsefulOutBuf_OutUBuf(&(me->OutBuf));
Laurence Lundblade83f5b7f2019-04-06 11:22:37 -0700634 *pWrappedCBOR = UsefulBuf_Tail(PartialResult, uInsertPosition);
Laurence Lundbladea954db92018-09-28 19:27:31 -0700635 }
636 Nesting_Decrease(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700637 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700638 }
639}
640
Jan Jongboom4a93a662019-07-25 08:44:58 +0200641/*
642 Public functions for closing arrays and maps. See header qcbor.h
643 */
644void QCBOREncode_CloseMapOrArrayIndefiniteLength(QCBOREncodeContext *me, uint8_t uMajorType, UsefulBufC *pWrappedCBOR)
645{
646 if(me->uError == QCBOR_SUCCESS) {
647 if(!Nesting_IsInNest(&(me->nesting))) {
648 me->uError = QCBOR_ERR_TOO_MANY_CLOSES;
649 } else if(Nesting_GetMajorType(&(me->nesting)) != uMajorType) {
650 me->uError = QCBOR_ERR_CLOSE_MISMATCH;
651 } else {
652 // insert the break marker (0xff for both arrays and maps)
653 InsertEncodedTypeAndNumber(me, CBOR_MAJOR_TYPE_SIMPLE, 0, CBOR_SIMPLE_BREAK, UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
654
655 // Return pointer and length to the enclosed encoded CBOR. The intended
656 // use is for it to be hashed (e.g., SHA-256) in a COSE implementation.
657 // This must be used right away, as the pointer and length go invalid
658 // on any subsequent calls to this function because there might be calls to
659 // InsertEncodedTypeAndNumber() that slides data to the right.
660 if(pWrappedCBOR) {
661 const UsefulBufC PartialResult = UsefulOutBuf_OutUBuf(&(me->OutBuf));
662 *pWrappedCBOR = UsefulBuf_Tail(PartialResult, UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
663 }
664
665 // Decrease nesting level
666 Nesting_Decrease(&(me->nesting));
667 }
668 }
669}
670
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700671
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700672/*
673 Public functions to finish and get the encoded result. See header qcbor.h
674 */
Laurence Lundblade30816f22018-11-10 13:40:22 +0700675QCBORError QCBOREncode_Finish(QCBOREncodeContext *me, UsefulBufC *pEncodedCBOR)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700676{
Laurence Lundbladef607a2a2019-07-05 21:25:25 -0700677 QCBORError uReturn = QCBOREncode_GetErrorState(me);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800678
Laurence Lundblade067035b2018-11-28 17:35:25 -0800679 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700680 goto Done;
Laurence Lundblade067035b2018-11-28 17:35:25 -0800681 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800682
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700683 if (Nesting_IsInNest(&(me->nesting))) {
Laurence Lundblade067035b2018-11-28 17:35:25 -0800684 uReturn = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700685 goto Done;
686 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800687
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700688 *pEncodedCBOR = UsefulOutBuf_OutUBuf(&(me->OutBuf));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800689
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700690Done:
Laurence Lundblade067035b2018-11-28 17:35:25 -0800691 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700692}
693
Laurence Lundblade0595e932018-11-02 22:22:47 +0700694
Laurence Lundbladef607a2a2019-07-05 21:25:25 -0700695
Laurence Lundblade067035b2018-11-28 17:35:25 -0800696/*
697 Public functions to finish and get the encoded result. See header qcbor.h
698 */
Laurence Lundblade30816f22018-11-10 13:40:22 +0700699QCBORError QCBOREncode_FinishGetSize(QCBOREncodeContext *me, size_t *puEncodedLen)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700700{
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700701 UsefulBufC Enc;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800702
Laurence Lundblade30816f22018-11-10 13:40:22 +0700703 QCBORError nReturn = QCBOREncode_Finish(me, &Enc);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800704
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700705 if(nReturn == QCBOR_SUCCESS) {
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700706 *puEncodedLen = Enc.len;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700707 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800708
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700709 return nReturn;
710}
711
712
Laurence Lundblade067035b2018-11-28 17:35:25 -0800713
714
715/*
716 Notes on the code
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800717
Laurence Lundblade067035b2018-11-28 17:35:25 -0800718 CBOR Major Type Public Function
719 0 QCBOREncode_AddUInt64
720 0, 1 QCBOREncode_AddUInt64, QCBOREncode_AddInt64
721 2, 3 QCBOREncode_AddBuffer, Also QCBOREncode_OpenMapOrArray
722 4, 5 QCBOREncode_OpenMapOrArray
723 6 QCBOREncode_AddTag
Laurence Lundblade4e7bc682018-12-14 23:21:04 -0800724 7 QCBOREncode_AddDouble, QCBOREncode_AddType7
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800725
Laurence Lundblade241705e2018-12-30 18:56:14 -0800726 Object code sizes on X86 with LLVM compiler and -Os (Dec 30, 2018)
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800727
Laurence Lundblade9c097392018-12-30 13:52:24 -0800728 _QCBOREncode_Init 69
Laurence Lundblade067035b2018-11-28 17:35:25 -0800729 _QCBOREncode_AddUInt64 76
730 _QCBOREncode_AddInt64 87
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800731 _QCBOREncode_AddBuffer 113
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800732 _QCBOREncode_AddTag 27
Laurence Lundblade9c097392018-12-30 13:52:24 -0800733 _QCBOREncode_AddType7 87
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800734 _QCBOREncode_AddDouble 36
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800735 _QCBOREncode_OpenMapOrArray 103
Laurence Lundblade067035b2018-11-28 17:35:25 -0800736 _QCBOREncode_CloseMapOrArray 181
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800737 _InsertEncodedTypeAndNumber 190
Laurence Lundblade067035b2018-11-28 17:35:25 -0800738 _QCBOREncode_Finish 72
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800739 _QCBOREncode_FinishGetSize 70
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800740
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800741 Total is about 1.1KB
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800742
Laurence Lundblade067035b2018-11-28 17:35:25 -0800743 _QCBOREncode_CloseMapOrArray is larger because it has a lot
744 of nesting tracking to do and much of Nesting_ inlines
745 into it. It probably can't be reduced much.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800746
Laurence Lundblade067035b2018-11-28 17:35:25 -0800747 If the error returned by Nesting_Increment() can be ignored
748 because the limit is so high and the consequence of exceeding
749 is proved to be inconsequential, then a lot of if(me->uError)
750 instance can be removed, saving some code.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800751
Laurence Lundblade067035b2018-11-28 17:35:25 -0800752 */