blob: 28ff84d89e539fa873c3bda6bc2a603a230d35ff [file] [log] [blame]
Laurence Lundbladed253e412024-08-21 11:02:56 -07001/* ===========================================================================
2 * Copyright (c) 2016-2018, The Linux Foundation.
3 * Copyright (c) 2018-2024, Laurence Lundblade.
4 * Copyright (c) 2021, Arm Limited.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
9 * met:
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following
14 * disclaimer in the documentation and/or other materials provided
15 * with the distribution.
16 * * Neither the name of The Linux Foundation nor the names of its
17 * contributors, nor the name "Laurence Lundblade" may be used to
18 * endorse or promote products derived from this software without
19 * specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
22 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
30 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
31 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 * ========================================================================= */
Laurence Lundblade624405d2018-09-18 20:10:47 -070033
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080034
Laurence Lundblade844bb5c2020-03-01 17:27:25 -080035#include "qcbor/qcbor_encode.h"
Laurence Lundblade12d32c52018-09-19 11:25:27 -070036#include "ieee754.h"
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070037
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -080038#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
39#include <math.h> /* Only for NAN definition */
40#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
41
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070042
Laurence Lundblade1fa579b2020-11-25 00:31:37 -080043/**
44 * @file qcbor_encode.c
Laurence Lundblade3f1318a2021-01-04 18:26:44 -080045 *
Laurence Lundblade1fa579b2020-11-25 00:31:37 -080046 * The entire implementation of the QCBOR encoder.
47 */
48
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070049
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070050/*
Laurence Lundblade1fa579b2020-11-25 00:31:37 -080051 * == Nesting Tracking ==
52 *
53 * The following functions and data type QCBORTrackNesting implement
54 * the nesting management for encoding.
55 *
56 * CBOR's two nesting types, arrays and maps, are tracked here. There
57 * is a limit of QCBOR_MAX_ARRAY_NESTING to the number of arrays and
58 * maps that can be nested in one encoding so the encoding context
59 * stays small enough to fit on the stack.
60 *
61 * When an array/map is opened, pCurrentNesting points to the element
62 * in pArrays that records the type, start position and accumulates a
63 * count of the number of items added. When closed the start position
64 * is used to go back and fill in the type and number of items in the
65 * array/map.
66 *
67 * Encoded output can be a CBOR Sequence (RFC 8742) in which case
68 * there is no top-level array or map. It starts out with a string,
69 * integer or other non-aggregate type. It may have an array or map
70 * other than at the start, in which case that nesting is tracked
71 * here.
72 *
73 * QCBOR has a special feature to allow constructing byte string
74 * wrapped CBOR directly into the output buffer, so no extra buffer is
75 * needed for byte string wrapping. This is implemented as nesting
76 * with the type CBOR_MAJOR_TYPE_BYTE_STRING and is tracked here. Byte
77 * string wrapped CBOR is used by COSE for data that is to be hashed.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070078 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -070079static void
Laurence Lundblade274ddef2022-05-17 09:12:23 -070080Nesting_Init(QCBORTrackNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070081{
Laurence Lundblade1fa579b2020-11-25 00:31:37 -080082 /* Assumes pNesting has been zeroed. */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070083 pNesting->pCurrentNesting = &pNesting->pArrays[0];
Laurence Lundblade1fa579b2020-11-25 00:31:37 -080084 /* Implied CBOR array at the top nesting level. This is never
85 * returned, but makes the item count work correctly.
86 */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070087 pNesting->pCurrentNesting->uMajorType = CBOR_MAJOR_TYPE_ARRAY;
88}
89
Laurence Lundblade8e36f812024-01-26 10:59:29 -070090static uint8_t
Laurence Lundblade274ddef2022-05-17 09:12:23 -070091Nesting_Increase(QCBORTrackNesting *pNesting,
Laurence Lundblade8e36f812024-01-26 10:59:29 -070092 const uint8_t uMajorType,
93 const uint32_t uPos)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070094{
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070095 if(pNesting->pCurrentNesting == &pNesting->pArrays[QCBOR_MAX_ARRAY_NESTING]) {
Laurence Lundblade29497c02020-07-11 15:44:03 -070096 return QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070097 } else {
98 pNesting->pCurrentNesting++;
99 pNesting->pCurrentNesting->uCount = 0;
100 pNesting->pCurrentNesting->uStart = uPos;
101 pNesting->pCurrentNesting->uMajorType = uMajorType;
Laurence Lundblade29497c02020-07-11 15:44:03 -0700102 return QCBOR_SUCCESS;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700103 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700104}
105
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700106static void
Laurence Lundblade274ddef2022-05-17 09:12:23 -0700107Nesting_Decrease(QCBORTrackNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700108{
Laurence Lundblade274ddef2022-05-17 09:12:23 -0700109 if(pNesting->pCurrentNesting > &pNesting->pArrays[0]) {
110 pNesting->pCurrentNesting--;
111 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700112}
113
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700114static uint8_t
Laurence Lundblade274ddef2022-05-17 09:12:23 -0700115Nesting_Increment(QCBORTrackNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700116{
Laurence Lundbladedaefdec2020-11-02 20:22:03 -0800117#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
Laurence Lundbladeb95afec2024-08-26 10:51:28 -0700118 if(pNesting->pCurrentNesting->uCount >= QCBOR_MAX_ITEMS_IN_ARRAY) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700119 return QCBOR_ERR_ARRAY_TOO_LONG;
120 }
Laurence Lundbladed253e412024-08-21 11:02:56 -0700121#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800122
Laurence Lundbladee6bcef12020-04-01 10:56:27 -0700123 pNesting->pCurrentNesting->uCount++;
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800124
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700125 return QCBOR_SUCCESS;
126}
127
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700128static void
Laurence Lundblade274ddef2022-05-17 09:12:23 -0700129Nesting_Decrement(QCBORTrackNesting *pNesting)
Laurence Lundblade8d3b8552021-06-10 11:11:54 -0700130{
131 /* No error check for going below 0 here needed because this
132 * is only used by QCBOREncode_CancelBstrWrap() and it checks
133 * the nesting level before calling this. */
134 pNesting->pCurrentNesting->uCount--;
135}
136
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700137static uint16_t
Laurence Lundblade274ddef2022-05-17 09:12:23 -0700138Nesting_GetCount(QCBORTrackNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700139{
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800140 /* The nesting count recorded is always the actual number of
141 * individual data items in the array or map. For arrays CBOR uses
142 * the actual item count. For maps, CBOR uses the number of pairs.
143 * This function returns the number needed for the CBOR encoding,
144 * so it divides the number of items by two for maps to get the
145 * number of pairs.
146 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800147 if(pNesting->pCurrentNesting->uMajorType == CBOR_MAJOR_TYPE_MAP) {
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800148 /* Cast back to uint16_t after integer promotion from bit shift */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800149 return (uint16_t)(pNesting->pCurrentNesting->uCount >> 1);
150 } else {
151 return pNesting->pCurrentNesting->uCount;
152 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700153}
154
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700155static uint32_t
Laurence Lundblade274ddef2022-05-17 09:12:23 -0700156Nesting_GetStartPos(QCBORTrackNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700157{
158 return pNesting->pCurrentNesting->uStart;
159}
160
Laurence Lundbladed8e1c512020-11-04 23:03:44 -0800161#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700162static uint8_t
Laurence Lundblade274ddef2022-05-17 09:12:23 -0700163Nesting_GetMajorType(QCBORTrackNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700164{
165 return pNesting->pCurrentNesting->uMajorType;
166}
167
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700168static bool
Laurence Lundblade274ddef2022-05-17 09:12:23 -0700169Nesting_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}
Laurence Lundbladee2226742024-08-16 10:50:23 -0700173#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700174
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700175
176
177
178/*
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800179 * == Major CBOR Types ==
180 *
181 * Encoding of the major CBOR types is by these functions:
182 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800183 * CBOR Major Type Public Function
184 * 0 QCBOREncode_AddUInt64()
185 * 0, 1 QCBOREncode_AddUInt64(), QCBOREncode_AddInt64()
186 * 2, 3 QCBOREncode_AddBuffer()
187 * 4, 5 QCBOREncode_OpenMapOrArray(), QCBOREncode_CloseMapOrArray(),
188 * QCBOREncode_OpenMapOrArrayIndefiniteLength(),
189 * QCBOREncode_CloseMapOrArrayIndefiniteLength()
Laurence Lundblade721b56e2024-10-22 03:02:04 -0700190 * 6 QCBOREncode_AddTagNumber()
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800191 * 7 QCBOREncode_AddDouble(), QCBOREncode_AddFloat(),
192 * QCBOREncode_AddDoubleNoPreferred(),
193 * QCBOREncode_AddFloatNoPreferred(), QCBOREncode_AddType7()
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800194 *
195 * Additionally, encoding of decimal fractions and bigfloats is by
196 * QCBOREncode_AddExponentAndMantissa() and byte strings that wrap
197 * encoded CBOR are handled by QCBOREncode_OpenMapOrArray() and
198 * QCBOREncode_CloseBstrWrap2().
199 *
200 *
201 * == Error Tracking Plan ==
202 *
203 * Errors are tracked internally and not returned until
204 * QCBOREncode_Finish() or QCBOREncode_GetErrorState() is called. The
205 * CBOR errors are in me->uError. UsefulOutBuf also tracks whether
206 * the buffer is full or not in its context. Once either of these
207 * errors is set they are never cleared. Only QCBOREncode_Init()
208 * resets them. Or said another way, they must never be cleared or
209 * we'll tell the caller all is good when it is not.
210 *
211 * Only one error code is reported by QCBOREncode_Finish() even if
212 * there are multiple errors. The last one set wins. The caller might
213 * have to fix one error to reveal the next one they have to fix.
214 * This is OK.
215 *
216 * The buffer full error tracked by UsefulBuf is only pulled out of
217 * UsefulBuf in QCBOREncode_Finish() so it is the one that usually
218 * wins. UsefulBuf will never go off the end of the buffer even if it
219 * is called again and again when full.
220 *
221 * QCBOR_DISABLE_ENCODE_USAGE_GUARDS disables about half of the error
222 * checks here to reduce code size by about 150 bytes leaving only the
223 * checks for size to avoid buffer overflow. If the calling code is
224 * completely correct, checks are completely unnecessary. For
225 * example, there is no need to check that all the opens are matched
226 * by a close.
227 *
228 * QCBOR_DISABLE_ENCODE_USAGE_GUARDS also disables the check for more
229 * than QCBOR_MAX_ITEMS_IN_ARRAY in an array. Since
Laurence Lundbladeb95afec2024-08-26 10:51:28 -0700230 * QCBOR_MAX_ITEMS_IN_ARRAY is very large (65,534) it is very unlikely
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800231 * to be reached. If it is reached, the count will wrap around to zero
232 * and CBOR that is not well formed will be produced, but there will
233 * be no buffers overrun and new security issues in the code.
234 *
235 * The 8 errors returned here fall into three categories:
236 *
237 * Sizes
238 * QCBOR_ERR_BUFFER_TOO_LARGE -- Encoded output exceeded UINT32_MAX
239 * QCBOR_ERR_BUFFER_TOO_SMALL -- Output buffer too small
240 * QCBOR_ERR_ARRAY_NESTING_TOO_DEEP -- Nesting > QCBOR_MAX_ARRAY_NESTING1
241 * QCBOR_ERR_ARRAY_TOO_LONG -- Too many items added to an array/map [1]
242 *
243 * Nesting constructed incorrectly
244 * QCBOR_ERR_TOO_MANY_CLOSES -- More close calls than opens [1]
245 * QCBOR_ERR_CLOSE_MISMATCH -- Type of close does not match open [1]
246 * QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN -- Finish called without enough closes [1]
247 *
248 * Would generate not-well-formed CBOR
249 * QCBOR_ERR_ENCODE_UNSUPPORTED -- Simple type between 24 and 31 [1]
250 *
251 * [1] indicated disabled by QCBOR_DISABLE_ENCODE_USAGE_GUARDS
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700252 */
253
254
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800255/* Forward declaration for reference in QCBOREncode_Init() */
256static void
257QCBOREncode_Private_CloseMapUnsorted(QCBOREncodeContext *pMe);
258
259
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700260/*
Laurence Lundbladeb9ccd6b2024-02-06 05:44:25 -0700261 * Public function for initialization. See qcbor/qcbor_encode.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700262 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700263void
264QCBOREncode_Init(QCBOREncodeContext *pMe, UsefulBuf Storage)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700265{
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700266 memset(pMe, 0, sizeof(QCBOREncodeContext));
267 UsefulOutBuf_Init(&(pMe->OutBuf), Storage);
268 Nesting_Init(&(pMe->nesting));
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800269 pMe->pfnCloseMap = QCBOREncode_Private_CloseMapUnsorted;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700270}
271
272
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000273/*
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800274 * Public function to encode a CBOR head. See qcbor/qcbor_encode.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700275 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700276UsefulBufC
277QCBOREncode_EncodeHead(UsefulBuf Buffer,
278 uint8_t uMajorType,
279 uint8_t uMinLen,
280 uint64_t uArgument)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700281{
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800282 /*
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800283 * == Description of the CBOR Head ==
284 *
285 * The head of a CBOR data item
286 * +---+-----+ +--------+ +--------+ +--------+ +--------+
287 * |M T| A R G U M E N T . . . |
288 * +---+-----+ +--------+ +--------+ +--------+ ... +--------+
289 *
290 * Every CBOR data item has a "head". It is made up of the "major
291 * type" and the "argument".
292 *
293 * The major type indicates whether the data item is an integer,
294 * string, array or such. It is encoded in 3 bits giving it a range
295 * from 0 to 7. 0 indicates the major type is a positive integer,
296 * 1 a negative integer, 2 a byte string and so on.
297 *
298 * These 3 bits are the first part of the "initial byte" in a data
299 * item. Every data item has an initial byte, and some only have
300 * the initial byte.
301 *
302 * The argument is essentially a number between 0 and UINT64_MAX
303 * (18446744073709551615). This number is interpreted to mean
304 * different things for the different major types. For major type
305 * 0, a positive integer, it is value of the data item. For major
306 * type 2, a byte string, it is the length in bytes of the byte
307 * string. For major type 4, an array, it is the number of data
308 * items in the array.
309 *
310 * Special encoding is used so that the argument values less than
311 * 24 can be encoded very compactly in the same byte as the major
312 * type is encoded. When the lower 5 bits of the initial byte have
313 * a value less than 24, then that is the value of the argument.
314 *
315 * If the lower 5 bits of the initial byte are less than 24, then
316 * they are the value of the argument. This allows integer values 0
317 * - 23 to be CBOR encoded in just one byte.
318 *
319 * When the value of lower 5 bits are 24, 25, 26, or 27 the
320 * argument is encoded in 1, 2, 4 or 8 bytes following the initial
321 * byte in network byte order (bit endian). The cases when it is
322 * 28, 29 and 30 are reserved for future use. The value 31 is a
323 * special indicator for indefinite length strings, arrays and
324 * maps.
325 *
326 * The lower 5 bits are called the "additional information."
327 *
328 * Thus the CBOR head may be 1, 2, 3, 5 or 9 bytes long.
329 *
330 * It is legal in CBOR to encode the argument using any of these
331 * lengths even if it could be encoded in a shorter length. For
332 * example it is legal to encode a data item representing the
333 * positive integer 0 in 9 bytes even though it could be encoded in
334 * only 0. This is legal to allow for for very simple code or even
335 * hardware-only implementations that just output a register
336 * directly.
337 *
338 * CBOR defines preferred encoding as the encoding of the argument
339 * in the smallest number of bytes needed to encode it.
340 *
341 * This function takes the major type and argument as inputs and
342 * outputs the encoded CBOR head for them. It does conversion to
343 * network byte order. It implements CBOR preferred encoding,
344 * outputting the shortest representation of the argument.
345 *
346 * == Endian Conversion ==
347 *
348 * This code does endian conversion without hton() or knowing the
349 * endianness of the machine by using masks and shifts. This avoids
350 * the dependency on hton() and the mess of figuring out how to
351 * find the machine's endianness.
352 *
353 * This is a good efficient implementation on little-endian
354 * machines. A faster and smaller implementation is possible on
355 * big-endian machines because CBOR/network byte order is
356 * big-endian. However big-endian machines are uncommon.
357 *
358 * On x86, this is about 150 bytes instead of 500 bytes for the
359 * original, more formal unoptimized code.
360 *
361 * This also does the CBOR preferred shortest encoding for integers
362 * and is called to do endian conversion for floats.
363 *
364 * It works backwards from the least significant byte to the most
365 * significant byte.
366 *
367 * == Floating Point ==
368 *
369 * When the major type is 7 and the 5 lower bits have the values
370 * 25, 26 or 27, the argument is a floating-point number that is
371 * half, single or double-precision. Note that it is not the
372 * conversion from a floating-point value to an integer value like
373 * converting 0x00 to 0.00, it is the interpretation of the bits in
374 * the argument as an IEEE 754 float-point number.
375 *
376 * Floating-point numbers must be converted to network byte
377 * order. That is accomplished here by exactly the same code that
378 * converts integer arguments to network byte order.
379 *
380 * There is preferred encoding for floating-point numbers in CBOR,
381 * but it is very different than for integers and it is not
382 * implemented here. Half-precision is preferred to
383 * single-precision which is preferred to double-precision only if
384 * the conversion can be performed without loss of precision. Zero
385 * and infinity can always be converted to half-precision, without
386 * loss but 3.141592653589 cannot.
387 *
388 * The way this function knows to not do preferred encoding on the
389 * argument passed here when it is a floating point number is the
390 * uMinLen parameter. It should be 2, 4 or 8 for half, single and
391 * double precision floating point values. This prevents and the
392 * incorrect removal of leading zeros when encoding arguments that
393 * are floating-point numbers.
394 *
395 * == Use of Type int and Static Analyzers ==
396 *
397 * The type int is used here for several variables because of the
398 * way integer promotion works in C for variables that are uint8_t
399 * or uint16_t. The basic rule is that they will always be promoted
400 * to int if they will fit. These integer variables here need only
401 * hold values less than 255 so they will always fit into an int.
402 *
403 * Most of values stored are never negative, so one might think
404 * that unsigned int would be more correct than int. However the C
405 * integer promotion rules only promote to unsigned int if the
406 * result won't fit into an int even if the promotion is for an
407 * unsigned variable like uint8_t.
408 *
409 * By declaring these int, there are few implicit conversions and
410 * fewer casts needed. Code size is reduced a little. It makes
411 * static analyzers happier.
412 *
413 * Note also that declaring these uint8_t won't stop integer wrap
414 * around if the code is wrong. It won't make the code more
415 * correct.
416 *
417 * https://stackoverflow.com/questions/46073295/implicit-type-promotion-rules
418 * https://stackoverflow.com/questions/589575/what-does-the-c-standard-state-the-size-of-int-long-type-to-be
419 *
420 * Code Reviewers: THIS FUNCTION DOES POINTER MATH
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800421 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800422
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800423 /* The buffer must have room for the largest CBOR HEAD + one
424 * extra. The one extra is needed for this code to work as it does
425 * a pre-decrement.
426 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700427 if(Buffer.len < QCBOR_HEAD_BUFFER_SIZE) {
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000428 return NULLUsefulBufC;
429 }
430
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800431 /* Pointer to last valid byte in the buffer */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700432 uint8_t * const pBufferEnd = &((uint8_t *)Buffer.ptr)[QCBOR_HEAD_BUFFER_SIZE-1];
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000433
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800434 /* Point to the last byte and work backwards */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000435 uint8_t *pByte = pBufferEnd;
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800436 /* The 5 bits in the initial byte that are not the major type */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800437 int nAdditionalInfo;
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800438
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700439#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade8c858ab2020-11-02 19:53:49 -0800440 if(uMajorType > QCBOR_INDEFINITE_LEN_TYPE_MODIFIER) {
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800441 /* Special case for start & end of indefinite length */
Laurence Lundblade8c858ab2020-11-02 19:53:49 -0800442 uMajorType = uMajorType - QCBOR_INDEFINITE_LEN_TYPE_MODIFIER;
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800443 /* This takes advantage of design of CBOR where additional info
444 * is 31 for both opening and closing indefinite length
445 * maps and arrays.
446 */
447 #if CBOR_SIMPLE_BREAK != LEN_IS_INDEFINITE
448 #error additional info for opening array not the same as for closing
449 #endif
Laurence Lundblade8c858ab2020-11-02 19:53:49 -0800450 nAdditionalInfo = CBOR_SIMPLE_BREAK;
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800451
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700452 } else
Laurence Lundbladed253e412024-08-21 11:02:56 -0700453#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700454 if (uArgument < CBOR_TWENTY_FOUR && uMinLen == 0) {
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800455 /* Simple case where argument is < 24 */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000456 nAdditionalInfo = (int)uArgument;
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800457
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800458 } else {
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800459 /* This encodes the argument in 1,2,4 or 8 bytes. The outer loop
460 * runs once for 1 byte and 4 times for 8 bytes. The inner loop
461 * runs 1, 2 or 4 times depending on outer loop counter. This
462 * works backwards shifting 8 bits off the argument being
463 * encoded at a time until all bits from uArgument have been
464 * encoded and the minimum encoding size is reached. Minimum
465 * encoding size is for floating-point numbers that have some
466 * zero-value bytes that must be output.
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800467 */
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800468 static const uint8_t aIterate[] = {1,1,2,4};
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000469
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800470 /* uMinLen passed in is unsigned, but goes negative in the loop
471 * so it must be converted to a signed value.
472 */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000473 int nMinLen = (int)uMinLen;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800474 int i;
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000475 for(i = 0; uArgument || nMinLen > 0; i++) {
476 const int nIterations = (int)aIterate[i];
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800477 for(int j = 0; j < nIterations; j++) {
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000478 *--pByte = (uint8_t)(uArgument & 0xff);
479 uArgument = uArgument >> 8;
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800480 }
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800481 nMinLen -= nIterations;
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800482 }
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800483
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800484 nAdditionalInfo = LEN_IS_ONE_BYTE-1 + i;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700485 }
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800486
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800487 /* This expression integer-promotes to type int. The code above in
488 * function guarantees that nAdditionalInfo will never be larger
489 * than 0x1f. The caller may pass in a too-large uMajor type. The
Laurence Lundblade11654912024-05-09 11:49:24 -0700490 * conversion to uint8_t will cause an integer wrap around and
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800491 * incorrect CBOR will be generated, but no security issue will
492 * occur.
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800493 */
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800494 const int nInitialByte = (uMajorType << 5) + nAdditionalInfo;
495 *--pByte = (uint8_t)nInitialByte;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800496
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000497#ifdef EXTRA_ENCODE_HEAD_CHECK
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800498 /* This is a sanity check that can be turned on to verify the
499 * pointer math in this function is not going wrong. Turn it on and
500 * run the whole test suite to perform the check.
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800501 */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000502 if(pBufferEnd - pByte > 9 || pBufferEnd - pByte < 1 || pByte < (uint8_t *)buffer.ptr) {
503 return NULLUsefulBufC;
504 }
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800505#endif /* EXTRA_ENCODE_HEAD_CHECK */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800506
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800507 /* Length will not go negative because the loops run for at most 8 decrements
508 * of pByte, only one other decrement is made, and the array is sized
509 * for this.
510 */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000511 return (UsefulBufC){pByte, (size_t)(pBufferEnd - pByte)};
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700512}
513
514
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000515/**
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700516 * @brief Increment item counter for maps and arrays.
517 *
518 * @param pMe QCBOR encoding context.
519 *
520 * This is mostly a separate function to make code more readable and
521 * to have fewer occurrences of #ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
522 */
523static void
524QCBOREncode_Private_IncrementMapOrArrayCount(QCBOREncodeContext *pMe)
525{
526#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
527 if(pMe->uError == QCBOR_SUCCESS) {
528 pMe->uError = Nesting_Increment(&(pMe->nesting));
529 }
530#else
531 (void)Nesting_Increment(&(pMe->nesting));
Laurence Lundbladed253e412024-08-21 11:02:56 -0700532#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700533}
534
535
536/**
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800537 * @brief Append the CBOR head, the major type and argument
538 *
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700539 * @param pMe Encoder context.
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800540 * @param uMajorType Major type to insert.
541 * @param uArgument The argument (an integer value or a length).
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800542 * @param uMinLen Minimum number of bytes for encoding the CBOR argument.
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800543 *
544 * This formats the CBOR "head" and appends it to the output.
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700545 *
546 * This also increments the array/map item counter in most cases.
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000547 */
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700548void
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700549QCBOREncode_Private_AppendCBORHead(QCBOREncodeContext *pMe,
550 const uint8_t uMajorType,
551 const uint64_t uArgument,
552 const uint8_t uMinLen)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700553{
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800554 /* A stack buffer large enough for a CBOR head */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000555 UsefulBuf_MAKE_STACK_UB (pBufferForEncodedHead, QCBOR_HEAD_BUFFER_SIZE);
556
557 UsefulBufC EncodedHead = QCBOREncode_EncodeHead(pBufferForEncodedHead,
558 uMajorType,
559 uMinLen,
560 uArgument);
561
562 /* No check for EncodedHead == NULLUsefulBufC is performed here to
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800563 * save object code. It is very clear that pBufferForEncodedHead is
564 * the correct size. If EncodedHead == NULLUsefulBufC then
565 * UsefulOutBuf_AppendUsefulBuf() will do nothing so there is no
566 * security hole introduced.
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000567 */
568
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700569 UsefulOutBuf_AppendUsefulBuf(&(pMe->OutBuf), EncodedHead);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700570
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700571 if(!(uMajorType & QCBOR_INDEFINITE_LEN_TYPE_MODIFIER || uMajorType == CBOR_MAJOR_TYPE_TAG)) {
572 /* Don't increment the map count for tag or break because that is
573 * not needed. Don't do it for indefinite-length arrays and maps
574 * because it is done elsewhere. This is never called for definite-length
575 * arrays and maps.
576 */
577 QCBOREncode_Private_IncrementMapOrArrayCount(pMe);
Laurence Lundblade274ddef2022-05-17 09:12:23 -0700578 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700579}
580
Laurence Lundblade56230d12018-11-01 11:14:51 +0700581
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700582/*
Laurence Lundbladed253e412024-08-21 11:02:56 -0700583 * Public function for adding signed integers. See qcbor/qcbor_encode.h
Laurence Lundblade067035b2018-11-28 17:35:25 -0800584 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700585void
586QCBOREncode_AddInt64(QCBOREncodeContext *pMe, const int64_t nNum)
Laurence Lundblade067035b2018-11-28 17:35:25 -0800587{
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800588 uint8_t uMajorType;
589 uint64_t uValue;
Laurence Lundbladedaefdec2020-11-02 20:22:03 -0800590
591 if(nNum < 0) {
Laurence Lundblade9c5c0ef2022-12-23 17:56:27 -0700592 /* In CBOR -1 encodes as 0x00 with major type negative int.
593 * First add one as a signed integer because that will not
Laurence Lundblade2d493002024-02-01 11:09:17 -0700594 * overflow. Then change the sign as needed for encoding (the
Laurence Lundblade9c5c0ef2022-12-23 17:56:27 -0700595 * opposite order, changing the sign and subtracting, can cause
Laurence Lundblade2d493002024-02-01 11:09:17 -0700596 * an overflow when encoding INT64_MIN). */
Laurence Lundblade9c5c0ef2022-12-23 17:56:27 -0700597 int64_t nTmp = nNum + 1;
598 uValue = (uint64_t)-nTmp;
Laurence Lundbladedaefdec2020-11-02 20:22:03 -0800599 uMajorType = CBOR_MAJOR_TYPE_NEGATIVE_INT;
600 } else {
601 uValue = (uint64_t)nNum;
602 uMajorType = CBOR_MAJOR_TYPE_POSITIVE_INT;
603 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700604 QCBOREncode_Private_AppendCBORHead(pMe, uMajorType, uValue, 0);
Laurence Lundblade067035b2018-11-28 17:35:25 -0800605}
606
607
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700608/**
609 * @brief Semi-private method to add a buffer full of bytes to encoded output.
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800610 *
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700611 * @param[in] pMe The encoding context to add the string to.
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700612 * @param[in] uMajorType The CBOR major type of the bytes.
613 * @param[in] Bytes The bytes to add.
614 *
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700615 * Called by inline functions to add text and byte strings.
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700616 *
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700617 * (This used to support QCBOREncode_AddEncoded() and
618 * QCBOREncode_AddBytesLenOnly(), but that was pulled out to make this
619 * smaller. This is one of the most used methods and they are some of
620 * the least used).
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700621 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700622void
623QCBOREncode_Private_AddBuffer(QCBOREncodeContext *pMe,
624 const uint8_t uMajorType,
625 const UsefulBufC Bytes)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700626{
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700627 QCBOREncode_Private_AppendCBORHead(pMe, uMajorType, Bytes.len, 0);
Laurence Lundblade15b93d42024-02-07 17:39:10 -0800628 UsefulOutBuf_AppendUsefulBuf(&(pMe->OutBuf), Bytes);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700629}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700630
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700631
Laurence Lundblade55a24832018-10-30 04:35:08 +0700632/*
Laurence Lundbladed253e412024-08-21 11:02:56 -0700633 * Public function for adding raw encoded CBOR. See qcbor/qcbor_encode.h
Laurence Lundblade55a24832018-10-30 04:35:08 +0700634 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700635void
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700636QCBOREncode_AddEncoded(QCBOREncodeContext *pMe, const UsefulBufC Encoded)
Laurence Lundblade55a24832018-10-30 04:35:08 +0700637{
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700638 UsefulOutBuf_AppendUsefulBuf(&(pMe->OutBuf), Encoded);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700639 QCBOREncode_Private_IncrementMapOrArrayCount(pMe);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700640}
641
642
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -0700643#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade8d9e0cd2024-05-25 18:12:19 -0700644/**
645 * @brief Semi-private method to add a double using preferred encoding.
646 *
647 * @param[in] pMe The encode context.
648 * @param[in] dNum The double to add.
649 *
650 * This converts the double to a float or half-precision if it can be done
651 * without a loss of precision. See QCBOREncode_AddDouble().
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700652 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700653void
Laurence Lundblade70fc1252024-05-31 10:57:28 -0700654QCBOREncode_Private_AddPreferredDouble(QCBOREncodeContext *pMe, double dNum)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700655{
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800656 IEEE754_union FloatResult;
657 bool bNoNaNPayload;
658 struct IEEE754_ToInt IntResult;
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700659 uint64_t uNegValue;
Laurence Lundblade2feb1e12020-07-15 03:50:45 -0700660
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800661#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700662 if(IEEE754_DoubleHasNaNPayload(dNum) && !(pMe->uAllow & QCBOR_ENCODE_ALLOW_NAN_PAYLOAD)) {
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800663 pMe->uError = QCBOR_ERR_NOT_ALLOWED;
664 return;
665 }
666#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
667
668 if(pMe->uMode == QCBOR_ENCODE_MODE_DCBOR) {
669 IntResult = IEEE754_DoubleToInt(dNum);
670 switch(IntResult.type) {
671 case IEEE754_ToInt_IS_INT:
672 QCBOREncode_AddInt64(pMe, IntResult.integer.is_signed);
673 return;
674 case IEEE754_ToInt_IS_UINT:
675 QCBOREncode_AddUInt64(pMe, IntResult.integer.un_signed);
676 return;
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700677 case IEEE754_ToInt_IS_65BIT_NEG:
678 {
679 if(IntResult.integer.un_signed == 0) {
680 uNegValue = UINT64_MAX;
681 } else {
682 uNegValue = IntResult.integer.un_signed-1;
683 }
684 QCBOREncode_AddNegativeUInt64(pMe, uNegValue);
685 }
686 return;
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800687 case IEEE754_ToInt_NaN:
688 dNum = NAN;
689 bNoNaNPayload = true;
690 break;
691 case IEEE754_ToInt_NO_CONVERSION:
692 bNoNaNPayload = true;
693 }
694 } else {
695 bNoNaNPayload = false;
696 }
697
698 FloatResult = IEEE754_DoubleToSmaller(dNum, true, bNoNaNPayload);
699
700 QCBOREncode_Private_AddType7(pMe, (uint8_t)FloatResult.uSize, FloatResult.uValue);
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -0700701}
Laurence Lundblade9682a532020-06-06 18:33:04 -0700702
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -0700703
Laurence Lundblade8d9e0cd2024-05-25 18:12:19 -0700704/**
705 * @brief Semi-private method to add a float using preferred encoding.
706 *
707 * @param[in] pMe The encode context.
708 * @param[in] fNum The float to add.
709 *
710 * This converts the float to a half-precision if it can be done
711 * without a loss of precision. See QCBOREncode_AddFloat().
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800712 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700713void
Laurence Lundblade70fc1252024-05-31 10:57:28 -0700714QCBOREncode_Private_AddPreferredFloat(QCBOREncodeContext *pMe, float fNum)
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -0700715{
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800716 IEEE754_union FloatResult;
717 bool bNoNaNPayload;
718 struct IEEE754_ToInt IntResult;
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700719 uint64_t uNegValue;
Laurence Lundblade2feb1e12020-07-15 03:50:45 -0700720
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800721#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700722 if(IEEE754_SingleHasNaNPayload(fNum) && !(pMe->uAllow & QCBOR_ENCODE_ALLOW_NAN_PAYLOAD)) {
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800723 pMe->uError = QCBOR_ERR_NOT_ALLOWED;
724 return;
725 }
726#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
727
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800728 if(pMe->uMode == QCBOR_ENCODE_MODE_DCBOR) {
729 IntResult = IEEE754_SingleToInt(fNum);
730 switch(IntResult.type) {
731 case IEEE754_ToInt_IS_INT:
732 QCBOREncode_AddInt64(pMe, IntResult.integer.is_signed);
733 return;
734 case IEEE754_ToInt_IS_UINT:
735 QCBOREncode_AddUInt64(pMe, IntResult.integer.un_signed);
736 return;
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700737 case IEEE754_ToInt_IS_65BIT_NEG:
738 {
739 if(IntResult.integer.un_signed == 0) {
740 uNegValue = UINT64_MAX;
741 } else {
742 uNegValue = IntResult.integer.un_signed-1;
743 }
744 QCBOREncode_AddNegativeUInt64(pMe, uNegValue);
745 }
746 return;
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800747 case IEEE754_ToInt_NaN:
748 fNum = NAN;
749 bNoNaNPayload = true;
750 break;
751 case IEEE754_ToInt_NO_CONVERSION:
752 bNoNaNPayload = true;
753 }
754 } else {
755 bNoNaNPayload = false;
756 }
757
758 FloatResult = IEEE754_SingleToHalf(fNum, bNoNaNPayload);
759
760 QCBOREncode_Private_AddType7(pMe, (uint8_t)FloatResult.uSize, FloatResult.uValue);
Laurence Lundblade067035b2018-11-28 17:35:25 -0800761}
Laurence Lundbladed253e412024-08-21 11:02:56 -0700762#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundblade067035b2018-11-28 17:35:25 -0800763
Laurence Lundblade067035b2018-11-28 17:35:25 -0800764
765
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700766
767/* Actual addition of a positive/negative big num tag */
768static void
769QCBOREncode_Private_AddTBignum(QCBOREncodeContext *pMe,
770 const uint64_t uTag,
771 const uint8_t uTagRequirement,
772 const UsefulBufC BigNum)
773{
774 if(uTagRequirement == QCBOR_ENCODE_AS_TAG) {
Laurence Lundblade721b56e2024-10-22 03:02:04 -0700775 QCBOREncode_AddTagNumber(pMe, uTag);
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700776 }
777 QCBOREncode_AddBytes(pMe, BigNum);
778}
779
780
781/* Add a positive/negative big num, non-preferred */
782static void
783QCBOREncode_Private_AddTBignumNoPreferred(QCBOREncodeContext *pMe,
784 const uint64_t uTag,
785 const uint8_t uTagRequirement,
786 const UsefulBufC BigNum)
787{
788#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
789 if(pMe->uMode >= QCBOR_ENCODE_MODE_PREFERRED) {
790 pMe->uError = QCBOR_ERR_NOT_PREFERRED;
791 return;
792 }
793#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
794
795 QCBOREncode_Private_AddTBignum(pMe, uTag, uTagRequirement, BigNum);
796}
797
798
799/* Is there a carry when you add 1 to the BigNum? */
800static bool
801QCBOREncode_Private_BigNumCarry(UsefulBufC BigNum)
802{
803 bool bCarry;
804 UsefulBufC SubBigNum;
805
806 if(BigNum.len == 0) {
807 return true; /* Adding one to zero-length string gives a carry */
808 } else {
809 SubBigNum = UsefulBuf_Tail(BigNum, 1);
810 bCarry = QCBOREncode_Private_BigNumCarry(SubBigNum);
811 if(*(const uint8_t *)BigNum.ptr == 0x00 && bCarry) {
812 return true;
813 } else {
814 return false;
815 }
816 }
817}
818
819
820/*
821 * Output negative bignum bytes with subtraction of 1
822 */
823void
824QCBOREncode_Private_AddTNegativeBignum(QCBOREncodeContext *pMe,
825 const uint8_t uTagRequirement,
826 const UsefulBufC BigNum)
827{
828 size_t uLen;
829 bool bCarry;
830 bool bCopiedSomething;
831 uint8_t uByte;
832 UsefulBufC SubString;
833 UsefulBufC NextSubString;
834
835 if(uTagRequirement == QCBOR_ENCODE_AS_TAG) {
Laurence Lundblade721b56e2024-10-22 03:02:04 -0700836 QCBOREncode_AddTagNumber(pMe, CBOR_TAG_NEG_BIGNUM);
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700837 }
838
839 /* This works on any length without the need of an additional buffer */
840
841 /* This subtracts one, possibly making the string shorter by one
842 * 0x01 -> 0x00
843 * 0x01 0x00 -> 0xff
844 * 0x00 0x01 0x00 -> 0x00 0xff
845 * 0x02 0x00 -> 0x01 0xff
846 * 0xff -> 0xfe
847 * 0xff 0x00 -> 0xfe 0xff
848 * 0x01 0x00 0x00 -> 0xff 0xff
849 */
850
851 /* Compute the length up front because it goes in the head */
852 bCarry = QCBOREncode_Private_BigNumCarry(UsefulBuf_Tail(BigNum, 1));
853 uLen = BigNum.len;
854 if(bCarry && *(const uint8_t *)BigNum.ptr >= 1 && BigNum.len > 1) {
855 uLen--;
856 }
857 QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_TYPE_BYTE_STRING, uLen, 0);
858
859 SubString = BigNum;
860 bCopiedSomething = false;
861 while(SubString.len) {
862 uByte = *((const uint8_t *)SubString.ptr);
863 NextSubString = UsefulBuf_Tail(SubString, 1);
864 bCarry = QCBOREncode_Private_BigNumCarry(NextSubString);
865 if(bCarry) {
866 uByte--;
867 }
868 if(bCopiedSomething || NextSubString.len == 0 || uByte != 0) { /* No leading zeros, but one zero is OK */
869 UsefulOutBuf_AppendByte(&(pMe->OutBuf), uByte);
870 bCopiedSomething = true;
871 }
872 SubString = NextSubString;
873 }
874}
875
876
877static UsefulBufC
878QCBOREncode_Private_RemoveLeadingZeros(UsefulBufC String)
879{
880 while(String.len > 1) {
881 if(*(const uint8_t *)String.ptr) {
882 break;
883 }
884 String.len--;
885 String.ptr = (const uint8_t *)String.ptr + 1;
886 }
887
888 return String;
889}
890
891
892/*
893 * Public function. See qcbor/qcbor_encode.h
894 */
895void
896QCBOREncode_AddTNegativeBignumNoPreferred(QCBOREncodeContext *pMe,
897 const uint8_t uTagRequirement,
898 const UsefulBufC BigNum)
899{
900#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
901 if(pMe->uMode >= QCBOR_ENCODE_MODE_PREFERRED) {
902 pMe->uError = QCBOR_ERR_NOT_PREFERRED;
903 return;
904 }
905#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
906
907 if(UsefulBuf_IsValue(BigNum, 0) == SIZE_MAX) {
908 pMe->uError = QCBOR_ERR_NO_NEGATIVE_ZERO;
909 return;
910 }
911
912 if(pMe->uConfig & QCBOR_ENCODE_CONFIG_V1_COMPAT) {
913 QCBOREncode_Private_AddTBignum(pMe, CBOR_TAG_NEG_BIGNUM, uTagRequirement, BigNum);
914 } else {
915 QCBOREncode_Private_AddTNegativeBignum(pMe, uTagRequirement, QCBOREncode_Private_RemoveLeadingZeros(BigNum));
916 }
917}
918
919
920void
921QCBOREncode_AddTNegativeBignumNoPreferredToMap(QCBOREncodeContext *pMe,
922 const char *szLabel,
923 uint8_t uTagRequirement,
924 UsefulBufC BigNumber)
925{
926 QCBOREncode_AddSZString(pMe, szLabel);
927 QCBOREncode_AddTNegativeBignumNoPreferred(pMe, uTagRequirement, BigNumber);
928}
929
930
931void
932QCBOREncode_AddTNegativeBignumNoPreferredToMapN(QCBOREncodeContext *pMe,
933 int64_t nLabel,
934 uint8_t uTagRequirement,
935 UsefulBufC BigNumber)
936{
937 QCBOREncode_AddInt64(pMe, nLabel);
938 QCBOREncode_AddTNegativeBignumNoPreferred(pMe, uTagRequirement, BigNumber);
939}
940
941/*
942 * Public function. See qcbor/qcbor_encode.h
943 */
944void
945QCBOREncode_AddTPositiveBignumNoPreferred(QCBOREncodeContext *pMe,
946 const uint8_t uTagRequirement,
947 const UsefulBufC BigNum)
948{
949 QCBOREncode_Private_AddTBignumNoPreferred(pMe, CBOR_TAG_POS_BIGNUM, uTagRequirement, BigNum);
950}
951
952void
953QCBOREncode_AddTPositiveBignumNoPreferredToMap(QCBOREncodeContext *pMe,
954 const char *szLabel,
955 const uint8_t uTagRequirement,
956 const UsefulBufC BigNum)
957{
958 QCBOREncode_AddSZString(pMe, szLabel);
959 QCBOREncode_Private_AddTBignumNoPreferred(pMe, CBOR_TAG_POS_BIGNUM, uTagRequirement, BigNum);
960}
961
962void
963QCBOREncode_AddTPositiveBignumNoPreferredToMapN(QCBOREncodeContext *pMe,
964 int64_t nLabel,
965 const uint8_t uTagRequirement,
966 const UsefulBufC BigNum)
967{
968 QCBOREncode_AddInt64(pMe, nLabel);
969 QCBOREncode_Private_AddTBignumNoPreferred(pMe, CBOR_TAG_POS_BIGNUM, uTagRequirement, BigNum);
970}
971
972
973
974
975/* This will return an erroneous value if BigNum.len > 8 */
976/* Convert from bignum to uint with endianess conversion */
977static uint64_t
978QCBOREncode_Private_BigNumToUInt(const UsefulBufC BigNum)
979{
980 uint64_t uInt;
981 size_t uIndex;
982
983 uInt = 0;
984 for(uIndex = 0; uIndex < BigNum.len; uIndex++) {
985 uInt = (uInt << 8) + ((const uint8_t *)BigNum.ptr)[uIndex];
986 }
987
988 return uInt;
989}
990
991
992/*
993 * Public function. See qcbor/qcbor_encode.h
994 */
995void
996QCBOREncode_AddTPositiveBignum(QCBOREncodeContext *pMe,
997 const uint8_t uTagRequirement,
998 const UsefulBufC BigNum)
999{
1000 if(pMe->uConfig & QCBOR_ENCODE_CONFIG_V1_COMPAT) {
1001 QCBOREncode_AddTPositiveBignumNoPreferred(pMe, uTagRequirement, BigNum);
1002 } else {
1003 const UsefulBufC BigNumNLZ = QCBOREncode_Private_RemoveLeadingZeros(BigNum);
1004 if(BigNumNLZ.len <= 8) {
1005 /* Preferred serialization requires conversion to type 0 */
1006 QCBOREncode_AddUInt64(pMe, QCBOREncode_Private_BigNumToUInt(BigNumNLZ));
1007 } else {
1008 QCBOREncode_Private_AddTBignum(pMe, CBOR_TAG_POS_BIGNUM, uTagRequirement, BigNumNLZ);
1009 }
1010 }
1011}
1012
1013
1014/*
1015 * Public function. See qcbor/qcbor_encode.h
1016 */
1017void
1018QCBOREncode_AddTNegativeBignum(QCBOREncodeContext *pMe,
1019 const uint8_t uTagRequirement,
1020 const UsefulBufC BigNum)
1021{
1022 uint64_t uInt;
1023 bool bIs2exp64;
1024 static const uint8_t twoExp64[] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
1025
1026 if(UsefulBuf_IsValue(BigNum, 0) == SIZE_MAX) {
1027 pMe->uError = QCBOR_ERR_NO_NEGATIVE_ZERO;
1028 return;
1029 }
1030
1031 if(pMe->uConfig & QCBOR_ENCODE_CONFIG_V1_COMPAT) {
1032 QCBOREncode_AddTNegativeBignumNoPreferred(pMe, uTagRequirement, BigNum);
1033
1034 } else {
1035 /* Here we do preferred serialization. That requires removal of leading zeros */
1036 const UsefulBufC BigNumNLZ = QCBOREncode_Private_RemoveLeadingZeros(BigNum);
1037
1038 bIs2exp64 = ! UsefulBuf_Compare(BigNumNLZ, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(twoExp64));
1039
1040 if(BigNumNLZ.len <= 8 || bIs2exp64) {
1041 /* Must convert to CBOR type 1, a negative integer */
1042 if(bIs2exp64) {
1043 /* 2^64 is a 9 byte big number. Since negative numbers are offset
1044 * by one in CBOR, it can be encoded as a type 1 negative. The
1045 * conversion below won't work because the uInt will overflow
1046 * before the subtraction of 1.
1047 */
1048 uInt = UINT64_MAX;
1049 } else {
1050 uInt = QCBOREncode_Private_BigNumToUInt(BigNumNLZ);
1051 uInt--; /* CBOR's negative offset of 1 */
1052 }
1053 QCBOREncode_AddNegativeUInt64(pMe, uInt);
1054
1055 } else {
1056 QCBOREncode_Private_AddTNegativeBignum(pMe, uTagRequirement, BigNumNLZ);
1057 }
1058 }
1059}
1060
1061
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07001062#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001063/**
1064 * @brief Semi-private method to add bigfloats and decimal fractions.
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001065 *
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001066 * @param[in] pMe The encoding context to add the value to.
1067 * @param[in] uTag The type 6 tag indicating what this is to be.
1068 * @param[in] BigNumMantissa Is @ref NULLUsefulBufC if mantissa is an
1069 * @c int64_t or the actual big number mantissa
1070 * if not.
1071 * @param[in] bBigNumIsNegative This is @c true if the big number is negative.
1072 * @param[in] nMantissa The @c int64_t mantissa if it is not a big number.
1073 * @param[in] nExponent The exponent.
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001074 *
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001075 * This outputs either the @ref CBOR_TAG_DECIMAL_FRACTION or
1076 * @ref CBOR_TAG_BIGFLOAT tag. if @c uTag is @ref CBOR_TAG_INVALID64,
1077 * then this outputs the "borrowed" content format.
1078 *
1079 * The tag content output by this is an array with two members, the
1080 * exponent and then the mantissa. The mantissa can be either a big
1081 * number or an @c int64_t.
1082 *
1083 * This implementation cannot output an exponent further from 0 than
1084 * @c INT64_MAX.
1085 *
1086 * To output a mantissa that is between INT64_MAX and UINT64_MAX from 0,
1087 * it must be as a big number.
1088 *
1089 * Typically, QCBOREncode_AddDecimalFraction(), QCBOREncode_AddBigFloat(),
1090 * QCBOREncode_AddDecimalFractionBigNum() or QCBOREncode_AddBigFloatBigNum()
1091 * is called instead of this.
Laurence Lundblade59289e52019-12-30 13:44:37 -08001092 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001093void
1094QCBOREncode_Private_AddExpMantissa(QCBOREncodeContext *pMe,
1095 const uint64_t uTag,
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001096 const int64_t nExponent,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001097 const UsefulBufC BigNumMantissa,
1098 const bool bBigNumIsNegative,
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001099 const int64_t nMantissa)
Laurence Lundblade59289e52019-12-30 13:44:37 -08001100{
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001101 /* This is for encoding either a big float or a decimal fraction,
1102 * both of which are an array of two items, an exponent and a
1103 * mantissa. The difference between the two is that the exponent
1104 * is base-2 for big floats and base-10 for decimal fractions, but
1105 * that has no effect on the code here.
Laurence Lundbladeee851742020-01-08 08:37:05 -08001106 */
Laurence Lundbladeae66d3f2020-09-14 18:12:08 -07001107 if(uTag != CBOR_TAG_INVALID64) {
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001108 QCBOREncode_AddTagNumber(pMe, uTag);
Laurence Lundbladeae66d3f2020-09-14 18:12:08 -07001109 }
Laurence Lundblade59289e52019-12-30 13:44:37 -08001110 QCBOREncode_OpenArray(pMe);
1111 QCBOREncode_AddInt64(pMe, nExponent);
1112 if(!UsefulBuf_IsNULLC(BigNumMantissa)) {
1113 if(bBigNumIsNegative) {
1114 QCBOREncode_AddNegativeBignum(pMe, BigNumMantissa);
1115 } else {
1116 QCBOREncode_AddPositiveBignum(pMe, BigNumMantissa);
1117 }
1118 } else {
1119 QCBOREncode_AddInt64(pMe, nMantissa);
1120 }
1121 QCBOREncode_CloseArray(pMe);
1122}
Laurence Lundbladed253e412024-08-21 11:02:56 -07001123#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade59289e52019-12-30 13:44:37 -08001124
1125
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001126/**
1127 * @brief Semi-private method to open a map, array or bstr-wrapped CBOR
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001128 *
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001129 * @param[in] pMe The context to add to.
1130 * @param[in] uMajorType The major CBOR type to close
1131 *
1132 * Call QCBOREncode_OpenArray(), QCBOREncode_OpenMap() or
1133 * QCBOREncode_BstrWrap() instead of this.
Laurence Lundblade274ddef2022-05-17 09:12:23 -07001134 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001135void
1136QCBOREncode_Private_OpenMapOrArray(QCBOREncodeContext *pMe,
1137 const uint8_t uMajorType)
Laurence Lundblade067035b2018-11-28 17:35:25 -08001138{
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001139 /* Add one item to the nesting level we are in for the new map or array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001140 QCBOREncode_Private_IncrementMapOrArrayCount(pMe);
Laurence Lundbladed39cd392019-01-11 18:17:38 -08001141
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001142 /* The offset where the length of an array or map will get written
1143 * is stored in a uint32_t, not a size_t to keep stack usage
1144 * smaller. This checks to be sure there is no wrap around when
1145 * recording the offset. Note that on 64-bit machines CBOR larger
1146 * than 4GB can be encoded as long as no array/map offsets occur
1147 * past the 4GB mark, but the public interface says that the
1148 * maximum is 4GB to keep the discussion simpler.
1149 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001150 size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(pMe->OutBuf));
Laurence Lundbladed39cd392019-01-11 18:17:38 -08001151
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001152 /* QCBOR_MAX_ARRAY_OFFSET is slightly less than UINT32_MAX so this
1153 * code can run on a 32-bit machine and tests can pass on a 32-bit
1154 * machine. If it was exactly UINT32_MAX, then this code would not
1155 * compile or run on a 32-bit machine and an #ifdef or some machine
1156 * size detection would be needed reducing portability.
1157 */
Laurence Lundblade3e0a45c2020-11-05 11:12:04 -08001158 if(uEndPosition >= QCBOR_MAX_ARRAY_OFFSET) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001159 pMe->uError = QCBOR_ERR_BUFFER_TOO_LARGE;
Laurence Lundblade3e0a45c2020-11-05 11:12:04 -08001160
1161 } else {
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001162 /* Increase nesting level because this is a map or array. Cast
1163 * from size_t to uin32_t is safe because of check above.
1164 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001165 pMe->uError = Nesting_Increase(&(pMe->nesting), uMajorType, (uint32_t)uEndPosition);
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -08001166 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001167}
1168
Laurence Lundblade59289e52019-12-30 13:44:37 -08001169
Laurence Lundbladecbd7d132024-05-19 11:11:22 -07001170#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001171/**
1172 * @brief Semi-private method to open a map, array with indefinite length
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001173 *
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001174 * @param[in] pMe The context to add to.
1175 * @param[in] uMajorType The major CBOR type to close
1176 *
1177 * Call QCBOREncode_OpenArrayIndefiniteLength() or
1178 * QCBOREncode_OpenMapIndefiniteLength() instead of this.
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001179 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001180void
1181QCBOREncode_Private_OpenMapOrArrayIndefiniteLength(QCBOREncodeContext *pMe,
1182 const uint8_t uMajorType)
Jan Jongboom4a93a662019-07-25 08:44:58 +02001183{
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -08001184#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
1185 if(pMe->uMode >= QCBOR_ENCODE_MODE_PREFERRED) {
1186 pMe->uError = QCBOR_ERR_NOT_PREFERRED;
1187 return;
1188 }
1189#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001190 /* Insert the indefinite length marker (0x9f for arrays, 0xbf for maps) */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001191 QCBOREncode_Private_AppendCBORHead(pMe, uMajorType, 0, 0);
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001192
1193 /* Call the definite-length opener just to do the bookkeeping for
1194 * nesting. It will record the position of the opening item in the
1195 * encoded output but this is not used when closing this open.
1196 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001197 QCBOREncode_Private_OpenMapOrArray(pMe, uMajorType);
Jan Jongboom4a93a662019-07-25 08:44:58 +02001198}
Laurence Lundbladed253e412024-08-21 11:02:56 -07001199#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundbladecbd7d132024-05-19 11:11:22 -07001200
1201
1202/**
1203 * @brief Check for errors when decreasing nesting.
1204 *
1205 * @param pMe QCBOR encoding context.
1206 * @param uMajorType The major type of the nesting.
1207 *
1208 * Check that there is no previous error, that there is actually some
1209 * nesting and that the major type of the opening of the nesting
1210 * matches the major type of the nesting being closed.
1211 *
1212 * This is called when closing maps, arrays, byte string wrapping and
1213 * open/close of byte strings.
1214 */
1215static bool
1216QCBOREncode_Private_CheckDecreaseNesting(QCBOREncodeContext *pMe,
1217 const uint8_t uMajorType)
1218{
1219#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
1220 if(pMe->uError != QCBOR_SUCCESS) {
1221 return true;
1222 }
1223
1224 if(!Nesting_IsInNest(&(pMe->nesting))) {
1225 pMe->uError = QCBOR_ERR_TOO_MANY_CLOSES;
1226 return true;
1227 }
1228
1229 if(Nesting_GetMajorType(&(pMe->nesting)) != uMajorType) {
1230 pMe->uError = QCBOR_ERR_CLOSE_MISMATCH;
1231 return true;
1232 }
1233
Laurence Lundbladed253e412024-08-21 11:02:56 -07001234#else /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
Laurence Lundbladecbd7d132024-05-19 11:11:22 -07001235 /* None of these checks are performed if the encode guards are
1236 * turned off as they all relate to correct calling.
1237 *
1238 * Turning off all these checks does not turn off any checking for
1239 * buffer overflows or pointer issues.
1240 */
1241
1242 (void)uMajorType;
1243 (void)pMe;
Laurence Lundbladed253e412024-08-21 11:02:56 -07001244#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
Laurence Lundbladecbd7d132024-05-19 11:11:22 -07001245
1246 return false;
1247}
1248
1249
1250/**
Laurence Lundbladed253e412024-08-21 11:02:56 -07001251 * @brief Insert the CBOR head for a map, array or wrapped bstr.
Laurence Lundbladecbd7d132024-05-19 11:11:22 -07001252 *
1253 * @param pMe QCBOR encoding context.
1254 * @param uMajorType One of CBOR_MAJOR_TYPE_XXXX.
1255 * @param uLen The length of the data item.
1256 *
1257 * When an array, map or bstr was opened, nothing was done but note
1258 * the position. This function goes back to that position and inserts
1259 * the CBOR Head with the major type and length.
1260 */
1261static void
1262QCBOREncode_Private_CloseAggregate(QCBOREncodeContext *pMe,
1263 uint8_t uMajorType,
1264 size_t uLen)
1265{
1266 if(QCBOREncode_Private_CheckDecreaseNesting(pMe, uMajorType)) {
1267 return;
1268 }
1269
1270 if(uMajorType == CBOR_MAJOR_NONE_TYPE_OPEN_BSTR) {
1271 uMajorType = CBOR_MAJOR_TYPE_BYTE_STRING;
1272 }
1273
1274 /* A stack buffer large enough for a CBOR head (9 bytes) */
1275 UsefulBuf_MAKE_STACK_UB(pBufferForEncodedHead, QCBOR_HEAD_BUFFER_SIZE);
1276
1277 UsefulBufC EncodedHead = QCBOREncode_EncodeHead(pBufferForEncodedHead,
1278 uMajorType,
1279 0,
1280 uLen);
1281
1282 /* No check for EncodedHead == NULLUsefulBufC is performed here to
1283 * save object code. It is very clear that pBufferForEncodedHead is
1284 * the correct size. If EncodedHead == NULLUsefulBufC then
1285 * UsefulOutBuf_InsertUsefulBuf() will do nothing so there is no
1286 * security hole introduced.
1287 */
1288 UsefulOutBuf_InsertUsefulBuf(&(pMe->OutBuf),
1289 EncodedHead,
1290 Nesting_GetStartPos(&(pMe->nesting)));
1291
1292 Nesting_Decrease(&(pMe->nesting));
1293}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001294
Laurence Lundbladeee851742020-01-08 08:37:05 -08001295
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001296/**
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -08001297 * @brief Semi-private method to close a map, array or bstr wrapped CBOR.
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001298 *
1299 * @param[in] pMe The context to add to.
1300 * @param[in] uMajorType The major CBOR type to close.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001301 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001302void
1303QCBOREncode_Private_CloseMapOrArray(QCBOREncodeContext *pMe,
1304 const uint8_t uMajorType)
Laurence Lundbladea954db92018-09-28 19:27:31 -07001305{
Laurence Lundbladecbd7d132024-05-19 11:11:22 -07001306 QCBOREncode_Private_CloseAggregate(pMe, uMajorType, Nesting_GetCount(&(pMe->nesting)));
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +00001307}
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001308
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001309
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -08001310/**
1311 * @brief Private method to close a map without sorting.
1312 *
1313 * @param[in] pMe The encode context with map to close.
1314 *
1315 * See QCBOREncode_SerializationCDE() implemention for explantion for why
1316 * this exists in this form.
1317 */
1318static void
1319QCBOREncode_Private_CloseMapUnsorted(QCBOREncodeContext *pMe)
1320{
1321 QCBOREncode_Private_CloseMapOrArray(pMe, CBOR_MAJOR_TYPE_MAP);
1322}
1323
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001324
1325/**
1326 * @brief Decode a CBOR item head.
1327 *
1328 * @param[in] pUInBuf UsefulInputBuf to read from.
1329 * @param[out] pnMajorType Major type of decoded head.
1330 * @param[out] puArgument Argument of decoded head.
1331 * @param[out] pnAdditionalInfo Additional info from decoded head.
1332 *
1333 * @return SUCCESS if a head was decoded
1334 * HIT_END if there were not enough bytes to decode a head
1335 * UNSUPPORTED if the decoded item is not one that is supported
1336 *
1337 * This is copied from qcbor_decode.c rather than referenced. This
1338 * makes the core decoder 60 bytes smaller because it gets inlined.
1339 * It would not get inlined if it was referenced. It is important to
1340 * make the core decoder as small as possible. The copy here does make
1341 * map sorting 200 bytes bigger, but map sorting is rarely used in
1342 * environments that need small object code. It would also make
1343 * qcbor_encode.c depend on qcbor_decode.c
1344 *
1345 * This is also super stable and tested. It implements the very
1346 * well-defined part of CBOR that will never change. So this won't
1347 * change.
1348 */
1349static QCBORError
1350QCBOREncodePriv_DecodeHead(UsefulInputBuf *pUInBuf,
1351 int *pnMajorType,
1352 uint64_t *puArgument,
1353 int *pnAdditionalInfo)
1354{
1355 QCBORError uReturn;
1356
1357 /* Get the initial byte that every CBOR data item has and break it
1358 * down. */
1359 const int nInitialByte = (int)UsefulInputBuf_GetByte(pUInBuf);
1360 const int nTmpMajorType = nInitialByte >> 5;
1361 const int nAdditionalInfo = nInitialByte & 0x1f;
1362
1363 /* Where the argument accumulates */
1364 uint64_t uArgument;
1365
1366 if(nAdditionalInfo >= LEN_IS_ONE_BYTE && nAdditionalInfo <= LEN_IS_EIGHT_BYTES) {
1367 /* Need to get 1,2,4 or 8 additional argument bytes. Map
1368 * LEN_IS_ONE_BYTE..LEN_IS_EIGHT_BYTES to actual length.
1369 */
1370 static const uint8_t aIterate[] = {1,2,4,8};
1371
1372 /* Loop getting all the bytes in the argument */
1373 uArgument = 0;
1374 for(int i = aIterate[nAdditionalInfo - LEN_IS_ONE_BYTE]; i; i--) {
1375 /* This shift and add gives the endian conversion. */
1376 uArgument = (uArgument << 8) + UsefulInputBuf_GetByte(pUInBuf);
1377 }
1378 } else if(nAdditionalInfo >= ADDINFO_RESERVED1 && nAdditionalInfo <= ADDINFO_RESERVED3) {
1379 /* The reserved and thus-far unused additional info values */
1380 uReturn = QCBOR_ERR_UNSUPPORTED;
1381 goto Done;
1382 } else {
1383 /* Less than 24, additional info is argument or 31, an
1384 * indefinite-length. No more bytes to get.
1385 */
1386 uArgument = (uint64_t)nAdditionalInfo;
1387 }
1388
1389 if(UsefulInputBuf_GetError(pUInBuf)) {
1390 uReturn = QCBOR_ERR_HIT_END;
1391 goto Done;
1392 }
1393
1394 /* All successful if arrived here. */
1395 uReturn = QCBOR_SUCCESS;
1396 *pnMajorType = nTmpMajorType;
1397 *puArgument = uArgument;
1398 *pnAdditionalInfo = nAdditionalInfo;
1399
1400Done:
1401 return uReturn;
1402}
1403
1404
1405/**
1406 * @brief Consume the next item from a UsefulInputBuf.
1407 *
1408 * @param[in] pInBuf UsefulInputBuf from which to consume item.
1409 *
1410 * Recursive, but stack usage is light and encoding depth limit
1411 */
1412static QCBORError
Laurence Lundblade3b703b82024-01-27 20:17:20 -07001413QCBOR_Private_ConsumeNext(UsefulInputBuf *pInBuf)
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001414{
1415 int nMajor;
1416 uint64_t uArgument;
1417 int nAdditional;
1418 uint16_t uItemCount;
1419 uint16_t uMul;
1420 uint16_t i;
1421 QCBORError uCBORError;
1422
1423 uCBORError = QCBOREncodePriv_DecodeHead(pInBuf, &nMajor, &uArgument, &nAdditional);
1424 if(uCBORError != QCBOR_SUCCESS) {
1425 return uCBORError;
1426 }
1427
1428 uMul = 1;
1429
1430 switch(nMajor) {
1431 case CBOR_MAJOR_TYPE_POSITIVE_INT: /* Major type 0 */
1432 case CBOR_MAJOR_TYPE_NEGATIVE_INT: /* Major type 1 */
1433 break;
1434
1435 case CBOR_MAJOR_TYPE_SIMPLE:
1436 return uArgument == CBOR_SIMPLE_BREAK ? 1 : 0;
1437 break;
1438
1439 case CBOR_MAJOR_TYPE_BYTE_STRING:
1440 case CBOR_MAJOR_TYPE_TEXT_STRING:
1441 if(nAdditional == LEN_IS_INDEFINITE) {
1442 /* Segments of indefinite length */
Laurence Lundblade3b703b82024-01-27 20:17:20 -07001443 while(QCBOR_Private_ConsumeNext(pInBuf) == 0);
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001444 }
1445 (void)UsefulInputBuf_GetBytes(pInBuf, uArgument);
1446 break;
1447
1448 case CBOR_MAJOR_TYPE_TAG:
Laurence Lundblade3b703b82024-01-27 20:17:20 -07001449 QCBOR_Private_ConsumeNext(pInBuf);
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001450 break;
1451
1452 case CBOR_MAJOR_TYPE_MAP:
1453 uMul = 2;
1454 /* Fallthrough */
1455 case CBOR_MAJOR_TYPE_ARRAY:
1456 uItemCount = (uint16_t)uArgument * uMul;
1457 if(nAdditional == LEN_IS_INDEFINITE) {
1458 uItemCount = UINT16_MAX;
1459 }
1460 for(i = uItemCount; i > 0; i--) {
Laurence Lundblade3b703b82024-01-27 20:17:20 -07001461 if(QCBOR_Private_ConsumeNext(pInBuf)) {
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001462 /* End of indefinite length */
1463 break;
1464 }
1465 }
1466 break;
1467 }
1468
1469 return QCBOR_SUCCESS;
1470}
1471
1472
1473/**
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001474 * @brief Decoded next item to get its lengths.
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001475 *
1476 * Decode the next item in map no matter what type it is. It works
1477 * recursively when an item is a map or array It returns offset just
1478 * past the item decoded or zero there are no more items in the output
1479 * buffer.
1480 *
1481 * This doesn't distinguish between end of the input and an error
1482 * because it is used to decode stuff we encoded into a buffer, not
1483 * stuff that came in from outside. We still want a check for safety
1484 * in case of bugs here, but it is OK to report end of input on error.
1485 */
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001486struct ItemLens {
1487 uint32_t uLabelLen;
1488 uint32_t uItemLen;
1489};
1490
1491static struct ItemLens
Laurence Lundblade3b703b82024-01-27 20:17:20 -07001492QCBOREncode_Private_DecodeNextInMap(QCBOREncodeContext *pMe, uint32_t uStart)
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001493{
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001494 UsefulInputBuf InBuf;
1495 UsefulBufC EncodedMapBytes;
1496 QCBORError uCBORError;
1497 struct ItemLens Result;
1498
1499 Result.uLabelLen = 0;
1500 Result.uItemLen = 0;
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001501
1502 EncodedMapBytes = UsefulOutBuf_OutUBufOffset(&(pMe->OutBuf), uStart);
1503 if(UsefulBuf_IsNULLC(EncodedMapBytes)) {
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001504 return Result;
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001505 }
1506
1507 UsefulInputBuf_Init(&InBuf, EncodedMapBytes);
1508
1509 /* This is always used on maps, so consume two, the label and the value */
Laurence Lundblade3b703b82024-01-27 20:17:20 -07001510 uCBORError = QCBOR_Private_ConsumeNext(&InBuf);
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001511 if(uCBORError) {
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001512 return Result;
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001513 }
1514
1515 /* Cast is safe because this is QCBOR which limits sizes to UINT32_MAX */
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001516 Result.uLabelLen = (uint32_t)UsefulInputBuf_Tell(&InBuf);
1517
1518 uCBORError = QCBOR_Private_ConsumeNext(&InBuf);
1519 if(uCBORError) {
1520 Result.uLabelLen = 0;
1521 return Result;
1522 }
1523
1524 Result.uItemLen = (uint32_t)UsefulInputBuf_Tell(&InBuf);
1525
1526 /* Cast is safe because this is QCBOR which limits sizes to UINT32_MAX */
1527 return Result;
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001528}
1529
1530
1531/**
1532 * @brief Sort items lexographically by encoded labels.
1533 *
1534 * @param[in] pMe Encoding context.
1535 * @param[in] uStart Offset in outbuf of first item for sorting.
1536 *
1537 * This reaches into the UsefulOutBuf in the encoding context and
1538 * sorts encoded CBOR items. The byte offset start of the items is at
1539 * @c uStart and it goes to the end of valid bytes in the
1540 * UsefulOutBuf.
1541 */
1542static void
Laurence Lundblade3b703b82024-01-27 20:17:20 -07001543QCBOREncode_Private_SortMap(QCBOREncodeContext *pMe, uint32_t uStart)
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001544{
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001545 bool bSwapped;
1546 int nComparison;
1547 uint32_t uStart1;
1548 uint32_t uStart2;
1549 struct ItemLens Lens1;
1550 struct ItemLens Lens2;
1551
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001552
1553 if(pMe->uError != QCBOR_SUCCESS) {
1554 return;
1555 }
1556
1557 /* Bubble sort because the sizes of all the items are not the
1558 * same. It works with adjacent pairs so the swap is not too
1559 * difficult even though sizes are different.
1560 *
1561 * While bubble sort is n-squared, it seems OK here because n will
1562 * usually be small and the comparison and swap functions aren't
1563 * too CPU intensive.
1564 *
1565 * Another approach would be to have an array of offsets to the
1566 * items. However this requires memory allocation and the swap
1567 * operation for quick sort or such is complicated because the item
1568 * sizes are not the same and overlap may occur in the bytes being
1569 * swapped.
1570 */
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001571 do { /* Loop until nothing was swapped */
1572 Lens1 = QCBOREncode_Private_DecodeNextInMap(pMe, uStart);
1573 if(Lens1.uLabelLen == 0) {
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001574 /* It's an empty map. Nothing to do. */
1575 break;
1576 }
1577 uStart1 = uStart;
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001578 uStart2 = uStart1 + Lens1.uItemLen;
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001579 bSwapped = false;
1580
1581 while(1) {
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001582 Lens2 = QCBOREncode_Private_DecodeNextInMap(pMe, uStart2);
1583 if(Lens2.uLabelLen == 0) {
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001584 break;
1585 }
1586
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001587 nComparison = UsefulOutBuf_Compare(&(pMe->OutBuf),
1588 uStart1, Lens1.uLabelLen,
1589 uStart2, Lens2.uLabelLen);
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001590 if(nComparison < 0) {
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001591 UsefulOutBuf_Swap(&(pMe->OutBuf), uStart1, uStart2, uStart2 + Lens2.uItemLen);
1592 uStart1 = uStart1 + Lens2.uItemLen; /* item 2 now in position of item 1 */
1593 /* Lens1 is still valid as Lens1 for the next loop */
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001594 bSwapped = true;
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001595 } else if(nComparison > 0) {
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001596 uStart1 = uStart2;
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001597 Lens1 = Lens2;
1598 } else /* nComparison == 0 */ {
1599 pMe->uError = QCBOR_ERR_DUPLICATE_LABEL;
1600 return;
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001601 }
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001602 uStart2 = uStart2 + Lens2.uItemLen;
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001603 }
1604 } while(bSwapped);
1605}
1606
1607
1608/*
1609 * Public functions for closing sorted maps. See qcbor/qcbor_encode.h
1610 */
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001611void
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001612QCBOREncode_CloseAndSortMap(QCBOREncodeContext *pMe)
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001613{
1614 uint32_t uStart;
1615
1616 /* The Header for the map we are about to sort hasn't been
1617 * inserted yet, so uStart is the position of the first item
1618 * and the end out the UsefulOutBuf data is the end of the
1619 * items we are about to sort.
1620 */
1621 uStart = Nesting_GetStartPos(&(pMe->nesting));
Laurence Lundblade3b703b82024-01-27 20:17:20 -07001622 QCBOREncode_Private_SortMap(pMe, uStart);
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001623
Laurence Lundblade70fc1252024-05-31 10:57:28 -07001624 QCBOREncode_Private_CloseAggregate(pMe, CBOR_MAJOR_TYPE_MAP, Nesting_GetCount(&(pMe->nesting)));
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001625}
1626
1627
Laurence Lundbladed3f07842024-06-19 13:05:07 -07001628#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001629/*
1630 * Public functions for closing sorted maps. See qcbor/qcbor_encode.h
1631 */
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001632void
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001633QCBOREncode_CloseAndSortMapIndef(QCBOREncodeContext *pMe)
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001634{
1635 uint32_t uStart;
1636
1637 uStart = Nesting_GetStartPos(&(pMe->nesting));
Laurence Lundblade3b703b82024-01-27 20:17:20 -07001638 QCBOREncode_Private_SortMap(pMe, uStart);
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001639
Laurence Lundblade3b703b82024-01-27 20:17:20 -07001640 QCBOREncode_Private_CloseMapOrArrayIndefiniteLength(pMe, CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN);
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001641}
Laurence Lundbladed3f07842024-06-19 13:05:07 -07001642#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001643
1644
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +00001645/*
Laurence Lundbladed253e412024-08-21 11:02:56 -07001646 * Public function for closing bstr wrapping. See qcbor/qcbor_encode.h
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +00001647 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001648void
1649QCBOREncode_CloseBstrWrap2(QCBOREncodeContext *pMe,
1650 const bool bIncludeCBORHead,
1651 UsefulBufC *pWrappedCBOR)
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +00001652{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001653 const size_t uInsertPosition = Nesting_GetStartPos(&(pMe->nesting));
1654 const size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(pMe->OutBuf));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001655
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001656 /* This subtraction can't go negative because the UsefulOutBuf
1657 * always only grows and never shrinks. UsefulOutBut itself also
1658 * has defenses such that it won't write where it should not even
1659 * if given incorrect input lengths.
1660 */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +00001661 const size_t uBstrLen = uEndPosition - uInsertPosition;
1662
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001663 /* Actually insert */
Laurence Lundbladecbd7d132024-05-19 11:11:22 -07001664 QCBOREncode_Private_CloseAggregate(pMe, CBOR_MAJOR_TYPE_BYTE_STRING, uBstrLen);
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +00001665
1666 if(pWrappedCBOR) {
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001667 /* Return pointer and length to the enclosed encoded CBOR. The
1668 * intended use is for it to be hashed (e.g., SHA-256) in a COSE
1669 * implementation. This must be used right away, as the pointer
1670 * and length go invalid on any subsequent calls to this
1671 * function because there might be calls to
1672 * InsertEncodedTypeAndNumber() that slides data to the right.
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +00001673 */
1674 size_t uStartOfNew = uInsertPosition;
1675 if(!bIncludeCBORHead) {
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001676 /* Skip over the CBOR head to just get the inserted bstr */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001677 const size_t uNewEndPosition = UsefulOutBuf_GetEndPosition(&(pMe->OutBuf));
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +00001678 uStartOfNew += uNewEndPosition - uEndPosition;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001679 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001680 const UsefulBufC PartialResult = UsefulOutBuf_OutUBuf(&(pMe->OutBuf));
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +00001681 *pWrappedCBOR = UsefulBuf_Tail(PartialResult, uStartOfNew);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001682 }
1683}
1684
Laurence Lundbladeee851742020-01-08 08:37:05 -08001685
Jan Jongboom4a93a662019-07-25 08:44:58 +02001686/*
Laurence Lundblade8d3b8552021-06-10 11:11:54 -07001687 * Public function for canceling a bstr wrap. See qcbor/qcbor_encode.h
1688 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001689void
1690QCBOREncode_CancelBstrWrap(QCBOREncodeContext *pMe)
Laurence Lundblade8d3b8552021-06-10 11:11:54 -07001691{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001692 if(QCBOREncode_Private_CheckDecreaseNesting(pMe, CBOR_MAJOR_TYPE_BYTE_STRING)) {
Laurence Lundblade274ddef2022-05-17 09:12:23 -07001693 return;
1694 }
1695
Laurence Lundblade8d3b8552021-06-10 11:11:54 -07001696#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
Laurence Lundblade274ddef2022-05-17 09:12:23 -07001697 const size_t uCurrent = UsefulOutBuf_GetEndPosition(&(pMe->OutBuf));
1698 if(pMe->nesting.pCurrentNesting->uStart != uCurrent) {
1699 pMe->uError = QCBOR_ERR_CANNOT_CANCEL;
1700 return;
Laurence Lundblade8d3b8552021-06-10 11:11:54 -07001701 }
1702 /* QCBOREncode_CancelBstrWrap() can't correctly undo
1703 * QCBOREncode_BstrWrapInMap() or QCBOREncode_BstrWrapInMapN(). It
1704 * can't undo the labels they add. It also doesn't catch the error
1705 * of using it this way. QCBOREncode_CancelBstrWrap() is used
1706 * infrequently and the the result is incorrect CBOR, not a
1707 * security hole, so no extra code or state is added to handle this
1708 * condition.
1709 */
Laurence Lundbladed253e412024-08-21 11:02:56 -07001710#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
Laurence Lundblade8d3b8552021-06-10 11:11:54 -07001711
1712 Nesting_Decrease(&(pMe->nesting));
1713 Nesting_Decrement(&(pMe->nesting));
1714}
1715
1716
1717/*
Laurence Lundbladeb24faef2022-04-26 11:03:08 -06001718 * Public function for opening a byte string. See qcbor/qcbor_encode.h
1719 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001720void
1721QCBOREncode_OpenBytes(QCBOREncodeContext *pMe, UsefulBuf *pPlace)
Laurence Lundbladeb24faef2022-04-26 11:03:08 -06001722{
1723 *pPlace = UsefulOutBuf_GetOutPlace(&(pMe->OutBuf));
Laurence Lundbladeb24faef2022-04-26 11:03:08 -06001724#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
Paul Liétar79789772022-07-26 20:33:18 +01001725 uint8_t uMajorType = Nesting_GetMajorType(&(pMe->nesting));
1726 if(uMajorType == CBOR_MAJOR_NONE_TYPE_OPEN_BSTR) {
Laurence Lundblade716d10c2024-02-07 16:54:42 -08001727 /* It's OK to nest a byte string in any type but
1728 * another open byte string. */
Paul Liétar79789772022-07-26 20:33:18 +01001729 pMe->uError = QCBOR_ERR_OPEN_BYTE_STRING;
1730 return;
1731 }
Laurence Lundbladed253e412024-08-21 11:02:56 -07001732#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
Laurence Lundbladeb24faef2022-04-26 11:03:08 -06001733
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001734 QCBOREncode_Private_OpenMapOrArray(pMe, CBOR_MAJOR_NONE_TYPE_OPEN_BSTR);
Laurence Lundbladeb24faef2022-04-26 11:03:08 -06001735}
1736
1737
1738/*
1739 * Public function for closing a byte string. See qcbor/qcbor_encode.h
1740 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001741void
1742QCBOREncode_CloseBytes(QCBOREncodeContext *pMe, const size_t uAmount)
Laurence Lundbladeb24faef2022-04-26 11:03:08 -06001743{
1744 UsefulOutBuf_Advance(&(pMe->OutBuf), uAmount);
1745 if(UsefulOutBuf_GetError(&(pMe->OutBuf))) {
1746 /* Advance too far. Normal off-end error handling in effect here. */
1747 return;
1748 }
1749
Laurence Lundbladecbd7d132024-05-19 11:11:22 -07001750 QCBOREncode_Private_CloseAggregate(pMe, CBOR_MAJOR_NONE_TYPE_OPEN_BSTR, uAmount);
Laurence Lundbladeb24faef2022-04-26 11:03:08 -06001751}
1752
1753
Laurence Lundbladecbd7d132024-05-19 11:11:22 -07001754#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001755/**
1756 * @brief Semi-private method to close a map, array with indefinite length
1757 *
1758 * @param[in] pMe The context to add to.
1759 * @param[in] uMajorType The major CBOR type to close.
1760 *
1761 * Call QCBOREncode_CloseArrayIndefiniteLength() or
1762 * QCBOREncode_CloseMapIndefiniteLength() instead of this.
Jan Jongboom4a93a662019-07-25 08:44:58 +02001763 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001764void
1765QCBOREncode_Private_CloseMapOrArrayIndefiniteLength(QCBOREncodeContext *pMe,
1766 const uint8_t uMajorType)
Jan Jongboom4a93a662019-07-25 08:44:58 +02001767{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001768 if(QCBOREncode_Private_CheckDecreaseNesting(pMe, uMajorType)) {
Laurence Lundblade274ddef2022-05-17 09:12:23 -07001769 return;
Jan Jongboom4a93a662019-07-25 08:44:58 +02001770 }
Laurence Lundbladedaefdec2020-11-02 20:22:03 -08001771
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001772 /* Append the break marker (0xff for both arrays and maps) */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001773 QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_NONE_TYPE_SIMPLE_BREAK, CBOR_SIMPLE_BREAK, 0);
Laurence Lundblade274ddef2022-05-17 09:12:23 -07001774 Nesting_Decrease(&(pMe->nesting));
Jan Jongboom4a93a662019-07-25 08:44:58 +02001775}
Laurence Lundbladed253e412024-08-21 11:02:56 -07001776#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Jan Jongboom4a93a662019-07-25 08:44:58 +02001777
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001778
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001779/*
Laurence Lundblade8d3b8552021-06-10 11:11:54 -07001780 * Public function to finish and get the encoded result. See qcbor/qcbor_encode.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001781 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001782QCBORError
1783QCBOREncode_Finish(QCBOREncodeContext *pMe, UsefulBufC *pEncodedCBOR)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001784{
Laurence Lundbladef2f0c3f2024-04-12 13:01:54 -07001785 if(QCBOREncode_GetErrorState(pMe) != QCBOR_SUCCESS) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001786 goto Done;
Laurence Lundblade067035b2018-11-28 17:35:25 -08001787 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001788
Laurence Lundbladedaefdec2020-11-02 20:22:03 -08001789#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001790 if(Nesting_IsInNest(&(pMe->nesting))) {
Laurence Lundbladef2f0c3f2024-04-12 13:01:54 -07001791 pMe->uError = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001792 goto Done;
1793 }
Laurence Lundbladed253e412024-08-21 11:02:56 -07001794#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001795
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001796 *pEncodedCBOR = UsefulOutBuf_OutUBuf(&(pMe->OutBuf));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001797
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001798Done:
Laurence Lundbladef2f0c3f2024-04-12 13:01:54 -07001799 return pMe->uError;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001800}
1801
Laurence Lundblade0595e932018-11-02 22:22:47 +07001802
Laurence Lundblade067035b2018-11-28 17:35:25 -08001803/*
Laurence Lundbladed253e412024-08-21 11:02:56 -07001804 * Public function to get size of the encoded result. See qcbor/qcbor_encode.h
Laurence Lundblade067035b2018-11-28 17:35:25 -08001805 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001806QCBORError
1807QCBOREncode_FinishGetSize(QCBOREncodeContext *pMe, size_t *puEncodedLen)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001808{
Laurence Lundbladeda3f0822018-09-18 19:49:02 -07001809 UsefulBufC Enc;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001810
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001811 QCBORError nReturn = QCBOREncode_Finish(pMe, &Enc);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001812
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001813 if(nReturn == QCBOR_SUCCESS) {
Laurence Lundbladeda3f0822018-09-18 19:49:02 -07001814 *puEncodedLen = Enc.len;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001815 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001816
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001817 return nReturn;
1818}
Laurence Lundbladee2226742024-08-16 10:50:23 -07001819
1820
1821/*
1822 * Public function to get substring of encoded-so-far. See qcbor/qcbor_encode.h
1823 */
1824UsefulBufC
1825QCBOREncode_SubString(QCBOREncodeContext *pMe, const size_t uStart)
1826{
1827 if(pMe->uError) {
1828 return NULLUsefulBufC;
1829 }
1830
1831 /* An attempt was made to detect usage errors by comparing uStart
1832 * to offsets of open arrays and maps in pMe->nesting, but it is
1833 * not possible because there's not enough information in just
1834 * the offset. It's not possible to known if Tell() was called before
1835 * or after an Open(). To detect this error, the nesting level
1836 * would also need to be known. This is not frequently used, so
1837 * it is not worth adding this complexity.
1838 */
1839
1840 const size_t uEnd = QCBOREncode_Tell(pMe);
1841
1842 return UsefulOutBuf_SubString(&(pMe->OutBuf), uStart, uEnd - uStart);
1843}