blob: 7e16595e539d908b69ef4441998f55879c7d34c3 [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 Lundbladec9f0fbc2020-02-07 10:48:33 +000043 when who what, where, why
44 -------- ---- ---------------------------------------------------
45 02/07/2020 llundblade QCBOREncode_EncodeHead() and other for bstr hashing.
46 01/25/2020 llundblade Refine use of integer types to quiet static analysis.
47 01/08/2020 llundblade Documentation corrections & improved code formatting.
48 12/30/19 llundblade Add support for decimal fractions and bigfloats.
49 8/7/19 llundblade Prevent encoding simple type reserved values 24..31
50 7/25/19 janjongboom Add indefinite length encoding for maps and arrays
51 4/6/19 llundblade Wrapped bstr returned now includes the wrapping bstr.
52 12/30/18 llundblade Small efficient clever encode of type & argument.
53 11/29/18 llundblade Rework to simpler handling of tags and labels.
54 11/9/18 llundblade Error codes are now enums.
55 11/1/18 llundblade Floating support.
56 10/31/18 llundblade Switch to one license that is almost BSD-3.
57 09/28/18 llundblade Added bstr wrapping feature for COSE implementation.
58 02/05/18 llundbla Works on CPUs which require integer alignment.
59 Requires new version of UsefulBuf.
60 07/05/17 llundbla Add bstr wrapping of maps/arrays for COSE
61 03/01/17 llundbla More data types
62 11/13/16 llundbla Integrate most TZ changes back into github version.
63 09/30/16 gkanike Porting to TZ.
64 03/15/16 llundbla Initial Version.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080065
Laurence Lundbladeee851742020-01-08 08:37:05 -080066 =============================================================================*/
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070067
68#include "qcbor.h"
Laurence Lundblade12d32c52018-09-19 11:25:27 -070069#include "ieee754.h"
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070070
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070071
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070072
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070073/*
Laurence Lundbladeee851742020-01-08 08:37:05 -080074 Nesting -- This tracks the nesting of maps and arrays.
75
76 The following functions and data type QCBORTrackNesting implement the
77 nesting management for encoding.
78
79 CBOR's two nesting types, arrays and maps, are tracked here. There is
80 a limit of QCBOR_MAX_ARRAY_NESTING to the number of arrays and maps
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070081 that can be nested in one encoding so the encoding context stays
82 small enough to fit on the stack.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080083
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070084 When an array / map is opened, pCurrentNesting points to the element
Laurence Lundbladeee851742020-01-08 08:37:05 -080085 in pArrays that records the type, start position and accumulates a
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070086 count of the number of items added. When closed the start position is
87 used to go back and fill in the type and number of items in the array
88 / map.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080089
Laurence Lundbladeee851742020-01-08 08:37:05 -080090 Encoded output can be just items like ints and strings that are not
91 part of any array / map. That is, the first thing encoded does not
92 have to be an array or a map.
93
94 QCBOR has a special feature to allow constructing bstr-wrapped CBOR
95 directly into the output buffer, so an extra buffer for it is not
96 needed. This is implemented as nesting with type
97 CBOR_MAJOR_TYPE_BYTE_STRING and uses this code. Bstr-wrapped CBOR is
98 used by COSE for data that is to be hashed.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070099 */
100inline static void Nesting_Init(QCBORTrackNesting *pNesting)
101{
Laurence Lundbladeee851742020-01-08 08:37:05 -0800102 // Assumes pNesting has been zeroed
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700103 pNesting->pCurrentNesting = &pNesting->pArrays[0];
104 // Implied CBOR array at the top nesting level. This is never returned,
105 // but makes the item count work correctly.
106 pNesting->pCurrentNesting->uMajorType = CBOR_MAJOR_TYPE_ARRAY;
107}
108
Laurence Lundblade29497c02020-07-11 15:44:03 -0700109inline static uint8_t Nesting_Increase(QCBORTrackNesting *pNesting,
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800110 uint8_t uMajorType,
111 uint32_t uPos)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700112{
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 Lundblade29497c02020-07-11 15:44:03 -0700115 return QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700116 } else {
117 pNesting->pCurrentNesting++;
118 pNesting->pCurrentNesting->uCount = 0;
119 pNesting->pCurrentNesting->uStart = uPos;
120 pNesting->pCurrentNesting->uMajorType = uMajorType;
Laurence Lundblade29497c02020-07-11 15:44:03 -0700121 return QCBOR_SUCCESS;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700122 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700123}
124
125inline static void Nesting_Decrease(QCBORTrackNesting *pNesting)
126{
127 pNesting->pCurrentNesting--;
128}
129
Laurence Lundblade29497c02020-07-11 15:44:03 -0700130inline static uint8_t 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.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800150
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800151 if(pNesting->pCurrentNesting->uMajorType == CBOR_MAJOR_TYPE_MAP) {
152 // Cast back to uint16_t after integer promotion for bit shift
153 return (uint16_t)(pNesting->pCurrentNesting->uCount >> 1);
154 } else {
155 return pNesting->pCurrentNesting->uCount;
156 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700157}
158
159inline static uint32_t Nesting_GetStartPos(QCBORTrackNesting *pNesting)
160{
161 return pNesting->pCurrentNesting->uStart;
162}
163
164inline static uint8_t Nesting_GetMajorType(QCBORTrackNesting *pNesting)
165{
166 return pNesting->pCurrentNesting->uMajorType;
167}
168
Laurence Lundbladeee851742020-01-08 08:37:05 -0800169inline static bool Nesting_IsInNest(QCBORTrackNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700170{
Laurence Lundbladeee851742020-01-08 08:37:05 -0800171 return pNesting->pCurrentNesting == &pNesting->pArrays[0] ? false : true;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700172}
173
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700174
175
176
177/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800178 Encoding of the major CBOR types is by these functions:
179
180 CBOR Major Type Public Function
181 0 QCBOREncode_AddUInt64()
182 0, 1 QCBOREncode_AddUInt64(), QCBOREncode_AddInt64()
183 2, 3 QCBOREncode_AddBuffer(), Also QCBOREncode_OpenMapOrArray(),
184 QCBOREncode_CloseMapOrArray()
185 4, 5 QCBOREncode_OpenMapOrArray(), QCBOREncode_CloseMapOrArray(),
186 QCBOREncode_OpenMapOrArrayIndefiniteLength(),
187 QCBOREncode_CloseMapOrArrayIndefiniteLength()
188 6 QCBOREncode_AddTag()
189 7 QCBOREncode_AddDouble(), QCBOREncode_AddType7()
190
191 Additionally, encoding of decimal fractions and bigfloats is by
192 QCBOREncode_AddExponentAndMantissa()
193*/
194
195/*
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700196 Error tracking plan -- Errors are tracked internally and not returned
Laurence Lundbladeee851742020-01-08 08:37:05 -0800197 until QCBOREncode_Finish is called. The CBOR errors are in me->uError.
Laurence Lundblade067035b2018-11-28 17:35:25 -0800198 UsefulOutBuf also tracks whether the buffer is full or not in its
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700199 context. Once either of these errors is set they are never
Laurence Lundblade241705e2018-12-30 18:56:14 -0800200 cleared. Only QCBOREncode_Init() resets them. Or said another way, they must
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700201 never be cleared or we'll tell the caller all is good when it is not.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800202
Laurence Lundblade241705e2018-12-30 18:56:14 -0800203 Only one error code is reported by QCBOREncode_Finish() even if there are
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700204 multiple errors. The last one set wins. The caller might have to fix
205 one error to reveal the next one they have to fix. This is OK.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800206
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700207 The buffer full error tracked by UsefulBuf is only pulled out of
208 UsefulBuf in Finish() so it is the one that usually wins. UsefulBuf
209 will never go off the end of the buffer even if it is called again
210 and again when full.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800211
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700212 It is really tempting to not check for overflow on the count in the
213 number of items in an array. It would save a lot of code, it is
214 extremely unlikely that any one will every put 65,000 items in an
215 array, and the only bad thing that would happen is the CBOR would be
Laurence Lundblade241705e2018-12-30 18:56:14 -0800216 bogus.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800217
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700218 Since this does not parse any input, you could in theory remove all
219 error checks in this code if you knew the caller called it
220 correctly. Maybe someday CDDL or some such language will be able to
221 generate the code to call this and the calling code would always be
Laurence Lundblade56230d12018-11-01 11:14:51 +0700222 correct. This could also automatically size some of the data
Laurence Lundblade241705e2018-12-30 18:56:14 -0800223 structures like array/map nesting resulting in some stack memory
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700224 savings.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800225
Laurence Lundbladeee851742020-01-08 08:37:05 -0800226 The 8 errors returned here fall into three categories:
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800227
Laurence Lundblade067035b2018-11-28 17:35:25 -0800228 Sizes
Laurence Lundbladeee851742020-01-08 08:37:05 -0800229 QCBOR_ERR_BUFFER_TOO_LARGE -- Encoded output exceeded UINT32_MAX
230 QCBOR_ERR_BUFFER_TOO_SMALL -- Output buffer too small
231 QCBOR_ERR_ARRAY_NESTING_TOO_DEEP -- Nesting > QCBOR_MAX_ARRAY_NESTING1
232 QCBOR_ERR_ARRAY_TOO_LONG -- Too many things added to an array/map
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800233
Laurence Lundblade067035b2018-11-28 17:35:25 -0800234 Nesting constructed incorrectly
Laurence Lundbladeee851742020-01-08 08:37:05 -0800235 QCBOR_ERR_TOO_MANY_CLOSES -- More close calls than opens
236 QCBOR_ERR_CLOSE_MISMATCH -- Type of close does not match open
Laurence Lundblade067035b2018-11-28 17:35:25 -0800237 QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN -- Finish called without enough closes
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700238
239 Would generate not-well-formed CBOR
Laurence Lundbladeee851742020-01-08 08:37:05 -0800240 QCBOR_ERR_UNSUPPORTED -- Simple type between 24 and 31
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700241 */
242
243
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700244/*
245 Public function for initialization. See header qcbor.h
246 */
Laurence Lundblade2296db52018-09-14 18:08:39 -0700247void QCBOREncode_Init(QCBOREncodeContext *me, UsefulBuf Storage)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700248{
249 memset(me, 0, sizeof(QCBOREncodeContext));
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800250 UsefulOutBuf_Init(&(me->OutBuf), Storage);
251 Nesting_Init(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700252}
253
254
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000255/*
256 Public function for initialization. See header qcbor.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700257 */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000258UsefulBufC QCBOREncode_EncodeHead(UsefulBuf buffer,
259 uint8_t uMajorType,
260 uint8_t uMinLen,
261 uint64_t uArgument)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700262{
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000263 /**
264 All CBOR data items have a type and an "argument". The argument is
265 either the value of the item for integer types, the length of the
266 content for string, byte, array and map types, a tag for major type
267 6, and has several uses for major type 7.
268
269 This function encodes the type and the argument. There are several
270 encodings for the argument depending on how large it is and how it is
271 used.
272
273 Every encoding of the type and argument has at least one byte, the
274 "initial byte".
275
276 The top three bits of the initial byte are the major type for the
277 CBOR data item. The eight major types defined by the standard are
278 defined as CBOR_MAJOR_TYPE_xxxx in qcbor.h.
279
280 The remaining five bits, known as "additional information", and
281 possibly more bytes encode the argument. If the argument is less than
282 24, then it is encoded entirely in the five bits. This is neat
283 because it allows you to encode an entire CBOR data item in 1 byte
284 for many values and types (integers 0-23, true, false, and tags).
285
286 If the argument is larger than 24, then it is encoded in 1,2,4 or 8
287 additional bytes, with the number of these bytes indicated by the
288 values of the 5 bits 24, 25, 25 and 27.
289
290 It is possible to encode a particular argument in many ways with this
291 representation. This implementation always uses the smallest
292 possible representation. This conforms with CBOR preferred encoding.
293
294 This function inserts them into the output buffer at the specified
295 position. AppendEncodedTypeAndNumber() appends to the end.
296
297 This function takes care of converting to network byte order.
298
299 This function is also used to insert floats and doubles. Before this
300 function is called the float or double must be copied into a
301 uint64_t. That is how they are passed in. They are then converted to
302 network byte order correctly. The uMinLen parameter makes sure that
303 even if all the digits of a half, float or double are 0 it is still
304 correctly encoded in 2, 4 or 8 bytes.
305 */
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800306 /*
307 This code does endian conversion without hton or knowing the
Laurence Lundblade241705e2018-12-30 18:56:14 -0800308 endianness of the machine using masks and shifts. This avoids the
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800309 dependency on hton and the mess of figuring out how to find the
310 machine's endianness.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800311
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800312 This is a good efficient implementation on little-endian machines.
313 A faster and small implementation is possible on big-endian
314 machines because CBOR/network byte order is big endian. However
315 big endian machines are uncommon.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800316
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800317 On x86, it is about 200 bytes instead of 500 bytes for the more
318 formal unoptimized code.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800319
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800320 This also does the CBOR preferred shortest encoding for integers
321 and is called to do endian conversion for floats.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800322
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800323 It works backwards from the LSB to the MSB as needed.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800324
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800325 Code Reviewers: THIS FUNCTION DOES POINTER MATH
326 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800327 /*
328 The type int is used here for several variables because of the way
329 integer promotion works in C for integer variables that are
330 uint8_t or uint16_t. The basic rule is that they will always be
331 promoted to int if they will fit. All of these integer variables
332 need only hold values less than 255 or are promoted from uint8_t,
333 so they will always fit into an int. Note that promotion is only
334 to unsigned int if the value won't fit into an int even if the
335 promotion is for an unsigned like uint8_t.
336
337 By declaring them int, there are few implicit conversions and fewer
338 casts needed. Code size is reduced a little. It also makes static
339 analyzers happier.
340
341 Note also that declaring them uint8_t won't stop integer wrap
342 around if the code is wrong. It won't make the code more correct.
343
344 https://stackoverflow.com/questions/46073295/implicit-type-promotion-rules
345 https://stackoverflow.com/questions/589575/what-does-the-c-standard-state-the-size-of-int-long-type-to-be
346 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800347
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000348 // Buffer must have room for the largest CBOR HEAD + one extra as the
349 // one extra is needed for this code to work as it does a pre-decrement.
350 if(buffer.len < QCBOR_HEAD_BUFFER_SIZE) {
351 return NULLUsefulBufC;
352 }
353
354 // Pointer to last valid byte in the buffer
355 uint8_t * const pBufferEnd = &((uint8_t *)buffer.ptr)[QCBOR_HEAD_BUFFER_SIZE-1];
356
357 // Point to the last byte and work backwards
358 uint8_t *pByte = pBufferEnd;
359 // The 5 bits in the initial byte that are not the major type
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800360 int nAdditionalInfo;
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800361
Jan Jongboom5d827882019-08-07 12:51:15 +0200362 if (uMajorType == CBOR_MAJOR_NONE_TYPE_ARRAY_INDEFINITE_LEN) {
363 uMajorType = CBOR_MAJOR_TYPE_ARRAY;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800364 nAdditionalInfo = LEN_IS_INDEFINITE;
Jan Jongboom5d827882019-08-07 12:51:15 +0200365 } else if (uMajorType == CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN) {
366 uMajorType = CBOR_MAJOR_TYPE_MAP;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800367 nAdditionalInfo = LEN_IS_INDEFINITE;
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000368 } else if (uArgument < CBOR_TWENTY_FOUR && uMinLen == 0) {
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800369 // Simple case where argument is < 24
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000370 nAdditionalInfo = (int)uArgument;
371 } else if (uMajorType == CBOR_MAJOR_TYPE_SIMPLE && uArgument == CBOR_SIMPLE_BREAK) {
Jan Jongboom4a93a662019-07-25 08:44:58 +0200372 // Break statement can be encoded in single byte too (0xff)
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000373 nAdditionalInfo = (int)uArgument;
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800374 } else {
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800375 /*
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000376 Encode argument in 1,2,4 or 8 bytes. Outer loop
377 runs once for 1 byte and 4 times for 8 bytes.
378 Inner loop runs 1, 2 or 4 times depending on
379 outer loop counter. This works backwards taking
380 8 bits off the argument being encoded at a time
381 until all bits from uNumber have been encoded
382 and the minimum encoding size is reached.
383 Minimum encoding size is for floating point
384 numbers with zero bytes.
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800385 */
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800386 static const uint8_t aIterate[] = {1,1,2,4};
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000387
388 // The parameter passed in is unsigned, but goes negative in the loop
389 // so it must be converted to a signed value.
390 int nMinLen = (int)uMinLen;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800391 int i;
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000392 for(i = 0; uArgument || nMinLen > 0; i++) {
393 const int nIterations = (int)aIterate[i];
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800394 for(int j = 0; j < nIterations; j++) {
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000395 *--pByte = (uint8_t)(uArgument & 0xff);
396 uArgument = uArgument >> 8;
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800397 }
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800398 nMinLen -= nIterations;
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800399 }
Laurence Lundbladeee851742020-01-08 08:37:05 -0800400 // Additional info is the encoding of the number of additional
401 // bytes to encode argument.
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800402 nAdditionalInfo = LEN_IS_ONE_BYTE-1 + i;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700403 }
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800404
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800405 /*
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000406 This expression integer-promotes to type int. The code above in
407 function guarantees that nAdditionalInfo will never be larger than
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800408 0x1f. The caller may pass in a too-large uMajor type. The
409 conversion to unint8_t will cause an integer wrap around and
410 incorrect CBOR will be generated, but no security issue will
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000411 occur.
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800412 */
413 *--pByte = (uint8_t)((uMajorType << 5) + nAdditionalInfo);
414
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000415#ifdef EXTRA_ENCODE_HEAD_CHECK
416 /* This is a sanity check that can be turned on to verify the pointer
417 * math in this function is not going wrong. Turn it on and run the
418 * whole test suite to perform the check.
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800419 */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000420 if(pBufferEnd - pByte > 9 || pBufferEnd - pByte < 1 || pByte < (uint8_t *)buffer.ptr) {
421 return NULLUsefulBufC;
422 }
423#endif
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800424
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000425 // Length will not go negative because the loops run for at most 8 decrements
426 // of pByte, only one other decrement is made, and the array is sized
427 // for this.
428 return (UsefulBufC){pByte, (size_t)(pBufferEnd - pByte)};
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700429}
430
431
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000432/**
433 @brief Append the CBOR head, the major type and argument
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800434
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000435 @param me Encoder context.
436 @param uMajorType Major type to insert.
437 @param uArgument The argument (an integer value or a length).
438 @param uMinLen The minimum number of bytes for encoding the CBOR argument.
439
440 This formats the CBOR "head" and appends it to the output.
441 */
442static void AppendCBORHead(QCBOREncodeContext *me, uint8_t uMajorType, uint64_t uArgument, uint8_t uMinLen)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700443{
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000444 // A stack buffer large enough for a CBOR head
445 UsefulBuf_MAKE_STACK_UB (pBufferForEncodedHead, QCBOR_HEAD_BUFFER_SIZE);
446
447 UsefulBufC EncodedHead = QCBOREncode_EncodeHead(pBufferForEncodedHead,
448 uMajorType,
449 uMinLen,
450 uArgument);
451
452 /* No check for EncodedHead == NULLUsefulBufC is performed here to
453 * save object code. It is very clear that pBufferForEncodedHead
454 * is the correct size. If EncodedHead == NULLUsefulBufC then
455 * UsefulOutBuf_AppendUsefulBuf() will do nothing so there is
456 * no security hole introduced.
457 */
458
459 UsefulOutBuf_AppendUsefulBuf(&(me->OutBuf), EncodedHead);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700460}
461
462
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000463/**
464 @brief Insert the CBOR head for a map, array or wrapped bstr
465
466 @param me QCBOR encoding context.
467 @param uMajorType One of CBOR_MAJOR_TYPE_XXXX.
468 @param uLen The length of the data item.
469
470 When an array, map or bstr was opened, nothing was done but note
471 the position. This function goes back to that position and inserts
472 the CBOR Head with the major type and length.
473 */
474static void InsertCBORHead(QCBOREncodeContext *me, uint8_t uMajorType, size_t uLen)
475{
476 if(me->uError == QCBOR_SUCCESS) {
477 if(!Nesting_IsInNest(&(me->nesting))) {
478 me->uError = QCBOR_ERR_TOO_MANY_CLOSES;
479 } else if(Nesting_GetMajorType(&(me->nesting)) != uMajorType) {
480 me->uError = QCBOR_ERR_CLOSE_MISMATCH;
481 } else {
482 // A stack buffer large enough for a CBOR head
483 UsefulBuf_MAKE_STACK_UB (pBufferForEncodedHead,QCBOR_HEAD_BUFFER_SIZE);
484
485 UsefulBufC EncodedHead = QCBOREncode_EncodeHead(pBufferForEncodedHead,
486 uMajorType,
487 0,
488 uLen);
489
490 /* No check for EncodedHead == NULLUsefulBufC is performed here to
491 * save object code. It is very clear that pBufferForEncodedHead
492 * is the correct size. If EncodedHead == NULLUsefulBufC then
493 * UsefulOutBuf_InsertUsefulBuf() will do nothing so there is
494 * no security whole introduced.
495 */
496 UsefulOutBuf_InsertUsefulBuf(&(me->OutBuf), EncodedHead, Nesting_GetStartPos(&(me->nesting)) );
497
498 Nesting_Decrease(&(me->nesting));
499 }
500 }
501}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700502
Laurence Lundblade241705e2018-12-30 18:56:14 -0800503
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700504/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800505 Public functions for closing arrays and maps. See qcbor.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700506 */
Laurence Lundblade067035b2018-11-28 17:35:25 -0800507void QCBOREncode_AddUInt64(QCBOREncodeContext *me, uint64_t uValue)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700508{
Laurence Lundblade067035b2018-11-28 17:35:25 -0800509 if(me->uError == QCBOR_SUCCESS) {
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000510 AppendCBORHead(me, CBOR_MAJOR_TYPE_POSITIVE_INT, uValue, 0);
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800511 me->uError = Nesting_Increment(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700512 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700513}
514
Laurence Lundblade56230d12018-11-01 11:14:51 +0700515
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700516/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800517 Public functions for closing arrays and maps. See qcbor.h
Laurence Lundblade067035b2018-11-28 17:35:25 -0800518 */
519void QCBOREncode_AddInt64(QCBOREncodeContext *me, int64_t nNum)
520{
521 if(me->uError == QCBOR_SUCCESS) {
522 uint8_t uMajorType;
523 uint64_t uValue;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800524
Laurence Lundblade067035b2018-11-28 17:35:25 -0800525 if(nNum < 0) {
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800526 // In CBOR -1 encodes as 0x00 with major type negative int.
527 uValue = (uint64_t)(-nNum - 1);
Laurence Lundblade067035b2018-11-28 17:35:25 -0800528 uMajorType = CBOR_MAJOR_TYPE_NEGATIVE_INT;
529 } else {
530 uValue = (uint64_t)nNum;
531 uMajorType = CBOR_MAJOR_TYPE_POSITIVE_INT;
532 }
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000533 AppendCBORHead(me, uMajorType, uValue, 0);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800534
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800535 me->uError = Nesting_Increment(&(me->nesting));
Laurence Lundblade067035b2018-11-28 17:35:25 -0800536 }
537}
538
539
540/*
Laurence Lundbladeda532272019-04-07 11:40:17 -0700541 Semi-private function. It is exposed to user of the interface, but
542 they will usually call one of the inline wrappers rather than this.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800543
Laurence Lundbladeee851742020-01-08 08:37:05 -0800544 See qcbor.h
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800545
Laurence Lundbladeda532272019-04-07 11:40:17 -0700546 Does the work of adding actual strings bytes to the CBOR output (as
547 opposed to numbers and opening / closing aggregate types).
548
549 There are four use cases:
550 CBOR_MAJOR_TYPE_BYTE_STRING -- Byte strings
551 CBOR_MAJOR_TYPE_TEXT_STRING -- Text strings
552 CBOR_MAJOR_NONE_TYPE_RAW -- Already-encoded CBOR
553 CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY -- Special case
554
555 The first two add the type and length plus the actual bytes. The
556 third just adds the bytes as the type and length are presumed to be
557 in the bytes. The fourth just adds the type and length for the very
558 special case of QCBOREncode_AddBytesLenOnly().
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700559 */
Laurence Lundblade067035b2018-11-28 17:35:25 -0800560void QCBOREncode_AddBuffer(QCBOREncodeContext *me, uint8_t uMajorType, UsefulBufC Bytes)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700561{
Laurence Lundblade241705e2018-12-30 18:56:14 -0800562 if(me->uError == QCBOR_SUCCESS) {
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800563 // If it is not Raw CBOR, add the type and the length
564 if(uMajorType != CBOR_MAJOR_NONE_TYPE_RAW) {
Laurence Lundbladeda532272019-04-07 11:40:17 -0700565 uint8_t uRealMajorType = uMajorType;
566 if(uRealMajorType == CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY) {
567 uRealMajorType = CBOR_MAJOR_TYPE_BYTE_STRING;
568 }
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000569 AppendCBORHead(me, uRealMajorType, Bytes.len, 0);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700570 }
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800571
Laurence Lundbladeda532272019-04-07 11:40:17 -0700572 if(uMajorType != CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY) {
573 // Actually add the bytes
574 UsefulOutBuf_AppendUsefulBuf(&(me->OutBuf), Bytes);
575 }
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800576
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800577 // Update the array counting if there is any nesting at all
578 me->uError = Nesting_Increment(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700579 }
580}
581
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700582
Laurence Lundblade55a24832018-10-30 04:35:08 +0700583/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800584 Public functions for closing arrays and maps. See qcbor.h
Laurence Lundblade55a24832018-10-30 04:35:08 +0700585 */
586void QCBOREncode_AddTag(QCBOREncodeContext *me, uint64_t uTag)
587{
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000588 AppendCBORHead(me, CBOR_MAJOR_TYPE_OPTIONAL, uTag, 0);
Laurence Lundblade55a24832018-10-30 04:35:08 +0700589}
590
591
Laurence Lundblade56230d12018-11-01 11:14:51 +0700592/*
Laurence Lundblade487930f2018-11-30 11:01:45 -0800593 Semi-private function. It is exposed to user of the interface,
594 but they will usually call one of the inline wrappers rather than this.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800595
Laurence Lundblade487930f2018-11-30 11:01:45 -0800596 See header qcbor.h
Laurence Lundblade56230d12018-11-01 11:14:51 +0700597 */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000598void QCBOREncode_AddType7(QCBOREncodeContext *me, uint8_t uMinLen, uint64_t uNum)
Laurence Lundblade55a24832018-10-30 04:35:08 +0700599{
Laurence Lundblade487930f2018-11-30 11:01:45 -0800600 if(me->uError == QCBOR_SUCCESS) {
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700601 if(uNum >= CBOR_SIMPLEV_RESERVED_START && uNum <= CBOR_SIMPLEV_RESERVED_END) {
602 me->uError = QCBOR_ERR_UNSUPPORTED;
603 } else {
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000604 // AppendHead() does endian swapping for the float / double
605 AppendCBORHead(me, CBOR_MAJOR_TYPE_SIMPLE, uNum, uMinLen);
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700606 me->uError = Nesting_Increment(&(me->nesting));
607 }
Laurence Lundblade487930f2018-11-30 11:01:45 -0800608 }
Laurence Lundblade55a24832018-10-30 04:35:08 +0700609}
610
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700611
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700612/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800613 Public functions for closing arrays and maps. See qcbor.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700614 */
Laurence Lundblade067035b2018-11-28 17:35:25 -0800615void QCBOREncode_AddDouble(QCBOREncodeContext *me, double dNum)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700616{
Laurence Lundblade9682a532020-06-06 18:33:04 -0700617#ifndef QCBOR_CONFIG_DISABLE_ENCODE_IEEE754
Laurence Lundblade067035b2018-11-28 17:35:25 -0800618 const IEEE754_union uNum = IEEE754_DoubleToSmallest(dNum);
Laurence Lundblade9682a532020-06-06 18:33:04 -0700619
Laurence Lundblade487930f2018-11-30 11:01:45 -0800620 QCBOREncode_AddType7(me, uNum.uSize, uNum.uValue);
Laurence Lundblade9682a532020-06-06 18:33:04 -0700621#else
622 QCBOREncode_AddType7(me, sizeof(uint64_t), UsefulBufUtil_CopyDoubleToUint64(dNum));
623#endif
624
625}
626
627
628/*
629 Public functions for closing arrays and maps. See qcbor.h
630 */
631void QCBOREncode_AddFloat(QCBOREncodeContext *me, float fNum)
632{
633#ifndef QCBOR_CONFIG_DISABLE_ENCODE_IEEE754
634 const IEEE754_union uNum = IEEE754_FloatToSmallest(fNum);
635
636 QCBOREncode_AddType7(me, uNum.uSize, uNum.uValue);
637#else
638 QCBOREncode_AddType7(me, sizeof(uint32_t), UsefulBufUtil_CopyFloatToUint32(fNum));
639#endif
Laurence Lundblade067035b2018-11-28 17:35:25 -0800640}
641
642
Laurence Lundblade59289e52019-12-30 13:44:37 -0800643#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
644/*
645 Semi-public function. It is exposed to the user of the interface, but
646 one of the inline wrappers will usually be called rather than this.
647
648 See qcbor.h
649 */
650void QCBOREncode_AddExponentAndMantissa(QCBOREncodeContext *pMe,
651 uint64_t uTag,
652 UsefulBufC BigNumMantissa,
653 bool bBigNumIsNegative,
654 int64_t nMantissa,
655 int64_t nExponent)
656{
Laurence Lundbladeee851742020-01-08 08:37:05 -0800657 /*
658 This is for encoding either a big float or a decimal fraction,
659 both of which are an array of two items, an exponent and a
660 mantissa. The difference between the two is that the exponent is
661 base-2 for big floats and base-10 for decimal fractions, but that
662 has no effect on the code here.
663 */
Laurence Lundblade59289e52019-12-30 13:44:37 -0800664 QCBOREncode_AddTag(pMe, uTag);
665 QCBOREncode_OpenArray(pMe);
666 QCBOREncode_AddInt64(pMe, nExponent);
667 if(!UsefulBuf_IsNULLC(BigNumMantissa)) {
668 if(bBigNumIsNegative) {
669 QCBOREncode_AddNegativeBignum(pMe, BigNumMantissa);
670 } else {
671 QCBOREncode_AddPositiveBignum(pMe, BigNumMantissa);
672 }
673 } else {
674 QCBOREncode_AddInt64(pMe, nMantissa);
675 }
676 QCBOREncode_CloseArray(pMe);
677}
678#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
679
680
Laurence Lundblade067035b2018-11-28 17:35:25 -0800681/*
682 Semi-public function. It is exposed to user of the interface,
683 but they will usually call one of the inline wrappers rather than this.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800684
Laurence Lundblade067035b2018-11-28 17:35:25 -0800685 See header qcbor.h
686*/
687void QCBOREncode_OpenMapOrArray(QCBOREncodeContext *me, uint8_t uMajorType)
688{
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800689 // Add one item to the nesting level we are in for the new map or array
690 me->uError = Nesting_Increment(&(me->nesting));
Laurence Lundblade241705e2018-12-30 18:56:14 -0800691 if(me->uError == QCBOR_SUCCESS) {
Laurence Lundbladeee851742020-01-08 08:37:05 -0800692 /*
693 The offset where the length of an array or map will get written
694 is stored in a uint32_t, not a size_t to keep stack usage
695 smaller. This checks to be sure there is no wrap around when
696 recording the offset. Note that on 64-bit machines CBOR larger
697 than 4GB can be encoded as long as no array / map offsets occur
698 past the 4GB mark, but the public interface says that the
699 maximum is 4GB to keep the discussion simpler.
700 */
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800701 size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf));
Laurence Lundbladed39cd392019-01-11 18:17:38 -0800702
Laurence Lundbladeee851742020-01-08 08:37:05 -0800703 /*
704 QCBOR_MAX_ARRAY_OFFSET is slightly less than UINT32_MAX so this
705 code can run on a 32-bit machine and tests can pass on a 32-bit
706 machine. If it was exactly UINT32_MAX, then this code would not
707 compile or run on a 32-bit machine and an #ifdef or some
708 machine size detection would be needed reducing portability.
709 */
Laurence Lundbladed39cd392019-01-11 18:17:38 -0800710 if(uEndPosition >= QCBOR_MAX_ARRAY_OFFSET) {
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800711 me->uError = QCBOR_ERR_BUFFER_TOO_LARGE;
Laurence Lundbladed39cd392019-01-11 18:17:38 -0800712
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800713 } else {
Laurence Lundbladeee851742020-01-08 08:37:05 -0800714 // Increase nesting level because this is a map or array. Cast
715 // from size_t to uin32_t is safe because of check above
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800716 me->uError = Nesting_Increase(&(me->nesting), uMajorType, (uint32_t)uEndPosition);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700717 }
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800718 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700719}
720
Laurence Lundblade59289e52019-12-30 13:44:37 -0800721
Jan Jongboom4a93a662019-07-25 08:44:58 +0200722/*
723 Semi-public function. It is exposed to user of the interface,
724 but they will usually call one of the inline wrappers rather than this.
725
Laurence Lundbladeee851742020-01-08 08:37:05 -0800726 See qcbor.h
Jan Jongboom4a93a662019-07-25 08:44:58 +0200727*/
728void QCBOREncode_OpenMapOrArrayIndefiniteLength(QCBOREncodeContext *me, uint8_t uMajorType)
729{
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000730 // Insert the indefinite length marker (0x9f for arrays, 0xbf for maps)
731 AppendCBORHead(me, uMajorType, 0, 0);
732 // Call the definite-length opener just to do the bookkeeping for
733 // nesting. It will record the position of the opening item in
734 // the encoded output but this is not used when closing this open.
Jan Jongboom4a93a662019-07-25 08:44:58 +0200735 QCBOREncode_OpenMapOrArray(me, uMajorType);
736}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700737
Laurence Lundbladeee851742020-01-08 08:37:05 -0800738
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700739/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800740 Public functions for closing arrays and maps. See qcbor.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700741 */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000742void QCBOREncode_CloseMapOrArray(QCBOREncodeContext *me, uint8_t uMajorType)
Laurence Lundbladea954db92018-09-28 19:27:31 -0700743{
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000744 InsertCBORHead(me, uMajorType, Nesting_GetCount(&(me->nesting)));
745}
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800746
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800747
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000748/*
749 Public functions for closing bstr wrapping. See qcbor.h
750 */
751void QCBOREncode_CloseBstrWrap2(QCBOREncodeContext *me, bool bIncludeCBORHead, UsefulBufC *pWrappedCBOR)
752{
753 const size_t uInsertPosition = Nesting_GetStartPos(&(me->nesting));
754 const size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800755
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000756 // This can't go negative because the UsefulOutBuf always only grows
757 // and never shrinks. UsefulOutBut itself also has defenses such that
758 // it won't write where it should not even if given hostile input lengths.
759 const size_t uBstrLen = uEndPosition - uInsertPosition;
760
761 // Actually insert
762 InsertCBORHead(me, CBOR_MAJOR_TYPE_BYTE_STRING, uBstrLen);
763
764 if(pWrappedCBOR) {
765 /*
766 Return pointer and length to the enclosed encoded CBOR. The
767 intended use is for it to be hashed (e.g., SHA-256) in a COSE
768 implementation. This must be used right away, as the pointer
769 and length go invalid on any subsequent calls to this function
770 because there might be calls to InsertEncodedTypeAndNumber()
771 that slides data to the right.
772 */
773 size_t uStartOfNew = uInsertPosition;
774 if(!bIncludeCBORHead) {
775 // Skip over the CBOR head to just get the inserted bstr
776 const size_t uNewEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf));
777 uStartOfNew += uNewEndPosition - uEndPosition;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700778 }
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000779 const UsefulBufC PartialResult = UsefulOutBuf_OutUBuf(&(me->OutBuf));
780 *pWrappedCBOR = UsefulBuf_Tail(PartialResult, uStartOfNew);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700781 }
782}
783
Laurence Lundbladeee851742020-01-08 08:37:05 -0800784
Jan Jongboom4a93a662019-07-25 08:44:58 +0200785/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800786 Public functions for closing arrays and maps. See qcbor.h
Jan Jongboom4a93a662019-07-25 08:44:58 +0200787 */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000788void QCBOREncode_CloseMapOrArrayIndefiniteLength(QCBOREncodeContext *me, uint8_t uMajorType)
Jan Jongboom4a93a662019-07-25 08:44:58 +0200789{
790 if(me->uError == QCBOR_SUCCESS) {
791 if(!Nesting_IsInNest(&(me->nesting))) {
792 me->uError = QCBOR_ERR_TOO_MANY_CLOSES;
793 } else if(Nesting_GetMajorType(&(me->nesting)) != uMajorType) {
794 me->uError = QCBOR_ERR_CLOSE_MISMATCH;
795 } else {
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000796 // Append the break marker (0xff for both arrays and maps)
797 AppendCBORHead(me, CBOR_MAJOR_TYPE_SIMPLE, CBOR_SIMPLE_BREAK, 0);
Jan Jongboom4a93a662019-07-25 08:44:58 +0200798
Jan Jongboom4a93a662019-07-25 08:44:58 +0200799 Nesting_Decrease(&(me->nesting));
800 }
801 }
802}
803
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700804
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700805/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800806 Public functions to finish and get the encoded result. See qcbor.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700807 */
Laurence Lundblade30816f22018-11-10 13:40:22 +0700808QCBORError QCBOREncode_Finish(QCBOREncodeContext *me, UsefulBufC *pEncodedCBOR)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700809{
Laurence Lundbladef607a2a2019-07-05 21:25:25 -0700810 QCBORError uReturn = QCBOREncode_GetErrorState(me);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800811
Laurence Lundblade067035b2018-11-28 17:35:25 -0800812 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700813 goto Done;
Laurence Lundblade067035b2018-11-28 17:35:25 -0800814 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800815
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700816 if (Nesting_IsInNest(&(me->nesting))) {
Laurence Lundblade067035b2018-11-28 17:35:25 -0800817 uReturn = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700818 goto Done;
819 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800820
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700821 *pEncodedCBOR = UsefulOutBuf_OutUBuf(&(me->OutBuf));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800822
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700823Done:
Laurence Lundblade067035b2018-11-28 17:35:25 -0800824 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700825}
826
Laurence Lundblade0595e932018-11-02 22:22:47 +0700827
Laurence Lundblade067035b2018-11-28 17:35:25 -0800828/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800829 Public functions to finish and get the encoded result. See qcbor.h
Laurence Lundblade067035b2018-11-28 17:35:25 -0800830 */
Laurence Lundblade30816f22018-11-10 13:40:22 +0700831QCBORError QCBOREncode_FinishGetSize(QCBOREncodeContext *me, size_t *puEncodedLen)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700832{
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700833 UsefulBufC Enc;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800834
Laurence Lundblade30816f22018-11-10 13:40:22 +0700835 QCBORError nReturn = QCBOREncode_Finish(me, &Enc);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800836
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700837 if(nReturn == QCBOR_SUCCESS) {
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700838 *puEncodedLen = Enc.len;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700839 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800840
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700841 return nReturn;
842}
843
844
Laurence Lundblade067035b2018-11-28 17:35:25 -0800845
846
847/*
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000848Object code sizes on 64-bit x86 with GCC -Os Jan 2020. GCC compiles smaller
849than LLVM and optimizations have been made to decrease code size. Bigfloat,
850Decimal fractions and indefinite length encoding were added to increase code
851size. Bstr wrapping is now separate which means if you don't use it, it gets
852dead stripped.
853
854_QCBOREncode_EncodeHead 187
855_QCBOREncode_CloseBstrWrap2: 154
856_QCBOREncode_AddExponentAndMantissa: 144
857_QCBOREncode_AddBuffer 105
858_QCBOREncode_OpenMapOrArray 101
859_QCBOREncode_CloseMapOrArrayIndefiniteLength: 72
860_QCBOREncode_Finish 71
861_InsertCBORHead.part.0 66
862_QCBOREncode_CloseMapOrArray 64
863_QCBOREncode_AddType7 58
864_QCBOREncode_AddInt64 57
865_AppendCBORHead 54
866_QCBOREncode_AddUInt64 40
867_QCBOREncode_Init 38
868_Nesting_Increment.isra.0 36
869_QCBOREncode_FinishGetSize: 34
870_QCBOREncode_AddDouble: 26
871_QCBOREncode_AddTag: 15
872Total 1322
873Min_encode use case 776
874
875
Laurence Lundblade241705e2018-12-30 18:56:14 -0800876 Object code sizes on X86 with LLVM compiler and -Os (Dec 30, 2018)
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800877
Laurence Lundblade9c097392018-12-30 13:52:24 -0800878 _QCBOREncode_Init 69
Laurence Lundblade067035b2018-11-28 17:35:25 -0800879 _QCBOREncode_AddUInt64 76
880 _QCBOREncode_AddInt64 87
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800881 _QCBOREncode_AddBuffer 113
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800882 _QCBOREncode_AddTag 27
Laurence Lundblade9c097392018-12-30 13:52:24 -0800883 _QCBOREncode_AddType7 87
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800884 _QCBOREncode_AddDouble 36
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800885 _QCBOREncode_OpenMapOrArray 103
Laurence Lundblade067035b2018-11-28 17:35:25 -0800886 _QCBOREncode_CloseMapOrArray 181
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800887 _InsertEncodedTypeAndNumber 190
Laurence Lundblade067035b2018-11-28 17:35:25 -0800888 _QCBOREncode_Finish 72
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800889 _QCBOREncode_FinishGetSize 70
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800890
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800891 Total is about 1.1KB
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800892
Laurence Lundblade067035b2018-11-28 17:35:25 -0800893 _QCBOREncode_CloseMapOrArray is larger because it has a lot
894 of nesting tracking to do and much of Nesting_ inlines
895 into it. It probably can't be reduced much.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800896
Laurence Lundblade067035b2018-11-28 17:35:25 -0800897 If the error returned by Nesting_Increment() can be ignored
898 because the limit is so high and the consequence of exceeding
899 is proved to be inconsequential, then a lot of if(me->uError)
900 instance can be removed, saving some code.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800901
Laurence Lundblade067035b2018-11-28 17:35:25 -0800902 */