blob: a8f01fefcf10dd146cfc9228b7b1861f952770c2 [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
Laurence Lundblade68769332024-11-03 13:09:20 -0800767/**
768 * @brief Convert a big number to unsigned integer.
769 *
770 * @param[in] BigNumber Big number to convert.
771 *
772 * @return Converted unsigned.
773 *
774 * The big number must be less than 8 bytes long.
775 **/
776static uint64_t
777QCBOREncode_Private_BigNumberToUInt(const UsefulBufC BigNumber)
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700778{
Laurence Lundblade68769332024-11-03 13:09:20 -0800779 uint64_t uInt;
780 size_t uIndex;
781
782 uInt = 0;
783 for(uIndex = 0; uIndex < BigNumber.len; uIndex++) {
784 uInt = (uInt << 8) + UsefulBufC_NTH_BYTE(BigNumber, uIndex);
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700785 }
Laurence Lundblade68769332024-11-03 13:09:20 -0800786
787 return uInt;
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700788}
789
790
Laurence Lundblade68769332024-11-03 13:09:20 -0800791/**
792 * @brief Is there a carry when you subtract 1 from the BigNumber.
793 *
794 * @param[in] BigNumber Big number to check for carry.
795 *
796 * @return If there is a carry, \c true.
797 *
Laurence Lundblade05369de2024-11-17 17:00:28 -0800798 * If this returns @c true, then @c BigNumber - 1 is one byte shorter
799 * than @c BigNumber.
Laurence Lundblade68769332024-11-03 13:09:20 -0800800 **/
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700801static bool
Laurence Lundblade68769332024-11-03 13:09:20 -0800802QCBOREncode_Private_BigNumberCarry(const UsefulBufC BigNumber)
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700803{
804 bool bCarry;
805 UsefulBufC SubBigNum;
806
Laurence Lundblade68769332024-11-03 13:09:20 -0800807 // Improvement: rework without recursion?
808
809 if(BigNumber.len == 0) {
810 return true; /* Subtracting one from zero-length string gives a carry */
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700811 } else {
Laurence Lundblade68769332024-11-03 13:09:20 -0800812 SubBigNum = UsefulBuf_Tail(BigNumber, 1);
813 bCarry = QCBOREncode_Private_BigNumberCarry(SubBigNum);
814 if(UsefulBufC_NTH_BYTE(BigNumber, 0) == 0x00 && bCarry) {
815 /* Subtracting one from 0 gives a carry */
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700816 return true;
817 } else {
818 return false;
819 }
820 }
821}
822
823
Laurence Lundblade05369de2024-11-17 17:00:28 -0800824/**
Laurence Lundblade68769332024-11-03 13:09:20 -0800825 * @brief Output negative bignum bytes with subtraction of 1.
826 *
827 * @param[in] pMe The decode context.
828 * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or
829 * @ref QCBOR_ENCODE_AS_BORROWED.
830 * @param[in] BigNumber The negative big number.
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700831 */
Laurence Lundblade68769332024-11-03 13:09:20 -0800832static void
833QCBOREncode_Private_AddTNegativeBigNumber(QCBOREncodeContext *pMe,
834 const uint8_t uTagRequirement,
835 const UsefulBufC BigNumber)
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700836{
837 size_t uLen;
838 bool bCarry;
839 bool bCopiedSomething;
840 uint8_t uByte;
841 UsefulBufC SubString;
842 UsefulBufC NextSubString;
843
Laurence Lundblade68769332024-11-03 13:09:20 -0800844 QCBOREncode_Private_BigNumberTag(pMe, uTagRequirement, true);
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700845
846 /* This works on any length without the need of an additional buffer */
847
848 /* This subtracts one, possibly making the string shorter by one
849 * 0x01 -> 0x00
850 * 0x01 0x00 -> 0xff
851 * 0x00 0x01 0x00 -> 0x00 0xff
852 * 0x02 0x00 -> 0x01 0xff
853 * 0xff -> 0xfe
854 * 0xff 0x00 -> 0xfe 0xff
855 * 0x01 0x00 0x00 -> 0xff 0xff
Laurence Lundblade68769332024-11-03 13:09:20 -0800856 *
857 * This outputs the big number a byte at a time to be able to operate on
858 * a big number of any length without memory allocation.
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700859 */
860
Laurence Lundblade68769332024-11-03 13:09:20 -0800861 /* Compute the length up front because it goes in the encoded head */
862 bCarry = QCBOREncode_Private_BigNumberCarry(UsefulBuf_Tail(BigNumber, 1));
863 uLen = BigNumber.len;
864 if(bCarry && BigNumber.len > 1 && UsefulBufC_NTH_BYTE(BigNumber, 0) >= 1) {
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700865 uLen--;
866 }
Laurence Lundblade05369de2024-11-17 17:00:28 -0800867 QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_TYPE_BYTE_STRING, uLen,0);
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700868
Laurence Lundblade68769332024-11-03 13:09:20 -0800869 SubString = BigNumber;
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700870 bCopiedSomething = false;
871 while(SubString.len) {
Laurence Lundblade68769332024-11-03 13:09:20 -0800872 uByte = UsefulBufC_NTH_BYTE(SubString, 0);
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700873 NextSubString = UsefulBuf_Tail(SubString, 1);
Laurence Lundblade68769332024-11-03 13:09:20 -0800874 bCarry = QCBOREncode_Private_BigNumberCarry(NextSubString);
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700875 if(bCarry) {
876 uByte--;
877 }
Laurence Lundblade68769332024-11-03 13:09:20 -0800878 /* This avoids all but the last leading zero. See
879 * QCBOREncode_Private_SkipLeadingZeros() */
880 if(bCopiedSomething || NextSubString.len == 0 || uByte != 0) {
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700881 UsefulOutBuf_AppendByte(&(pMe->OutBuf), uByte);
882 bCopiedSomething = true;
883 }
884 SubString = NextSubString;
885 }
886}
887
888
Laurence Lundblade68769332024-11-03 13:09:20 -0800889/**
Laurence Lundblade68769332024-11-03 13:09:20 -0800890 * @brief Remove leading zeros.
891 *
Laurence Lundblade05369de2024-11-17 17:00:28 -0800892 * @param[in] BigNumber The big number.
Laurence Lundblade68769332024-11-03 13:09:20 -0800893 *
894 * @return Big number with no leading zeros.
895 *
Laurence Lundblade05369de2024-11-17 17:00:28 -0800896 * If the big number is all zeros, this returns a big number that is
897 * one zero rather than the empty string.
Laurence Lundblade68769332024-11-03 13:09:20 -0800898 *
Laurence Lundblade05369de2024-11-17 17:00:28 -0800899 * RFC 8949 3.4.3 does not explicitly decoders MUST handle the empty
900 * string, but does say decoders MUST handle leading zeros. So
901 * Postel's Law is applied here and 0 is not encoded as an empty
902 * string.
Laurence Lundblade68769332024-11-03 13:09:20 -0800903 */
904static UsefulBufC
905QCBOREncode_Private_SkipLeadingZeros(const UsefulBufC BigNumber)
906{
907 UsefulBufC NLZ;
908 NLZ = UsefulBuf_SkipLeading(BigNumber, 0x00);
909
910 /* An all-zero string reduces to one 0, not an empty string. */
Laurence Lundblade05369de2024-11-17 17:00:28 -0800911 if(NLZ.len == 0 &&
912 BigNumber.len > 0 &&
913 UsefulBufC_NTH_BYTE(BigNumber, 0) == 0x00) {
914 NLZ.len = 1;
Laurence Lundblade68769332024-11-03 13:09:20 -0800915 }
916
917 return NLZ;
918}
919
920
Laurence Lundblade05369de2024-11-17 17:00:28 -0800921/**
922 * @brief Output a big number, preferred or not, with negative offset
923 *
924 * @param[in] pMe The decode context.
925 * @param[in] uTagRequirement Either @ref QCBOR_ENCODE_AS_TAG or
926 * @ref QCBOR_ENCODE_AS_BORROWED.
927 * @param[in] bPreferred Uses preferred serialization if true
928 * @param[in] bNegative Indicates big number is negative or postive.
929 * @param[in] BigNumber The big number.
930 *
931 * Regardless of whether preferred serialization is used, if the big
932 * number is negative, one is subtracted before is output per CBOR
933 * convetion for big numbers. This requires a little big number
934 * arithmetic and adds some object code.
935 *
936 * If preferred serialization is used, then if the number is smaller
937 * than UINT64_MAX and postive it is output as type 0 and if it is
938 * equal to or smaller than UINT64_MAX it is output as a type 1
939 * integer minus one.
940 *
941 * See QCBOREncode_AddTBigNumberRaw() for simple copy through.
Laurence Lundblade68769332024-11-03 13:09:20 -0800942 */
943void
Laurence Lundblade05369de2024-11-17 17:00:28 -0800944QCBOREncode_Private_AddTBigNumberMain(QCBOREncodeContext *pMe,
945 const uint8_t uTagRequirement,
946 const bool bPreferred,
947 const bool bNegative,
948 const UsefulBufC BigNumber)
Laurence Lundblade68769332024-11-03 13:09:20 -0800949{
Laurence Lundblade05369de2024-11-17 17:00:28 -0800950 uint64_t uInt;
951 bool bIs2exp64;
952 uint8_t uMajorType;
953 UsefulBufC BigNumberNLZ;
Laurence Lundblade68769332024-11-03 13:09:20 -0800954
Laurence Lundblade05369de2024-11-17 17:00:28 -0800955 BigNumberNLZ = QCBOREncode_Private_SkipLeadingZeros(BigNumber);
Laurence Lundblade68769332024-11-03 13:09:20 -0800956
Laurence Lundblade05369de2024-11-17 17:00:28 -0800957 static const uint8_t twoExp64[] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
958 bIs2exp64 = ! UsefulBuf_Compare(BigNumber, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(twoExp64));
959
960 if(bPreferred && (BigNumberNLZ.len <= 8 || (bNegative && bIs2exp64))) {
961 if(bIs2exp64) {
962 /* 2^64 is a 9 byte big number. Since negative numbers are offset
963 * by one in CBOR, it can be encoded as a type 1 negative. The
964 * conversion below won't work because the uInt will overflow
965 * before the subtraction of 1.
966 */
967 uInt = UINT64_MAX;
Laurence Lundblade68769332024-11-03 13:09:20 -0800968 } else {
Laurence Lundblade05369de2024-11-17 17:00:28 -0800969 uInt = QCBOREncode_Private_BigNumberToUInt(BigNumberNLZ);
970 if(bNegative) {
971 uInt--;
972 }
973 }
974 uMajorType = bNegative ? CBOR_MAJOR_TYPE_NEGATIVE_INT :
975 CBOR_MAJOR_TYPE_POSITIVE_INT;
976 QCBOREncode_Private_AppendCBORHead(pMe, uMajorType, uInt, 0);
977 } else {
978 if(bNegative) {
Laurence Lundblade68769332024-11-03 13:09:20 -0800979 QCBOREncode_Private_AddTNegativeBigNumber(pMe, uTagRequirement, BigNumberNLZ);
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700980 } else {
Laurence Lundblade05369de2024-11-17 17:00:28 -0800981 QCBOREncode_AddTBigNumberRaw(pMe, false, uTagRequirement, BigNumberNLZ);
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700982 }
983 }
984}
985
986
Laurence Lundblade68769332024-11-03 13:09:20 -0800987
988
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -0700989#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700990/**
991 * @brief Semi-private method to add bigfloats and decimal fractions.
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800992 *
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700993 * @param[in] pMe The encoding context to add the value to.
Laurence Lundblade68769332024-11-03 13:09:20 -0800994 * @param[in] uTagNumber The type 6 tag indicating what this is to be.
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700995 * @param[in] nMantissa The @c int64_t mantissa if it is not a big number.
996 * @param[in] nExponent The exponent.
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800997 *
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700998 * This outputs either the @ref CBOR_TAG_DECIMAL_FRACTION or
999 * @ref CBOR_TAG_BIGFLOAT tag. if @c uTag is @ref CBOR_TAG_INVALID64,
1000 * then this outputs the "borrowed" content format.
1001 *
1002 * The tag content output by this is an array with two members, the
1003 * exponent and then the mantissa. The mantissa can be either a big
1004 * number or an @c int64_t.
1005 *
1006 * This implementation cannot output an exponent further from 0 than
1007 * @c INT64_MAX.
1008 *
1009 * To output a mantissa that is between INT64_MAX and UINT64_MAX from 0,
1010 * it must be as a big number.
1011 *
Laurence Lundblade0f143652024-10-06 11:06:19 -07001012 * Typically, QCBOREncode_AddTDecimalFraction(), QCBOREncode_AddTBigFloat(),
1013 * QCBOREncode_AddTDecimalFractionBigNum() or QCBOREncode_AddTBigFloatBigNum()
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001014 * is called instead of this.
Laurence Lundblade59289e52019-12-30 13:44:37 -08001015 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001016void
Laurence Lundblade68769332024-11-03 13:09:20 -08001017QCBOREncode_Private_AddTExpIntMantissa(QCBOREncodeContext *pMe,
1018 const int uTagRequirement,
1019 const uint64_t uTagNumber,
1020 const int64_t nExponent,
1021 const int64_t nMantissa)
Laurence Lundblade59289e52019-12-30 13:44:37 -08001022{
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001023 /* This is for encoding either a big float or a decimal fraction,
1024 * both of which are an array of two items, an exponent and a
1025 * mantissa. The difference between the two is that the exponent
1026 * is base-2 for big floats and base-10 for decimal fractions, but
1027 * that has no effect on the code here.
Laurence Lundbladeee851742020-01-08 08:37:05 -08001028 */
Laurence Lundblade68769332024-11-03 13:09:20 -08001029 /* Separate from QCBOREncode_Private_AddTExpBigMantissa() because
1030 * linking QCBOREncode_AddTBigNumber() adds a lot because it
1031 * does preferred serialization of big numbers and the offset of 1
1032 * for CBOR negative numbers.
1033 */
1034 if(uTagRequirement == QCBOR_ENCODE_AS_TAG) {
1035 QCBOREncode_AddTagNumber(pMe, uTagNumber);
Laurence Lundbladeae66d3f2020-09-14 18:12:08 -07001036 }
Laurence Lundblade59289e52019-12-30 13:44:37 -08001037 QCBOREncode_OpenArray(pMe);
1038 QCBOREncode_AddInt64(pMe, nExponent);
Laurence Lundblade68769332024-11-03 13:09:20 -08001039 QCBOREncode_AddInt64(pMe, nMantissa);
Laurence Lundblade59289e52019-12-30 13:44:37 -08001040 QCBOREncode_CloseArray(pMe);
1041}
Laurence Lundblade68769332024-11-03 13:09:20 -08001042
1043void
1044QCBOREncode_Private_AddTExpBigMantissa(QCBOREncodeContext *pMe,
1045 const int uTagRequirement,
1046 const uint64_t uTagNumber,
1047 const int64_t nExponent,
1048 const UsefulBufC BigNumMantissa,
1049 const bool bBigNumIsNegative)
1050{
1051 /* This is for encoding either a big float or a decimal fraction,
1052 * both of which are an array of two items, an exponent and a
1053 * mantissa. The difference between the two is that the exponent
1054 * is base-2 for big floats and base-10 for decimal fractions, but
1055 * that has no effect on the code here.
1056 */
1057 if(uTagRequirement == QCBOR_ENCODE_AS_TAG) {
Laurence Lundblade05369de2024-11-17 17:00:28 -08001058 QCBOREncode_AddTagNumber(pMe, uTagNumber);
Laurence Lundblade68769332024-11-03 13:09:20 -08001059 }
1060 QCBOREncode_OpenArray(pMe);
1061 QCBOREncode_AddInt64(pMe, nExponent);
1062 QCBOREncode_AddTBigNumber(pMe, QCBOR_ENCODE_AS_TAG, bBigNumIsNegative, BigNumMantissa);
1063 QCBOREncode_CloseArray(pMe);
1064}
1065
1066
1067void
1068QCBOREncode_Private_AddTExpBigMantissaRaw(QCBOREncodeContext *pMe,
1069 const int uTagRequirement,
1070 const uint64_t uTagNumber,
1071 const int64_t nExponent,
1072 const UsefulBufC BigNumMantissa,
1073 const bool bBigNumIsNegative)
1074{
1075 /* This is for encoding either a big float or a decimal fraction,
1076 * both of which are an array of two items, an exponent and a
1077 * mantissa. The difference between the two is that the exponent
1078 * is base-2 for big floats and base-10 for decimal fractions, but
1079 * that has no effect on the code here.
1080 */
1081 /* Separate from QCBOREncode_Private_AddTExpBigMantissa() because
1082 * linking QCBOREncode_AddTBigNumber() adds a lot because it
1083 * does preferred serialization of big numbers and the offset of 1
1084 * for CBOR negative numbers.
1085 */
1086 if(uTagRequirement == QCBOR_ENCODE_AS_TAG) {
Laurence Lundblade05369de2024-11-17 17:00:28 -08001087 QCBOREncode_AddTagNumber(pMe, uTagNumber);
Laurence Lundblade68769332024-11-03 13:09:20 -08001088 }
1089 QCBOREncode_OpenArray(pMe);
1090 QCBOREncode_AddInt64(pMe, nExponent);
1091 QCBOREncode_AddTBigNumberRaw(pMe, QCBOR_ENCODE_AS_TAG, bBigNumIsNegative, BigNumMantissa);
1092 QCBOREncode_CloseArray(pMe);
1093}
1094
Laurence Lundbladed253e412024-08-21 11:02:56 -07001095#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade59289e52019-12-30 13:44:37 -08001096
1097
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001098/**
1099 * @brief Semi-private method to open a map, array or bstr-wrapped CBOR
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001100 *
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001101 * @param[in] pMe The context to add to.
1102 * @param[in] uMajorType The major CBOR type to close
1103 *
1104 * Call QCBOREncode_OpenArray(), QCBOREncode_OpenMap() or
1105 * QCBOREncode_BstrWrap() instead of this.
Laurence Lundblade274ddef2022-05-17 09:12:23 -07001106 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001107void
1108QCBOREncode_Private_OpenMapOrArray(QCBOREncodeContext *pMe,
1109 const uint8_t uMajorType)
Laurence Lundblade067035b2018-11-28 17:35:25 -08001110{
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001111 /* Add one item to the nesting level we are in for the new map or array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001112 QCBOREncode_Private_IncrementMapOrArrayCount(pMe);
Laurence Lundbladed39cd392019-01-11 18:17:38 -08001113
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001114 /* The offset where the length of an array or map will get written
1115 * is stored in a uint32_t, not a size_t to keep stack usage
1116 * smaller. This checks to be sure there is no wrap around when
1117 * recording the offset. Note that on 64-bit machines CBOR larger
1118 * than 4GB can be encoded as long as no array/map offsets occur
1119 * past the 4GB mark, but the public interface says that the
1120 * maximum is 4GB to keep the discussion simpler.
1121 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001122 size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(pMe->OutBuf));
Laurence Lundbladed39cd392019-01-11 18:17:38 -08001123
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001124 /* QCBOR_MAX_ARRAY_OFFSET is slightly less than UINT32_MAX so this
1125 * code can run on a 32-bit machine and tests can pass on a 32-bit
1126 * machine. If it was exactly UINT32_MAX, then this code would not
1127 * compile or run on a 32-bit machine and an #ifdef or some machine
1128 * size detection would be needed reducing portability.
1129 */
Laurence Lundblade3e0a45c2020-11-05 11:12:04 -08001130 if(uEndPosition >= QCBOR_MAX_ARRAY_OFFSET) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001131 pMe->uError = QCBOR_ERR_BUFFER_TOO_LARGE;
Laurence Lundblade3e0a45c2020-11-05 11:12:04 -08001132
1133 } else {
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001134 /* Increase nesting level because this is a map or array. Cast
1135 * from size_t to uin32_t is safe because of check above.
1136 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001137 pMe->uError = Nesting_Increase(&(pMe->nesting), uMajorType, (uint32_t)uEndPosition);
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -08001138 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001139}
1140
Laurence Lundblade59289e52019-12-30 13:44:37 -08001141
Laurence Lundbladecbd7d132024-05-19 11:11:22 -07001142#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001143/**
1144 * @brief Semi-private method to open a map, array with indefinite length
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001145 *
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001146 * @param[in] pMe The context to add to.
1147 * @param[in] uMajorType The major CBOR type to close
1148 *
1149 * Call QCBOREncode_OpenArrayIndefiniteLength() or
1150 * QCBOREncode_OpenMapIndefiniteLength() instead of this.
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001151 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001152void
1153QCBOREncode_Private_OpenMapOrArrayIndefiniteLength(QCBOREncodeContext *pMe,
1154 const uint8_t uMajorType)
Jan Jongboom4a93a662019-07-25 08:44:58 +02001155{
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -08001156#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
1157 if(pMe->uMode >= QCBOR_ENCODE_MODE_PREFERRED) {
1158 pMe->uError = QCBOR_ERR_NOT_PREFERRED;
1159 return;
1160 }
1161#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001162 /* Insert the indefinite length marker (0x9f for arrays, 0xbf for maps) */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001163 QCBOREncode_Private_AppendCBORHead(pMe, uMajorType, 0, 0);
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001164
1165 /* Call the definite-length opener just to do the bookkeeping for
1166 * nesting. It will record the position of the opening item in the
1167 * encoded output but this is not used when closing this open.
1168 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001169 QCBOREncode_Private_OpenMapOrArray(pMe, uMajorType);
Jan Jongboom4a93a662019-07-25 08:44:58 +02001170}
Laurence Lundbladed253e412024-08-21 11:02:56 -07001171#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundbladecbd7d132024-05-19 11:11:22 -07001172
1173
1174/**
1175 * @brief Check for errors when decreasing nesting.
1176 *
1177 * @param pMe QCBOR encoding context.
1178 * @param uMajorType The major type of the nesting.
1179 *
1180 * Check that there is no previous error, that there is actually some
1181 * nesting and that the major type of the opening of the nesting
1182 * matches the major type of the nesting being closed.
1183 *
1184 * This is called when closing maps, arrays, byte string wrapping and
1185 * open/close of byte strings.
1186 */
1187static bool
1188QCBOREncode_Private_CheckDecreaseNesting(QCBOREncodeContext *pMe,
1189 const uint8_t uMajorType)
1190{
1191#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
1192 if(pMe->uError != QCBOR_SUCCESS) {
1193 return true;
1194 }
1195
1196 if(!Nesting_IsInNest(&(pMe->nesting))) {
1197 pMe->uError = QCBOR_ERR_TOO_MANY_CLOSES;
1198 return true;
1199 }
1200
1201 if(Nesting_GetMajorType(&(pMe->nesting)) != uMajorType) {
1202 pMe->uError = QCBOR_ERR_CLOSE_MISMATCH;
1203 return true;
1204 }
1205
Laurence Lundbladed253e412024-08-21 11:02:56 -07001206#else /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
Laurence Lundbladecbd7d132024-05-19 11:11:22 -07001207 /* None of these checks are performed if the encode guards are
1208 * turned off as they all relate to correct calling.
1209 *
1210 * Turning off all these checks does not turn off any checking for
1211 * buffer overflows or pointer issues.
1212 */
1213
1214 (void)uMajorType;
1215 (void)pMe;
Laurence Lundbladed253e412024-08-21 11:02:56 -07001216#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
Laurence Lundbladecbd7d132024-05-19 11:11:22 -07001217
1218 return false;
1219}
1220
1221
1222/**
Laurence Lundbladed253e412024-08-21 11:02:56 -07001223 * @brief Insert the CBOR head for a map, array or wrapped bstr.
Laurence Lundbladecbd7d132024-05-19 11:11:22 -07001224 *
1225 * @param pMe QCBOR encoding context.
1226 * @param uMajorType One of CBOR_MAJOR_TYPE_XXXX.
1227 * @param uLen The length of the data item.
1228 *
1229 * When an array, map or bstr was opened, nothing was done but note
1230 * the position. This function goes back to that position and inserts
1231 * the CBOR Head with the major type and length.
1232 */
1233static void
1234QCBOREncode_Private_CloseAggregate(QCBOREncodeContext *pMe,
1235 uint8_t uMajorType,
1236 size_t uLen)
1237{
1238 if(QCBOREncode_Private_CheckDecreaseNesting(pMe, uMajorType)) {
1239 return;
1240 }
1241
1242 if(uMajorType == CBOR_MAJOR_NONE_TYPE_OPEN_BSTR) {
1243 uMajorType = CBOR_MAJOR_TYPE_BYTE_STRING;
1244 }
1245
1246 /* A stack buffer large enough for a CBOR head (9 bytes) */
1247 UsefulBuf_MAKE_STACK_UB(pBufferForEncodedHead, QCBOR_HEAD_BUFFER_SIZE);
1248
1249 UsefulBufC EncodedHead = QCBOREncode_EncodeHead(pBufferForEncodedHead,
1250 uMajorType,
1251 0,
1252 uLen);
1253
1254 /* No check for EncodedHead == NULLUsefulBufC is performed here to
1255 * save object code. It is very clear that pBufferForEncodedHead is
1256 * the correct size. If EncodedHead == NULLUsefulBufC then
1257 * UsefulOutBuf_InsertUsefulBuf() will do nothing so there is no
1258 * security hole introduced.
1259 */
1260 UsefulOutBuf_InsertUsefulBuf(&(pMe->OutBuf),
1261 EncodedHead,
1262 Nesting_GetStartPos(&(pMe->nesting)));
1263
1264 Nesting_Decrease(&(pMe->nesting));
1265}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001266
Laurence Lundbladeee851742020-01-08 08:37:05 -08001267
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001268/**
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -08001269 * @brief Semi-private method to close a map, array or bstr wrapped CBOR.
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001270 *
1271 * @param[in] pMe The context to add to.
1272 * @param[in] uMajorType The major CBOR type to close.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001273 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001274void
1275QCBOREncode_Private_CloseMapOrArray(QCBOREncodeContext *pMe,
1276 const uint8_t uMajorType)
Laurence Lundbladea954db92018-09-28 19:27:31 -07001277{
Laurence Lundbladecbd7d132024-05-19 11:11:22 -07001278 QCBOREncode_Private_CloseAggregate(pMe, uMajorType, Nesting_GetCount(&(pMe->nesting)));
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +00001279}
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001280
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001281
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -08001282/**
1283 * @brief Private method to close a map without sorting.
1284 *
1285 * @param[in] pMe The encode context with map to close.
1286 *
1287 * See QCBOREncode_SerializationCDE() implemention for explantion for why
1288 * this exists in this form.
1289 */
1290static void
1291QCBOREncode_Private_CloseMapUnsorted(QCBOREncodeContext *pMe)
1292{
1293 QCBOREncode_Private_CloseMapOrArray(pMe, CBOR_MAJOR_TYPE_MAP);
1294}
1295
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001296
1297/**
1298 * @brief Decode a CBOR item head.
1299 *
1300 * @param[in] pUInBuf UsefulInputBuf to read from.
1301 * @param[out] pnMajorType Major type of decoded head.
1302 * @param[out] puArgument Argument of decoded head.
1303 * @param[out] pnAdditionalInfo Additional info from decoded head.
1304 *
1305 * @return SUCCESS if a head was decoded
1306 * HIT_END if there were not enough bytes to decode a head
1307 * UNSUPPORTED if the decoded item is not one that is supported
1308 *
1309 * This is copied from qcbor_decode.c rather than referenced. This
1310 * makes the core decoder 60 bytes smaller because it gets inlined.
1311 * It would not get inlined if it was referenced. It is important to
1312 * make the core decoder as small as possible. The copy here does make
1313 * map sorting 200 bytes bigger, but map sorting is rarely used in
1314 * environments that need small object code. It would also make
1315 * qcbor_encode.c depend on qcbor_decode.c
1316 *
1317 * This is also super stable and tested. It implements the very
1318 * well-defined part of CBOR that will never change. So this won't
1319 * change.
1320 */
1321static QCBORError
1322QCBOREncodePriv_DecodeHead(UsefulInputBuf *pUInBuf,
1323 int *pnMajorType,
1324 uint64_t *puArgument,
1325 int *pnAdditionalInfo)
1326{
1327 QCBORError uReturn;
1328
1329 /* Get the initial byte that every CBOR data item has and break it
1330 * down. */
1331 const int nInitialByte = (int)UsefulInputBuf_GetByte(pUInBuf);
1332 const int nTmpMajorType = nInitialByte >> 5;
1333 const int nAdditionalInfo = nInitialByte & 0x1f;
1334
1335 /* Where the argument accumulates */
1336 uint64_t uArgument;
1337
1338 if(nAdditionalInfo >= LEN_IS_ONE_BYTE && nAdditionalInfo <= LEN_IS_EIGHT_BYTES) {
1339 /* Need to get 1,2,4 or 8 additional argument bytes. Map
1340 * LEN_IS_ONE_BYTE..LEN_IS_EIGHT_BYTES to actual length.
1341 */
1342 static const uint8_t aIterate[] = {1,2,4,8};
1343
1344 /* Loop getting all the bytes in the argument */
1345 uArgument = 0;
1346 for(int i = aIterate[nAdditionalInfo - LEN_IS_ONE_BYTE]; i; i--) {
1347 /* This shift and add gives the endian conversion. */
1348 uArgument = (uArgument << 8) + UsefulInputBuf_GetByte(pUInBuf);
1349 }
1350 } else if(nAdditionalInfo >= ADDINFO_RESERVED1 && nAdditionalInfo <= ADDINFO_RESERVED3) {
1351 /* The reserved and thus-far unused additional info values */
1352 uReturn = QCBOR_ERR_UNSUPPORTED;
1353 goto Done;
1354 } else {
1355 /* Less than 24, additional info is argument or 31, an
1356 * indefinite-length. No more bytes to get.
1357 */
1358 uArgument = (uint64_t)nAdditionalInfo;
1359 }
1360
1361 if(UsefulInputBuf_GetError(pUInBuf)) {
1362 uReturn = QCBOR_ERR_HIT_END;
1363 goto Done;
1364 }
1365
1366 /* All successful if arrived here. */
1367 uReturn = QCBOR_SUCCESS;
1368 *pnMajorType = nTmpMajorType;
1369 *puArgument = uArgument;
1370 *pnAdditionalInfo = nAdditionalInfo;
1371
1372Done:
1373 return uReturn;
1374}
1375
1376
1377/**
1378 * @brief Consume the next item from a UsefulInputBuf.
1379 *
1380 * @param[in] pInBuf UsefulInputBuf from which to consume item.
1381 *
1382 * Recursive, but stack usage is light and encoding depth limit
1383 */
1384static QCBORError
Laurence Lundblade3b703b82024-01-27 20:17:20 -07001385QCBOR_Private_ConsumeNext(UsefulInputBuf *pInBuf)
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001386{
1387 int nMajor;
1388 uint64_t uArgument;
1389 int nAdditional;
1390 uint16_t uItemCount;
1391 uint16_t uMul;
1392 uint16_t i;
1393 QCBORError uCBORError;
1394
1395 uCBORError = QCBOREncodePriv_DecodeHead(pInBuf, &nMajor, &uArgument, &nAdditional);
1396 if(uCBORError != QCBOR_SUCCESS) {
1397 return uCBORError;
1398 }
1399
1400 uMul = 1;
1401
1402 switch(nMajor) {
1403 case CBOR_MAJOR_TYPE_POSITIVE_INT: /* Major type 0 */
1404 case CBOR_MAJOR_TYPE_NEGATIVE_INT: /* Major type 1 */
1405 break;
1406
1407 case CBOR_MAJOR_TYPE_SIMPLE:
1408 return uArgument == CBOR_SIMPLE_BREAK ? 1 : 0;
1409 break;
1410
1411 case CBOR_MAJOR_TYPE_BYTE_STRING:
1412 case CBOR_MAJOR_TYPE_TEXT_STRING:
1413 if(nAdditional == LEN_IS_INDEFINITE) {
1414 /* Segments of indefinite length */
Laurence Lundblade3b703b82024-01-27 20:17:20 -07001415 while(QCBOR_Private_ConsumeNext(pInBuf) == 0);
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001416 }
1417 (void)UsefulInputBuf_GetBytes(pInBuf, uArgument);
1418 break;
1419
1420 case CBOR_MAJOR_TYPE_TAG:
Laurence Lundblade3b703b82024-01-27 20:17:20 -07001421 QCBOR_Private_ConsumeNext(pInBuf);
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001422 break;
1423
1424 case CBOR_MAJOR_TYPE_MAP:
1425 uMul = 2;
1426 /* Fallthrough */
1427 case CBOR_MAJOR_TYPE_ARRAY:
1428 uItemCount = (uint16_t)uArgument * uMul;
1429 if(nAdditional == LEN_IS_INDEFINITE) {
1430 uItemCount = UINT16_MAX;
1431 }
1432 for(i = uItemCount; i > 0; i--) {
Laurence Lundblade3b703b82024-01-27 20:17:20 -07001433 if(QCBOR_Private_ConsumeNext(pInBuf)) {
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001434 /* End of indefinite length */
1435 break;
1436 }
1437 }
1438 break;
1439 }
1440
1441 return QCBOR_SUCCESS;
1442}
1443
1444
1445/**
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001446 * @brief Decoded next item to get its lengths.
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001447 *
1448 * Decode the next item in map no matter what type it is. It works
1449 * recursively when an item is a map or array It returns offset just
1450 * past the item decoded or zero there are no more items in the output
1451 * buffer.
1452 *
1453 * This doesn't distinguish between end of the input and an error
1454 * because it is used to decode stuff we encoded into a buffer, not
1455 * stuff that came in from outside. We still want a check for safety
1456 * in case of bugs here, but it is OK to report end of input on error.
1457 */
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001458struct ItemLens {
1459 uint32_t uLabelLen;
1460 uint32_t uItemLen;
1461};
1462
1463static struct ItemLens
Laurence Lundblade3b703b82024-01-27 20:17:20 -07001464QCBOREncode_Private_DecodeNextInMap(QCBOREncodeContext *pMe, uint32_t uStart)
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001465{
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001466 UsefulInputBuf InBuf;
1467 UsefulBufC EncodedMapBytes;
1468 QCBORError uCBORError;
1469 struct ItemLens Result;
1470
1471 Result.uLabelLen = 0;
1472 Result.uItemLen = 0;
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001473
1474 EncodedMapBytes = UsefulOutBuf_OutUBufOffset(&(pMe->OutBuf), uStart);
1475 if(UsefulBuf_IsNULLC(EncodedMapBytes)) {
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001476 return Result;
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001477 }
1478
1479 UsefulInputBuf_Init(&InBuf, EncodedMapBytes);
1480
1481 /* This is always used on maps, so consume two, the label and the value */
Laurence Lundblade3b703b82024-01-27 20:17:20 -07001482 uCBORError = QCBOR_Private_ConsumeNext(&InBuf);
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001483 if(uCBORError) {
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001484 return Result;
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001485 }
1486
1487 /* Cast is safe because this is QCBOR which limits sizes to UINT32_MAX */
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001488 Result.uLabelLen = (uint32_t)UsefulInputBuf_Tell(&InBuf);
1489
1490 uCBORError = QCBOR_Private_ConsumeNext(&InBuf);
1491 if(uCBORError) {
1492 Result.uLabelLen = 0;
1493 return Result;
1494 }
1495
1496 Result.uItemLen = (uint32_t)UsefulInputBuf_Tell(&InBuf);
1497
1498 /* Cast is safe because this is QCBOR which limits sizes to UINT32_MAX */
1499 return Result;
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001500}
1501
1502
1503/**
1504 * @brief Sort items lexographically by encoded labels.
1505 *
1506 * @param[in] pMe Encoding context.
1507 * @param[in] uStart Offset in outbuf of first item for sorting.
1508 *
1509 * This reaches into the UsefulOutBuf in the encoding context and
1510 * sorts encoded CBOR items. The byte offset start of the items is at
1511 * @c uStart and it goes to the end of valid bytes in the
1512 * UsefulOutBuf.
1513 */
1514static void
Laurence Lundblade3b703b82024-01-27 20:17:20 -07001515QCBOREncode_Private_SortMap(QCBOREncodeContext *pMe, uint32_t uStart)
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001516{
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001517 bool bSwapped;
1518 int nComparison;
1519 uint32_t uStart1;
1520 uint32_t uStart2;
1521 struct ItemLens Lens1;
1522 struct ItemLens Lens2;
1523
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001524
1525 if(pMe->uError != QCBOR_SUCCESS) {
1526 return;
1527 }
1528
1529 /* Bubble sort because the sizes of all the items are not the
1530 * same. It works with adjacent pairs so the swap is not too
1531 * difficult even though sizes are different.
1532 *
1533 * While bubble sort is n-squared, it seems OK here because n will
1534 * usually be small and the comparison and swap functions aren't
1535 * too CPU intensive.
1536 *
1537 * Another approach would be to have an array of offsets to the
1538 * items. However this requires memory allocation and the swap
1539 * operation for quick sort or such is complicated because the item
1540 * sizes are not the same and overlap may occur in the bytes being
1541 * swapped.
1542 */
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001543 do { /* Loop until nothing was swapped */
1544 Lens1 = QCBOREncode_Private_DecodeNextInMap(pMe, uStart);
1545 if(Lens1.uLabelLen == 0) {
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001546 /* It's an empty map. Nothing to do. */
1547 break;
1548 }
1549 uStart1 = uStart;
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001550 uStart2 = uStart1 + Lens1.uItemLen;
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001551 bSwapped = false;
1552
1553 while(1) {
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001554 Lens2 = QCBOREncode_Private_DecodeNextInMap(pMe, uStart2);
1555 if(Lens2.uLabelLen == 0) {
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001556 break;
1557 }
1558
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001559 nComparison = UsefulOutBuf_Compare(&(pMe->OutBuf),
1560 uStart1, Lens1.uLabelLen,
1561 uStart2, Lens2.uLabelLen);
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001562 if(nComparison < 0) {
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001563 UsefulOutBuf_Swap(&(pMe->OutBuf), uStart1, uStart2, uStart2 + Lens2.uItemLen);
1564 uStart1 = uStart1 + Lens2.uItemLen; /* item 2 now in position of item 1 */
1565 /* Lens1 is still valid as Lens1 for the next loop */
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001566 bSwapped = true;
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001567 } else if(nComparison > 0) {
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001568 uStart1 = uStart2;
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001569 Lens1 = Lens2;
1570 } else /* nComparison == 0 */ {
1571 pMe->uError = QCBOR_ERR_DUPLICATE_LABEL;
1572 return;
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001573 }
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001574 uStart2 = uStart2 + Lens2.uItemLen;
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001575 }
1576 } while(bSwapped);
1577}
1578
1579
1580/*
1581 * Public functions for closing sorted maps. See qcbor/qcbor_encode.h
1582 */
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001583void
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001584QCBOREncode_CloseAndSortMap(QCBOREncodeContext *pMe)
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001585{
1586 uint32_t uStart;
1587
1588 /* The Header for the map we are about to sort hasn't been
1589 * inserted yet, so uStart is the position of the first item
1590 * and the end out the UsefulOutBuf data is the end of the
1591 * items we are about to sort.
1592 */
1593 uStart = Nesting_GetStartPos(&(pMe->nesting));
Laurence Lundblade3b703b82024-01-27 20:17:20 -07001594 QCBOREncode_Private_SortMap(pMe, uStart);
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001595
Laurence Lundblade70fc1252024-05-31 10:57:28 -07001596 QCBOREncode_Private_CloseAggregate(pMe, CBOR_MAJOR_TYPE_MAP, Nesting_GetCount(&(pMe->nesting)));
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001597}
1598
1599
Laurence Lundbladed3f07842024-06-19 13:05:07 -07001600#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001601/*
1602 * Public functions for closing sorted maps. See qcbor/qcbor_encode.h
1603 */
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001604void
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001605QCBOREncode_CloseAndSortMapIndef(QCBOREncodeContext *pMe)
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001606{
1607 uint32_t uStart;
1608
1609 uStart = Nesting_GetStartPos(&(pMe->nesting));
Laurence Lundblade3b703b82024-01-27 20:17:20 -07001610 QCBOREncode_Private_SortMap(pMe, uStart);
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001611
Laurence Lundblade3b703b82024-01-27 20:17:20 -07001612 QCBOREncode_Private_CloseMapOrArrayIndefiniteLength(pMe, CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN);
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001613}
Laurence Lundbladed3f07842024-06-19 13:05:07 -07001614#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001615
1616
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +00001617/*
Laurence Lundbladed253e412024-08-21 11:02:56 -07001618 * Public function for closing bstr wrapping. See qcbor/qcbor_encode.h
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +00001619 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001620void
1621QCBOREncode_CloseBstrWrap2(QCBOREncodeContext *pMe,
1622 const bool bIncludeCBORHead,
1623 UsefulBufC *pWrappedCBOR)
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +00001624{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001625 const size_t uInsertPosition = Nesting_GetStartPos(&(pMe->nesting));
1626 const size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(pMe->OutBuf));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001627
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001628 /* This subtraction can't go negative because the UsefulOutBuf
1629 * always only grows and never shrinks. UsefulOutBut itself also
1630 * has defenses such that it won't write where it should not even
1631 * if given incorrect input lengths.
1632 */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +00001633 const size_t uBstrLen = uEndPosition - uInsertPosition;
1634
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001635 /* Actually insert */
Laurence Lundbladecbd7d132024-05-19 11:11:22 -07001636 QCBOREncode_Private_CloseAggregate(pMe, CBOR_MAJOR_TYPE_BYTE_STRING, uBstrLen);
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +00001637
1638 if(pWrappedCBOR) {
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001639 /* Return pointer and length to the enclosed encoded CBOR. The
1640 * intended use is for it to be hashed (e.g., SHA-256) in a COSE
1641 * implementation. This must be used right away, as the pointer
1642 * and length go invalid on any subsequent calls to this
1643 * function because there might be calls to
1644 * InsertEncodedTypeAndNumber() that slides data to the right.
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +00001645 */
1646 size_t uStartOfNew = uInsertPosition;
1647 if(!bIncludeCBORHead) {
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001648 /* Skip over the CBOR head to just get the inserted bstr */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001649 const size_t uNewEndPosition = UsefulOutBuf_GetEndPosition(&(pMe->OutBuf));
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +00001650 uStartOfNew += uNewEndPosition - uEndPosition;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001651 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001652 const UsefulBufC PartialResult = UsefulOutBuf_OutUBuf(&(pMe->OutBuf));
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +00001653 *pWrappedCBOR = UsefulBuf_Tail(PartialResult, uStartOfNew);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001654 }
1655}
1656
Laurence Lundbladeee851742020-01-08 08:37:05 -08001657
Jan Jongboom4a93a662019-07-25 08:44:58 +02001658/*
Laurence Lundblade8d3b8552021-06-10 11:11:54 -07001659 * Public function for canceling a bstr wrap. See qcbor/qcbor_encode.h
1660 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001661void
1662QCBOREncode_CancelBstrWrap(QCBOREncodeContext *pMe)
Laurence Lundblade8d3b8552021-06-10 11:11:54 -07001663{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001664 if(QCBOREncode_Private_CheckDecreaseNesting(pMe, CBOR_MAJOR_TYPE_BYTE_STRING)) {
Laurence Lundblade274ddef2022-05-17 09:12:23 -07001665 return;
1666 }
1667
Laurence Lundblade8d3b8552021-06-10 11:11:54 -07001668#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
Laurence Lundblade274ddef2022-05-17 09:12:23 -07001669 const size_t uCurrent = UsefulOutBuf_GetEndPosition(&(pMe->OutBuf));
1670 if(pMe->nesting.pCurrentNesting->uStart != uCurrent) {
1671 pMe->uError = QCBOR_ERR_CANNOT_CANCEL;
1672 return;
Laurence Lundblade8d3b8552021-06-10 11:11:54 -07001673 }
1674 /* QCBOREncode_CancelBstrWrap() can't correctly undo
Laurence Lundblade0f143652024-10-06 11:06:19 -07001675 * QCBOREncode_BstrWrapInMapSZ() or QCBOREncode_BstrWrapInMapN(). It
Laurence Lundblade8d3b8552021-06-10 11:11:54 -07001676 * can't undo the labels they add. It also doesn't catch the error
1677 * of using it this way. QCBOREncode_CancelBstrWrap() is used
1678 * infrequently and the the result is incorrect CBOR, not a
1679 * security hole, so no extra code or state is added to handle this
1680 * condition.
1681 */
Laurence Lundbladed253e412024-08-21 11:02:56 -07001682#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
Laurence Lundblade8d3b8552021-06-10 11:11:54 -07001683
1684 Nesting_Decrease(&(pMe->nesting));
1685 Nesting_Decrement(&(pMe->nesting));
1686}
1687
1688
1689/*
Laurence Lundbladeb24faef2022-04-26 11:03:08 -06001690 * Public function for opening a byte string. See qcbor/qcbor_encode.h
1691 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001692void
1693QCBOREncode_OpenBytes(QCBOREncodeContext *pMe, UsefulBuf *pPlace)
Laurence Lundbladeb24faef2022-04-26 11:03:08 -06001694{
1695 *pPlace = UsefulOutBuf_GetOutPlace(&(pMe->OutBuf));
Laurence Lundbladeb24faef2022-04-26 11:03:08 -06001696#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
Paul Liétar79789772022-07-26 20:33:18 +01001697 uint8_t uMajorType = Nesting_GetMajorType(&(pMe->nesting));
1698 if(uMajorType == CBOR_MAJOR_NONE_TYPE_OPEN_BSTR) {
Laurence Lundblade716d10c2024-02-07 16:54:42 -08001699 /* It's OK to nest a byte string in any type but
1700 * another open byte string. */
Paul Liétar79789772022-07-26 20:33:18 +01001701 pMe->uError = QCBOR_ERR_OPEN_BYTE_STRING;
1702 return;
1703 }
Laurence Lundbladed253e412024-08-21 11:02:56 -07001704#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
Laurence Lundbladeb24faef2022-04-26 11:03:08 -06001705
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001706 QCBOREncode_Private_OpenMapOrArray(pMe, CBOR_MAJOR_NONE_TYPE_OPEN_BSTR);
Laurence Lundbladeb24faef2022-04-26 11:03:08 -06001707}
1708
1709
1710/*
1711 * Public function for closing a byte string. See qcbor/qcbor_encode.h
1712 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001713void
1714QCBOREncode_CloseBytes(QCBOREncodeContext *pMe, const size_t uAmount)
Laurence Lundbladeb24faef2022-04-26 11:03:08 -06001715{
1716 UsefulOutBuf_Advance(&(pMe->OutBuf), uAmount);
1717 if(UsefulOutBuf_GetError(&(pMe->OutBuf))) {
1718 /* Advance too far. Normal off-end error handling in effect here. */
1719 return;
1720 }
1721
Laurence Lundbladecbd7d132024-05-19 11:11:22 -07001722 QCBOREncode_Private_CloseAggregate(pMe, CBOR_MAJOR_NONE_TYPE_OPEN_BSTR, uAmount);
Laurence Lundbladeb24faef2022-04-26 11:03:08 -06001723}
1724
1725
Laurence Lundbladecbd7d132024-05-19 11:11:22 -07001726#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001727/**
1728 * @brief Semi-private method to close a map, array with indefinite length
1729 *
1730 * @param[in] pMe The context to add to.
1731 * @param[in] uMajorType The major CBOR type to close.
1732 *
1733 * Call QCBOREncode_CloseArrayIndefiniteLength() or
1734 * QCBOREncode_CloseMapIndefiniteLength() instead of this.
Jan Jongboom4a93a662019-07-25 08:44:58 +02001735 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001736void
1737QCBOREncode_Private_CloseMapOrArrayIndefiniteLength(QCBOREncodeContext *pMe,
1738 const uint8_t uMajorType)
Jan Jongboom4a93a662019-07-25 08:44:58 +02001739{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001740 if(QCBOREncode_Private_CheckDecreaseNesting(pMe, uMajorType)) {
Laurence Lundblade274ddef2022-05-17 09:12:23 -07001741 return;
Jan Jongboom4a93a662019-07-25 08:44:58 +02001742 }
Laurence Lundbladedaefdec2020-11-02 20:22:03 -08001743
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001744 /* Append the break marker (0xff for both arrays and maps) */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001745 QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_NONE_TYPE_SIMPLE_BREAK, CBOR_SIMPLE_BREAK, 0);
Laurence Lundblade274ddef2022-05-17 09:12:23 -07001746 Nesting_Decrease(&(pMe->nesting));
Jan Jongboom4a93a662019-07-25 08:44:58 +02001747}
Laurence Lundbladed253e412024-08-21 11:02:56 -07001748#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Jan Jongboom4a93a662019-07-25 08:44:58 +02001749
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001750
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001751/*
Laurence Lundblade8d3b8552021-06-10 11:11:54 -07001752 * Public function to finish and get the encoded result. See qcbor/qcbor_encode.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001753 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001754QCBORError
1755QCBOREncode_Finish(QCBOREncodeContext *pMe, UsefulBufC *pEncodedCBOR)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001756{
Laurence Lundbladef2f0c3f2024-04-12 13:01:54 -07001757 if(QCBOREncode_GetErrorState(pMe) != QCBOR_SUCCESS) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001758 goto Done;
Laurence Lundblade067035b2018-11-28 17:35:25 -08001759 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001760
Laurence Lundbladedaefdec2020-11-02 20:22:03 -08001761#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001762 if(Nesting_IsInNest(&(pMe->nesting))) {
Laurence Lundbladef2f0c3f2024-04-12 13:01:54 -07001763 pMe->uError = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001764 goto Done;
1765 }
Laurence Lundbladed253e412024-08-21 11:02:56 -07001766#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001767
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001768 *pEncodedCBOR = UsefulOutBuf_OutUBuf(&(pMe->OutBuf));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001769
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001770Done:
Laurence Lundbladef2f0c3f2024-04-12 13:01:54 -07001771 return pMe->uError;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001772}
1773
Laurence Lundblade0595e932018-11-02 22:22:47 +07001774
Laurence Lundblade067035b2018-11-28 17:35:25 -08001775/*
Laurence Lundbladed253e412024-08-21 11:02:56 -07001776 * Public function to get size of the encoded result. See qcbor/qcbor_encode.h
Laurence Lundblade067035b2018-11-28 17:35:25 -08001777 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001778QCBORError
1779QCBOREncode_FinishGetSize(QCBOREncodeContext *pMe, size_t *puEncodedLen)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001780{
Laurence Lundbladeda3f0822018-09-18 19:49:02 -07001781 UsefulBufC Enc;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001782
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001783 QCBORError nReturn = QCBOREncode_Finish(pMe, &Enc);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001784
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001785 if(nReturn == QCBOR_SUCCESS) {
Laurence Lundbladeda3f0822018-09-18 19:49:02 -07001786 *puEncodedLen = Enc.len;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001787 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001788
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001789 return nReturn;
1790}
Laurence Lundbladee2226742024-08-16 10:50:23 -07001791
1792
1793/*
1794 * Public function to get substring of encoded-so-far. See qcbor/qcbor_encode.h
1795 */
1796UsefulBufC
1797QCBOREncode_SubString(QCBOREncodeContext *pMe, const size_t uStart)
1798{
1799 if(pMe->uError) {
1800 return NULLUsefulBufC;
1801 }
1802
1803 /* An attempt was made to detect usage errors by comparing uStart
1804 * to offsets of open arrays and maps in pMe->nesting, but it is
1805 * not possible because there's not enough information in just
1806 * the offset. It's not possible to known if Tell() was called before
1807 * or after an Open(). To detect this error, the nesting level
1808 * would also need to be known. This is not frequently used, so
1809 * it is not worth adding this complexity.
1810 */
1811
1812 const size_t uEnd = QCBOREncode_Tell(pMe);
1813
1814 return UsefulOutBuf_SubString(&(pMe->OutBuf), uStart, uEnd - uStart);
1815}