blob: 623b8d5c3d0d31f64f03f0de72cb34f348b762fc [file] [log] [blame]
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001/*==============================================================================
Laurence Lundbladed92a6162018-11-01 11:38:35 +07002 Copyright (c) 2016-2018, The Linux Foundation.
Laurence Lundbladeee851742020-01-08 08:37:05 -08003 Copyright (c) 2018-2020, Laurence Lundblade.
Laurence Lundbladed92a6162018-11-01 11:38:35 +07004 All rights reserved.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08005
Laurence Lundblade0dbc9172018-11-01 14:17:21 +07006Redistribution and use in source and binary forms, with or without
7modification, are permitted provided that the following conditions are
8met:
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of The Linux Foundation nor the names of its
16 contributors, nor the name "Laurence Lundblade" may be used to
17 endorse or promote products derived from this software without
18 specific prior written permission.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080019
Laurence Lundblade0dbc9172018-11-01 14:17:21 +070020THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
21WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
23ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
24BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
27BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
29OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
30IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Laurence Lundbladeee851742020-01-08 08:37:05 -080031 =============================================================================*/
Laurence Lundblade624405d2018-09-18 20:10:47 -070032
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080033
Laurence Lundblade844bb5c2020-03-01 17:27:25 -080034#include "qcbor/qcbor_encode.h"
Laurence Lundblade12d32c52018-09-19 11:25:27 -070035#include "ieee754.h"
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070036
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070037
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070038
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070039/*
Laurence Lundbladeee851742020-01-08 08:37:05 -080040 Nesting -- This tracks the nesting of maps and arrays.
41
42 The following functions and data type QCBORTrackNesting implement the
43 nesting management for encoding.
44
45 CBOR's two nesting types, arrays and maps, are tracked here. There is
46 a limit of QCBOR_MAX_ARRAY_NESTING to the number of arrays and maps
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070047 that can be nested in one encoding so the encoding context stays
48 small enough to fit on the stack.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080049
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070050 When an array / map is opened, pCurrentNesting points to the element
Laurence Lundbladeee851742020-01-08 08:37:05 -080051 in pArrays that records the type, start position and accumulates a
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070052 count of the number of items added. When closed the start position is
53 used to go back and fill in the type and number of items in the array
54 / map.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080055
Laurence Lundbladeee851742020-01-08 08:37:05 -080056 Encoded output can be just items like ints and strings that are not
57 part of any array / map. That is, the first thing encoded does not
58 have to be an array or a map.
59
60 QCBOR has a special feature to allow constructing bstr-wrapped CBOR
61 directly into the output buffer, so an extra buffer for it is not
62 needed. This is implemented as nesting with type
63 CBOR_MAJOR_TYPE_BYTE_STRING and uses this code. Bstr-wrapped CBOR is
64 used by COSE for data that is to be hashed.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070065 */
66inline static void Nesting_Init(QCBORTrackNesting *pNesting)
67{
Laurence Lundbladeee851742020-01-08 08:37:05 -080068 // Assumes pNesting has been zeroed
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070069 pNesting->pCurrentNesting = &pNesting->pArrays[0];
70 // Implied CBOR array at the top nesting level. This is never returned,
71 // but makes the item count work correctly.
72 pNesting->pCurrentNesting->uMajorType = CBOR_MAJOR_TYPE_ARRAY;
73}
74
Laurence Lundblade29497c02020-07-11 15:44:03 -070075inline static uint8_t Nesting_Increase(QCBORTrackNesting *pNesting,
Laurence Lundblade2c40ab82018-12-30 14:20:29 -080076 uint8_t uMajorType,
77 uint32_t uPos)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070078{
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070079 if(pNesting->pCurrentNesting == &pNesting->pArrays[QCBOR_MAX_ARRAY_NESTING]) {
Laurence Lundbladeee851742020-01-08 08:37:05 -080080 // Trying to open one too many
Laurence Lundblade29497c02020-07-11 15:44:03 -070081 return QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070082 } else {
83 pNesting->pCurrentNesting++;
84 pNesting->pCurrentNesting->uCount = 0;
85 pNesting->pCurrentNesting->uStart = uPos;
86 pNesting->pCurrentNesting->uMajorType = uMajorType;
Laurence Lundblade29497c02020-07-11 15:44:03 -070087 return QCBOR_SUCCESS;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070088 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070089}
90
91inline static void Nesting_Decrease(QCBORTrackNesting *pNesting)
92{
93 pNesting->pCurrentNesting--;
94}
95
Laurence Lundblade29497c02020-07-11 15:44:03 -070096inline static uint8_t Nesting_Increment(QCBORTrackNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070097{
Laurence Lundbladedaefdec2020-11-02 20:22:03 -080098#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -080099 if(1 >= QCBOR_MAX_ITEMS_IN_ARRAY - pNesting->pCurrentNesting->uCount) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700100 return QCBOR_ERR_ARRAY_TOO_LONG;
101 }
Laurence Lundbladedaefdec2020-11-02 20:22:03 -0800102#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800103
Laurence Lundbladee6bcef12020-04-01 10:56:27 -0700104 pNesting->pCurrentNesting->uCount++;
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800105
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700106 return QCBOR_SUCCESS;
107}
108
109inline static uint16_t Nesting_GetCount(QCBORTrackNesting *pNesting)
110{
111 // The nesting count recorded is always the actual number of individiual
112 // data items in the array or map. For arrays CBOR uses the actual item
113 // count. For maps, CBOR uses the number of pairs. This function returns
114 // the number needed for the CBOR encoding, so it divides the number of
115 // items by two for maps to get the number of pairs. This implementation
116 // takes advantage of the map major type being one larger the array major
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800117 // type, hence uDivisor is either 1 or 2.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800118
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800119 if(pNesting->pCurrentNesting->uMajorType == CBOR_MAJOR_TYPE_MAP) {
120 // Cast back to uint16_t after integer promotion for bit shift
121 return (uint16_t)(pNesting->pCurrentNesting->uCount >> 1);
122 } else {
123 return pNesting->pCurrentNesting->uCount;
124 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700125}
126
127inline static uint32_t Nesting_GetStartPos(QCBORTrackNesting *pNesting)
128{
129 return pNesting->pCurrentNesting->uStart;
130}
131
Laurence Lundbladed8e1c512020-11-04 23:03:44 -0800132#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700133inline static uint8_t Nesting_GetMajorType(QCBORTrackNesting *pNesting)
134{
135 return pNesting->pCurrentNesting->uMajorType;
136}
137
Laurence Lundbladeee851742020-01-08 08:37:05 -0800138inline static bool Nesting_IsInNest(QCBORTrackNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700139{
Laurence Lundbladeee851742020-01-08 08:37:05 -0800140 return pNesting->pCurrentNesting == &pNesting->pArrays[0] ? false : true;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700141}
Laurence Lundbladed8e1c512020-11-04 23:03:44 -0800142#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700143
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700144
145
146
147/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800148 Encoding of the major CBOR types is by these functions:
149
150 CBOR Major Type Public Function
151 0 QCBOREncode_AddUInt64()
152 0, 1 QCBOREncode_AddUInt64(), QCBOREncode_AddInt64()
153 2, 3 QCBOREncode_AddBuffer(), Also QCBOREncode_OpenMapOrArray(),
154 QCBOREncode_CloseMapOrArray()
155 4, 5 QCBOREncode_OpenMapOrArray(), QCBOREncode_CloseMapOrArray(),
156 QCBOREncode_OpenMapOrArrayIndefiniteLength(),
157 QCBOREncode_CloseMapOrArrayIndefiniteLength()
158 6 QCBOREncode_AddTag()
159 7 QCBOREncode_AddDouble(), QCBOREncode_AddType7()
160
161 Additionally, encoding of decimal fractions and bigfloats is by
162 QCBOREncode_AddExponentAndMantissa()
163*/
164
165/*
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700166 Error tracking plan -- Errors are tracked internally and not returned
Laurence Lundblade3e0a45c2020-11-05 11:12:04 -0800167 until QCBOREncode_Finish() or QCBOREncode_GetErrorState() is
168 called. The CBOR errors are in me->uError. UsefulOutBuf also tracks
169 whether the buffer is full or not in its context. Once either of
170 these errors is set they are never cleared. Only QCBOREncode_Init()
171 resets them. Or said another way, they must never be cleared or we'll
172 tell the caller all is good when it is not.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800173
Laurence Lundblade3e0a45c2020-11-05 11:12:04 -0800174 Only one error code is reported by QCBOREncode_Finish() even if there
175 are multiple errors. The last one set wins. The caller might have to
176 fix one error to reveal the next one they have to fix. This is OK.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800177
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700178 The buffer full error tracked by UsefulBuf is only pulled out of
Laurence Lundblade3e0a45c2020-11-05 11:12:04 -0800179 UsefulBuf in QCBOREncode_Finish() so it is the one that usually wins.
180 UsefulBuf will never go off the end of the buffer even if it is
181 called again and again when full.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800182
Laurence Lundblade3e0a45c2020-11-05 11:12:04 -0800183 QCBOR_DISABLE_ENCODE_USAGE_GUARDS disables about half of the error
184 checks here to reduce code size by about 150 bytes leaving only the
185 checks for size to avoid buffer overflow. If the calling code is
186 completely correct, checks are completely unnecessary. For example,
187 there is no need to check that all the opens are matched by a close.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800188
Laurence Lundblade3e0a45c2020-11-05 11:12:04 -0800189 QCBOR_DISABLE_ENCODE_USAGE_GUARDS also disables the check for more
190 than QCBOR_MAX_ITEMS_IN_ARRAY in an array. Since
191 QCBOR_MAX_ITEMS_IN_ARRAY is very large (65,535) it is very unlikely
192 to be reached. If it is reached, the count will wrap around to zero
193 and CBOR that is not well formed will be produced, but there will be
194 no buffers overrun and new security issues in the code.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800195
Laurence Lundbladeee851742020-01-08 08:37:05 -0800196 The 8 errors returned here fall into three categories:
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800197
Laurence Lundblade067035b2018-11-28 17:35:25 -0800198 Sizes
Laurence Lundbladeee851742020-01-08 08:37:05 -0800199 QCBOR_ERR_BUFFER_TOO_LARGE -- Encoded output exceeded UINT32_MAX
200 QCBOR_ERR_BUFFER_TOO_SMALL -- Output buffer too small
201 QCBOR_ERR_ARRAY_NESTING_TOO_DEEP -- Nesting > QCBOR_MAX_ARRAY_NESTING1
Laurence Lundblade3e0a45c2020-11-05 11:12:04 -0800202 QCBOR_ERR_ARRAY_TOO_LONG -- Too many items added to an array/map [1]
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800203
Laurence Lundblade067035b2018-11-28 17:35:25 -0800204 Nesting constructed incorrectly
Laurence Lundblade3e0a45c2020-11-05 11:12:04 -0800205 QCBOR_ERR_TOO_MANY_CLOSES -- More close calls than opens [1]
206 QCBOR_ERR_CLOSE_MISMATCH -- Type of close does not match open [1]
207 QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN -- Finish called without enough closes [1]
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700208
209 Would generate not-well-formed CBOR
Laurence Lundblade3e0a45c2020-11-05 11:12:04 -0800210 QCBOR_ERR_ENCODE_UNSUPPORTED -- Simple type between 24 and 31 [1]
211
212 [1] indicated disabled by QCBOR_DISABLE_ENCODE_USAGE_GUARDS
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700213 */
214
215
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700216/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800217 Public function for initialization. See qcbor/qcbor_encode.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700218 */
Laurence Lundblade2296db52018-09-14 18:08:39 -0700219void QCBOREncode_Init(QCBOREncodeContext *me, UsefulBuf Storage)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700220{
221 memset(me, 0, sizeof(QCBOREncodeContext));
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800222 UsefulOutBuf_Init(&(me->OutBuf), Storage);
223 Nesting_Init(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700224}
225
226
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000227/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800228 Public function to encode a CBOR head. See qcbor/qcbor_encode.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700229 */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000230UsefulBufC QCBOREncode_EncodeHead(UsefulBuf buffer,
231 uint8_t uMajorType,
232 uint8_t uMinLen,
233 uint64_t uArgument)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700234{
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000235 /**
236 All CBOR data items have a type and an "argument". The argument is
237 either the value of the item for integer types, the length of the
238 content for string, byte, array and map types, a tag for major type
239 6, and has several uses for major type 7.
240
241 This function encodes the type and the argument. There are several
242 encodings for the argument depending on how large it is and how it is
243 used.
244
245 Every encoding of the type and argument has at least one byte, the
246 "initial byte".
247
248 The top three bits of the initial byte are the major type for the
249 CBOR data item. The eight major types defined by the standard are
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800250 defined as CBOR_MAJOR_TYPE_xxxx in qcbor/qcbor_common.h.
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000251
252 The remaining five bits, known as "additional information", and
253 possibly more bytes encode the argument. If the argument is less than
254 24, then it is encoded entirely in the five bits. This is neat
255 because it allows you to encode an entire CBOR data item in 1 byte
256 for many values and types (integers 0-23, true, false, and tags).
257
258 If the argument is larger than 24, then it is encoded in 1,2,4 or 8
259 additional bytes, with the number of these bytes indicated by the
260 values of the 5 bits 24, 25, 25 and 27.
261
262 It is possible to encode a particular argument in many ways with this
263 representation. This implementation always uses the smallest
264 possible representation. This conforms with CBOR preferred encoding.
265
266 This function inserts them into the output buffer at the specified
267 position. AppendEncodedTypeAndNumber() appends to the end.
268
269 This function takes care of converting to network byte order.
270
271 This function is also used to insert floats and doubles. Before this
272 function is called the float or double must be copied into a
273 uint64_t. That is how they are passed in. They are then converted to
274 network byte order correctly. The uMinLen parameter makes sure that
275 even if all the digits of a half, float or double are 0 it is still
276 correctly encoded in 2, 4 or 8 bytes.
277 */
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800278 /*
279 This code does endian conversion without hton or knowing the
Laurence Lundblade241705e2018-12-30 18:56:14 -0800280 endianness of the machine using masks and shifts. This avoids the
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800281 dependency on hton and the mess of figuring out how to find the
282 machine's endianness.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800283
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800284 This is a good efficient implementation on little-endian machines.
285 A faster and small implementation is possible on big-endian
286 machines because CBOR/network byte order is big endian. However
287 big endian machines are uncommon.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800288
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800289 On x86, it is about 200 bytes instead of 500 bytes for the more
290 formal unoptimized code.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800291
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800292 This also does the CBOR preferred shortest encoding for integers
293 and is called to do endian conversion for floats.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800294
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800295 It works backwards from the LSB to the MSB as needed.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800296
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800297 Code Reviewers: THIS FUNCTION DOES POINTER MATH
298 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800299 /*
300 The type int is used here for several variables because of the way
301 integer promotion works in C for integer variables that are
302 uint8_t or uint16_t. The basic rule is that they will always be
303 promoted to int if they will fit. All of these integer variables
304 need only hold values less than 255 or are promoted from uint8_t,
305 so they will always fit into an int. Note that promotion is only
306 to unsigned int if the value won't fit into an int even if the
307 promotion is for an unsigned like uint8_t.
308
309 By declaring them int, there are few implicit conversions and fewer
310 casts needed. Code size is reduced a little. It also makes static
311 analyzers happier.
312
313 Note also that declaring them uint8_t won't stop integer wrap
314 around if the code is wrong. It won't make the code more correct.
315
316 https://stackoverflow.com/questions/46073295/implicit-type-promotion-rules
317 https://stackoverflow.com/questions/589575/what-does-the-c-standard-state-the-size-of-int-long-type-to-be
318 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800319
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000320 // Buffer must have room for the largest CBOR HEAD + one extra as the
321 // one extra is needed for this code to work as it does a pre-decrement.
322 if(buffer.len < QCBOR_HEAD_BUFFER_SIZE) {
323 return NULLUsefulBufC;
324 }
325
326 // Pointer to last valid byte in the buffer
327 uint8_t * const pBufferEnd = &((uint8_t *)buffer.ptr)[QCBOR_HEAD_BUFFER_SIZE-1];
328
329 // Point to the last byte and work backwards
330 uint8_t *pByte = pBufferEnd;
331 // The 5 bits in the initial byte that are not the major type
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800332 int nAdditionalInfo;
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800333
Laurence Lundblade8c858ab2020-11-02 19:53:49 -0800334 if(uMajorType > QCBOR_INDEFINITE_LEN_TYPE_MODIFIER) {
335 // Special case for start & end of indefinite length
336 uMajorType = uMajorType - QCBOR_INDEFINITE_LEN_TYPE_MODIFIER;
337 // Take advantage of design of CBOR where additional info
338 // is 31 for both opening and closing indefinite length
339 // maps and arrays.
340#if CBOR_SIMPLE_BREAK != LEN_IS_INDEFINITE
341#error additional info for opening array not the same as for closing
Laurence Lundbladedaefdec2020-11-02 20:22:03 -0800342#endif
Laurence Lundblade8c858ab2020-11-02 19:53:49 -0800343 nAdditionalInfo = CBOR_SIMPLE_BREAK;
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000344 } else if (uArgument < CBOR_TWENTY_FOUR && uMinLen == 0) {
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800345 // Simple case where argument is < 24
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000346 nAdditionalInfo = (int)uArgument;
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800347 } else {
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800348 /*
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000349 Encode argument in 1,2,4 or 8 bytes. Outer loop
350 runs once for 1 byte and 4 times for 8 bytes.
351 Inner loop runs 1, 2 or 4 times depending on
352 outer loop counter. This works backwards taking
353 8 bits off the argument being encoded at a time
354 until all bits from uNumber have been encoded
355 and the minimum encoding size is reached.
356 Minimum encoding size is for floating point
357 numbers with zero bytes.
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800358 */
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800359 static const uint8_t aIterate[] = {1,1,2,4};
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000360
361 // The parameter passed in is unsigned, but goes negative in the loop
362 // so it must be converted to a signed value.
363 int nMinLen = (int)uMinLen;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800364 int i;
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000365 for(i = 0; uArgument || nMinLen > 0; i++) {
366 const int nIterations = (int)aIterate[i];
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800367 for(int j = 0; j < nIterations; j++) {
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000368 *--pByte = (uint8_t)(uArgument & 0xff);
369 uArgument = uArgument >> 8;
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800370 }
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800371 nMinLen -= nIterations;
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800372 }
Laurence Lundbladeee851742020-01-08 08:37:05 -0800373 // Additional info is the encoding of the number of additional
374 // bytes to encode argument.
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800375 nAdditionalInfo = LEN_IS_ONE_BYTE-1 + i;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700376 }
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800377
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800378 /*
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000379 This expression integer-promotes to type int. The code above in
380 function guarantees that nAdditionalInfo will never be larger than
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800381 0x1f. The caller may pass in a too-large uMajor type. The
382 conversion to unint8_t will cause an integer wrap around and
383 incorrect CBOR will be generated, but no security issue will
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000384 occur.
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800385 */
386 *--pByte = (uint8_t)((uMajorType << 5) + nAdditionalInfo);
387
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000388#ifdef EXTRA_ENCODE_HEAD_CHECK
389 /* This is a sanity check that can be turned on to verify the pointer
390 * math in this function is not going wrong. Turn it on and run the
391 * whole test suite to perform the check.
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800392 */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000393 if(pBufferEnd - pByte > 9 || pBufferEnd - pByte < 1 || pByte < (uint8_t *)buffer.ptr) {
394 return NULLUsefulBufC;
395 }
396#endif
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800397
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000398 // Length will not go negative because the loops run for at most 8 decrements
399 // of pByte, only one other decrement is made, and the array is sized
400 // for this.
401 return (UsefulBufC){pByte, (size_t)(pBufferEnd - pByte)};
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700402}
403
404
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000405/**
406 @brief Append the CBOR head, the major type and argument
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800407
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000408 @param me Encoder context.
409 @param uMajorType Major type to insert.
410 @param uArgument The argument (an integer value or a length).
411 @param uMinLen The minimum number of bytes for encoding the CBOR argument.
412
413 This formats the CBOR "head" and appends it to the output.
414 */
415static void AppendCBORHead(QCBOREncodeContext *me, uint8_t uMajorType, uint64_t uArgument, uint8_t uMinLen)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700416{
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000417 // A stack buffer large enough for a CBOR head
418 UsefulBuf_MAKE_STACK_UB (pBufferForEncodedHead, QCBOR_HEAD_BUFFER_SIZE);
419
420 UsefulBufC EncodedHead = QCBOREncode_EncodeHead(pBufferForEncodedHead,
421 uMajorType,
422 uMinLen,
423 uArgument);
424
425 /* No check for EncodedHead == NULLUsefulBufC is performed here to
426 * save object code. It is very clear that pBufferForEncodedHead
427 * is the correct size. If EncodedHead == NULLUsefulBufC then
428 * UsefulOutBuf_AppendUsefulBuf() will do nothing so there is
429 * no security hole introduced.
430 */
431
432 UsefulOutBuf_AppendUsefulBuf(&(me->OutBuf), EncodedHead);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700433}
434
435
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000436/**
437 @brief Insert the CBOR head for a map, array or wrapped bstr
438
439 @param me QCBOR encoding context.
440 @param uMajorType One of CBOR_MAJOR_TYPE_XXXX.
441 @param uLen The length of the data item.
442
443 When an array, map or bstr was opened, nothing was done but note
444 the position. This function goes back to that position and inserts
445 the CBOR Head with the major type and length.
446 */
447static void InsertCBORHead(QCBOREncodeContext *me, uint8_t uMajorType, size_t uLen)
448{
Laurence Lundbladedaefdec2020-11-02 20:22:03 -0800449#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000450 if(me->uError == QCBOR_SUCCESS) {
451 if(!Nesting_IsInNest(&(me->nesting))) {
452 me->uError = QCBOR_ERR_TOO_MANY_CLOSES;
Laurence Lundbladedaefdec2020-11-02 20:22:03 -0800453 return;
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000454 } else if(Nesting_GetMajorType(&(me->nesting)) != uMajorType) {
455 me->uError = QCBOR_ERR_CLOSE_MISMATCH;
Laurence Lundbladedaefdec2020-11-02 20:22:03 -0800456 return;
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000457 }
458 }
Laurence Lundbladedaefdec2020-11-02 20:22:03 -0800459#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
Laurence Lundbladed8e1c512020-11-04 23:03:44 -0800460
Laurence Lundbladedaefdec2020-11-02 20:22:03 -0800461 // A stack buffer large enough for a CBOR head
Laurence Lundbladed8e1c512020-11-04 23:03:44 -0800462 UsefulBuf_MAKE_STACK_UB(pBufferForEncodedHead, QCBOR_HEAD_BUFFER_SIZE);
Laurence Lundbladedaefdec2020-11-02 20:22:03 -0800463
464 UsefulBufC EncodedHead = QCBOREncode_EncodeHead(pBufferForEncodedHead,
465 uMajorType,
466 0,
467 uLen);
468
469 /* No check for EncodedHead == NULLUsefulBufC is performed here to
470 * save object code. It is very clear that pBufferForEncodedHead
471 * is the correct size. If EncodedHead == NULLUsefulBufC then
472 * UsefulOutBuf_InsertUsefulBuf() will do nothing so there is
473 * no security whole introduced.
474 */
475 UsefulOutBuf_InsertUsefulBuf(&(me->OutBuf),
476 EncodedHead,
477 Nesting_GetStartPos(&(me->nesting)));
478
479 Nesting_Decrease(&(me->nesting));
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000480}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700481
Laurence Lundblade241705e2018-12-30 18:56:14 -0800482
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700483/*
Laurence Lundblade3e0a45c2020-11-05 11:12:04 -0800484 Increment the count of items in a map or array. This is mostly
485 a separate function to have fewer occurance of
486 #ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
487 */
488static inline void IncrementMapOrArrayCount(QCBOREncodeContext *pMe)
489{
490#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
491 if(pMe->uError == QCBOR_SUCCESS) {
492 pMe->uError = Nesting_Increment(&(pMe->nesting));
493 }
494#else
495 (void)Nesting_Increment(&(pMe->nesting));
496#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
497}
498
499
500/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800501 Public functions for adding integers. See qcbor/qcbor_encode.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700502 */
Laurence Lundblade067035b2018-11-28 17:35:25 -0800503void QCBOREncode_AddUInt64(QCBOREncodeContext *me, uint64_t uValue)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700504{
Laurence Lundbladedaefdec2020-11-02 20:22:03 -0800505 AppendCBORHead(me, CBOR_MAJOR_TYPE_POSITIVE_INT, uValue, 0);
506
Laurence Lundblade3e0a45c2020-11-05 11:12:04 -0800507 IncrementMapOrArrayCount(me);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700508}
509
Laurence Lundblade56230d12018-11-01 11:14:51 +0700510
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700511/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800512 Public functions for adding unsigned. See qcbor/qcbor_encode.h
Laurence Lundblade067035b2018-11-28 17:35:25 -0800513 */
514void QCBOREncode_AddInt64(QCBOREncodeContext *me, int64_t nNum)
515{
Laurence Lundbladedaefdec2020-11-02 20:22:03 -0800516 uint8_t uMajorType;
517 uint64_t uValue;
518
519 if(nNum < 0) {
520 // In CBOR -1 encodes as 0x00 with major type negative int.
521 uValue = (uint64_t)(-nNum - 1);
522 uMajorType = CBOR_MAJOR_TYPE_NEGATIVE_INT;
523 } else {
524 uValue = (uint64_t)nNum;
525 uMajorType = CBOR_MAJOR_TYPE_POSITIVE_INT;
526 }
527 AppendCBORHead(me, uMajorType, uValue, 0);
528
Laurence Lundblade3e0a45c2020-11-05 11:12:04 -0800529 IncrementMapOrArrayCount(me);
Laurence Lundblade067035b2018-11-28 17:35:25 -0800530}
531
532
533/*
Laurence Lundbladeda532272019-04-07 11:40:17 -0700534 Semi-private function. It is exposed to user of the interface, but
535 they will usually call one of the inline wrappers rather than this.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800536
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800537 See qcbor/qcbor_encode.h
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800538
Laurence Lundbladeda532272019-04-07 11:40:17 -0700539 Does the work of adding actual strings bytes to the CBOR output (as
540 opposed to numbers and opening / closing aggregate types).
541
542 There are four use cases:
543 CBOR_MAJOR_TYPE_BYTE_STRING -- Byte strings
544 CBOR_MAJOR_TYPE_TEXT_STRING -- Text strings
545 CBOR_MAJOR_NONE_TYPE_RAW -- Already-encoded CBOR
546 CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY -- Special case
547
548 The first two add the type and length plus the actual bytes. The
549 third just adds the bytes as the type and length are presumed to be
550 in the bytes. The fourth just adds the type and length for the very
551 special case of QCBOREncode_AddBytesLenOnly().
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700552 */
Laurence Lundblade067035b2018-11-28 17:35:25 -0800553void QCBOREncode_AddBuffer(QCBOREncodeContext *me, uint8_t uMajorType, UsefulBufC Bytes)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700554{
Laurence Lundbladedaefdec2020-11-02 20:22:03 -0800555 // If it is not Raw CBOR, add the type and the length
556 if(uMajorType != CBOR_MAJOR_NONE_TYPE_RAW) {
557 uint8_t uRealMajorType = uMajorType;
558 if(uRealMajorType == CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY) {
559 uRealMajorType = CBOR_MAJOR_TYPE_BYTE_STRING;
560 }
561 AppendCBORHead(me, uRealMajorType, Bytes.len, 0);
562 }
563
564 if(uMajorType != CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY) {
565 // Actually add the bytes
566 UsefulOutBuf_AppendUsefulBuf(&(me->OutBuf), Bytes);
567 }
568
Laurence Lundblade3e0a45c2020-11-05 11:12:04 -0800569 IncrementMapOrArrayCount(me);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700570}
571
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700572
Laurence Lundblade55a24832018-10-30 04:35:08 +0700573/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800574 Public functions for adding a tag. See qcbor/qcbor_encode.h
Laurence Lundblade55a24832018-10-30 04:35:08 +0700575 */
576void QCBOREncode_AddTag(QCBOREncodeContext *me, uint64_t uTag)
577{
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000578 AppendCBORHead(me, CBOR_MAJOR_TYPE_OPTIONAL, uTag, 0);
Laurence Lundblade55a24832018-10-30 04:35:08 +0700579}
580
581
Laurence Lundblade56230d12018-11-01 11:14:51 +0700582/*
Laurence Lundblade487930f2018-11-30 11:01:45 -0800583 Semi-private function. It is exposed to user of the interface,
584 but they will usually call one of the inline wrappers rather than this.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800585
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800586 See header qcbor/qcbor_encode.h
Laurence Lundblade56230d12018-11-01 11:14:51 +0700587 */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000588void QCBOREncode_AddType7(QCBOREncodeContext *me, uint8_t uMinLen, uint64_t uNum)
Laurence Lundblade55a24832018-10-30 04:35:08 +0700589{
Laurence Lundbladedaefdec2020-11-02 20:22:03 -0800590#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
Laurence Lundblade487930f2018-11-30 11:01:45 -0800591 if(me->uError == QCBOR_SUCCESS) {
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700592 if(uNum >= CBOR_SIMPLEV_RESERVED_START && uNum <= CBOR_SIMPLEV_RESERVED_END) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -0700593 me->uError = QCBOR_ERR_ENCODE_UNSUPPORTED;
Laurence Lundbladedaefdec2020-11-02 20:22:03 -0800594 return;
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700595 }
Laurence Lundblade487930f2018-11-30 11:01:45 -0800596 }
Laurence Lundbladedaefdec2020-11-02 20:22:03 -0800597#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
598
599 // AppendHead() does endian swapping for the float / double
600 AppendCBORHead(me, CBOR_MAJOR_TYPE_SIMPLE, uNum, uMinLen);
601
Laurence Lundblade3e0a45c2020-11-05 11:12:04 -0800602 IncrementMapOrArrayCount(me);
Laurence Lundblade55a24832018-10-30 04:35:08 +0700603}
604
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700605
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700606/*
607 Public functions for adding a double. See qcbor/qcbor_encode.h
608*/
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -0700609void QCBOREncode_AddDoubleNoPreferred(QCBOREncodeContext *me, double dNum)
610{
Laurence Lundblade2feb1e12020-07-15 03:50:45 -0700611 QCBOREncode_AddType7(me,
612 sizeof(uint64_t),
613 UsefulBufUtil_CopyDoubleToUint64(dNum));
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -0700614}
615
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700616
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700617/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800618 Public functions for adding a double. See qcbor/qcbor_encode.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700619 */
Laurence Lundblade067035b2018-11-28 17:35:25 -0800620void QCBOREncode_AddDouble(QCBOREncodeContext *me, double dNum)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700621{
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -0700622#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade067035b2018-11-28 17:35:25 -0800623 const IEEE754_union uNum = IEEE754_DoubleToSmallest(dNum);
Laurence Lundblade2feb1e12020-07-15 03:50:45 -0700624
Laurence Lundblade487930f2018-11-30 11:01:45 -0800625 QCBOREncode_AddType7(me, uNum.uSize, uNum.uValue);
Laurence Lundblade9682a532020-06-06 18:33:04 -0700626#else
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -0700627 QCBOREncode_AddDoubleNoPreferred(me, dNum);
Laurence Lundblade9682a532020-06-06 18:33:04 -0700628#endif
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -0700629}
Laurence Lundblade9682a532020-06-06 18:33:04 -0700630
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -0700631
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700632/*
633 Public functions for adding a float. See qcbor/qcbor_encode.h
634*/
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -0700635void QCBOREncode_AddFloatNoPreferred(QCBOREncodeContext *me, float fNum)
636{
Laurence Lundblade2feb1e12020-07-15 03:50:45 -0700637 QCBOREncode_AddType7(me,
638 sizeof(uint32_t),
639 UsefulBufUtil_CopyFloatToUint32(fNum));
Laurence Lundblade9682a532020-06-06 18:33:04 -0700640}
641
642
643/*
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700644 Public functions for adding a float. See qcbor/qcbor_encode.h
Laurence Lundblade9682a532020-06-06 18:33:04 -0700645 */
646void QCBOREncode_AddFloat(QCBOREncodeContext *me, float fNum)
647{
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -0700648#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade9682a532020-06-06 18:33:04 -0700649 const IEEE754_union uNum = IEEE754_FloatToSmallest(fNum);
Laurence Lundblade2feb1e12020-07-15 03:50:45 -0700650
Laurence Lundblade9682a532020-06-06 18:33:04 -0700651 QCBOREncode_AddType7(me, uNum.uSize, uNum.uValue);
652#else
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -0700653 QCBOREncode_AddFloatNoPreferred(me, fNum);
Laurence Lundblade9682a532020-06-06 18:33:04 -0700654#endif
Laurence Lundblade067035b2018-11-28 17:35:25 -0800655}
656
657
Laurence Lundblade59289e52019-12-30 13:44:37 -0800658#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
659/*
660 Semi-public function. It is exposed to the user of the interface, but
661 one of the inline wrappers will usually be called rather than this.
662
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800663 See qcbor/qcbor_encode.h
Laurence Lundblade45d5e482020-09-15 21:15:15 -0700664
665 Improvement: create another version of this that only
666 takes a big number mantissa and converts the output to
667 a type 0 or 1 integer when mantissa is small enough.
Laurence Lundblade59289e52019-12-30 13:44:37 -0800668 */
669void QCBOREncode_AddExponentAndMantissa(QCBOREncodeContext *pMe,
670 uint64_t uTag,
671 UsefulBufC BigNumMantissa,
672 bool bBigNumIsNegative,
673 int64_t nMantissa,
674 int64_t nExponent)
675{
Laurence Lundbladeee851742020-01-08 08:37:05 -0800676 /*
677 This is for encoding either a big float or a decimal fraction,
678 both of which are an array of two items, an exponent and a
679 mantissa. The difference between the two is that the exponent is
680 base-2 for big floats and base-10 for decimal fractions, but that
681 has no effect on the code here.
682 */
Laurence Lundbladeae66d3f2020-09-14 18:12:08 -0700683 if(uTag != CBOR_TAG_INVALID64) {
684 QCBOREncode_AddTag(pMe, uTag);
685 }
Laurence Lundblade59289e52019-12-30 13:44:37 -0800686 QCBOREncode_OpenArray(pMe);
687 QCBOREncode_AddInt64(pMe, nExponent);
688 if(!UsefulBuf_IsNULLC(BigNumMantissa)) {
689 if(bBigNumIsNegative) {
690 QCBOREncode_AddNegativeBignum(pMe, BigNumMantissa);
691 } else {
692 QCBOREncode_AddPositiveBignum(pMe, BigNumMantissa);
693 }
694 } else {
695 QCBOREncode_AddInt64(pMe, nMantissa);
696 }
697 QCBOREncode_CloseArray(pMe);
698}
699#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
700
701
Laurence Lundblade067035b2018-11-28 17:35:25 -0800702/*
703 Semi-public function. It is exposed to user of the interface,
704 but they will usually call one of the inline wrappers rather than this.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800705
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800706 See qcbor/qcbor_encode.h
Laurence Lundblade067035b2018-11-28 17:35:25 -0800707*/
708void QCBOREncode_OpenMapOrArray(QCBOREncodeContext *me, uint8_t uMajorType)
709{
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800710 // Add one item to the nesting level we are in for the new map or array
Laurence Lundblade3e0a45c2020-11-05 11:12:04 -0800711 IncrementMapOrArrayCount(me);
Laurence Lundbladed39cd392019-01-11 18:17:38 -0800712
Laurence Lundblade3e0a45c2020-11-05 11:12:04 -0800713 /*
714 The offset where the length of an array or map will get written
715 is stored in a uint32_t, not a size_t to keep stack usage
716 smaller. This checks to be sure there is no wrap around when
717 recording the offset. Note that on 64-bit machines CBOR larger
718 than 4GB can be encoded as long as no array / map offsets occur
719 past the 4GB mark, but the public interface says that the
720 maximum is 4GB to keep the discussion simpler.
721 */
722 size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf));
Laurence Lundbladed39cd392019-01-11 18:17:38 -0800723
Laurence Lundblade3e0a45c2020-11-05 11:12:04 -0800724 /*
725 QCBOR_MAX_ARRAY_OFFSET is slightly less than UINT32_MAX so this
726 code can run on a 32-bit machine and tests can pass on a 32-bit
727 machine. If it was exactly UINT32_MAX, then this code would not
728 compile or run on a 32-bit machine and an #ifdef or some
729 machine size detection would be needed reducing portability.
730 */
731 if(uEndPosition >= QCBOR_MAX_ARRAY_OFFSET) {
732 me->uError = QCBOR_ERR_BUFFER_TOO_LARGE;
733
734 } else {
735 // Increase nesting level because this is a map or array. Cast
736 // from size_t to uin32_t is safe because of check above
737 me->uError = Nesting_Increase(&(me->nesting), uMajorType, (uint32_t)uEndPosition);
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800738 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700739}
740
Laurence Lundblade59289e52019-12-30 13:44:37 -0800741
Jan Jongboom4a93a662019-07-25 08:44:58 +0200742/*
743 Semi-public function. It is exposed to user of the interface,
744 but they will usually call one of the inline wrappers rather than this.
745
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800746 See qcbor/qcbor_encode.h
Jan Jongboom4a93a662019-07-25 08:44:58 +0200747*/
748void QCBOREncode_OpenMapOrArrayIndefiniteLength(QCBOREncodeContext *me, uint8_t uMajorType)
749{
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000750 // Insert the indefinite length marker (0x9f for arrays, 0xbf for maps)
751 AppendCBORHead(me, uMajorType, 0, 0);
752 // Call the definite-length opener just to do the bookkeeping for
753 // nesting. It will record the position of the opening item in
754 // the encoded output but this is not used when closing this open.
Jan Jongboom4a93a662019-07-25 08:44:58 +0200755 QCBOREncode_OpenMapOrArray(me, uMajorType);
756}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700757
Laurence Lundbladeee851742020-01-08 08:37:05 -0800758
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700759/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800760 Public functions for closing arrays and maps. See qcbor/qcbor_encode.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700761 */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000762void QCBOREncode_CloseMapOrArray(QCBOREncodeContext *me, uint8_t uMajorType)
Laurence Lundbladea954db92018-09-28 19:27:31 -0700763{
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000764 InsertCBORHead(me, uMajorType, Nesting_GetCount(&(me->nesting)));
765}
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800766
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800767
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000768/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800769 Public functions for closing bstr wrapping. See qcbor/qcbor_encode.h
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000770 */
771void QCBOREncode_CloseBstrWrap2(QCBOREncodeContext *me, bool bIncludeCBORHead, UsefulBufC *pWrappedCBOR)
772{
773 const size_t uInsertPosition = Nesting_GetStartPos(&(me->nesting));
774 const size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800775
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000776 // This can't go negative because the UsefulOutBuf always only grows
777 // and never shrinks. UsefulOutBut itself also has defenses such that
778 // it won't write where it should not even if given hostile input lengths.
779 const size_t uBstrLen = uEndPosition - uInsertPosition;
780
781 // Actually insert
782 InsertCBORHead(me, CBOR_MAJOR_TYPE_BYTE_STRING, uBstrLen);
783
784 if(pWrappedCBOR) {
785 /*
786 Return pointer and length to the enclosed encoded CBOR. The
787 intended use is for it to be hashed (e.g., SHA-256) in a COSE
788 implementation. This must be used right away, as the pointer
789 and length go invalid on any subsequent calls to this function
790 because there might be calls to InsertEncodedTypeAndNumber()
791 that slides data to the right.
792 */
793 size_t uStartOfNew = uInsertPosition;
794 if(!bIncludeCBORHead) {
795 // Skip over the CBOR head to just get the inserted bstr
796 const size_t uNewEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf));
797 uStartOfNew += uNewEndPosition - uEndPosition;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700798 }
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000799 const UsefulBufC PartialResult = UsefulOutBuf_OutUBuf(&(me->OutBuf));
800 *pWrappedCBOR = UsefulBuf_Tail(PartialResult, uStartOfNew);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700801 }
802}
803
Laurence Lundbladeee851742020-01-08 08:37:05 -0800804
Jan Jongboom4a93a662019-07-25 08:44:58 +0200805/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800806 Public functions for closing arrays and maps. See qcbor/qcbor_encode.h
Jan Jongboom4a93a662019-07-25 08:44:58 +0200807 */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000808void QCBOREncode_CloseMapOrArrayIndefiniteLength(QCBOREncodeContext *me, uint8_t uMajorType)
Jan Jongboom4a93a662019-07-25 08:44:58 +0200809{
Laurence Lundbladedaefdec2020-11-02 20:22:03 -0800810#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
Jan Jongboom4a93a662019-07-25 08:44:58 +0200811 if(me->uError == QCBOR_SUCCESS) {
812 if(!Nesting_IsInNest(&(me->nesting))) {
813 me->uError = QCBOR_ERR_TOO_MANY_CLOSES;
Laurence Lundbladedaefdec2020-11-02 20:22:03 -0800814 return;
Jan Jongboom4a93a662019-07-25 08:44:58 +0200815 } else if(Nesting_GetMajorType(&(me->nesting)) != uMajorType) {
816 me->uError = QCBOR_ERR_CLOSE_MISMATCH;
Laurence Lundbladedaefdec2020-11-02 20:22:03 -0800817 return;
Jan Jongboom4a93a662019-07-25 08:44:58 +0200818 }
819 }
Laurence Lundbladedaefdec2020-11-02 20:22:03 -0800820#else
821 (void) uMajorType;
822#endif
823
824 // Append the break marker (0xff for both arrays and maps)
Laurence Lundbladed8e1c512020-11-04 23:03:44 -0800825 AppendCBORHead(me, CBOR_MAJOR_NONE_TYPE_SIMPLE_BREAK, CBOR_SIMPLE_BREAK, 0);
Laurence Lundbladedaefdec2020-11-02 20:22:03 -0800826 Nesting_Decrease(&(me->nesting));
Jan Jongboom4a93a662019-07-25 08:44:58 +0200827}
828
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700829
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700830/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800831 Public functions to finish and get the encoded result. See qcbor/qcbor_encode.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700832 */
Laurence Lundblade30816f22018-11-10 13:40:22 +0700833QCBORError QCBOREncode_Finish(QCBOREncodeContext *me, UsefulBufC *pEncodedCBOR)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700834{
Laurence Lundbladef607a2a2019-07-05 21:25:25 -0700835 QCBORError uReturn = QCBOREncode_GetErrorState(me);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800836
Laurence Lundblade067035b2018-11-28 17:35:25 -0800837 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700838 goto Done;
Laurence Lundblade067035b2018-11-28 17:35:25 -0800839 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800840
Laurence Lundbladedaefdec2020-11-02 20:22:03 -0800841#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
Laurence Lundblade3e0a45c2020-11-05 11:12:04 -0800842 if(Nesting_IsInNest(&(me->nesting))) {
Laurence Lundblade067035b2018-11-28 17:35:25 -0800843 uReturn = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700844 goto Done;
845 }
Laurence Lundbladedaefdec2020-11-02 20:22:03 -0800846#endif
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800847
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700848 *pEncodedCBOR = UsefulOutBuf_OutUBuf(&(me->OutBuf));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800849
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700850Done:
Laurence Lundblade067035b2018-11-28 17:35:25 -0800851 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700852}
853
Laurence Lundblade0595e932018-11-02 22:22:47 +0700854
Laurence Lundblade067035b2018-11-28 17:35:25 -0800855/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800856 Public functions to finish and get the encoded result. See qcbor/qcbor_encode.h
Laurence Lundblade067035b2018-11-28 17:35:25 -0800857 */
Laurence Lundblade30816f22018-11-10 13:40:22 +0700858QCBORError QCBOREncode_FinishGetSize(QCBOREncodeContext *me, size_t *puEncodedLen)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700859{
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700860 UsefulBufC Enc;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800861
Laurence Lundblade30816f22018-11-10 13:40:22 +0700862 QCBORError nReturn = QCBOREncode_Finish(me, &Enc);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800863
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700864 if(nReturn == QCBOR_SUCCESS) {
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700865 *puEncodedLen = Enc.len;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700866 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800867
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700868 return nReturn;
869}