blob: c30cbce116913ad32001d8bc4e7453464c8598ed [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 Lundbladeb69cad72018-09-13 11:09:01 -070038
Laurence Lundblade1fa579b2020-11-25 00:31:37 -080039/**
40 * @file qcbor_encode.c
Laurence Lundblade3f1318a2021-01-04 18:26:44 -080041 *
Laurence Lundblade1fa579b2020-11-25 00:31:37 -080042 * The entire implementation of the QCBOR encoder.
43 */
44
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070045
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070046/*
Laurence Lundblade1fa579b2020-11-25 00:31:37 -080047 * == Nesting Tracking ==
48 *
49 * The following functions and data type QCBORTrackNesting implement
50 * the nesting management for encoding.
51 *
52 * CBOR's two nesting types, arrays and maps, are tracked here. There
53 * is a limit of QCBOR_MAX_ARRAY_NESTING to the number of arrays and
54 * maps that can be nested in one encoding so the encoding context
55 * stays small enough to fit on the stack.
56 *
57 * When an array/map is opened, pCurrentNesting points to the element
58 * in pArrays that records the type, start position and accumulates a
59 * count of the number of items added. When closed the start position
60 * is used to go back and fill in the type and number of items in the
61 * array/map.
62 *
63 * Encoded output can be a CBOR Sequence (RFC 8742) in which case
64 * there is no top-level array or map. It starts out with a string,
65 * integer or other non-aggregate type. It may have an array or map
66 * other than at the start, in which case that nesting is tracked
67 * here.
68 *
69 * QCBOR has a special feature to allow constructing byte string
70 * wrapped CBOR directly into the output buffer, so no extra buffer is
71 * needed for byte string wrapping. This is implemented as nesting
72 * with the type CBOR_MAJOR_TYPE_BYTE_STRING and is tracked here. Byte
73 * string wrapped CBOR is used by COSE for data that is to be hashed.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070074 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -070075static void
Laurence Lundblade274ddef2022-05-17 09:12:23 -070076Nesting_Init(QCBORTrackNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070077{
Laurence Lundblade1fa579b2020-11-25 00:31:37 -080078 /* Assumes pNesting has been zeroed. */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070079 pNesting->pCurrentNesting = &pNesting->pArrays[0];
Laurence Lundblade1fa579b2020-11-25 00:31:37 -080080 /* Implied CBOR array at the top nesting level. This is never
81 * returned, but makes the item count work correctly.
82 */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070083 pNesting->pCurrentNesting->uMajorType = CBOR_MAJOR_TYPE_ARRAY;
84}
85
Laurence Lundblade8e36f812024-01-26 10:59:29 -070086static uint8_t
Laurence Lundblade274ddef2022-05-17 09:12:23 -070087Nesting_Increase(QCBORTrackNesting *pNesting,
Laurence Lundblade8e36f812024-01-26 10:59:29 -070088 const uint8_t uMajorType,
89 const uint32_t uPos)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070090{
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070091 if(pNesting->pCurrentNesting == &pNesting->pArrays[QCBOR_MAX_ARRAY_NESTING]) {
Laurence Lundblade29497c02020-07-11 15:44:03 -070092 return QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070093 } else {
94 pNesting->pCurrentNesting++;
95 pNesting->pCurrentNesting->uCount = 0;
96 pNesting->pCurrentNesting->uStart = uPos;
97 pNesting->pCurrentNesting->uMajorType = uMajorType;
Laurence Lundblade29497c02020-07-11 15:44:03 -070098 return QCBOR_SUCCESS;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070099 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700100}
101
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700102static void
Laurence Lundblade274ddef2022-05-17 09:12:23 -0700103Nesting_Decrease(QCBORTrackNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700104{
Laurence Lundblade274ddef2022-05-17 09:12:23 -0700105 if(pNesting->pCurrentNesting > &pNesting->pArrays[0]) {
106 pNesting->pCurrentNesting--;
107 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700108}
109
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700110static uint8_t
Laurence Lundblade274ddef2022-05-17 09:12:23 -0700111Nesting_Increment(QCBORTrackNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700112{
Laurence Lundbladedaefdec2020-11-02 20:22:03 -0800113#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
Laurence Lundbladeb95afec2024-08-26 10:51:28 -0700114 if(pNesting->pCurrentNesting->uCount >= QCBOR_MAX_ITEMS_IN_ARRAY) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700115 return QCBOR_ERR_ARRAY_TOO_LONG;
116 }
Laurence Lundbladed253e412024-08-21 11:02:56 -0700117#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800118
Laurence Lundbladee6bcef12020-04-01 10:56:27 -0700119 pNesting->pCurrentNesting->uCount++;
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800120
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700121 return QCBOR_SUCCESS;
122}
123
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700124static void
Laurence Lundblade274ddef2022-05-17 09:12:23 -0700125Nesting_Decrement(QCBORTrackNesting *pNesting)
Laurence Lundblade8d3b8552021-06-10 11:11:54 -0700126{
127 /* No error check for going below 0 here needed because this
128 * is only used by QCBOREncode_CancelBstrWrap() and it checks
129 * the nesting level before calling this. */
130 pNesting->pCurrentNesting->uCount--;
131}
132
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700133static uint16_t
Laurence Lundblade274ddef2022-05-17 09:12:23 -0700134Nesting_GetCount(QCBORTrackNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700135{
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800136 /* The nesting count recorded is always the actual number of
137 * individual data items in the array or map. For arrays CBOR uses
138 * the actual item count. For maps, CBOR uses the number of pairs.
139 * This function returns the number needed for the CBOR encoding,
140 * so it divides the number of items by two for maps to get the
141 * number of pairs.
142 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800143 if(pNesting->pCurrentNesting->uMajorType == CBOR_MAJOR_TYPE_MAP) {
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800144 /* Cast back to uint16_t after integer promotion from bit shift */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800145 return (uint16_t)(pNesting->pCurrentNesting->uCount >> 1);
146 } else {
147 return pNesting->pCurrentNesting->uCount;
148 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700149}
150
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700151static uint32_t
Laurence Lundblade274ddef2022-05-17 09:12:23 -0700152Nesting_GetStartPos(QCBORTrackNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700153{
154 return pNesting->pCurrentNesting->uStart;
155}
156
Laurence Lundbladed8e1c512020-11-04 23:03:44 -0800157#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700158static uint8_t
Laurence Lundblade274ddef2022-05-17 09:12:23 -0700159Nesting_GetMajorType(QCBORTrackNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700160{
161 return pNesting->pCurrentNesting->uMajorType;
162}
163
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700164static bool
Laurence Lundblade274ddef2022-05-17 09:12:23 -0700165Nesting_IsInNest(QCBORTrackNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700166{
Laurence Lundbladeee851742020-01-08 08:37:05 -0800167 return pNesting->pCurrentNesting == &pNesting->pArrays[0] ? false : true;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700168}
Laurence Lundbladee2226742024-08-16 10:50:23 -0700169#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700170
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700171
172
173
174/*
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800175 * == Major CBOR Types ==
176 *
177 * Encoding of the major CBOR types is by these functions:
178 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800179 * CBOR Major Type Public Function
180 * 0 QCBOREncode_AddUInt64()
181 * 0, 1 QCBOREncode_AddUInt64(), QCBOREncode_AddInt64()
182 * 2, 3 QCBOREncode_AddBuffer()
183 * 4, 5 QCBOREncode_OpenMapOrArray(), QCBOREncode_CloseMapOrArray(),
184 * QCBOREncode_OpenMapOrArrayIndefiniteLength(),
185 * QCBOREncode_CloseMapOrArrayIndefiniteLength()
186 * 6 QCBOREncode_AddTag()
187 * 7 QCBOREncode_AddDouble(), QCBOREncode_AddFloat(),
188 * QCBOREncode_AddDoubleNoPreferred(),
189 * QCBOREncode_AddFloatNoPreferred(), QCBOREncode_AddType7()
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800190 *
191 * Additionally, encoding of decimal fractions and bigfloats is by
192 * QCBOREncode_AddExponentAndMantissa() and byte strings that wrap
193 * encoded CBOR are handled by QCBOREncode_OpenMapOrArray() and
194 * QCBOREncode_CloseBstrWrap2().
195 *
196 *
197 * == Error Tracking Plan ==
198 *
199 * Errors are tracked internally and not returned until
200 * QCBOREncode_Finish() or QCBOREncode_GetErrorState() is called. The
201 * CBOR errors are in me->uError. UsefulOutBuf also tracks whether
202 * the buffer is full or not in its context. Once either of these
203 * errors is set they are never cleared. Only QCBOREncode_Init()
204 * resets them. Or said another way, they must never be cleared or
205 * we'll tell the caller all is good when it is not.
206 *
207 * Only one error code is reported by QCBOREncode_Finish() even if
208 * there are multiple errors. The last one set wins. The caller might
209 * have to fix one error to reveal the next one they have to fix.
210 * This is OK.
211 *
212 * The buffer full error tracked by UsefulBuf is only pulled out of
213 * UsefulBuf in QCBOREncode_Finish() so it is the one that usually
214 * wins. UsefulBuf will never go off the end of the buffer even if it
215 * is called again and again when full.
216 *
217 * QCBOR_DISABLE_ENCODE_USAGE_GUARDS disables about half of the error
218 * checks here to reduce code size by about 150 bytes leaving only the
219 * checks for size to avoid buffer overflow. If the calling code is
220 * completely correct, checks are completely unnecessary. For
221 * example, there is no need to check that all the opens are matched
222 * by a close.
223 *
224 * QCBOR_DISABLE_ENCODE_USAGE_GUARDS also disables the check for more
225 * than QCBOR_MAX_ITEMS_IN_ARRAY in an array. Since
Laurence Lundbladeb95afec2024-08-26 10:51:28 -0700226 * QCBOR_MAX_ITEMS_IN_ARRAY is very large (65,534) it is very unlikely
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800227 * to be reached. If it is reached, the count will wrap around to zero
228 * and CBOR that is not well formed will be produced, but there will
229 * be no buffers overrun and new security issues in the code.
230 *
231 * The 8 errors returned here fall into three categories:
232 *
233 * Sizes
234 * QCBOR_ERR_BUFFER_TOO_LARGE -- Encoded output exceeded UINT32_MAX
235 * QCBOR_ERR_BUFFER_TOO_SMALL -- Output buffer too small
236 * QCBOR_ERR_ARRAY_NESTING_TOO_DEEP -- Nesting > QCBOR_MAX_ARRAY_NESTING1
237 * QCBOR_ERR_ARRAY_TOO_LONG -- Too many items added to an array/map [1]
238 *
239 * Nesting constructed incorrectly
240 * QCBOR_ERR_TOO_MANY_CLOSES -- More close calls than opens [1]
241 * QCBOR_ERR_CLOSE_MISMATCH -- Type of close does not match open [1]
242 * QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN -- Finish called without enough closes [1]
243 *
244 * Would generate not-well-formed CBOR
245 * QCBOR_ERR_ENCODE_UNSUPPORTED -- Simple type between 24 and 31 [1]
246 *
247 * [1] indicated disabled by QCBOR_DISABLE_ENCODE_USAGE_GUARDS
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700248 */
249
250
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700251/*
Laurence Lundbladeb9ccd6b2024-02-06 05:44:25 -0700252 * Public function for initialization. See qcbor/qcbor_encode.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700253 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700254void
255QCBOREncode_Init(QCBOREncodeContext *pMe, UsefulBuf Storage)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700256{
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700257 memset(pMe, 0, sizeof(QCBOREncodeContext));
258 UsefulOutBuf_Init(&(pMe->OutBuf), Storage);
259 Nesting_Init(&(pMe->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700260}
261
262
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000263/*
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800264 * Public function to encode a CBOR head. See qcbor/qcbor_encode.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700265 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700266UsefulBufC
267QCBOREncode_EncodeHead(UsefulBuf Buffer,
268 uint8_t uMajorType,
269 uint8_t uMinLen,
270 uint64_t uArgument)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700271{
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800272 /*
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800273 * == Description of the CBOR Head ==
274 *
275 * The head of a CBOR data item
276 * +---+-----+ +--------+ +--------+ +--------+ +--------+
277 * |M T| A R G U M E N T . . . |
278 * +---+-----+ +--------+ +--------+ +--------+ ... +--------+
279 *
280 * Every CBOR data item has a "head". It is made up of the "major
281 * type" and the "argument".
282 *
283 * The major type indicates whether the data item is an integer,
284 * string, array or such. It is encoded in 3 bits giving it a range
285 * from 0 to 7. 0 indicates the major type is a positive integer,
286 * 1 a negative integer, 2 a byte string and so on.
287 *
288 * These 3 bits are the first part of the "initial byte" in a data
289 * item. Every data item has an initial byte, and some only have
290 * the initial byte.
291 *
292 * The argument is essentially a number between 0 and UINT64_MAX
293 * (18446744073709551615). This number is interpreted to mean
294 * different things for the different major types. For major type
295 * 0, a positive integer, it is value of the data item. For major
296 * type 2, a byte string, it is the length in bytes of the byte
297 * string. For major type 4, an array, it is the number of data
298 * items in the array.
299 *
300 * Special encoding is used so that the argument values less than
301 * 24 can be encoded very compactly in the same byte as the major
302 * type is encoded. When the lower 5 bits of the initial byte have
303 * a value less than 24, then that is the value of the argument.
304 *
305 * If the lower 5 bits of the initial byte are less than 24, then
306 * they are the value of the argument. This allows integer values 0
307 * - 23 to be CBOR encoded in just one byte.
308 *
309 * When the value of lower 5 bits are 24, 25, 26, or 27 the
310 * argument is encoded in 1, 2, 4 or 8 bytes following the initial
311 * byte in network byte order (bit endian). The cases when it is
312 * 28, 29 and 30 are reserved for future use. The value 31 is a
313 * special indicator for indefinite length strings, arrays and
314 * maps.
315 *
316 * The lower 5 bits are called the "additional information."
317 *
318 * Thus the CBOR head may be 1, 2, 3, 5 or 9 bytes long.
319 *
320 * It is legal in CBOR to encode the argument using any of these
321 * lengths even if it could be encoded in a shorter length. For
322 * example it is legal to encode a data item representing the
323 * positive integer 0 in 9 bytes even though it could be encoded in
324 * only 0. This is legal to allow for for very simple code or even
325 * hardware-only implementations that just output a register
326 * directly.
327 *
328 * CBOR defines preferred encoding as the encoding of the argument
329 * in the smallest number of bytes needed to encode it.
330 *
331 * This function takes the major type and argument as inputs and
332 * outputs the encoded CBOR head for them. It does conversion to
333 * network byte order. It implements CBOR preferred encoding,
334 * outputting the shortest representation of the argument.
335 *
336 * == Endian Conversion ==
337 *
338 * This code does endian conversion without hton() or knowing the
339 * endianness of the machine by using masks and shifts. This avoids
340 * the dependency on hton() and the mess of figuring out how to
341 * find the machine's endianness.
342 *
343 * This is a good efficient implementation on little-endian
344 * machines. A faster and smaller implementation is possible on
345 * big-endian machines because CBOR/network byte order is
346 * big-endian. However big-endian machines are uncommon.
347 *
348 * On x86, this is about 150 bytes instead of 500 bytes for the
349 * original, more formal unoptimized code.
350 *
351 * This also does the CBOR preferred shortest encoding for integers
352 * and is called to do endian conversion for floats.
353 *
354 * It works backwards from the least significant byte to the most
355 * significant byte.
356 *
357 * == Floating Point ==
358 *
359 * When the major type is 7 and the 5 lower bits have the values
360 * 25, 26 or 27, the argument is a floating-point number that is
361 * half, single or double-precision. Note that it is not the
362 * conversion from a floating-point value to an integer value like
363 * converting 0x00 to 0.00, it is the interpretation of the bits in
364 * the argument as an IEEE 754 float-point number.
365 *
366 * Floating-point numbers must be converted to network byte
367 * order. That is accomplished here by exactly the same code that
368 * converts integer arguments to network byte order.
369 *
370 * There is preferred encoding for floating-point numbers in CBOR,
371 * but it is very different than for integers and it is not
372 * implemented here. Half-precision is preferred to
373 * single-precision which is preferred to double-precision only if
374 * the conversion can be performed without loss of precision. Zero
375 * and infinity can always be converted to half-precision, without
376 * loss but 3.141592653589 cannot.
377 *
378 * The way this function knows to not do preferred encoding on the
379 * argument passed here when it is a floating point number is the
380 * uMinLen parameter. It should be 2, 4 or 8 for half, single and
381 * double precision floating point values. This prevents and the
382 * incorrect removal of leading zeros when encoding arguments that
383 * are floating-point numbers.
384 *
385 * == Use of Type int and Static Analyzers ==
386 *
387 * The type int is used here for several variables because of the
388 * way integer promotion works in C for variables that are uint8_t
389 * or uint16_t. The basic rule is that they will always be promoted
390 * to int if they will fit. These integer variables here need only
391 * hold values less than 255 so they will always fit into an int.
392 *
393 * Most of values stored are never negative, so one might think
394 * that unsigned int would be more correct than int. However the C
395 * integer promotion rules only promote to unsigned int if the
396 * result won't fit into an int even if the promotion is for an
397 * unsigned variable like uint8_t.
398 *
399 * By declaring these int, there are few implicit conversions and
400 * fewer casts needed. Code size is reduced a little. It makes
401 * static analyzers happier.
402 *
403 * Note also that declaring these uint8_t won't stop integer wrap
404 * around if the code is wrong. It won't make the code more
405 * correct.
406 *
407 * https://stackoverflow.com/questions/46073295/implicit-type-promotion-rules
408 * https://stackoverflow.com/questions/589575/what-does-the-c-standard-state-the-size-of-int-long-type-to-be
409 *
410 * Code Reviewers: THIS FUNCTION DOES POINTER MATH
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800411 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800412
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800413 /* The buffer must have room for the largest CBOR HEAD + one
414 * extra. The one extra is needed for this code to work as it does
415 * a pre-decrement.
416 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700417 if(Buffer.len < QCBOR_HEAD_BUFFER_SIZE) {
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000418 return NULLUsefulBufC;
419 }
420
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800421 /* Pointer to last valid byte in the buffer */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700422 uint8_t * const pBufferEnd = &((uint8_t *)Buffer.ptr)[QCBOR_HEAD_BUFFER_SIZE-1];
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000423
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800424 /* Point to the last byte and work backwards */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000425 uint8_t *pByte = pBufferEnd;
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800426 /* The 5 bits in the initial byte that are not the major type */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800427 int nAdditionalInfo;
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800428
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700429#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade8c858ab2020-11-02 19:53:49 -0800430 if(uMajorType > QCBOR_INDEFINITE_LEN_TYPE_MODIFIER) {
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800431 /* Special case for start & end of indefinite length */
Laurence Lundblade8c858ab2020-11-02 19:53:49 -0800432 uMajorType = uMajorType - QCBOR_INDEFINITE_LEN_TYPE_MODIFIER;
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800433 /* This takes advantage of design of CBOR where additional info
434 * is 31 for both opening and closing indefinite length
435 * maps and arrays.
436 */
437 #if CBOR_SIMPLE_BREAK != LEN_IS_INDEFINITE
438 #error additional info for opening array not the same as for closing
439 #endif
Laurence Lundblade8c858ab2020-11-02 19:53:49 -0800440 nAdditionalInfo = CBOR_SIMPLE_BREAK;
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800441
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700442 } else
Laurence Lundbladed253e412024-08-21 11:02:56 -0700443#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700444 if (uArgument < CBOR_TWENTY_FOUR && uMinLen == 0) {
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800445 /* Simple case where argument is < 24 */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000446 nAdditionalInfo = (int)uArgument;
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800447
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800448 } else {
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800449 /* This encodes the argument in 1,2,4 or 8 bytes. The outer loop
450 * runs once for 1 byte and 4 times for 8 bytes. The inner loop
451 * runs 1, 2 or 4 times depending on outer loop counter. This
452 * works backwards shifting 8 bits off the argument being
453 * encoded at a time until all bits from uArgument have been
454 * encoded and the minimum encoding size is reached. Minimum
455 * encoding size is for floating-point numbers that have some
456 * zero-value bytes that must be output.
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800457 */
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800458 static const uint8_t aIterate[] = {1,1,2,4};
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000459
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800460 /* uMinLen passed in is unsigned, but goes negative in the loop
461 * so it must be converted to a signed value.
462 */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000463 int nMinLen = (int)uMinLen;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800464 int i;
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000465 for(i = 0; uArgument || nMinLen > 0; i++) {
466 const int nIterations = (int)aIterate[i];
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800467 for(int j = 0; j < nIterations; j++) {
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000468 *--pByte = (uint8_t)(uArgument & 0xff);
469 uArgument = uArgument >> 8;
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800470 }
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800471 nMinLen -= nIterations;
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800472 }
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800473
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800474 nAdditionalInfo = LEN_IS_ONE_BYTE-1 + i;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700475 }
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800476
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800477 /* This expression integer-promotes to type int. The code above in
478 * function guarantees that nAdditionalInfo will never be larger
479 * than 0x1f. The caller may pass in a too-large uMajor type. The
Laurence Lundblade11654912024-05-09 11:49:24 -0700480 * conversion to uint8_t will cause an integer wrap around and
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800481 * incorrect CBOR will be generated, but no security issue will
482 * occur.
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800483 */
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800484 const int nInitialByte = (uMajorType << 5) + nAdditionalInfo;
485 *--pByte = (uint8_t)nInitialByte;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800486
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000487#ifdef EXTRA_ENCODE_HEAD_CHECK
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800488 /* This is a sanity check that can be turned on to verify the
489 * pointer math in this function is not going wrong. Turn it on and
490 * run the whole test suite to perform the check.
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800491 */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000492 if(pBufferEnd - pByte > 9 || pBufferEnd - pByte < 1 || pByte < (uint8_t *)buffer.ptr) {
493 return NULLUsefulBufC;
494 }
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800495#endif /* EXTRA_ENCODE_HEAD_CHECK */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800496
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800497 /* Length will not go negative because the loops run for at most 8 decrements
498 * of pByte, only one other decrement is made, and the array is sized
499 * for this.
500 */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000501 return (UsefulBufC){pByte, (size_t)(pBufferEnd - pByte)};
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700502}
503
504
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000505/**
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700506 * @brief Increment item counter for maps and arrays.
507 *
508 * @param pMe QCBOR encoding context.
509 *
510 * This is mostly a separate function to make code more readable and
511 * to have fewer occurrences of #ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
512 */
513static void
514QCBOREncode_Private_IncrementMapOrArrayCount(QCBOREncodeContext *pMe)
515{
516#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
517 if(pMe->uError == QCBOR_SUCCESS) {
518 pMe->uError = Nesting_Increment(&(pMe->nesting));
519 }
520#else
521 (void)Nesting_Increment(&(pMe->nesting));
Laurence Lundbladed253e412024-08-21 11:02:56 -0700522#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700523}
524
525
526/**
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800527 * @brief Append the CBOR head, the major type and argument
528 *
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700529 * @param pMe Encoder context.
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800530 * @param uMajorType Major type to insert.
531 * @param uArgument The argument (an integer value or a length).
532 * @param uMinLen The minimum number of bytes for encoding the CBOR argument.
533 *
534 * This formats the CBOR "head" and appends it to the output.
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700535 *
536 * This also increments the array/map item counter in most cases.
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000537 */
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700538void
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700539QCBOREncode_Private_AppendCBORHead(QCBOREncodeContext *pMe,
540 const uint8_t uMajorType,
541 const uint64_t uArgument,
542 const uint8_t uMinLen)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700543{
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800544 /* A stack buffer large enough for a CBOR head */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000545 UsefulBuf_MAKE_STACK_UB (pBufferForEncodedHead, QCBOR_HEAD_BUFFER_SIZE);
546
547 UsefulBufC EncodedHead = QCBOREncode_EncodeHead(pBufferForEncodedHead,
548 uMajorType,
549 uMinLen,
550 uArgument);
551
552 /* No check for EncodedHead == NULLUsefulBufC is performed here to
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800553 * save object code. It is very clear that pBufferForEncodedHead is
554 * the correct size. If EncodedHead == NULLUsefulBufC then
555 * UsefulOutBuf_AppendUsefulBuf() will do nothing so there is no
556 * security hole introduced.
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000557 */
558
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700559 UsefulOutBuf_AppendUsefulBuf(&(pMe->OutBuf), EncodedHead);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700560
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700561 if(!(uMajorType & QCBOR_INDEFINITE_LEN_TYPE_MODIFIER || uMajorType == CBOR_MAJOR_TYPE_TAG)) {
562 /* Don't increment the map count for tag or break because that is
563 * not needed. Don't do it for indefinite-length arrays and maps
564 * because it is done elsewhere. This is never called for definite-length
565 * arrays and maps.
566 */
567 QCBOREncode_Private_IncrementMapOrArrayCount(pMe);
Laurence Lundblade274ddef2022-05-17 09:12:23 -0700568 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700569}
570
Laurence Lundblade56230d12018-11-01 11:14:51 +0700571
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700572/*
Laurence Lundbladed253e412024-08-21 11:02:56 -0700573 * Public function for adding signed integers. See qcbor/qcbor_encode.h
Laurence Lundblade067035b2018-11-28 17:35:25 -0800574 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700575void
576QCBOREncode_AddInt64(QCBOREncodeContext *pMe, const int64_t nNum)
Laurence Lundblade067035b2018-11-28 17:35:25 -0800577{
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800578 uint8_t uMajorType;
579 uint64_t uValue;
Laurence Lundbladedaefdec2020-11-02 20:22:03 -0800580
581 if(nNum < 0) {
Laurence Lundblade9c5c0ef2022-12-23 17:56:27 -0700582 /* In CBOR -1 encodes as 0x00 with major type negative int.
583 * First add one as a signed integer because that will not
584 * overflow. Then change the sign as needed for encoding. (The
585 * opposite order, changing the sign and subtracting, can cause
586 * an overflow when encoding INT64_MIN. */
587 int64_t nTmp = nNum + 1;
588 uValue = (uint64_t)-nTmp;
Laurence Lundbladedaefdec2020-11-02 20:22:03 -0800589 uMajorType = CBOR_MAJOR_TYPE_NEGATIVE_INT;
590 } else {
591 uValue = (uint64_t)nNum;
592 uMajorType = CBOR_MAJOR_TYPE_POSITIVE_INT;
593 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700594 QCBOREncode_Private_AppendCBORHead(pMe, uMajorType, uValue, 0);
Laurence Lundblade067035b2018-11-28 17:35:25 -0800595}
596
597
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700598/**
599 * @brief Semi-private method to add a buffer full of bytes to encoded output.
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800600 *
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700601 * @param[in] pMe The encoding context to add the string to.
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700602 * @param[in] uMajorType The CBOR major type of the bytes.
603 * @param[in] Bytes The bytes to add.
604 *
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700605 * Called by inline functions to add text and byte strings.
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700606 *
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700607 * (This used to support QCBOREncode_AddEncoded() and
608 * QCBOREncode_AddBytesLenOnly(), but that was pulled out to make this
609 * smaller. This is one of the most used methods and they are some of
610 * the least used).
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700611 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700612void
613QCBOREncode_Private_AddBuffer(QCBOREncodeContext *pMe,
614 const uint8_t uMajorType,
615 const UsefulBufC Bytes)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700616{
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700617 QCBOREncode_Private_AppendCBORHead(pMe, uMajorType, Bytes.len, 0);
618 UsefulOutBuf_AppendUsefulBuf(&(pMe->OutBuf), Bytes);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700619}
620
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700621
Laurence Lundblade55a24832018-10-30 04:35:08 +0700622/*
Laurence Lundbladed253e412024-08-21 11:02:56 -0700623 * Public function for adding raw encoded CBOR. See qcbor/qcbor_encode.h
Laurence Lundblade55a24832018-10-30 04:35:08 +0700624 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700625void
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700626QCBOREncode_AddEncoded(QCBOREncodeContext *pMe, const UsefulBufC Encoded)
Laurence Lundblade55a24832018-10-30 04:35:08 +0700627{
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700628 UsefulOutBuf_AppendUsefulBuf(&(pMe->OutBuf), Encoded);
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700629 QCBOREncode_Private_IncrementMapOrArrayCount(pMe);
Laurence Lundblade55a24832018-10-30 04:35:08 +0700630}
631
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700632
Laurence Lundblade8d9e0cd2024-05-25 18:12:19 -0700633#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
634/**
635 * @brief Semi-private method to add a double using preferred encoding.
636 *
637 * @param[in] pMe The encode context.
638 * @param[in] dNum The double to add.
639 *
640 * This converts the double to a float or half-precision if it can be done
641 * without a loss of precision. See QCBOREncode_AddDouble().
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800642 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700643void
Laurence Lundblade8d9e0cd2024-05-25 18:12:19 -0700644QCBOREncode_Private_AddPreferredDouble(QCBOREncodeContext *pMe, const double dNum)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700645{
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700646 const IEEE754_union uNum = IEEE754_DoubleToSmaller(dNum, true);
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700647 QCBOREncode_Private_AddType7(pMe, (uint8_t)uNum.uSize, uNum.uValue);
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -0700648}
Laurence Lundblade9682a532020-06-06 18:33:04 -0700649
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -0700650
Laurence Lundblade8d9e0cd2024-05-25 18:12:19 -0700651/**
652 * @brief Semi-private method to add a float using preferred encoding.
653 *
654 * @param[in] pMe The encode context.
655 * @param[in] fNum The float to add.
656 *
657 * This converts the float to a half-precision if it can be done
658 * without a loss of precision. See QCBOREncode_AddFloat().
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800659 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700660void
Laurence Lundblade8d9e0cd2024-05-25 18:12:19 -0700661QCBOREncode_Private_AddPreferredFloat(QCBOREncodeContext *pMe, const float fNum)
Laurence Lundblade9682a532020-06-06 18:33:04 -0700662{
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700663 const IEEE754_union uNum = IEEE754_SingleToHalf(fNum);
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700664 QCBOREncode_Private_AddType7(pMe, (uint8_t)uNum.uSize, uNum.uValue);
Laurence Lundblade067035b2018-11-28 17:35:25 -0800665}
Laurence Lundbladed253e412024-08-21 11:02:56 -0700666#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundblade067035b2018-11-28 17:35:25 -0800667
668
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -0700669#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700670/**
671 * @brief Semi-private method to add bigfloats and decimal fractions.
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800672 *
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700673 * @param[in] pMe The encoding context to add the value to.
674 * @param[in] uTag The type 6 tag indicating what this is to be.
675 * @param[in] BigNumMantissa Is @ref NULLUsefulBufC if mantissa is an
676 * @c int64_t or the actual big number mantissa
677 * if not.
678 * @param[in] bBigNumIsNegative This is @c true if the big number is negative.
679 * @param[in] nMantissa The @c int64_t mantissa if it is not a big number.
680 * @param[in] nExponent The exponent.
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800681 *
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700682 * This outputs either the @ref CBOR_TAG_DECIMAL_FRACTION or
683 * @ref CBOR_TAG_BIGFLOAT tag. if @c uTag is @ref CBOR_TAG_INVALID64,
684 * then this outputs the "borrowed" content format.
685 *
686 * The tag content output by this is an array with two members, the
687 * exponent and then the mantissa. The mantissa can be either a big
688 * number or an @c int64_t.
689 *
690 * This implementation cannot output an exponent further from 0 than
691 * @c INT64_MAX.
692 *
693 * To output a mantissa that is between INT64_MAX and UINT64_MAX from 0,
694 * it must be as a big number.
695 *
Laurence Lundbladec24e80f2024-10-05 09:01:30 -0700696 * Typically, QCBOREncode_AddTDecimalFraction(), QCBOREncode_AddTBigFloat(),
697 * QCBOREncode_AddTDecimalFractionBigNum() or QCBOREncode_AddTBigFloatBigNum()
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700698 * is called instead of this.
Laurence Lundblade59289e52019-12-30 13:44:37 -0800699 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700700void
701QCBOREncode_Private_AddExpMantissa(QCBOREncodeContext *pMe,
702 const uint64_t uTag,
703 const UsefulBufC BigNumMantissa,
704 const bool bBigNumIsNegative,
705 const int64_t nMantissa,
706 const int64_t nExponent)
Laurence Lundblade59289e52019-12-30 13:44:37 -0800707{
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800708 /* This is for encoding either a big float or a decimal fraction,
709 * both of which are an array of two items, an exponent and a
710 * mantissa. The difference between the two is that the exponent
711 * is base-2 for big floats and base-10 for decimal fractions, but
712 * that has no effect on the code here.
Laurence Lundbladeee851742020-01-08 08:37:05 -0800713 */
Laurence Lundbladeae66d3f2020-09-14 18:12:08 -0700714 if(uTag != CBOR_TAG_INVALID64) {
715 QCBOREncode_AddTag(pMe, uTag);
716 }
Laurence Lundblade59289e52019-12-30 13:44:37 -0800717 QCBOREncode_OpenArray(pMe);
718 QCBOREncode_AddInt64(pMe, nExponent);
719 if(!UsefulBuf_IsNULLC(BigNumMantissa)) {
720 if(bBigNumIsNegative) {
Laurence Lundbladec24e80f2024-10-05 09:01:30 -0700721 QCBOREncode_AddTNegativeBignum(pMe, QCBOR_ENCODE_AS_TAG, BigNumMantissa);
Laurence Lundblade59289e52019-12-30 13:44:37 -0800722 } else {
Laurence Lundbladec24e80f2024-10-05 09:01:30 -0700723 QCBOREncode_AddTPositiveBignum(pMe, QCBOR_ENCODE_AS_TAG, BigNumMantissa);
Laurence Lundblade59289e52019-12-30 13:44:37 -0800724 }
725 } else {
726 QCBOREncode_AddInt64(pMe, nMantissa);
727 }
728 QCBOREncode_CloseArray(pMe);
729}
Laurence Lundbladed253e412024-08-21 11:02:56 -0700730#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade59289e52019-12-30 13:44:37 -0800731
732
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700733/**
734 * @brief Semi-private method to open a map, array or bstr-wrapped CBOR
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800735 *
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700736 * @param[in] pMe The context to add to.
737 * @param[in] uMajorType The major CBOR type to close
738 *
739 * Call QCBOREncode_OpenArray(), QCBOREncode_OpenMap() or
740 * QCBOREncode_BstrWrap() instead of this.
Laurence Lundblade274ddef2022-05-17 09:12:23 -0700741 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700742void
743QCBOREncode_Private_OpenMapOrArray(QCBOREncodeContext *pMe,
744 const uint8_t uMajorType)
Laurence Lundblade067035b2018-11-28 17:35:25 -0800745{
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800746 /* Add one item to the nesting level we are in for the new map or array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700747 QCBOREncode_Private_IncrementMapOrArrayCount(pMe);
Laurence Lundbladed39cd392019-01-11 18:17:38 -0800748
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800749 /* The offset where the length of an array or map will get written
750 * is stored in a uint32_t, not a size_t to keep stack usage
751 * smaller. This checks to be sure there is no wrap around when
752 * recording the offset. Note that on 64-bit machines CBOR larger
753 * than 4GB can be encoded as long as no array/map offsets occur
754 * past the 4GB mark, but the public interface says that the
755 * maximum is 4GB to keep the discussion simpler.
756 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700757 size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(pMe->OutBuf));
Laurence Lundbladed39cd392019-01-11 18:17:38 -0800758
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800759 /* QCBOR_MAX_ARRAY_OFFSET is slightly less than UINT32_MAX so this
760 * code can run on a 32-bit machine and tests can pass on a 32-bit
761 * machine. If it was exactly UINT32_MAX, then this code would not
762 * compile or run on a 32-bit machine and an #ifdef or some machine
763 * size detection would be needed reducing portability.
764 */
Laurence Lundblade3e0a45c2020-11-05 11:12:04 -0800765 if(uEndPosition >= QCBOR_MAX_ARRAY_OFFSET) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700766 pMe->uError = QCBOR_ERR_BUFFER_TOO_LARGE;
Laurence Lundblade3e0a45c2020-11-05 11:12:04 -0800767
768 } else {
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800769 /* Increase nesting level because this is a map or array. Cast
770 * from size_t to uin32_t is safe because of check above.
771 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700772 pMe->uError = Nesting_Increase(&(pMe->nesting), uMajorType, (uint32_t)uEndPosition);
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800773 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700774}
775
Laurence Lundblade59289e52019-12-30 13:44:37 -0800776
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700777#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700778/**
779 * @brief Semi-private method to open a map, array with indefinite length
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800780 *
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700781 * @param[in] pMe The context to add to.
782 * @param[in] uMajorType The major CBOR type to close
783 *
784 * Call QCBOREncode_OpenArrayIndefiniteLength() or
785 * QCBOREncode_OpenMapIndefiniteLength() instead of this.
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800786 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700787void
788QCBOREncode_Private_OpenMapOrArrayIndefiniteLength(QCBOREncodeContext *pMe,
789 const uint8_t uMajorType)
Jan Jongboom4a93a662019-07-25 08:44:58 +0200790{
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800791 /* Insert the indefinite length marker (0x9f for arrays, 0xbf for maps) */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700792 QCBOREncode_Private_AppendCBORHead(pMe, uMajorType, 0, 0);
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800793
794 /* Call the definite-length opener just to do the bookkeeping for
795 * nesting. It will record the position of the opening item in the
796 * encoded output but this is not used when closing this open.
797 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700798 QCBOREncode_Private_OpenMapOrArray(pMe, uMajorType);
Jan Jongboom4a93a662019-07-25 08:44:58 +0200799}
Laurence Lundbladed253e412024-08-21 11:02:56 -0700800#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700801
802
803/**
804 * @brief Check for errors when decreasing nesting.
805 *
806 * @param pMe QCBOR encoding context.
807 * @param uMajorType The major type of the nesting.
808 *
809 * Check that there is no previous error, that there is actually some
810 * nesting and that the major type of the opening of the nesting
811 * matches the major type of the nesting being closed.
812 *
813 * This is called when closing maps, arrays, byte string wrapping and
814 * open/close of byte strings.
815 */
816static bool
817QCBOREncode_Private_CheckDecreaseNesting(QCBOREncodeContext *pMe,
818 const uint8_t uMajorType)
819{
820#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
821 if(pMe->uError != QCBOR_SUCCESS) {
822 return true;
823 }
824
825 if(!Nesting_IsInNest(&(pMe->nesting))) {
826 pMe->uError = QCBOR_ERR_TOO_MANY_CLOSES;
827 return true;
828 }
829
830 if(Nesting_GetMajorType(&(pMe->nesting)) != uMajorType) {
831 pMe->uError = QCBOR_ERR_CLOSE_MISMATCH;
832 return true;
833 }
834
Laurence Lundbladed253e412024-08-21 11:02:56 -0700835#else /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700836 /* None of these checks are performed if the encode guards are
837 * turned off as they all relate to correct calling.
838 *
839 * Turning off all these checks does not turn off any checking for
840 * buffer overflows or pointer issues.
841 */
842
843 (void)uMajorType;
844 (void)pMe;
Laurence Lundbladed253e412024-08-21 11:02:56 -0700845#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700846
847 return false;
848}
849
850
851/**
Laurence Lundbladed253e412024-08-21 11:02:56 -0700852 * @brief Insert the CBOR head for a map, array or wrapped bstr.
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700853 *
854 * @param pMe QCBOR encoding context.
855 * @param uMajorType One of CBOR_MAJOR_TYPE_XXXX.
856 * @param uLen The length of the data item.
857 *
858 * When an array, map or bstr was opened, nothing was done but note
859 * the position. This function goes back to that position and inserts
860 * the CBOR Head with the major type and length.
861 */
862static void
863QCBOREncode_Private_CloseAggregate(QCBOREncodeContext *pMe,
864 uint8_t uMajorType,
865 size_t uLen)
866{
867 if(QCBOREncode_Private_CheckDecreaseNesting(pMe, uMajorType)) {
868 return;
869 }
870
871 if(uMajorType == CBOR_MAJOR_NONE_TYPE_OPEN_BSTR) {
872 uMajorType = CBOR_MAJOR_TYPE_BYTE_STRING;
873 }
874
875 /* A stack buffer large enough for a CBOR head (9 bytes) */
876 UsefulBuf_MAKE_STACK_UB(pBufferForEncodedHead, QCBOR_HEAD_BUFFER_SIZE);
877
878 UsefulBufC EncodedHead = QCBOREncode_EncodeHead(pBufferForEncodedHead,
879 uMajorType,
880 0,
881 uLen);
882
883 /* No check for EncodedHead == NULLUsefulBufC is performed here to
884 * save object code. It is very clear that pBufferForEncodedHead is
885 * the correct size. If EncodedHead == NULLUsefulBufC then
886 * UsefulOutBuf_InsertUsefulBuf() will do nothing so there is no
887 * security hole introduced.
888 */
889 UsefulOutBuf_InsertUsefulBuf(&(pMe->OutBuf),
890 EncodedHead,
891 Nesting_GetStartPos(&(pMe->nesting)));
892
893 Nesting_Decrease(&(pMe->nesting));
894}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700895
Laurence Lundbladeee851742020-01-08 08:37:05 -0800896
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700897/**
898 * @brief Semi-private method to close a map, array or bstr wrapped CBOR
899 *
900 * @param[in] pMe The context to add to.
901 * @param[in] uMajorType The major CBOR type to close.
902 *
903 * Call QCBOREncode_CloseArray() or QCBOREncode_CloseMap() instead of this.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700904 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700905void
906QCBOREncode_Private_CloseMapOrArray(QCBOREncodeContext *pMe,
907 const uint8_t uMajorType)
Laurence Lundbladea954db92018-09-28 19:27:31 -0700908{
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700909 QCBOREncode_Private_CloseAggregate(pMe, uMajorType, Nesting_GetCount(&(pMe->nesting)));
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000910}
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800911
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800912
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000913/*
Laurence Lundbladed253e412024-08-21 11:02:56 -0700914 * Public function for closing bstr wrapping. See qcbor/qcbor_encode.h
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000915 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700916void
917QCBOREncode_CloseBstrWrap2(QCBOREncodeContext *pMe,
918 const bool bIncludeCBORHead,
919 UsefulBufC *pWrappedCBOR)
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000920{
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700921 const size_t uInsertPosition = Nesting_GetStartPos(&(pMe->nesting));
922 const size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(pMe->OutBuf));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800923
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800924 /* This subtraction can't go negative because the UsefulOutBuf
925 * always only grows and never shrinks. UsefulOutBut itself also
926 * has defenses such that it won't write where it should not even
927 * if given incorrect input lengths.
928 */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000929 const size_t uBstrLen = uEndPosition - uInsertPosition;
930
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800931 /* Actually insert */
Laurence Lundbladecbd7d132024-05-19 11:11:22 -0700932 QCBOREncode_Private_CloseAggregate(pMe, CBOR_MAJOR_TYPE_BYTE_STRING, uBstrLen);
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000933
934 if(pWrappedCBOR) {
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800935 /* Return pointer and length to the enclosed encoded CBOR. The
936 * intended use is for it to be hashed (e.g., SHA-256) in a COSE
937 * implementation. This must be used right away, as the pointer
938 * and length go invalid on any subsequent calls to this
939 * function because there might be calls to
940 * InsertEncodedTypeAndNumber() that slides data to the right.
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000941 */
942 size_t uStartOfNew = uInsertPosition;
943 if(!bIncludeCBORHead) {
Laurence Lundblade1fa579b2020-11-25 00:31:37 -0800944 /* Skip over the CBOR head to just get the inserted bstr */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700945 const size_t uNewEndPosition = UsefulOutBuf_GetEndPosition(&(pMe->OutBuf));
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000946 uStartOfNew += uNewEndPosition - uEndPosition;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700947 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700948 const UsefulBufC PartialResult = UsefulOutBuf_OutUBuf(&(pMe->OutBuf));
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000949 *pWrappedCBOR = UsefulBuf_Tail(PartialResult, uStartOfNew);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700950 }
951}
952
Laurence Lundbladeee851742020-01-08 08:37:05 -0800953
Jan Jongboom4a93a662019-07-25 08:44:58 +0200954/*
Laurence Lundblade8d3b8552021-06-10 11:11:54 -0700955 * Public function for canceling a bstr wrap. See qcbor/qcbor_encode.h
956 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700957void
958QCBOREncode_CancelBstrWrap(QCBOREncodeContext *pMe)
Laurence Lundblade8d3b8552021-06-10 11:11:54 -0700959{
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700960 if(QCBOREncode_Private_CheckDecreaseNesting(pMe, CBOR_MAJOR_TYPE_BYTE_STRING)) {
Laurence Lundblade274ddef2022-05-17 09:12:23 -0700961 return;
962 }
963
Laurence Lundblade8d3b8552021-06-10 11:11:54 -0700964#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
Laurence Lundblade274ddef2022-05-17 09:12:23 -0700965 const size_t uCurrent = UsefulOutBuf_GetEndPosition(&(pMe->OutBuf));
966 if(pMe->nesting.pCurrentNesting->uStart != uCurrent) {
967 pMe->uError = QCBOR_ERR_CANNOT_CANCEL;
968 return;
Laurence Lundblade8d3b8552021-06-10 11:11:54 -0700969 }
970 /* QCBOREncode_CancelBstrWrap() can't correctly undo
Laurence Lundbladec24e80f2024-10-05 09:01:30 -0700971 * QCBOREncode_BstrWrapInMapSZ() or QCBOREncode_BstrWrapInMapN(). It
Laurence Lundblade8d3b8552021-06-10 11:11:54 -0700972 * can't undo the labels they add. It also doesn't catch the error
973 * of using it this way. QCBOREncode_CancelBstrWrap() is used
974 * infrequently and the the result is incorrect CBOR, not a
975 * security hole, so no extra code or state is added to handle this
976 * condition.
977 */
Laurence Lundbladed253e412024-08-21 11:02:56 -0700978#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
Laurence Lundblade8d3b8552021-06-10 11:11:54 -0700979
980 Nesting_Decrease(&(pMe->nesting));
981 Nesting_Decrement(&(pMe->nesting));
982}
983
984
985/*
Laurence Lundbladeb24faef2022-04-26 11:03:08 -0600986 * Public function for opening a byte string. See qcbor/qcbor_encode.h
987 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700988void
989QCBOREncode_OpenBytes(QCBOREncodeContext *pMe, UsefulBuf *pPlace)
Laurence Lundbladeb24faef2022-04-26 11:03:08 -0600990{
991 *pPlace = UsefulOutBuf_GetOutPlace(&(pMe->OutBuf));
Laurence Lundbladeb24faef2022-04-26 11:03:08 -0600992#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
Paul Liétar79789772022-07-26 20:33:18 +0100993 uint8_t uMajorType = Nesting_GetMajorType(&(pMe->nesting));
994 if(uMajorType == CBOR_MAJOR_NONE_TYPE_OPEN_BSTR) {
Laurence Lundblade716d10c2024-02-07 16:54:42 -0800995 /* It's OK to nest a byte string in any type but
996 * another open byte string. */
Paul Liétar79789772022-07-26 20:33:18 +0100997 pMe->uError = QCBOR_ERR_OPEN_BYTE_STRING;
998 return;
999 }
Laurence Lundbladed253e412024-08-21 11:02:56 -07001000#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
Laurence Lundbladeb24faef2022-04-26 11:03:08 -06001001
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001002 QCBOREncode_Private_OpenMapOrArray(pMe, CBOR_MAJOR_NONE_TYPE_OPEN_BSTR);
Laurence Lundbladeb24faef2022-04-26 11:03:08 -06001003}
1004
1005
1006/*
1007 * Public function for closing a byte string. See qcbor/qcbor_encode.h
1008 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001009void
1010QCBOREncode_CloseBytes(QCBOREncodeContext *pMe, const size_t uAmount)
Laurence Lundbladeb24faef2022-04-26 11:03:08 -06001011{
1012 UsefulOutBuf_Advance(&(pMe->OutBuf), uAmount);
1013 if(UsefulOutBuf_GetError(&(pMe->OutBuf))) {
1014 /* Advance too far. Normal off-end error handling in effect here. */
1015 return;
1016 }
1017
Laurence Lundbladecbd7d132024-05-19 11:11:22 -07001018 QCBOREncode_Private_CloseAggregate(pMe, CBOR_MAJOR_NONE_TYPE_OPEN_BSTR, uAmount);
Laurence Lundbladeb24faef2022-04-26 11:03:08 -06001019}
1020
1021
Laurence Lundbladecbd7d132024-05-19 11:11:22 -07001022#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001023/**
1024 * @brief Semi-private method to close a map, array with indefinite length
1025 *
1026 * @param[in] pMe The context to add to.
1027 * @param[in] uMajorType The major CBOR type to close.
1028 *
1029 * Call QCBOREncode_CloseArrayIndefiniteLength() or
1030 * QCBOREncode_CloseMapIndefiniteLength() instead of this.
Jan Jongboom4a93a662019-07-25 08:44:58 +02001031 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001032void
1033QCBOREncode_Private_CloseMapOrArrayIndefiniteLength(QCBOREncodeContext *pMe,
1034 const uint8_t uMajorType)
Jan Jongboom4a93a662019-07-25 08:44:58 +02001035{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001036 if(QCBOREncode_Private_CheckDecreaseNesting(pMe, uMajorType)) {
Laurence Lundblade274ddef2022-05-17 09:12:23 -07001037 return;
Jan Jongboom4a93a662019-07-25 08:44:58 +02001038 }
Laurence Lundbladedaefdec2020-11-02 20:22:03 -08001039
Laurence Lundblade1fa579b2020-11-25 00:31:37 -08001040 /* Append the break marker (0xff for both arrays and maps) */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001041 QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_NONE_TYPE_SIMPLE_BREAK, CBOR_SIMPLE_BREAK, 0);
Laurence Lundblade274ddef2022-05-17 09:12:23 -07001042 Nesting_Decrease(&(pMe->nesting));
Jan Jongboom4a93a662019-07-25 08:44:58 +02001043}
Laurence Lundbladed253e412024-08-21 11:02:56 -07001044#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Jan Jongboom4a93a662019-07-25 08:44:58 +02001045
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001046
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001047/*
Laurence Lundblade8d3b8552021-06-10 11:11:54 -07001048 * Public function to finish and get the encoded result. See qcbor/qcbor_encode.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001049 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001050QCBORError
1051QCBOREncode_Finish(QCBOREncodeContext *pMe, UsefulBufC *pEncodedCBOR)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001052{
Laurence Lundbladef2f0c3f2024-04-12 13:01:54 -07001053 if(QCBOREncode_GetErrorState(pMe) != QCBOR_SUCCESS) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001054 goto Done;
Laurence Lundblade067035b2018-11-28 17:35:25 -08001055 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001056
Laurence Lundbladedaefdec2020-11-02 20:22:03 -08001057#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001058 if(Nesting_IsInNest(&(pMe->nesting))) {
Laurence Lundbladef2f0c3f2024-04-12 13:01:54 -07001059 pMe->uError = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001060 goto Done;
1061 }
Laurence Lundbladed253e412024-08-21 11:02:56 -07001062#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001063
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001064 *pEncodedCBOR = UsefulOutBuf_OutUBuf(&(pMe->OutBuf));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001065
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001066Done:
Laurence Lundbladef2f0c3f2024-04-12 13:01:54 -07001067 return pMe->uError;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001068}
1069
Laurence Lundblade0595e932018-11-02 22:22:47 +07001070
Laurence Lundblade067035b2018-11-28 17:35:25 -08001071/*
Laurence Lundbladed253e412024-08-21 11:02:56 -07001072 * Public function to get size of the encoded result. See qcbor/qcbor_encode.h
Laurence Lundblade067035b2018-11-28 17:35:25 -08001073 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001074QCBORError
1075QCBOREncode_FinishGetSize(QCBOREncodeContext *pMe, size_t *puEncodedLen)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001076{
Laurence Lundbladeda3f0822018-09-18 19:49:02 -07001077 UsefulBufC Enc;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001078
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001079 QCBORError nReturn = QCBOREncode_Finish(pMe, &Enc);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001080
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001081 if(nReturn == QCBOR_SUCCESS) {
Laurence Lundbladeda3f0822018-09-18 19:49:02 -07001082 *puEncodedLen = Enc.len;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001083 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001084
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001085 return nReturn;
1086}
Laurence Lundbladee2226742024-08-16 10:50:23 -07001087
1088
1089/*
1090 * Public function to get substring of encoded-so-far. See qcbor/qcbor_encode.h
1091 */
1092UsefulBufC
1093QCBOREncode_SubString(QCBOREncodeContext *pMe, const size_t uStart)
1094{
1095 if(pMe->uError) {
1096 return NULLUsefulBufC;
1097 }
1098
1099 /* An attempt was made to detect usage errors by comparing uStart
1100 * to offsets of open arrays and maps in pMe->nesting, but it is
1101 * not possible because there's not enough information in just
1102 * the offset. It's not possible to known if Tell() was called before
1103 * or after an Open(). To detect this error, the nesting level
1104 * would also need to be known. This is not frequently used, so
1105 * it is not worth adding this complexity.
1106 */
1107
1108 const size_t uEnd = QCBOREncode_Tell(pMe);
1109
1110 return UsefulOutBuf_SubString(&(pMe->OutBuf), uStart, uEnd - uStart);
1111}