blob: ce14e41b9151e0534682bfb898b7fa5ab1747696 [file] [log] [blame]
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001/*==============================================================================
Laurence Lundbladed92a6162018-11-01 11:38:35 +07002 Copyright (c) 2016-2018, The Linux Foundation.
Laurence Lundbladeee851742020-01-08 08:37:05 -08003 Copyright (c) 2018-2020, Laurence Lundblade.
Laurence Lundbladed92a6162018-11-01 11:38:35 +07004 All rights reserved.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08005
Laurence Lundblade0dbc9172018-11-01 14:17:21 +07006Redistribution and use in source and binary forms, with or without
7modification, are permitted provided that the following conditions are
8met:
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of The Linux Foundation nor the names of its
16 contributors, nor the name "Laurence Lundblade" may be used to
17 endorse or promote products derived from this software without
18 specific prior written permission.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080019
Laurence Lundblade0dbc9172018-11-01 14:17:21 +070020THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
21WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
23ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
24BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
27BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
29OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
30IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Laurence Lundbladeee851742020-01-08 08:37:05 -080031 =============================================================================*/
Laurence Lundblade624405d2018-09-18 20:10:47 -070032
Laurence Lundbladeee851742020-01-08 08:37:05 -080033/*=============================================================================
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070034 FILE: qcbor_encode.c
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080035
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070036 DESCRIPTION: This file contains the implementation of QCBOR.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080037
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070038 EDIT HISTORY FOR FILE:
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080039
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070040 This section contains comments describing changes made to the module.
41 Notice that changes are listed in reverse chronological order.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080042
Laurence Lundbladeee851742020-01-08 08:37:05 -080043 when who what, where, why
44 -------- ---- ---------------------------------------------------
Laurence Lundbladec5fef682020-01-25 11:38:45 -080045 01/25/2020 llundblade Refine use of integer types to quiet static analysis.
Laurence Lundbladeee851742020-01-08 08:37:05 -080046 01/08/2020 llundblade Documentation corrections & improved code formatting.
47 12/30/19 llundblade Add support for decimal fractions and bigfloats.
48 8/7/19 llundblade Prevent encoding simple type reserved values 24..31
49 7/25/19 janjongboom Add indefinite length encoding for maps and arrays
50 4/6/19 llundblade Wrapped bstr returned now includes the wrapping bstr
51 12/30/18 llundblade Small efficient clever encode of type & argument.
52 11/29/18 llundblade Rework to simpler handling of tags and labels.
53 11/9/18 llundblade Error codes are now enums.
54 11/1/18 llundblade Floating support.
55 10/31/18 llundblade Switch to one license that is almost BSD-3.
56 09/28/18 llundblade Added bstr wrapping feature for COSE implementation.
57 02/05/18 llundbla Works on CPUs which require integer alignment.
58 Requires new version of UsefulBuf.
59 07/05/17 llundbla Add bstr wrapping of maps/arrays for COSE
60 03/01/17 llundbla More data types
61 11/13/16 llundbla Integrate most TZ changes back into github version.
62 09/30/16 gkanike Porting to TZ.
63 03/15/16 llundbla Initial Version.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080064
Laurence Lundbladeee851742020-01-08 08:37:05 -080065 =============================================================================*/
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070066
67#include "qcbor.h"
Laurence Lundblade12d32c52018-09-19 11:25:27 -070068#include "ieee754.h"
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070069
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070070
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070071
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070072/*
Laurence Lundbladeee851742020-01-08 08:37:05 -080073 Nesting -- This tracks the nesting of maps and arrays.
74
75 The following functions and data type QCBORTrackNesting implement the
76 nesting management for encoding.
77
78 CBOR's two nesting types, arrays and maps, are tracked here. There is
79 a limit of QCBOR_MAX_ARRAY_NESTING to the number of arrays and maps
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070080 that can be nested in one encoding so the encoding context stays
81 small enough to fit on the stack.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080082
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070083 When an array / map is opened, pCurrentNesting points to the element
Laurence Lundbladeee851742020-01-08 08:37:05 -080084 in pArrays that records the type, start position and accumulates a
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070085 count of the number of items added. When closed the start position is
86 used to go back and fill in the type and number of items in the array
87 / map.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080088
Laurence Lundbladeee851742020-01-08 08:37:05 -080089 Encoded output can be just items like ints and strings that are not
90 part of any array / map. That is, the first thing encoded does not
91 have to be an array or a map.
92
93 QCBOR has a special feature to allow constructing bstr-wrapped CBOR
94 directly into the output buffer, so an extra buffer for it is not
95 needed. This is implemented as nesting with type
96 CBOR_MAJOR_TYPE_BYTE_STRING and uses this code. Bstr-wrapped CBOR is
97 used by COSE for data that is to be hashed.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070098 */
99inline static void Nesting_Init(QCBORTrackNesting *pNesting)
100{
Laurence Lundbladeee851742020-01-08 08:37:05 -0800101 // Assumes pNesting has been zeroed
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700102 pNesting->pCurrentNesting = &pNesting->pArrays[0];
103 // Implied CBOR array at the top nesting level. This is never returned,
104 // but makes the item count work correctly.
105 pNesting->pCurrentNesting->uMajorType = CBOR_MAJOR_TYPE_ARRAY;
106}
107
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800108inline static QCBORError Nesting_Increase(QCBORTrackNesting *pNesting,
109 uint8_t uMajorType,
110 uint32_t uPos)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700111{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700112 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800113
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700114 if(pNesting->pCurrentNesting == &pNesting->pArrays[QCBOR_MAX_ARRAY_NESTING]) {
Laurence Lundbladeee851742020-01-08 08:37:05 -0800115 // Trying to open one too many
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700116 nReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
117 } else {
118 pNesting->pCurrentNesting++;
119 pNesting->pCurrentNesting->uCount = 0;
120 pNesting->pCurrentNesting->uStart = uPos;
121 pNesting->pCurrentNesting->uMajorType = uMajorType;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700122 }
123 return nReturn;
124}
125
126inline static void Nesting_Decrease(QCBORTrackNesting *pNesting)
127{
128 pNesting->pCurrentNesting--;
129}
130
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800131inline static QCBORError Nesting_Increment(QCBORTrackNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700132{
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800133 if(1 >= QCBOR_MAX_ITEMS_IN_ARRAY - pNesting->pCurrentNesting->uCount) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700134 return QCBOR_ERR_ARRAY_TOO_LONG;
135 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800136
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800137 pNesting->pCurrentNesting->uCount += 1;
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800138
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700139 return QCBOR_SUCCESS;
140}
141
142inline static uint16_t Nesting_GetCount(QCBORTrackNesting *pNesting)
143{
144 // The nesting count recorded is always the actual number of individiual
145 // data items in the array or map. For arrays CBOR uses the actual item
146 // count. For maps, CBOR uses the number of pairs. This function returns
147 // the number needed for the CBOR encoding, so it divides the number of
148 // items by two for maps to get the number of pairs. This implementation
149 // takes advantage of the map major type being one larger the array major
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800150 // type, hence uDivisor is either 1 or 2.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800151
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800152 if(pNesting->pCurrentNesting->uMajorType == CBOR_MAJOR_TYPE_MAP) {
153 // Cast back to uint16_t after integer promotion for bit shift
154 return (uint16_t)(pNesting->pCurrentNesting->uCount >> 1);
155 } else {
156 return pNesting->pCurrentNesting->uCount;
157 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700158}
159
160inline static uint32_t Nesting_GetStartPos(QCBORTrackNesting *pNesting)
161{
162 return pNesting->pCurrentNesting->uStart;
163}
164
165inline static uint8_t Nesting_GetMajorType(QCBORTrackNesting *pNesting)
166{
167 return pNesting->pCurrentNesting->uMajorType;
168}
169
Laurence Lundbladeee851742020-01-08 08:37:05 -0800170inline static bool Nesting_IsInNest(QCBORTrackNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700171{
Laurence Lundbladeee851742020-01-08 08:37:05 -0800172 return pNesting->pCurrentNesting == &pNesting->pArrays[0] ? false : true;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700173}
174
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700175
176
177
178/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800179 Encoding of the major CBOR types is by these functions:
180
181 CBOR Major Type Public Function
182 0 QCBOREncode_AddUInt64()
183 0, 1 QCBOREncode_AddUInt64(), QCBOREncode_AddInt64()
184 2, 3 QCBOREncode_AddBuffer(), Also QCBOREncode_OpenMapOrArray(),
185 QCBOREncode_CloseMapOrArray()
186 4, 5 QCBOREncode_OpenMapOrArray(), QCBOREncode_CloseMapOrArray(),
187 QCBOREncode_OpenMapOrArrayIndefiniteLength(),
188 QCBOREncode_CloseMapOrArrayIndefiniteLength()
189 6 QCBOREncode_AddTag()
190 7 QCBOREncode_AddDouble(), QCBOREncode_AddType7()
191
192 Additionally, encoding of decimal fractions and bigfloats is by
193 QCBOREncode_AddExponentAndMantissa()
194*/
195
196/*
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700197 Error tracking plan -- Errors are tracked internally and not returned
Laurence Lundbladeee851742020-01-08 08:37:05 -0800198 until QCBOREncode_Finish is called. The CBOR errors are in me->uError.
Laurence Lundblade067035b2018-11-28 17:35:25 -0800199 UsefulOutBuf also tracks whether the buffer is full or not in its
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700200 context. Once either of these errors is set they are never
Laurence Lundblade241705e2018-12-30 18:56:14 -0800201 cleared. Only QCBOREncode_Init() resets them. Or said another way, they must
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700202 never be cleared or we'll tell the caller all is good when it is not.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800203
Laurence Lundblade241705e2018-12-30 18:56:14 -0800204 Only one error code is reported by QCBOREncode_Finish() even if there are
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700205 multiple errors. The last one set wins. The caller might have to fix
206 one error to reveal the next one they have to fix. This is OK.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800207
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700208 The buffer full error tracked by UsefulBuf is only pulled out of
209 UsefulBuf in Finish() so it is the one that usually wins. UsefulBuf
210 will never go off the end of the buffer even if it is called again
211 and again when full.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800212
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700213 It is really tempting to not check for overflow on the count in the
214 number of items in an array. It would save a lot of code, it is
215 extremely unlikely that any one will every put 65,000 items in an
216 array, and the only bad thing that would happen is the CBOR would be
Laurence Lundblade241705e2018-12-30 18:56:14 -0800217 bogus.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800218
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700219 Since this does not parse any input, you could in theory remove all
220 error checks in this code if you knew the caller called it
221 correctly. Maybe someday CDDL or some such language will be able to
222 generate the code to call this and the calling code would always be
Laurence Lundblade56230d12018-11-01 11:14:51 +0700223 correct. This could also automatically size some of the data
Laurence Lundblade241705e2018-12-30 18:56:14 -0800224 structures like array/map nesting resulting in some stack memory
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700225 savings.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800226
Laurence Lundbladeee851742020-01-08 08:37:05 -0800227 The 8 errors returned here fall into three categories:
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800228
Laurence Lundblade067035b2018-11-28 17:35:25 -0800229 Sizes
Laurence Lundbladeee851742020-01-08 08:37:05 -0800230 QCBOR_ERR_BUFFER_TOO_LARGE -- Encoded output exceeded UINT32_MAX
231 QCBOR_ERR_BUFFER_TOO_SMALL -- Output buffer too small
232 QCBOR_ERR_ARRAY_NESTING_TOO_DEEP -- Nesting > QCBOR_MAX_ARRAY_NESTING1
233 QCBOR_ERR_ARRAY_TOO_LONG -- Too many things added to an array/map
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800234
Laurence Lundblade067035b2018-11-28 17:35:25 -0800235 Nesting constructed incorrectly
Laurence Lundbladeee851742020-01-08 08:37:05 -0800236 QCBOR_ERR_TOO_MANY_CLOSES -- More close calls than opens
237 QCBOR_ERR_CLOSE_MISMATCH -- Type of close does not match open
Laurence Lundblade067035b2018-11-28 17:35:25 -0800238 QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN -- Finish called without enough closes
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700239
240 Would generate not-well-formed CBOR
Laurence Lundbladeee851742020-01-08 08:37:05 -0800241 QCBOR_ERR_UNSUPPORTED -- Simple type between 24 and 31
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700242 */
243
244
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700245/*
246 Public function for initialization. See header qcbor.h
247 */
Laurence Lundblade2296db52018-09-14 18:08:39 -0700248void QCBOREncode_Init(QCBOREncodeContext *me, UsefulBuf Storage)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700249{
250 memset(me, 0, sizeof(QCBOREncodeContext));
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800251 UsefulOutBuf_Init(&(me->OutBuf), Storage);
252 Nesting_Init(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700253}
254
255
Laurence Lundbladeee851742020-01-08 08:37:05 -0800256/**
257 @brief Encode a data item, the most atomic part of CBOR
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700258
Laurence Lundbladeee851742020-01-08 08:37:05 -0800259 @param[in,out] me Encoding context including output buffer
260 @param[in] uMajorType One of CBOR_MAJOR_TYPE_XX
261 @param[in] nMinLen Include zero bytes up to this length. If 0 include
262 no zero bytes. Non-zero to encode floats and doubles.
263 @param[in] uNumber The number to encode, the argument.
264 @param[in] uPos The position in the output buffer (which is inside
265 the encoding context) to insert the result. This is
266 usually at the end, an append.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700267
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800268 All CBOR data items have a type and an "argument". The argument is
269 either the value of the item for integer types, the length of the
270 content for string, byte, array and map types, a tag for major type
271 6, and has several uses for major type 7.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800272
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800273 This function encodes the type and the argument. There are several
274 encodings for the argument depending on how large it is and how it is
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700275 used.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800276
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800277 Every encoding of the type and argument has at least one byte, the
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700278 "initial byte".
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800279
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700280 The top three bits of the initial byte are the major type for the
281 CBOR data item. The eight major types defined by the standard are
282 defined as CBOR_MAJOR_TYPE_xxxx in qcbor.h.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800283
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700284 The remaining five bits, known as "additional information", and
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800285 possibly more bytes encode the argument. If the argument is less than
286 24, then it is encoded entirely in the five bits. This is neat
287 because it allows you to encode an entire CBOR data item in 1 byte
288 for many values and types (integers 0-23, true, false, and tags).
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800289
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800290 If the argument is larger than 24, then it is encoded in 1,2,4 or 8
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700291 additional bytes, with the number of these bytes indicated by the
292 values of the 5 bits 24, 25, 25 and 27.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800293
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800294 It is possible to encode a particular argument in many ways with this
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700295 representation. This implementation always uses the smallest
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800296 possible representation. This conforms with CBOR preferred encoding.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800297
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700298 This function inserts them into the output buffer at the specified
Laurence Lundblade067035b2018-11-28 17:35:25 -0800299 position. AppendEncodedTypeAndNumber() appends to the end.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800300
301 This function takes care of converting to network byte order.
302
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700303 This function is also used to insert floats and doubles. Before this
304 function is called the float or double must be copied into a
305 uint64_t. That is how they are passed in. They are then converted to
Laurence Lundbladeee851742020-01-08 08:37:05 -0800306 network byte order correctly. The uMinLen parameter makes sure that
307 even if all the digits of a half, float or double are 0 it is still
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800308 correctly encoded in 2, 4 or 8 bytes.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700309 */
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800310static void InsertEncodedTypeAndNumber(QCBOREncodeContext *me,
Laurence Lundbladeee851742020-01-08 08:37:05 -0800311 uint8_t uMajorType,
312 int nMinLen,
313 uint64_t uNumber,
314 size_t uPos)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700315{
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800316 /*
317 This code does endian conversion without hton or knowing the
Laurence Lundblade241705e2018-12-30 18:56:14 -0800318 endianness of the machine using masks and shifts. This avoids the
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800319 dependency on hton and the mess of figuring out how to find the
320 machine's endianness.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800321
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800322 This is a good efficient implementation on little-endian machines.
323 A faster and small implementation is possible on big-endian
324 machines because CBOR/network byte order is big endian. However
325 big endian machines are uncommon.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800326
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800327 On x86, it is about 200 bytes instead of 500 bytes for the more
328 formal unoptimized code.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800329
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800330 This also does the CBOR preferred shortest encoding for integers
331 and is called to do endian conversion for floats.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800332
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800333 It works backwards from the LSB to the MSB as needed.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800334
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800335 Code Reviewers: THIS FUNCTION DOES POINTER MATH
336 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800337 /*
338 The type int is used here for several variables because of the way
339 integer promotion works in C for integer variables that are
340 uint8_t or uint16_t. The basic rule is that they will always be
341 promoted to int if they will fit. All of these integer variables
342 need only hold values less than 255 or are promoted from uint8_t,
343 so they will always fit into an int. Note that promotion is only
344 to unsigned int if the value won't fit into an int even if the
345 promotion is for an unsigned like uint8_t.
346
347 By declaring them int, there are few implicit conversions and fewer
348 casts needed. Code size is reduced a little. It also makes static
349 analyzers happier.
350
351 Note also that declaring them uint8_t won't stop integer wrap
352 around if the code is wrong. It won't make the code more correct.
353
354 https://stackoverflow.com/questions/46073295/implicit-type-promotion-rules
355 https://stackoverflow.com/questions/589575/what-does-the-c-standard-state-the-size-of-int-long-type-to-be
356 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800357
358 // Holds up to 9 bytes of type and argument plus one extra so pointer
359 // always points to valid bytes.
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800360 uint8_t bytes[sizeof(uint64_t)+2];
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800361 // Point to the last bytes and work backwards
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800362 uint8_t *pByte = &bytes[sizeof(bytes)-1];
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800363 // This is the 5 bits in the initial byte that is not the major type
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800364 int nAdditionalInfo;
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800365
Jan Jongboom5d827882019-08-07 12:51:15 +0200366 if (uMajorType == CBOR_MAJOR_NONE_TYPE_ARRAY_INDEFINITE_LEN) {
367 uMajorType = CBOR_MAJOR_TYPE_ARRAY;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800368 nAdditionalInfo = LEN_IS_INDEFINITE;
Jan Jongboom5d827882019-08-07 12:51:15 +0200369 } else if (uMajorType == CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN) {
370 uMajorType = CBOR_MAJOR_TYPE_MAP;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800371 nAdditionalInfo = LEN_IS_INDEFINITE;
Jan Jongboom5d827882019-08-07 12:51:15 +0200372 } else if (uNumber < CBOR_TWENTY_FOUR && nMinLen == 0) {
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800373 // Simple case where argument is < 24
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800374 nAdditionalInfo = (int)uNumber;
Jan Jongboom4a93a662019-07-25 08:44:58 +0200375 } else if (uMajorType == CBOR_MAJOR_TYPE_SIMPLE && uNumber == CBOR_SIMPLE_BREAK) {
376 // Break statement can be encoded in single byte too (0xff)
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800377 nAdditionalInfo = (int)uNumber;
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800378 } else {
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800379 /*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800380 Encode argument in 1,2,4 or 8 bytes. Outer loop runs once for 1
381 byte and 4 times for 8 bytes. Inner loop runs 1, 2 or 4 times
382 depending on outer loop counter. This works backwards taking 8
383 bits off the argument being encoded at a time until all bits
384 from uNumber have been encoded and the minimum encoding size is
385 reached. Minimum encoding size is for floating-point numbers
386 with zero bytes.
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800387 */
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800388 static const uint8_t aIterate[] = {1,1,2,4};
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800389 int i;
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800390 for(i = 0; uNumber || nMinLen > 0; i++) {
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800391 const int nIterations = aIterate[i];
392 for(int j = 0; j < nIterations; j++) {
393 *--pByte = (uint8_t)(uNumber & 0xff);
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800394 uNumber = uNumber >> 8;
395 }
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800396 nMinLen -= nIterations;
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800397 }
Laurence Lundbladeee851742020-01-08 08:37:05 -0800398 // Additional info is the encoding of the number of additional
399 // bytes to encode argument.
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800400 nAdditionalInfo = LEN_IS_ONE_BYTE-1 + i;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700401 }
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800402
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800403 /*
404 Expression integer-promotes to type int. The code above in
405 function gaurantees that uAdditionalInfo will never be larger than
406 0x1f. The caller may pass in a too-large uMajor type. The
407 conversion to unint8_t will cause an integer wrap around and
408 incorrect CBOR will be generated, but no security issue will
409 incur.
410 */
411 *--pByte = (uint8_t)((uMajorType << 5) + nAdditionalInfo);
412
413 /*
414 Will not go negative because the loops run for at most 8
415 decrements of pByte, only one other decrement is made and the
416 array is sized for this.
417 */
418 const size_t uHeadLen = (size_t)(&bytes[sizeof(bytes)-1] - pByte);
419
420 UsefulOutBuf_InsertData(&(me->OutBuf), pByte, uHeadLen, uPos);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700421}
422
423
424/*
425 Append the type and number info to the end of the buffer.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800426
Laurence Lundbladeee851742020-01-08 08:37:05 -0800427 See InsertEncodedTypeAndNumber() function above for details.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700428*/
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800429inline static void AppendEncodedTypeAndNumber(QCBOREncodeContext *me,
430 uint8_t uMajorType,
431 uint64_t uNumber)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700432{
433 // An append is an insert at the end.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800434 InsertEncodedTypeAndNumber(me,
435 uMajorType,
436 0,
437 uNumber,
438 UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700439}
440
441
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700442
Laurence Lundblade241705e2018-12-30 18:56:14 -0800443
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700444/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800445 Public functions for closing arrays and maps. See qcbor.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700446 */
Laurence Lundblade067035b2018-11-28 17:35:25 -0800447void QCBOREncode_AddUInt64(QCBOREncodeContext *me, uint64_t uValue)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700448{
Laurence Lundblade067035b2018-11-28 17:35:25 -0800449 if(me->uError == QCBOR_SUCCESS) {
450 AppendEncodedTypeAndNumber(me, CBOR_MAJOR_TYPE_POSITIVE_INT, uValue);
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800451 me->uError = Nesting_Increment(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700452 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700453}
454
Laurence Lundblade56230d12018-11-01 11:14:51 +0700455
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700456/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800457 Public functions for closing arrays and maps. See qcbor.h
Laurence Lundblade067035b2018-11-28 17:35:25 -0800458 */
459void QCBOREncode_AddInt64(QCBOREncodeContext *me, int64_t nNum)
460{
461 if(me->uError == QCBOR_SUCCESS) {
462 uint8_t uMajorType;
463 uint64_t uValue;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800464
Laurence Lundblade067035b2018-11-28 17:35:25 -0800465 if(nNum < 0) {
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800466 // In CBOR -1 encodes as 0x00 with major type negative int.
467 uValue = (uint64_t)(-nNum - 1);
Laurence Lundblade067035b2018-11-28 17:35:25 -0800468 uMajorType = CBOR_MAJOR_TYPE_NEGATIVE_INT;
469 } else {
470 uValue = (uint64_t)nNum;
471 uMajorType = CBOR_MAJOR_TYPE_POSITIVE_INT;
472 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800473
Laurence Lundblade067035b2018-11-28 17:35:25 -0800474 AppendEncodedTypeAndNumber(me, uMajorType, uValue);
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800475 me->uError = Nesting_Increment(&(me->nesting));
Laurence Lundblade067035b2018-11-28 17:35:25 -0800476 }
477}
478
479
480/*
Laurence Lundbladeda532272019-04-07 11:40:17 -0700481 Semi-private function. It is exposed to user of the interface, but
482 they will usually call one of the inline wrappers rather than this.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800483
Laurence Lundbladeee851742020-01-08 08:37:05 -0800484 See qcbor.h
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800485
Laurence Lundbladeda532272019-04-07 11:40:17 -0700486 Does the work of adding actual strings bytes to the CBOR output (as
487 opposed to numbers and opening / closing aggregate types).
488
489 There are four use cases:
490 CBOR_MAJOR_TYPE_BYTE_STRING -- Byte strings
491 CBOR_MAJOR_TYPE_TEXT_STRING -- Text strings
492 CBOR_MAJOR_NONE_TYPE_RAW -- Already-encoded CBOR
493 CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY -- Special case
494
495 The first two add the type and length plus the actual bytes. The
496 third just adds the bytes as the type and length are presumed to be
497 in the bytes. The fourth just adds the type and length for the very
498 special case of QCBOREncode_AddBytesLenOnly().
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700499 */
Laurence Lundblade067035b2018-11-28 17:35:25 -0800500void QCBOREncode_AddBuffer(QCBOREncodeContext *me, uint8_t uMajorType, UsefulBufC Bytes)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700501{
Laurence Lundblade241705e2018-12-30 18:56:14 -0800502 if(me->uError == QCBOR_SUCCESS) {
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800503 // If it is not Raw CBOR, add the type and the length
504 if(uMajorType != CBOR_MAJOR_NONE_TYPE_RAW) {
Laurence Lundbladeda532272019-04-07 11:40:17 -0700505 uint8_t uRealMajorType = uMajorType;
506 if(uRealMajorType == CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY) {
507 uRealMajorType = CBOR_MAJOR_TYPE_BYTE_STRING;
508 }
509 AppendEncodedTypeAndNumber(me, uRealMajorType, Bytes.len);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700510 }
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800511
Laurence Lundbladeda532272019-04-07 11:40:17 -0700512 if(uMajorType != CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY) {
513 // Actually add the bytes
514 UsefulOutBuf_AppendUsefulBuf(&(me->OutBuf), Bytes);
515 }
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800516
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800517 // Update the array counting if there is any nesting at all
518 me->uError = Nesting_Increment(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700519 }
520}
521
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700522
Laurence Lundblade55a24832018-10-30 04:35:08 +0700523/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800524 Public functions for closing arrays and maps. See qcbor.h
Laurence Lundblade55a24832018-10-30 04:35:08 +0700525 */
526void QCBOREncode_AddTag(QCBOREncodeContext *me, uint64_t uTag)
527{
Laurence Lundblade55a24832018-10-30 04:35:08 +0700528 AppendEncodedTypeAndNumber(me, CBOR_MAJOR_TYPE_OPTIONAL, uTag);
529}
530
531
Laurence Lundblade56230d12018-11-01 11:14:51 +0700532/*
Laurence Lundblade487930f2018-11-30 11:01:45 -0800533 Semi-private function. It is exposed to user of the interface,
534 but they will usually call one of the inline wrappers rather than this.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800535
Laurence Lundblade487930f2018-11-30 11:01:45 -0800536 See header qcbor.h
Laurence Lundblade56230d12018-11-01 11:14:51 +0700537 */
Laurence Lundblade487930f2018-11-30 11:01:45 -0800538void QCBOREncode_AddType7(QCBOREncodeContext *me, size_t uSize, uint64_t uNum)
Laurence Lundblade55a24832018-10-30 04:35:08 +0700539{
Laurence Lundblade487930f2018-11-30 11:01:45 -0800540 if(me->uError == QCBOR_SUCCESS) {
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700541 if(uNum >= CBOR_SIMPLEV_RESERVED_START && uNum <= CBOR_SIMPLEV_RESERVED_END) {
542 me->uError = QCBOR_ERR_UNSUPPORTED;
543 } else {
Laurence Lundbladeee851742020-01-08 08:37:05 -0800544 // This call takes care of endian swapping for the float / double
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700545 InsertEncodedTypeAndNumber(me,
546 // The major type for floats and doubles
547 CBOR_MAJOR_TYPE_SIMPLE,
Laurence Lundbladeee851742020-01-08 08:37:05 -0800548 // Must pass size to ensure floats
549 // with zero bytes encode correctly
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700550 (int)uSize,
Laurence Lundbladeee851742020-01-08 08:37:05 -0800551 // The floating-point number as a uint
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700552 uNum,
553 // end position because this is append
554 UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800555
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700556 me->uError = Nesting_Increment(&(me->nesting));
557 }
Laurence Lundblade487930f2018-11-30 11:01:45 -0800558 }
Laurence Lundblade55a24832018-10-30 04:35:08 +0700559}
560
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700561
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700562/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800563 Public functions for closing arrays and maps. See qcbor.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700564 */
Laurence Lundblade067035b2018-11-28 17:35:25 -0800565void QCBOREncode_AddDouble(QCBOREncodeContext *me, double dNum)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700566{
Laurence Lundblade067035b2018-11-28 17:35:25 -0800567 const IEEE754_union uNum = IEEE754_DoubleToSmallest(dNum);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800568
Laurence Lundblade487930f2018-11-30 11:01:45 -0800569 QCBOREncode_AddType7(me, uNum.uSize, uNum.uValue);
Laurence Lundblade067035b2018-11-28 17:35:25 -0800570}
571
572
Laurence Lundblade59289e52019-12-30 13:44:37 -0800573#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
574/*
575 Semi-public function. It is exposed to the user of the interface, but
576 one of the inline wrappers will usually be called rather than this.
577
578 See qcbor.h
579 */
580void QCBOREncode_AddExponentAndMantissa(QCBOREncodeContext *pMe,
581 uint64_t uTag,
582 UsefulBufC BigNumMantissa,
583 bool bBigNumIsNegative,
584 int64_t nMantissa,
585 int64_t nExponent)
586{
Laurence Lundbladeee851742020-01-08 08:37:05 -0800587 /*
588 This is for encoding either a big float or a decimal fraction,
589 both of which are an array of two items, an exponent and a
590 mantissa. The difference between the two is that the exponent is
591 base-2 for big floats and base-10 for decimal fractions, but that
592 has no effect on the code here.
593 */
Laurence Lundblade59289e52019-12-30 13:44:37 -0800594 QCBOREncode_AddTag(pMe, uTag);
595 QCBOREncode_OpenArray(pMe);
596 QCBOREncode_AddInt64(pMe, nExponent);
597 if(!UsefulBuf_IsNULLC(BigNumMantissa)) {
598 if(bBigNumIsNegative) {
599 QCBOREncode_AddNegativeBignum(pMe, BigNumMantissa);
600 } else {
601 QCBOREncode_AddPositiveBignum(pMe, BigNumMantissa);
602 }
603 } else {
604 QCBOREncode_AddInt64(pMe, nMantissa);
605 }
606 QCBOREncode_CloseArray(pMe);
607}
608#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
609
610
Laurence Lundblade067035b2018-11-28 17:35:25 -0800611/*
612 Semi-public function. It is exposed to user of the interface,
613 but they will usually call one of the inline wrappers rather than this.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800614
Laurence Lundblade067035b2018-11-28 17:35:25 -0800615 See header qcbor.h
616*/
617void QCBOREncode_OpenMapOrArray(QCBOREncodeContext *me, uint8_t uMajorType)
618{
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800619 // Add one item to the nesting level we are in for the new map or array
620 me->uError = Nesting_Increment(&(me->nesting));
Laurence Lundblade241705e2018-12-30 18:56:14 -0800621 if(me->uError == QCBOR_SUCCESS) {
Laurence Lundbladeee851742020-01-08 08:37:05 -0800622 /*
623 The offset where the length of an array or map will get written
624 is stored in a uint32_t, not a size_t to keep stack usage
625 smaller. This checks to be sure there is no wrap around when
626 recording the offset. Note that on 64-bit machines CBOR larger
627 than 4GB can be encoded as long as no array / map offsets occur
628 past the 4GB mark, but the public interface says that the
629 maximum is 4GB to keep the discussion simpler.
630 */
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800631 size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf));
Laurence Lundbladed39cd392019-01-11 18:17:38 -0800632
Laurence Lundbladeee851742020-01-08 08:37:05 -0800633 /*
634 QCBOR_MAX_ARRAY_OFFSET is slightly less than UINT32_MAX so this
635 code can run on a 32-bit machine and tests can pass on a 32-bit
636 machine. If it was exactly UINT32_MAX, then this code would not
637 compile or run on a 32-bit machine and an #ifdef or some
638 machine size detection would be needed reducing portability.
639 */
Laurence Lundbladed39cd392019-01-11 18:17:38 -0800640 if(uEndPosition >= QCBOR_MAX_ARRAY_OFFSET) {
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800641 me->uError = QCBOR_ERR_BUFFER_TOO_LARGE;
Laurence Lundbladed39cd392019-01-11 18:17:38 -0800642
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800643 } else {
Laurence Lundbladeee851742020-01-08 08:37:05 -0800644 // Increase nesting level because this is a map or array. Cast
645 // from size_t to uin32_t is safe because of check above
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800646 me->uError = Nesting_Increase(&(me->nesting), uMajorType, (uint32_t)uEndPosition);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700647 }
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800648 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700649}
650
Laurence Lundblade59289e52019-12-30 13:44:37 -0800651
Jan Jongboom4a93a662019-07-25 08:44:58 +0200652/*
653 Semi-public function. It is exposed to user of the interface,
654 but they will usually call one of the inline wrappers rather than this.
655
Laurence Lundbladeee851742020-01-08 08:37:05 -0800656 See qcbor.h
Jan Jongboom4a93a662019-07-25 08:44:58 +0200657*/
658void QCBOREncode_OpenMapOrArrayIndefiniteLength(QCBOREncodeContext *me, uint8_t uMajorType)
659{
660 // insert the indefinite length marker (0x9f for arrays, 0xbf for maps)
Jan Jongboom5d827882019-08-07 12:51:15 +0200661 InsertEncodedTypeAndNumber(me, uMajorType, 0, 0, UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
Jan Jongboom4a93a662019-07-25 08:44:58 +0200662
663 QCBOREncode_OpenMapOrArray(me, uMajorType);
664}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700665
Laurence Lundbladeee851742020-01-08 08:37:05 -0800666
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700667/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800668 Public functions for closing arrays and maps. See qcbor.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700669 */
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800670void QCBOREncode_CloseMapOrArray(QCBOREncodeContext *me,
671 uint8_t uMajorType,
672 UsefulBufC *pWrappedCBOR)
Laurence Lundbladea954db92018-09-28 19:27:31 -0700673{
Laurence Lundblade241705e2018-12-30 18:56:14 -0800674 if(me->uError == QCBOR_SUCCESS) {
Laurence Lundbladea954db92018-09-28 19:27:31 -0700675 if(!Nesting_IsInNest(&(me->nesting))) {
676 me->uError = QCBOR_ERR_TOO_MANY_CLOSES;
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800677 } else if(Nesting_GetMajorType(&(me->nesting)) != uMajorType) {
Laurence Lundblade067035b2018-11-28 17:35:25 -0800678 me->uError = QCBOR_ERR_CLOSE_MISMATCH;
Laurence Lundbladea954db92018-09-28 19:27:31 -0700679 } else {
Laurence Lundbladeee851742020-01-08 08:37:05 -0800680 /*
681 When the array, map or bstr wrap was started, nothing was
682 gone except note the position of the start of it. This code
683 goes back and inserts the actual CBOR array, map or bstr and
684 its length. That means all the data that is in the array,
685 map or wrapped needs to be slid to the right. This is done
686 by UsefulOutBuf's insert function that is called from inside
687 InsertEncodedTypeAndNumber()
688 */
689 const size_t uInsertPosition = Nesting_GetStartPos(&(me->nesting));
690 const size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf));
691 /*
692 This can't go negative because the UsefulOutBuf always only
693 grows and never shrinks. UsefulOutBut itself also has
694 defenses such that it won't write were it should not even if
695 given hostile input lengths
696 */
Laurence Lundblade56230d12018-11-01 11:14:51 +0700697 const size_t uLenOfEncodedMapOrArray = uEndPosition - uInsertPosition;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800698
Laurence Lundbladeee851742020-01-08 08:37:05 -0800699 // Number of bytes for a bstr or number of items a for map & array
700 const bool bIsBstr = uMajorType == CBOR_MAJOR_TYPE_BYTE_STRING;
701 const size_t uLength = bIsBstr ? uLenOfEncodedMapOrArray
702 : Nesting_GetCount(&(me->nesting));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800703
Laurence Lundbladea954db92018-09-28 19:27:31 -0700704 // Actually insert
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700705 InsertEncodedTypeAndNumber(me,
Laurence Lundbladeee851742020-01-08 08:37:05 -0800706 uMajorType, // bstr, array or map
707 0, // no minimum length
708 uLength, // either len of bstr or
709 // num map / array items
Laurence Lundbladea954db92018-09-28 19:27:31 -0700710 uInsertPosition); // position in out buffer
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800711
Laurence Lundbladeee851742020-01-08 08:37:05 -0800712 /*
713 Return pointer and length to the enclosed encoded CBOR. The
714 intended use is for it to be hashed (e.g., SHA-256) in a
715 COSE implementation. This must be used right away, as the
716 pointer and length go invalid on any subsequent calls to
717 this function because there might be calls to
718 InsertEncodedTypeAndNumber() that slides data to the right.
719 */
Laurence Lundbladea954db92018-09-28 19:27:31 -0700720 if(pWrappedCBOR) {
Laurence Lundblade25c6c0a2018-12-17 13:21:59 -0800721 const UsefulBufC PartialResult = UsefulOutBuf_OutUBuf(&(me->OutBuf));
Laurence Lundblade83f5b7f2019-04-06 11:22:37 -0700722 *pWrappedCBOR = UsefulBuf_Tail(PartialResult, uInsertPosition);
Laurence Lundbladea954db92018-09-28 19:27:31 -0700723 }
724 Nesting_Decrease(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700725 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700726 }
727}
728
Laurence Lundbladeee851742020-01-08 08:37:05 -0800729
Jan Jongboom4a93a662019-07-25 08:44:58 +0200730/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800731 Public functions for closing arrays and maps. See qcbor.h
Jan Jongboom4a93a662019-07-25 08:44:58 +0200732 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800733void QCBOREncode_CloseMapOrArrayIndefiniteLength(QCBOREncodeContext *me,
734 uint8_t uMajorType,
735 UsefulBufC *pWrappedCBOR)
Jan Jongboom4a93a662019-07-25 08:44:58 +0200736{
737 if(me->uError == QCBOR_SUCCESS) {
738 if(!Nesting_IsInNest(&(me->nesting))) {
739 me->uError = QCBOR_ERR_TOO_MANY_CLOSES;
740 } else if(Nesting_GetMajorType(&(me->nesting)) != uMajorType) {
741 me->uError = QCBOR_ERR_CLOSE_MISMATCH;
742 } else {
743 // insert the break marker (0xff for both arrays and maps)
Laurence Lundbladeee851742020-01-08 08:37:05 -0800744 InsertEncodedTypeAndNumber(me,
745 CBOR_MAJOR_TYPE_SIMPLE,
746 0,
747 CBOR_SIMPLE_BREAK,
748 UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
Jan Jongboom4a93a662019-07-25 08:44:58 +0200749
Laurence Lundbladeee851742020-01-08 08:37:05 -0800750 /*
751 Return pointer and length to the enclosed encoded CBOR. The
752 intended use is for it to be hashed (e.g., SHA-256) in a
753 COSE implementation. This must be used right away, as the
754 pointer and length go invalid on any subsequent calls to
755 this function because there might be calls to
756 InsertEncodedTypeAndNumber() that slides data to the right.
757 */
Jan Jongboom4a93a662019-07-25 08:44:58 +0200758 if(pWrappedCBOR) {
759 const UsefulBufC PartialResult = UsefulOutBuf_OutUBuf(&(me->OutBuf));
760 *pWrappedCBOR = UsefulBuf_Tail(PartialResult, UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
761 }
762
763 // Decrease nesting level
764 Nesting_Decrease(&(me->nesting));
765 }
766 }
767}
768
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700769
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700770/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800771 Public functions to finish and get the encoded result. See qcbor.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700772 */
Laurence Lundblade30816f22018-11-10 13:40:22 +0700773QCBORError QCBOREncode_Finish(QCBOREncodeContext *me, UsefulBufC *pEncodedCBOR)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700774{
Laurence Lundbladef607a2a2019-07-05 21:25:25 -0700775 QCBORError uReturn = QCBOREncode_GetErrorState(me);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800776
Laurence Lundblade067035b2018-11-28 17:35:25 -0800777 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700778 goto Done;
Laurence Lundblade067035b2018-11-28 17:35:25 -0800779 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800780
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700781 if (Nesting_IsInNest(&(me->nesting))) {
Laurence Lundblade067035b2018-11-28 17:35:25 -0800782 uReturn = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700783 goto Done;
784 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800785
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700786 *pEncodedCBOR = UsefulOutBuf_OutUBuf(&(me->OutBuf));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800787
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700788Done:
Laurence Lundblade067035b2018-11-28 17:35:25 -0800789 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700790}
791
Laurence Lundblade0595e932018-11-02 22:22:47 +0700792
Laurence Lundbladef607a2a2019-07-05 21:25:25 -0700793
Laurence Lundblade067035b2018-11-28 17:35:25 -0800794/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800795 Public functions to finish and get the encoded result. See qcbor.h
Laurence Lundblade067035b2018-11-28 17:35:25 -0800796 */
Laurence Lundblade30816f22018-11-10 13:40:22 +0700797QCBORError QCBOREncode_FinishGetSize(QCBOREncodeContext *me, size_t *puEncodedLen)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700798{
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700799 UsefulBufC Enc;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800800
Laurence Lundblade30816f22018-11-10 13:40:22 +0700801 QCBORError nReturn = QCBOREncode_Finish(me, &Enc);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800802
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700803 if(nReturn == QCBOR_SUCCESS) {
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700804 *puEncodedLen = Enc.len;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700805 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800806
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700807 return nReturn;
808}
809
810
Laurence Lundblade067035b2018-11-28 17:35:25 -0800811
812
813/*
Laurence Lundblade241705e2018-12-30 18:56:14 -0800814 Object code sizes on X86 with LLVM compiler and -Os (Dec 30, 2018)
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800815
Laurence Lundblade9c097392018-12-30 13:52:24 -0800816 _QCBOREncode_Init 69
Laurence Lundblade067035b2018-11-28 17:35:25 -0800817 _QCBOREncode_AddUInt64 76
818 _QCBOREncode_AddInt64 87
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800819 _QCBOREncode_AddBuffer 113
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800820 _QCBOREncode_AddTag 27
Laurence Lundblade9c097392018-12-30 13:52:24 -0800821 _QCBOREncode_AddType7 87
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800822 _QCBOREncode_AddDouble 36
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800823 _QCBOREncode_OpenMapOrArray 103
Laurence Lundblade067035b2018-11-28 17:35:25 -0800824 _QCBOREncode_CloseMapOrArray 181
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800825 _InsertEncodedTypeAndNumber 190
Laurence Lundblade067035b2018-11-28 17:35:25 -0800826 _QCBOREncode_Finish 72
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800827 _QCBOREncode_FinishGetSize 70
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800828
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800829 Total is about 1.1KB
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800830
Laurence Lundblade067035b2018-11-28 17:35:25 -0800831 _QCBOREncode_CloseMapOrArray is larger because it has a lot
832 of nesting tracking to do and much of Nesting_ inlines
833 into it. It probably can't be reduced much.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800834
Laurence Lundblade067035b2018-11-28 17:35:25 -0800835 If the error returned by Nesting_Increment() can be ignored
836 because the limit is so high and the consequence of exceeding
837 is proved to be inconsequential, then a lot of if(me->uError)
838 instance can be removed, saving some code.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800839
Laurence Lundblade067035b2018-11-28 17:35:25 -0800840 */