blob: fa7f48581424684a6d4ba3d9cc5ff1d41e69ab0b [file] [log] [blame]
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001/*==============================================================================
Laurence Lundbladed92a6162018-11-01 11:38:35 +07002 Copyright (c) 2016-2018, The Linux Foundation.
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003 Copyright (c) 2018-2024, Laurence Lundblade.
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02004 Copyright (c) 2021, Arm Limited.
Laurence Lundbladed92a6162018-11-01 11:38:35 +07005 All rights reserved.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08006
Laurence Lundblade0dbc9172018-11-01 14:17:21 +07007Redistribution and use in source and binary forms, with or without
8modification, are permitted provided that the following conditions are
9met:
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.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080020
Laurence Lundblade0dbc9172018-11-01 14:17:21 +070021THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
22WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
24ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
25BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
30OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
31IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Laurence Lundbladeee851742020-01-08 08:37:05 -080032 =============================================================================*/
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 Lundblade1ef8b2d2018-12-14 23:13:34 -0800118 if(1 >= QCBOR_MAX_ITEMS_IN_ARRAY - pNesting->pCurrentNesting->uCount) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700119 return QCBOR_ERR_ARRAY_TOO_LONG;
120 }
Laurence Lundbladecbd7d132024-05-19 11:11:22 -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 Lundbladed8e1c512020-11-04 23:03:44 -0800173#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()
190 * 6 QCBOREncode_AddTag()
191 * 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
230 * QCBOR_MAX_ITEMS_IN_ARRAY is very large (65,535) it is very unlikely
231 * 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
453#endif /* !QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
454 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));
532#endif /* !QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
533}
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 Lundblade1fa579b2020-11-25 00:31:37 -0800583 * Public functions 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 Lundbladecbd7d132024-05-19 11:11:22 -0700633 * Public functions 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 Lundblade8d9e0cd2024-05-25 18:12:19 -0700762#endif /* !QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundblade067035b2018-11-28 17:35:25 -0800763
Laurence Lundblade067035b2018-11-28 17:35:25 -0800764
765
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700766
767/* Actual addition of a positive/negative big num tag */
768static void
769QCBOREncode_Private_AddTBignum(QCBOREncodeContext *pMe,
770 const uint64_t uTag,
771 const uint8_t uTagRequirement,
772 const UsefulBufC BigNum)
773{
774 if(uTagRequirement == QCBOR_ENCODE_AS_TAG) {
775 QCBOREncode_AddTag(pMe, uTag);
776 }
777 QCBOREncode_AddBytes(pMe, BigNum);
778}
779
780
781/* Add a positive/negative big num, non-preferred */
782static void
783QCBOREncode_Private_AddTBignumNoPreferred(QCBOREncodeContext *pMe,
784 const uint64_t uTag,
785 const uint8_t uTagRequirement,
786 const UsefulBufC BigNum)
787{
788#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
789 if(pMe->uMode >= QCBOR_ENCODE_MODE_PREFERRED) {
790 pMe->uError = QCBOR_ERR_NOT_PREFERRED;
791 return;
792 }
793#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
794
795 QCBOREncode_Private_AddTBignum(pMe, uTag, uTagRequirement, BigNum);
796}
797
798
799/* Is there a carry when you add 1 to the BigNum? */
800static bool
801QCBOREncode_Private_BigNumCarry(UsefulBufC BigNum)
802{
803 bool bCarry;
804 UsefulBufC SubBigNum;
805
806 if(BigNum.len == 0) {
807 return true; /* Adding one to zero-length string gives a carry */
808 } else {
809 SubBigNum = UsefulBuf_Tail(BigNum, 1);
810 bCarry = QCBOREncode_Private_BigNumCarry(SubBigNum);
811 if(*(const uint8_t *)BigNum.ptr == 0x00 && bCarry) {
812 return true;
813 } else {
814 return false;
815 }
816 }
817}
818
819
820/*
821 * Output negative bignum bytes with subtraction of 1
822 */
823void
824QCBOREncode_Private_AddTNegativeBignum(QCBOREncodeContext *pMe,
825 const uint8_t uTagRequirement,
826 const UsefulBufC BigNum)
827{
828 size_t uLen;
829 bool bCarry;
830 bool bCopiedSomething;
831 uint8_t uByte;
832 UsefulBufC SubString;
833 UsefulBufC NextSubString;
834
835 if(uTagRequirement == QCBOR_ENCODE_AS_TAG) {
836 QCBOREncode_AddTag(pMe, CBOR_TAG_NEG_BIGNUM);
837 }
838
839 /* This works on any length without the need of an additional buffer */
840
841 /* This subtracts one, possibly making the string shorter by one
842 * 0x01 -> 0x00
843 * 0x01 0x00 -> 0xff
844 * 0x00 0x01 0x00 -> 0x00 0xff
845 * 0x02 0x00 -> 0x01 0xff
846 * 0xff -> 0xfe
847 * 0xff 0x00 -> 0xfe 0xff
848 * 0x01 0x00 0x00 -> 0xff 0xff
849 */
850
851 /* Compute the length up front because it goes in the head */
852 bCarry = QCBOREncode_Private_BigNumCarry(UsefulBuf_Tail(BigNum, 1));
853 uLen = BigNum.len;
854 if(bCarry && *(const uint8_t *)BigNum.ptr >= 1 && BigNum.len > 1) {
855 uLen--;
856 }
857 QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_TYPE_BYTE_STRING, uLen, 0);
858
859 SubString = BigNum;
860 bCopiedSomething = false;
861 while(SubString.len) {
862 uByte = *((const uint8_t *)SubString.ptr);
863 NextSubString = UsefulBuf_Tail(SubString, 1);
864 bCarry = QCBOREncode_Private_BigNumCarry(NextSubString);
865 if(bCarry) {
866 uByte--;
867 }
868 if(bCopiedSomething || NextSubString.len == 0 || uByte != 0) { /* No leading zeros, but one zero is OK */
869 UsefulOutBuf_AppendByte(&(pMe->OutBuf), uByte);
870 bCopiedSomething = true;
871 }
872 SubString = NextSubString;
873 }
874}
875
876
877static UsefulBufC
878QCBOREncode_Private_RemoveLeadingZeros(UsefulBufC String)
879{
880 while(String.len > 1) {
881 if(*(const uint8_t *)String.ptr) {
882 break;
883 }
884 String.len--;
885 String.ptr = (const uint8_t *)String.ptr + 1;
886 }
887
888 return String;
889}
890
891
892/*
893 * Public function. See qcbor/qcbor_encode.h
894 */
895void
896QCBOREncode_AddTNegativeBignumNoPreferred(QCBOREncodeContext *pMe,
897 const uint8_t uTagRequirement,
898 const UsefulBufC BigNum)
899{
900#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
901 if(pMe->uMode >= QCBOR_ENCODE_MODE_PREFERRED) {
902 pMe->uError = QCBOR_ERR_NOT_PREFERRED;
903 return;
904 }
905#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
906
907 if(UsefulBuf_IsValue(BigNum, 0) == SIZE_MAX) {
908 pMe->uError = QCBOR_ERR_NO_NEGATIVE_ZERO;
909 return;
910 }
911
912 if(pMe->uConfig & QCBOR_ENCODE_CONFIG_V1_COMPAT) {
913 QCBOREncode_Private_AddTBignum(pMe, CBOR_TAG_NEG_BIGNUM, uTagRequirement, BigNum);
914 } else {
915 QCBOREncode_Private_AddTNegativeBignum(pMe, uTagRequirement, QCBOREncode_Private_RemoveLeadingZeros(BigNum));
916 }
917}
918
919
920void
921QCBOREncode_AddTNegativeBignumNoPreferredToMap(QCBOREncodeContext *pMe,
922 const char *szLabel,
923 uint8_t uTagRequirement,
924 UsefulBufC BigNumber)
925{
926 QCBOREncode_AddSZString(pMe, szLabel);
927 QCBOREncode_AddTNegativeBignumNoPreferred(pMe, uTagRequirement, BigNumber);
928}
929
930
931void
932QCBOREncode_AddTNegativeBignumNoPreferredToMapN(QCBOREncodeContext *pMe,
933 int64_t nLabel,
934 uint8_t uTagRequirement,
935 UsefulBufC BigNumber)
936{
937 QCBOREncode_AddInt64(pMe, nLabel);
938 QCBOREncode_AddTNegativeBignumNoPreferred(pMe, uTagRequirement, BigNumber);
939}
940
941/*
942 * Public function. See qcbor/qcbor_encode.h
943 */
944void
945QCBOREncode_AddTPositiveBignumNoPreferred(QCBOREncodeContext *pMe,
946 const uint8_t uTagRequirement,
947 const UsefulBufC BigNum)
948{
949 QCBOREncode_Private_AddTBignumNoPreferred(pMe, CBOR_TAG_POS_BIGNUM, uTagRequirement, BigNum);
950}
951
952void
953QCBOREncode_AddTPositiveBignumNoPreferredToMap(QCBOREncodeContext *pMe,
954 const char *szLabel,
955 const uint8_t uTagRequirement,
956 const UsefulBufC BigNum)
957{
958 QCBOREncode_AddSZString(pMe, szLabel);
959 QCBOREncode_Private_AddTBignumNoPreferred(pMe, CBOR_TAG_POS_BIGNUM, uTagRequirement, BigNum);
960}
961
962void
963QCBOREncode_AddTPositiveBignumNoPreferredToMapN(QCBOREncodeContext *pMe,
964 int64_t nLabel,
965 const uint8_t uTagRequirement,
966 const UsefulBufC BigNum)
967{
968 QCBOREncode_AddInt64(pMe, nLabel);
969 QCBOREncode_Private_AddTBignumNoPreferred(pMe, CBOR_TAG_POS_BIGNUM, uTagRequirement, BigNum);
970}
971
972
973
974
975/* This will return an erroneous value if BigNum.len > 8 */
976/* Convert from bignum to uint with endianess conversion */
977static uint64_t
978QCBOREncode_Private_BigNumToUInt(const UsefulBufC BigNum)
979{
980 uint64_t uInt;
981 size_t uIndex;
982
983 uInt = 0;
984 for(uIndex = 0; uIndex < BigNum.len; uIndex++) {
985 uInt = (uInt << 8) + ((const uint8_t *)BigNum.ptr)[uIndex];
986 }
987
988 return uInt;
989}
990
991
992/*
993 * Public function. See qcbor/qcbor_encode.h
994 */
995void
996QCBOREncode_AddTPositiveBignum(QCBOREncodeContext *pMe,
997 const uint8_t uTagRequirement,
998 const UsefulBufC BigNum)
999{
1000 if(pMe->uConfig & QCBOR_ENCODE_CONFIG_V1_COMPAT) {
1001 QCBOREncode_AddTPositiveBignumNoPreferred(pMe, uTagRequirement, BigNum);
1002 } else {
1003 const UsefulBufC BigNumNLZ = QCBOREncode_Private_RemoveLeadingZeros(BigNum);
1004 if(BigNumNLZ.len <= 8) {
1005 /* Preferred serialization requires conversion to type 0 */
1006 QCBOREncode_AddUInt64(pMe, QCBOREncode_Private_BigNumToUInt(BigNumNLZ));
1007 } else {
1008 QCBOREncode_Private_AddTBignum(pMe, CBOR_TAG_POS_BIGNUM, uTagRequirement, BigNumNLZ);
1009 }
1010 }
1011}
1012
1013
1014/*
1015 * Public function. See qcbor/qcbor_encode.h
1016 */
1017void
1018QCBOREncode_AddTNegativeBignum(QCBOREncodeContext *pMe,
1019 const uint8_t uTagRequirement,
1020 const UsefulBufC BigNum)
1021{
1022 uint64_t uInt;
1023 bool bIs2exp64;
1024 static const uint8_t twoExp64[] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
1025
1026 if(UsefulBuf_IsValue(BigNum, 0) == SIZE_MAX) {
1027 pMe->uError = QCBOR_ERR_NO_NEGATIVE_ZERO;
1028 return;
1029 }
1030
1031 if(pMe->uConfig & QCBOR_ENCODE_CONFIG_V1_COMPAT) {
1032 QCBOREncode_AddTNegativeBignumNoPreferred(pMe, uTagRequirement, BigNum);
1033
1034 } else {
1035 /* Here we do preferred serialization. That requires removal of leading zeros */
1036 const UsefulBufC BigNumNLZ = QCBOREncode_Private_RemoveLeadingZeros(BigNum);
1037
1038 bIs2exp64 = ! UsefulBuf_Compare(BigNumNLZ, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(twoExp64));
1039
1040 if(BigNumNLZ.len <= 8 || bIs2exp64) {
1041 /* Must convert to CBOR type 1, a negative integer */
1042 if(bIs2exp64) {
1043 /* 2^64 is a 9 byte big number. Since negative numbers are offset
1044 * by one in CBOR, it can be encoded as a type 1 negative. The
1045 * conversion below won't work because the uInt will overflow
1046 * before the subtraction of 1.
1047 */
1048 uInt = UINT64_MAX;
1049 } else {
1050 uInt = QCBOREncode_Private_BigNumToUInt(BigNumNLZ);
1051 uInt--; /* CBOR's negative offset of 1 */
1052 }
1053 QCBOREncode_AddNegativeUInt64(pMe, uInt);
1054
1055 } else {
1056 QCBOREncode_Private_AddTNegativeBignum(pMe, uTagRequirement, BigNumNLZ);
1057 }
1058 }
1059}
1060
1061
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07001062#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001063/**
1064 * @brief Semi-private method to add bigfloats and decimal fractions.
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001065 *
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001066 * @param[in] pMe The encoding context to add the value to.
1067 * @param[in] uTag The type 6 tag indicating what this is to be.
1068 * @param[in] BigNumMantissa Is @ref NULLUsefulBufC if mantissa is an
1069 * @c int64_t or the actual big number mantissa
1070 * if not.
1071 * @param[in] bBigNumIsNegative This is @c true if the big number is negative.
1072 * @param[in] nMantissa The @c int64_t mantissa if it is not a big number.
1073 * @param[in] nExponent The exponent.
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001074 *
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001075 * This outputs either the @ref CBOR_TAG_DECIMAL_FRACTION or
1076 * @ref CBOR_TAG_BIGFLOAT tag. if @c uTag is @ref CBOR_TAG_INVALID64,
1077 * then this outputs the "borrowed" content format.
1078 *
1079 * The tag content output by this is an array with two members, the
1080 * exponent and then the mantissa. The mantissa can be either a big
1081 * number or an @c int64_t.
1082 *
1083 * This implementation cannot output an exponent further from 0 than
1084 * @c INT64_MAX.
1085 *
1086 * To output a mantissa that is between INT64_MAX and UINT64_MAX from 0,
1087 * it must be as a big number.
1088 *
1089 * Typically, QCBOREncode_AddDecimalFraction(), QCBOREncode_AddBigFloat(),
1090 * QCBOREncode_AddDecimalFractionBigNum() or QCBOREncode_AddBigFloatBigNum()
1091 * is called instead of this.
Laurence Lundblade59289e52019-12-30 13:44:37 -08001092 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001093void
1094QCBOREncode_Private_AddExpMantissa(QCBOREncodeContext *pMe,
1095 const uint64_t uTag,
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001096 const int64_t nExponent,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001097 const UsefulBufC BigNumMantissa,
1098 const bool bBigNumIsNegative,
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001099 const int64_t nMantissa)
Laurence Lundblade59289e52019-12-30 13:44:37 -08001100{
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001101 /* This is for encoding either a big float or a decimal fraction,
1102 * both of which are an array of two items, an exponent and a
1103 * mantissa. The difference between the two is that the exponent
1104 * is base-2 for big floats and base-10 for decimal fractions, but
1105 * that has no effect on the code here.
Laurence Lundbladeee851742020-01-08 08:37:05 -08001106 */
Laurence Lundbladeae66d3f2020-09-14 18:12:08 -07001107 if(uTag != CBOR_TAG_INVALID64) {
1108 QCBOREncode_AddTag(pMe, uTag);
1109 }
Laurence Lundblade59289e52019-12-30 13:44:37 -08001110 QCBOREncode_OpenArray(pMe);
1111 QCBOREncode_AddInt64(pMe, nExponent);
1112 if(!UsefulBuf_IsNULLC(BigNumMantissa)) {
1113 if(bBigNumIsNegative) {
1114 QCBOREncode_AddNegativeBignum(pMe, BigNumMantissa);
1115 } else {
1116 QCBOREncode_AddPositiveBignum(pMe, BigNumMantissa);
1117 }
1118 } else {
1119 QCBOREncode_AddInt64(pMe, nMantissa);
1120 }
1121 QCBOREncode_CloseArray(pMe);
1122}
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07001123#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade59289e52019-12-30 13:44:37 -08001124
1125
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001126/**
1127 * @brief Semi-private method to open a map, array or bstr-wrapped CBOR
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001128 *
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001129 * @param[in] pMe The context to add to.
1130 * @param[in] uMajorType The major CBOR type to close
1131 *
1132 * Call QCBOREncode_OpenArray(), QCBOREncode_OpenMap() or
1133 * QCBOREncode_BstrWrap() instead of this.
Laurence Lundblade274ddef2022-05-17 09:12:23 -07001134 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001135void
1136QCBOREncode_Private_OpenMapOrArray(QCBOREncodeContext *pMe,
1137 const uint8_t uMajorType)
Laurence Lundblade067035b2018-11-28 17:35:25 -08001138{
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001139 /* Add one item to the nesting level we are in for the new map or array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001140 QCBOREncode_Private_IncrementMapOrArrayCount(pMe);
Laurence Lundbladed39cd392019-01-11 18:17:38 -08001141
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001142 /* The offset where the length of an array or map will get written
1143 * is stored in a uint32_t, not a size_t to keep stack usage
1144 * smaller. This checks to be sure there is no wrap around when
1145 * recording the offset. Note that on 64-bit machines CBOR larger
1146 * than 4GB can be encoded as long as no array/map offsets occur
1147 * past the 4GB mark, but the public interface says that the
1148 * maximum is 4GB to keep the discussion simpler.
1149 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001150 size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(pMe->OutBuf));
Laurence Lundbladed39cd392019-01-11 18:17:38 -08001151
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001152 /* QCBOR_MAX_ARRAY_OFFSET is slightly less than UINT32_MAX so this
1153 * code can run on a 32-bit machine and tests can pass on a 32-bit
1154 * machine. If it was exactly UINT32_MAX, then this code would not
1155 * compile or run on a 32-bit machine and an #ifdef or some machine
1156 * size detection would be needed reducing portability.
1157 */
Laurence Lundblade3e0a45c2020-11-05 11:12:04 -08001158 if(uEndPosition >= QCBOR_MAX_ARRAY_OFFSET) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001159 pMe->uError = QCBOR_ERR_BUFFER_TOO_LARGE;
Laurence Lundblade3e0a45c2020-11-05 11:12:04 -08001160
1161 } else {
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001162 /* Increase nesting level because this is a map or array. Cast
1163 * from size_t to uin32_t is safe because of check above.
1164 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001165 pMe->uError = Nesting_Increase(&(pMe->nesting), uMajorType, (uint32_t)uEndPosition);
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -08001166 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001167}
1168
Laurence Lundblade59289e52019-12-30 13:44:37 -08001169
Laurence Lundbladecbd7d132024-05-19 11:11:22 -07001170#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001171/**
1172 * @brief Semi-private method to open a map, array with indefinite length
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001173 *
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001174 * @param[in] pMe The context to add to.
1175 * @param[in] uMajorType The major CBOR type to close
1176 *
1177 * Call QCBOREncode_OpenArrayIndefiniteLength() or
1178 * QCBOREncode_OpenMapIndefiniteLength() instead of this.
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001179 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001180void
1181QCBOREncode_Private_OpenMapOrArrayIndefiniteLength(QCBOREncodeContext *pMe,
1182 const uint8_t uMajorType)
Jan Jongboom4a93a662019-07-25 08:44:58 +02001183{
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -08001184#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
1185 if(pMe->uMode >= QCBOR_ENCODE_MODE_PREFERRED) {
1186 pMe->uError = QCBOR_ERR_NOT_PREFERRED;
1187 return;
1188 }
1189#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001190 /* Insert the indefinite length marker (0x9f for arrays, 0xbf for maps) */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001191 QCBOREncode_Private_AppendCBORHead(pMe, uMajorType, 0, 0);
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001192
1193 /* Call the definite-length opener just to do the bookkeeping for
1194 * nesting. It will record the position of the opening item in the
1195 * encoded output but this is not used when closing this open.
1196 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001197 QCBOREncode_Private_OpenMapOrArray(pMe, uMajorType);
Jan Jongboom4a93a662019-07-25 08:44:58 +02001198}
Laurence Lundbladecbd7d132024-05-19 11:11:22 -07001199#endif
1200
1201
1202/**
1203 * @brief Check for errors when decreasing nesting.
1204 *
1205 * @param pMe QCBOR encoding context.
1206 * @param uMajorType The major type of the nesting.
1207 *
1208 * Check that there is no previous error, that there is actually some
1209 * nesting and that the major type of the opening of the nesting
1210 * matches the major type of the nesting being closed.
1211 *
1212 * This is called when closing maps, arrays, byte string wrapping and
1213 * open/close of byte strings.
1214 */
1215static bool
1216QCBOREncode_Private_CheckDecreaseNesting(QCBOREncodeContext *pMe,
1217 const uint8_t uMajorType)
1218{
1219#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
1220 if(pMe->uError != QCBOR_SUCCESS) {
1221 return true;
1222 }
1223
1224 if(!Nesting_IsInNest(&(pMe->nesting))) {
1225 pMe->uError = QCBOR_ERR_TOO_MANY_CLOSES;
1226 return true;
1227 }
1228
1229 if(Nesting_GetMajorType(&(pMe->nesting)) != uMajorType) {
1230 pMe->uError = QCBOR_ERR_CLOSE_MISMATCH;
1231 return true;
1232 }
1233
1234#else /* !QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
1235 /* None of these checks are performed if the encode guards are
1236 * turned off as they all relate to correct calling.
1237 *
1238 * Turning off all these checks does not turn off any checking for
1239 * buffer overflows or pointer issues.
1240 */
1241
1242 (void)uMajorType;
1243 (void)pMe;
1244#endif /* !QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
1245
1246 return false;
1247}
1248
1249
1250/**
1251 * @brief Insert the CBOR head for a map, array or wrapped bstr
1252 *
1253 * @param pMe QCBOR encoding context.
1254 * @param uMajorType One of CBOR_MAJOR_TYPE_XXXX.
1255 * @param uLen The length of the data item.
1256 *
1257 * When an array, map or bstr was opened, nothing was done but note
1258 * the position. This function goes back to that position and inserts
1259 * the CBOR Head with the major type and length.
1260 */
1261static void
1262QCBOREncode_Private_CloseAggregate(QCBOREncodeContext *pMe,
1263 uint8_t uMajorType,
1264 size_t uLen)
1265{
1266 if(QCBOREncode_Private_CheckDecreaseNesting(pMe, uMajorType)) {
1267 return;
1268 }
1269
1270 if(uMajorType == CBOR_MAJOR_NONE_TYPE_OPEN_BSTR) {
1271 uMajorType = CBOR_MAJOR_TYPE_BYTE_STRING;
1272 }
1273
1274 /* A stack buffer large enough for a CBOR head (9 bytes) */
1275 UsefulBuf_MAKE_STACK_UB(pBufferForEncodedHead, QCBOR_HEAD_BUFFER_SIZE);
1276
1277 UsefulBufC EncodedHead = QCBOREncode_EncodeHead(pBufferForEncodedHead,
1278 uMajorType,
1279 0,
1280 uLen);
1281
1282 /* No check for EncodedHead == NULLUsefulBufC is performed here to
1283 * save object code. It is very clear that pBufferForEncodedHead is
1284 * the correct size. If EncodedHead == NULLUsefulBufC then
1285 * UsefulOutBuf_InsertUsefulBuf() will do nothing so there is no
1286 * security hole introduced.
1287 */
1288 UsefulOutBuf_InsertUsefulBuf(&(pMe->OutBuf),
1289 EncodedHead,
1290 Nesting_GetStartPos(&(pMe->nesting)));
1291
1292 Nesting_Decrease(&(pMe->nesting));
1293}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001294
Laurence Lundbladeee851742020-01-08 08:37:05 -08001295
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001296/**
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -08001297 * @brief Semi-private method to close a map, array or bstr wrapped CBOR.
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001298 *
1299 * @param[in] pMe The context to add to.
1300 * @param[in] uMajorType The major CBOR type to close.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001301 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001302void
1303QCBOREncode_Private_CloseMapOrArray(QCBOREncodeContext *pMe,
1304 const uint8_t uMajorType)
Laurence Lundbladea954db92018-09-28 19:27:31 -07001305{
Laurence Lundbladecbd7d132024-05-19 11:11:22 -07001306 QCBOREncode_Private_CloseAggregate(pMe, uMajorType, Nesting_GetCount(&(pMe->nesting)));
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +00001307}
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001308
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001309
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -08001310/**
1311 * @brief Private method to close a map without sorting.
1312 *
1313 * @param[in] pMe The encode context with map to close.
1314 *
1315 * See QCBOREncode_SerializationCDE() implemention for explantion for why
1316 * this exists in this form.
1317 */
1318static void
1319QCBOREncode_Private_CloseMapUnsorted(QCBOREncodeContext *pMe)
1320{
1321 QCBOREncode_Private_CloseMapOrArray(pMe, CBOR_MAJOR_TYPE_MAP);
1322}
1323
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001324
1325/**
1326 * @brief Decode a CBOR item head.
1327 *
1328 * @param[in] pUInBuf UsefulInputBuf to read from.
1329 * @param[out] pnMajorType Major type of decoded head.
1330 * @param[out] puArgument Argument of decoded head.
1331 * @param[out] pnAdditionalInfo Additional info from decoded head.
1332 *
1333 * @return SUCCESS if a head was decoded
1334 * HIT_END if there were not enough bytes to decode a head
1335 * UNSUPPORTED if the decoded item is not one that is supported
1336 *
1337 * This is copied from qcbor_decode.c rather than referenced. This
1338 * makes the core decoder 60 bytes smaller because it gets inlined.
1339 * It would not get inlined if it was referenced. It is important to
1340 * make the core decoder as small as possible. The copy here does make
1341 * map sorting 200 bytes bigger, but map sorting is rarely used in
1342 * environments that need small object code. It would also make
1343 * qcbor_encode.c depend on qcbor_decode.c
1344 *
1345 * This is also super stable and tested. It implements the very
1346 * well-defined part of CBOR that will never change. So this won't
1347 * change.
1348 */
1349static QCBORError
1350QCBOREncodePriv_DecodeHead(UsefulInputBuf *pUInBuf,
1351 int *pnMajorType,
1352 uint64_t *puArgument,
1353 int *pnAdditionalInfo)
1354{
1355 QCBORError uReturn;
1356
1357 /* Get the initial byte that every CBOR data item has and break it
1358 * down. */
1359 const int nInitialByte = (int)UsefulInputBuf_GetByte(pUInBuf);
1360 const int nTmpMajorType = nInitialByte >> 5;
1361 const int nAdditionalInfo = nInitialByte & 0x1f;
1362
1363 /* Where the argument accumulates */
1364 uint64_t uArgument;
1365
1366 if(nAdditionalInfo >= LEN_IS_ONE_BYTE && nAdditionalInfo <= LEN_IS_EIGHT_BYTES) {
1367 /* Need to get 1,2,4 or 8 additional argument bytes. Map
1368 * LEN_IS_ONE_BYTE..LEN_IS_EIGHT_BYTES to actual length.
1369 */
1370 static const uint8_t aIterate[] = {1,2,4,8};
1371
1372 /* Loop getting all the bytes in the argument */
1373 uArgument = 0;
1374 for(int i = aIterate[nAdditionalInfo - LEN_IS_ONE_BYTE]; i; i--) {
1375 /* This shift and add gives the endian conversion. */
1376 uArgument = (uArgument << 8) + UsefulInputBuf_GetByte(pUInBuf);
1377 }
1378 } else if(nAdditionalInfo >= ADDINFO_RESERVED1 && nAdditionalInfo <= ADDINFO_RESERVED3) {
1379 /* The reserved and thus-far unused additional info values */
1380 uReturn = QCBOR_ERR_UNSUPPORTED;
1381 goto Done;
1382 } else {
1383 /* Less than 24, additional info is argument or 31, an
1384 * indefinite-length. No more bytes to get.
1385 */
1386 uArgument = (uint64_t)nAdditionalInfo;
1387 }
1388
1389 if(UsefulInputBuf_GetError(pUInBuf)) {
1390 uReturn = QCBOR_ERR_HIT_END;
1391 goto Done;
1392 }
1393
1394 /* All successful if arrived here. */
1395 uReturn = QCBOR_SUCCESS;
1396 *pnMajorType = nTmpMajorType;
1397 *puArgument = uArgument;
1398 *pnAdditionalInfo = nAdditionalInfo;
1399
1400Done:
1401 return uReturn;
1402}
1403
1404
1405/**
1406 * @brief Consume the next item from a UsefulInputBuf.
1407 *
1408 * @param[in] pInBuf UsefulInputBuf from which to consume item.
1409 *
1410 * Recursive, but stack usage is light and encoding depth limit
1411 */
1412static QCBORError
Laurence Lundblade3b703b82024-01-27 20:17:20 -07001413QCBOR_Private_ConsumeNext(UsefulInputBuf *pInBuf)
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001414{
1415 int nMajor;
1416 uint64_t uArgument;
1417 int nAdditional;
1418 uint16_t uItemCount;
1419 uint16_t uMul;
1420 uint16_t i;
1421 QCBORError uCBORError;
1422
1423 uCBORError = QCBOREncodePriv_DecodeHead(pInBuf, &nMajor, &uArgument, &nAdditional);
1424 if(uCBORError != QCBOR_SUCCESS) {
1425 return uCBORError;
1426 }
1427
1428 uMul = 1;
1429
1430 switch(nMajor) {
1431 case CBOR_MAJOR_TYPE_POSITIVE_INT: /* Major type 0 */
1432 case CBOR_MAJOR_TYPE_NEGATIVE_INT: /* Major type 1 */
1433 break;
1434
1435 case CBOR_MAJOR_TYPE_SIMPLE:
1436 return uArgument == CBOR_SIMPLE_BREAK ? 1 : 0;
1437 break;
1438
1439 case CBOR_MAJOR_TYPE_BYTE_STRING:
1440 case CBOR_MAJOR_TYPE_TEXT_STRING:
1441 if(nAdditional == LEN_IS_INDEFINITE) {
1442 /* Segments of indefinite length */
Laurence Lundblade3b703b82024-01-27 20:17:20 -07001443 while(QCBOR_Private_ConsumeNext(pInBuf) == 0);
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001444 }
1445 (void)UsefulInputBuf_GetBytes(pInBuf, uArgument);
1446 break;
1447
1448 case CBOR_MAJOR_TYPE_TAG:
Laurence Lundblade3b703b82024-01-27 20:17:20 -07001449 QCBOR_Private_ConsumeNext(pInBuf);
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001450 break;
1451
1452 case CBOR_MAJOR_TYPE_MAP:
1453 uMul = 2;
1454 /* Fallthrough */
1455 case CBOR_MAJOR_TYPE_ARRAY:
1456 uItemCount = (uint16_t)uArgument * uMul;
1457 if(nAdditional == LEN_IS_INDEFINITE) {
1458 uItemCount = UINT16_MAX;
1459 }
1460 for(i = uItemCount; i > 0; i--) {
Laurence Lundblade3b703b82024-01-27 20:17:20 -07001461 if(QCBOR_Private_ConsumeNext(pInBuf)) {
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001462 /* End of indefinite length */
1463 break;
1464 }
1465 }
1466 break;
1467 }
1468
1469 return QCBOR_SUCCESS;
1470}
1471
1472
1473/**
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001474 * @brief Decoded next item to get its lengths.
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001475 *
1476 * Decode the next item in map no matter what type it is. It works
1477 * recursively when an item is a map or array It returns offset just
1478 * past the item decoded or zero there are no more items in the output
1479 * buffer.
1480 *
1481 * This doesn't distinguish between end of the input and an error
1482 * because it is used to decode stuff we encoded into a buffer, not
1483 * stuff that came in from outside. We still want a check for safety
1484 * in case of bugs here, but it is OK to report end of input on error.
1485 */
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001486struct ItemLens {
1487 uint32_t uLabelLen;
1488 uint32_t uItemLen;
1489};
1490
1491static struct ItemLens
Laurence Lundblade3b703b82024-01-27 20:17:20 -07001492QCBOREncode_Private_DecodeNextInMap(QCBOREncodeContext *pMe, uint32_t uStart)
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001493{
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001494 UsefulInputBuf InBuf;
1495 UsefulBufC EncodedMapBytes;
1496 QCBORError uCBORError;
1497 struct ItemLens Result;
1498
1499 Result.uLabelLen = 0;
1500 Result.uItemLen = 0;
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001501
1502 EncodedMapBytes = UsefulOutBuf_OutUBufOffset(&(pMe->OutBuf), uStart);
1503 if(UsefulBuf_IsNULLC(EncodedMapBytes)) {
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001504 return Result;
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001505 }
1506
1507 UsefulInputBuf_Init(&InBuf, EncodedMapBytes);
1508
1509 /* This is always used on maps, so consume two, the label and the value */
Laurence Lundblade3b703b82024-01-27 20:17:20 -07001510 uCBORError = QCBOR_Private_ConsumeNext(&InBuf);
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001511 if(uCBORError) {
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001512 return Result;
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001513 }
1514
1515 /* Cast is safe because this is QCBOR which limits sizes to UINT32_MAX */
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001516 Result.uLabelLen = (uint32_t)UsefulInputBuf_Tell(&InBuf);
1517
1518 uCBORError = QCBOR_Private_ConsumeNext(&InBuf);
1519 if(uCBORError) {
1520 Result.uLabelLen = 0;
1521 return Result;
1522 }
1523
1524 Result.uItemLen = (uint32_t)UsefulInputBuf_Tell(&InBuf);
1525
1526 /* Cast is safe because this is QCBOR which limits sizes to UINT32_MAX */
1527 return Result;
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001528}
1529
1530
1531/**
1532 * @brief Sort items lexographically by encoded labels.
1533 *
1534 * @param[in] pMe Encoding context.
1535 * @param[in] uStart Offset in outbuf of first item for sorting.
1536 *
1537 * This reaches into the UsefulOutBuf in the encoding context and
1538 * sorts encoded CBOR items. The byte offset start of the items is at
1539 * @c uStart and it goes to the end of valid bytes in the
1540 * UsefulOutBuf.
1541 */
1542static void
Laurence Lundblade3b703b82024-01-27 20:17:20 -07001543QCBOREncode_Private_SortMap(QCBOREncodeContext *pMe, uint32_t uStart)
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001544{
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001545 bool bSwapped;
1546 int nComparison;
1547 uint32_t uStart1;
1548 uint32_t uStart2;
1549 struct ItemLens Lens1;
1550 struct ItemLens Lens2;
1551
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001552
1553 if(pMe->uError != QCBOR_SUCCESS) {
1554 return;
1555 }
1556
1557 /* Bubble sort because the sizes of all the items are not the
1558 * same. It works with adjacent pairs so the swap is not too
1559 * difficult even though sizes are different.
1560 *
1561 * While bubble sort is n-squared, it seems OK here because n will
1562 * usually be small and the comparison and swap functions aren't
1563 * too CPU intensive.
1564 *
1565 * Another approach would be to have an array of offsets to the
1566 * items. However this requires memory allocation and the swap
1567 * operation for quick sort or such is complicated because the item
1568 * sizes are not the same and overlap may occur in the bytes being
1569 * swapped.
1570 */
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001571 do { /* Loop until nothing was swapped */
1572 Lens1 = QCBOREncode_Private_DecodeNextInMap(pMe, uStart);
1573 if(Lens1.uLabelLen == 0) {
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001574 /* It's an empty map. Nothing to do. */
1575 break;
1576 }
1577 uStart1 = uStart;
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001578 uStart2 = uStart1 + Lens1.uItemLen;
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001579 bSwapped = false;
1580
1581 while(1) {
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001582 Lens2 = QCBOREncode_Private_DecodeNextInMap(pMe, uStart2);
1583 if(Lens2.uLabelLen == 0) {
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001584 break;
1585 }
1586
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001587 nComparison = UsefulOutBuf_Compare(&(pMe->OutBuf),
1588 uStart1, Lens1.uLabelLen,
1589 uStart2, Lens2.uLabelLen);
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001590 if(nComparison < 0) {
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001591 UsefulOutBuf_Swap(&(pMe->OutBuf), uStart1, uStart2, uStart2 + Lens2.uItemLen);
1592 uStart1 = uStart1 + Lens2.uItemLen; /* item 2 now in position of item 1 */
1593 /* Lens1 is still valid as Lens1 for the next loop */
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001594 bSwapped = true;
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001595 } else if(nComparison > 0) {
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001596 uStart1 = uStart2;
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001597 Lens1 = Lens2;
1598 } else /* nComparison == 0 */ {
1599 pMe->uError = QCBOR_ERR_DUPLICATE_LABEL;
1600 return;
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001601 }
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001602 uStart2 = uStart2 + Lens2.uItemLen;
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001603 }
1604 } while(bSwapped);
1605}
1606
1607
1608/*
1609 * Public functions for closing sorted maps. See qcbor/qcbor_encode.h
1610 */
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001611void
1612QCBOREncode_CloseAndSortMap(QCBOREncodeContext *pMe)
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001613{
1614 uint32_t uStart;
1615
1616 /* The Header for the map we are about to sort hasn't been
1617 * inserted yet, so uStart is the position of the first item
1618 * and the end out the UsefulOutBuf data is the end of the
1619 * items we are about to sort.
1620 */
1621 uStart = Nesting_GetStartPos(&(pMe->nesting));
Laurence Lundblade3b703b82024-01-27 20:17:20 -07001622 QCBOREncode_Private_SortMap(pMe, uStart);
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001623
Laurence Lundblade70fc1252024-05-31 10:57:28 -07001624 QCBOREncode_Private_CloseAggregate(pMe, CBOR_MAJOR_TYPE_MAP, Nesting_GetCount(&(pMe->nesting)));
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001625}
1626
1627
Laurence Lundbladed3f07842024-06-19 13:05:07 -07001628#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001629/*
1630 * Public functions for closing sorted maps. See qcbor/qcbor_encode.h
1631 */
Laurence Lundbladedee0d4e2024-03-03 13:46:33 -07001632void
1633QCBOREncode_CloseAndSortMapIndef(QCBOREncodeContext *pMe)
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001634{
1635 uint32_t uStart;
1636
1637 uStart = Nesting_GetStartPos(&(pMe->nesting));
Laurence Lundblade3b703b82024-01-27 20:17:20 -07001638 QCBOREncode_Private_SortMap(pMe, uStart);
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001639
Laurence Lundblade3b703b82024-01-27 20:17:20 -07001640 QCBOREncode_Private_CloseMapOrArrayIndefiniteLength(pMe, CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN);
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001641}
Laurence Lundbladed3f07842024-06-19 13:05:07 -07001642#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundbladed6e13022023-11-26 10:14:02 -07001643
1644
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +00001645/*
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001646 * Public functions for closing bstr wrapping. See qcbor/qcbor_encode.h
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +00001647 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001648void
1649QCBOREncode_CloseBstrWrap2(QCBOREncodeContext *pMe,
1650 const bool bIncludeCBORHead,
1651 UsefulBufC *pWrappedCBOR)
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +00001652{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001653 const size_t uInsertPosition = Nesting_GetStartPos(&(pMe->nesting));
1654 const size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(pMe->OutBuf));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001655
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001656 /* This subtraction can't go negative because the UsefulOutBuf
1657 * always only grows and never shrinks. UsefulOutBut itself also
1658 * has defenses such that it won't write where it should not even
1659 * if given incorrect input lengths.
1660 */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +00001661 const size_t uBstrLen = uEndPosition - uInsertPosition;
1662
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001663 /* Actually insert */
Laurence Lundbladecbd7d132024-05-19 11:11:22 -07001664 QCBOREncode_Private_CloseAggregate(pMe, CBOR_MAJOR_TYPE_BYTE_STRING, uBstrLen);
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +00001665
1666 if(pWrappedCBOR) {
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001667 /* Return pointer and length to the enclosed encoded CBOR. The
1668 * intended use is for it to be hashed (e.g., SHA-256) in a COSE
1669 * implementation. This must be used right away, as the pointer
1670 * and length go invalid on any subsequent calls to this
1671 * function because there might be calls to
1672 * InsertEncodedTypeAndNumber() that slides data to the right.
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +00001673 */
1674 size_t uStartOfNew = uInsertPosition;
1675 if(!bIncludeCBORHead) {
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001676 /* Skip over the CBOR head to just get the inserted bstr */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001677 const size_t uNewEndPosition = UsefulOutBuf_GetEndPosition(&(pMe->OutBuf));
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +00001678 uStartOfNew += uNewEndPosition - uEndPosition;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001679 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001680 const UsefulBufC PartialResult = UsefulOutBuf_OutUBuf(&(pMe->OutBuf));
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +00001681 *pWrappedCBOR = UsefulBuf_Tail(PartialResult, uStartOfNew);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001682 }
1683}
1684
Laurence Lundbladeee851742020-01-08 08:37:05 -08001685
Jan Jongboom4a93a662019-07-25 08:44:58 +02001686/*
Laurence Lundblade8d3b8552021-06-10 11:11:54 -07001687 * Public function for canceling a bstr wrap. See qcbor/qcbor_encode.h
1688 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001689void
1690QCBOREncode_CancelBstrWrap(QCBOREncodeContext *pMe)
Laurence Lundblade8d3b8552021-06-10 11:11:54 -07001691{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001692 if(QCBOREncode_Private_CheckDecreaseNesting(pMe, CBOR_MAJOR_TYPE_BYTE_STRING)) {
Laurence Lundblade274ddef2022-05-17 09:12:23 -07001693 return;
1694 }
1695
Laurence Lundblade8d3b8552021-06-10 11:11:54 -07001696#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
Laurence Lundblade274ddef2022-05-17 09:12:23 -07001697 const size_t uCurrent = UsefulOutBuf_GetEndPosition(&(pMe->OutBuf));
1698 if(pMe->nesting.pCurrentNesting->uStart != uCurrent) {
1699 pMe->uError = QCBOR_ERR_CANNOT_CANCEL;
1700 return;
Laurence Lundblade8d3b8552021-06-10 11:11:54 -07001701 }
1702 /* QCBOREncode_CancelBstrWrap() can't correctly undo
1703 * QCBOREncode_BstrWrapInMap() or QCBOREncode_BstrWrapInMapN(). It
1704 * can't undo the labels they add. It also doesn't catch the error
1705 * of using it this way. QCBOREncode_CancelBstrWrap() is used
1706 * infrequently and the the result is incorrect CBOR, not a
1707 * security hole, so no extra code or state is added to handle this
1708 * condition.
1709 */
1710#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
1711
1712 Nesting_Decrease(&(pMe->nesting));
1713 Nesting_Decrement(&(pMe->nesting));
1714}
1715
1716
1717/*
Laurence Lundbladeb24faef2022-04-26 11:03:08 -06001718 * Public function for opening a byte string. See qcbor/qcbor_encode.h
1719 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001720void
1721QCBOREncode_OpenBytes(QCBOREncodeContext *pMe, UsefulBuf *pPlace)
Laurence Lundbladeb24faef2022-04-26 11:03:08 -06001722{
1723 *pPlace = UsefulOutBuf_GetOutPlace(&(pMe->OutBuf));
Laurence Lundbladeb24faef2022-04-26 11:03:08 -06001724#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
Paul Liétar79789772022-07-26 20:33:18 +01001725 uint8_t uMajorType = Nesting_GetMajorType(&(pMe->nesting));
1726 if(uMajorType == CBOR_MAJOR_NONE_TYPE_OPEN_BSTR) {
Laurence Lundblade716d10c2024-02-07 16:54:42 -08001727 /* It's OK to nest a byte string in any type but
1728 * another open byte string. */
Paul Liétar79789772022-07-26 20:33:18 +01001729 pMe->uError = QCBOR_ERR_OPEN_BYTE_STRING;
1730 return;
1731 }
Laurence Lundbladeb24faef2022-04-26 11:03:08 -06001732#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
1733
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001734 QCBOREncode_Private_OpenMapOrArray(pMe, CBOR_MAJOR_NONE_TYPE_OPEN_BSTR);
Laurence Lundbladeb24faef2022-04-26 11:03:08 -06001735}
1736
1737
1738/*
1739 * Public function for closing a byte string. See qcbor/qcbor_encode.h
1740 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001741void
1742QCBOREncode_CloseBytes(QCBOREncodeContext *pMe, const size_t uAmount)
Laurence Lundbladeb24faef2022-04-26 11:03:08 -06001743{
1744 UsefulOutBuf_Advance(&(pMe->OutBuf), uAmount);
1745 if(UsefulOutBuf_GetError(&(pMe->OutBuf))) {
1746 /* Advance too far. Normal off-end error handling in effect here. */
1747 return;
1748 }
1749
Laurence Lundbladecbd7d132024-05-19 11:11:22 -07001750 QCBOREncode_Private_CloseAggregate(pMe, CBOR_MAJOR_NONE_TYPE_OPEN_BSTR, uAmount);
Laurence Lundbladeb24faef2022-04-26 11:03:08 -06001751}
1752
1753
Laurence Lundbladecbd7d132024-05-19 11:11:22 -07001754#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
1755
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001756/**
1757 * @brief Semi-private method to close a map, array with indefinite length
1758 *
1759 * @param[in] pMe The context to add to.
1760 * @param[in] uMajorType The major CBOR type to close.
1761 *
1762 * Call QCBOREncode_CloseArrayIndefiniteLength() or
1763 * QCBOREncode_CloseMapIndefiniteLength() instead of this.
Jan Jongboom4a93a662019-07-25 08:44:58 +02001764 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001765void
1766QCBOREncode_Private_CloseMapOrArrayIndefiniteLength(QCBOREncodeContext *pMe,
1767 const uint8_t uMajorType)
Jan Jongboom4a93a662019-07-25 08:44:58 +02001768{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001769 if(QCBOREncode_Private_CheckDecreaseNesting(pMe, uMajorType)) {
Laurence Lundblade274ddef2022-05-17 09:12:23 -07001770 return;
Jan Jongboom4a93a662019-07-25 08:44:58 +02001771 }
Laurence Lundbladedaefdec2020-11-02 20:22:03 -08001772
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001773 /* Append the break marker (0xff for both arrays and maps) */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001774 QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_NONE_TYPE_SIMPLE_BREAK, CBOR_SIMPLE_BREAK, 0);
Laurence Lundblade274ddef2022-05-17 09:12:23 -07001775 Nesting_Decrease(&(pMe->nesting));
Jan Jongboom4a93a662019-07-25 08:44:58 +02001776}
Laurence Lundbladecbd7d132024-05-19 11:11:22 -07001777#endif
Jan Jongboom4a93a662019-07-25 08:44:58 +02001778
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001779
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001780/*
Laurence Lundblade8d3b8552021-06-10 11:11:54 -07001781 * Public function to finish and get the encoded result. See qcbor/qcbor_encode.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001782 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001783QCBORError
1784QCBOREncode_Finish(QCBOREncodeContext *pMe, UsefulBufC *pEncodedCBOR)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001785{
Laurence Lundbladef2f0c3f2024-04-12 13:01:54 -07001786 if(QCBOREncode_GetErrorState(pMe) != QCBOR_SUCCESS) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001787 goto Done;
Laurence Lundblade067035b2018-11-28 17:35:25 -08001788 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001789
Laurence Lundbladedaefdec2020-11-02 20:22:03 -08001790#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001791 if(Nesting_IsInNest(&(pMe->nesting))) {
Laurence Lundbladef2f0c3f2024-04-12 13:01:54 -07001792 pMe->uError = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001793 goto Done;
1794 }
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001795#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001796
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001797 *pEncodedCBOR = UsefulOutBuf_OutUBuf(&(pMe->OutBuf));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001798
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001799Done:
Laurence Lundbladef2f0c3f2024-04-12 13:01:54 -07001800 return pMe->uError;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001801}
1802
Laurence Lundblade0595e932018-11-02 22:22:47 +07001803
Laurence Lundblade067035b2018-11-28 17:35:25 -08001804/*
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001805 * Public functions to get size of the encoded result. See qcbor/qcbor_encode.h
Laurence Lundblade067035b2018-11-28 17:35:25 -08001806 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001807QCBORError
1808QCBOREncode_FinishGetSize(QCBOREncodeContext *pMe, size_t *puEncodedLen)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001809{
Laurence Lundbladeda3f0822018-09-18 19:49:02 -07001810 UsefulBufC Enc;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001811
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001812 QCBORError nReturn = QCBOREncode_Finish(pMe, &Enc);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001813
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001814 if(nReturn == QCBOR_SUCCESS) {
Laurence Lundbladeda3f0822018-09-18 19:49:02 -07001815 *puEncodedLen = Enc.len;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001816 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001817
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001818 return nReturn;
1819}