blob: 992fa87fa5124bd343f04c16c7cb9a458808258e [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 Lundblade1ef8b2d2018-12-14 23:13:34 -080098 if(1 >= QCBOR_MAX_ITEMS_IN_ARRAY - pNesting->pCurrentNesting->uCount) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070099 return QCBOR_ERR_ARRAY_TOO_LONG;
100 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800101
Laurence Lundbladee6bcef12020-04-01 10:56:27 -0700102 pNesting->pCurrentNesting->uCount++;
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800103
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700104 return QCBOR_SUCCESS;
105}
106
107inline static uint16_t Nesting_GetCount(QCBORTrackNesting *pNesting)
108{
109 // The nesting count recorded is always the actual number of individiual
110 // data items in the array or map. For arrays CBOR uses the actual item
111 // count. For maps, CBOR uses the number of pairs. This function returns
112 // the number needed for the CBOR encoding, so it divides the number of
113 // items by two for maps to get the number of pairs. This implementation
114 // takes advantage of the map major type being one larger the array major
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800115 // type, hence uDivisor is either 1 or 2.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800116
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800117 if(pNesting->pCurrentNesting->uMajorType == CBOR_MAJOR_TYPE_MAP) {
118 // Cast back to uint16_t after integer promotion for bit shift
119 return (uint16_t)(pNesting->pCurrentNesting->uCount >> 1);
120 } else {
121 return pNesting->pCurrentNesting->uCount;
122 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700123}
124
125inline static uint32_t Nesting_GetStartPos(QCBORTrackNesting *pNesting)
126{
127 return pNesting->pCurrentNesting->uStart;
128}
129
130inline static uint8_t Nesting_GetMajorType(QCBORTrackNesting *pNesting)
131{
132 return pNesting->pCurrentNesting->uMajorType;
133}
134
Laurence Lundbladeee851742020-01-08 08:37:05 -0800135inline static bool Nesting_IsInNest(QCBORTrackNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700136{
Laurence Lundbladeee851742020-01-08 08:37:05 -0800137 return pNesting->pCurrentNesting == &pNesting->pArrays[0] ? false : true;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700138}
139
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700140
141
142
143/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800144 Encoding of the major CBOR types is by these functions:
145
146 CBOR Major Type Public Function
147 0 QCBOREncode_AddUInt64()
148 0, 1 QCBOREncode_AddUInt64(), QCBOREncode_AddInt64()
149 2, 3 QCBOREncode_AddBuffer(), Also QCBOREncode_OpenMapOrArray(),
150 QCBOREncode_CloseMapOrArray()
151 4, 5 QCBOREncode_OpenMapOrArray(), QCBOREncode_CloseMapOrArray(),
152 QCBOREncode_OpenMapOrArrayIndefiniteLength(),
153 QCBOREncode_CloseMapOrArrayIndefiniteLength()
154 6 QCBOREncode_AddTag()
155 7 QCBOREncode_AddDouble(), QCBOREncode_AddType7()
156
157 Additionally, encoding of decimal fractions and bigfloats is by
158 QCBOREncode_AddExponentAndMantissa()
159*/
160
161/*
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700162 Error tracking plan -- Errors are tracked internally and not returned
Laurence Lundbladeee851742020-01-08 08:37:05 -0800163 until QCBOREncode_Finish is called. The CBOR errors are in me->uError.
Laurence Lundblade067035b2018-11-28 17:35:25 -0800164 UsefulOutBuf also tracks whether the buffer is full or not in its
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700165 context. Once either of these errors is set they are never
Laurence Lundblade241705e2018-12-30 18:56:14 -0800166 cleared. Only QCBOREncode_Init() resets them. Or said another way, they must
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700167 never be cleared or we'll tell the caller all is good when it is not.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800168
Laurence Lundblade241705e2018-12-30 18:56:14 -0800169 Only one error code is reported by QCBOREncode_Finish() even if there are
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700170 multiple errors. The last one set wins. The caller might have to fix
171 one error to reveal the next one they have to fix. This is OK.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800172
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700173 The buffer full error tracked by UsefulBuf is only pulled out of
174 UsefulBuf in Finish() so it is the one that usually wins. UsefulBuf
175 will never go off the end of the buffer even if it is called again
176 and again when full.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800177
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700178 It is really tempting to not check for overflow on the count in the
179 number of items in an array. It would save a lot of code, it is
180 extremely unlikely that any one will every put 65,000 items in an
181 array, and the only bad thing that would happen is the CBOR would be
Laurence Lundblade241705e2018-12-30 18:56:14 -0800182 bogus.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800183
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700184 Since this does not parse any input, you could in theory remove all
185 error checks in this code if you knew the caller called it
186 correctly. Maybe someday CDDL or some such language will be able to
187 generate the code to call this and the calling code would always be
Laurence Lundblade56230d12018-11-01 11:14:51 +0700188 correct. This could also automatically size some of the data
Laurence Lundblade241705e2018-12-30 18:56:14 -0800189 structures like array/map nesting resulting in some stack memory
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700190 savings.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800191
Laurence Lundbladeee851742020-01-08 08:37:05 -0800192 The 8 errors returned here fall into three categories:
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800193
Laurence Lundblade067035b2018-11-28 17:35:25 -0800194 Sizes
Laurence Lundbladeee851742020-01-08 08:37:05 -0800195 QCBOR_ERR_BUFFER_TOO_LARGE -- Encoded output exceeded UINT32_MAX
196 QCBOR_ERR_BUFFER_TOO_SMALL -- Output buffer too small
197 QCBOR_ERR_ARRAY_NESTING_TOO_DEEP -- Nesting > QCBOR_MAX_ARRAY_NESTING1
198 QCBOR_ERR_ARRAY_TOO_LONG -- Too many things added to an array/map
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800199
Laurence Lundblade067035b2018-11-28 17:35:25 -0800200 Nesting constructed incorrectly
Laurence Lundbladeee851742020-01-08 08:37:05 -0800201 QCBOR_ERR_TOO_MANY_CLOSES -- More close calls than opens
202 QCBOR_ERR_CLOSE_MISMATCH -- Type of close does not match open
Laurence Lundblade067035b2018-11-28 17:35:25 -0800203 QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN -- Finish called without enough closes
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700204
205 Would generate not-well-formed CBOR
Laurence Lundbladea9489f82020-09-12 13:50:56 -0700206 QCBOR_ERR_ENCODE_UNSUPPORTED -- Simple type between 24 and 31
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700207 */
208
209
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700210/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800211 Public function for initialization. See qcbor/qcbor_encode.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700212 */
Laurence Lundblade2296db52018-09-14 18:08:39 -0700213void QCBOREncode_Init(QCBOREncodeContext *me, UsefulBuf Storage)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700214{
215 memset(me, 0, sizeof(QCBOREncodeContext));
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800216 UsefulOutBuf_Init(&(me->OutBuf), Storage);
217 Nesting_Init(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700218}
219
220
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000221/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800222 Public function to encode a CBOR head. See qcbor/qcbor_encode.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700223 */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000224UsefulBufC QCBOREncode_EncodeHead(UsefulBuf buffer,
225 uint8_t uMajorType,
226 uint8_t uMinLen,
227 uint64_t uArgument)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700228{
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000229 /**
230 All CBOR data items have a type and an "argument". The argument is
231 either the value of the item for integer types, the length of the
232 content for string, byte, array and map types, a tag for major type
233 6, and has several uses for major type 7.
234
235 This function encodes the type and the argument. There are several
236 encodings for the argument depending on how large it is and how it is
237 used.
238
239 Every encoding of the type and argument has at least one byte, the
240 "initial byte".
241
242 The top three bits of the initial byte are the major type for the
243 CBOR data item. The eight major types defined by the standard are
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800244 defined as CBOR_MAJOR_TYPE_xxxx in qcbor/qcbor_common.h.
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000245
246 The remaining five bits, known as "additional information", and
247 possibly more bytes encode the argument. If the argument is less than
248 24, then it is encoded entirely in the five bits. This is neat
249 because it allows you to encode an entire CBOR data item in 1 byte
250 for many values and types (integers 0-23, true, false, and tags).
251
252 If the argument is larger than 24, then it is encoded in 1,2,4 or 8
253 additional bytes, with the number of these bytes indicated by the
254 values of the 5 bits 24, 25, 25 and 27.
255
256 It is possible to encode a particular argument in many ways with this
257 representation. This implementation always uses the smallest
258 possible representation. This conforms with CBOR preferred encoding.
259
260 This function inserts them into the output buffer at the specified
261 position. AppendEncodedTypeAndNumber() appends to the end.
262
263 This function takes care of converting to network byte order.
264
265 This function is also used to insert floats and doubles. Before this
266 function is called the float or double must be copied into a
267 uint64_t. That is how they are passed in. They are then converted to
268 network byte order correctly. The uMinLen parameter makes sure that
269 even if all the digits of a half, float or double are 0 it is still
270 correctly encoded in 2, 4 or 8 bytes.
271 */
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800272 /*
273 This code does endian conversion without hton or knowing the
Laurence Lundblade241705e2018-12-30 18:56:14 -0800274 endianness of the machine using masks and shifts. This avoids the
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800275 dependency on hton and the mess of figuring out how to find the
276 machine's endianness.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800277
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800278 This is a good efficient implementation on little-endian machines.
279 A faster and small implementation is possible on big-endian
280 machines because CBOR/network byte order is big endian. However
281 big endian machines are uncommon.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800282
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800283 On x86, it is about 200 bytes instead of 500 bytes for the more
284 formal unoptimized code.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800285
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800286 This also does the CBOR preferred shortest encoding for integers
287 and is called to do endian conversion for floats.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800288
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800289 It works backwards from the LSB to the MSB as needed.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800290
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800291 Code Reviewers: THIS FUNCTION DOES POINTER MATH
292 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800293 /*
294 The type int is used here for several variables because of the way
295 integer promotion works in C for integer variables that are
296 uint8_t or uint16_t. The basic rule is that they will always be
297 promoted to int if they will fit. All of these integer variables
298 need only hold values less than 255 or are promoted from uint8_t,
299 so they will always fit into an int. Note that promotion is only
300 to unsigned int if the value won't fit into an int even if the
301 promotion is for an unsigned like uint8_t.
302
303 By declaring them int, there are few implicit conversions and fewer
304 casts needed. Code size is reduced a little. It also makes static
305 analyzers happier.
306
307 Note also that declaring them uint8_t won't stop integer wrap
308 around if the code is wrong. It won't make the code more correct.
309
310 https://stackoverflow.com/questions/46073295/implicit-type-promotion-rules
311 https://stackoverflow.com/questions/589575/what-does-the-c-standard-state-the-size-of-int-long-type-to-be
312 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800313
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000314 // Buffer must have room for the largest CBOR HEAD + one extra as the
315 // one extra is needed for this code to work as it does a pre-decrement.
316 if(buffer.len < QCBOR_HEAD_BUFFER_SIZE) {
317 return NULLUsefulBufC;
318 }
319
320 // Pointer to last valid byte in the buffer
321 uint8_t * const pBufferEnd = &((uint8_t *)buffer.ptr)[QCBOR_HEAD_BUFFER_SIZE-1];
322
323 // Point to the last byte and work backwards
324 uint8_t *pByte = pBufferEnd;
325 // The 5 bits in the initial byte that are not the major type
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800326 int nAdditionalInfo;
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800327
Laurence Lundblade8c858ab2020-11-02 19:53:49 -0800328 if(uMajorType > QCBOR_INDEFINITE_LEN_TYPE_MODIFIER) {
329 // Special case for start & end of indefinite length
330 uMajorType = uMajorType - QCBOR_INDEFINITE_LEN_TYPE_MODIFIER;
331 // Take advantage of design of CBOR where additional info
332 // is 31 for both opening and closing indefinite length
333 // maps and arrays.
334#if CBOR_SIMPLE_BREAK != LEN_IS_INDEFINITE
335#error additional info for opening array not the same as for closing
336#endif
337 nAdditionalInfo = CBOR_SIMPLE_BREAK;
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000338 } else if (uArgument < CBOR_TWENTY_FOUR && uMinLen == 0) {
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800339 // Simple case where argument is < 24
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000340 nAdditionalInfo = (int)uArgument;
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800341 } else {
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800342 /*
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000343 Encode argument in 1,2,4 or 8 bytes. Outer loop
344 runs once for 1 byte and 4 times for 8 bytes.
345 Inner loop runs 1, 2 or 4 times depending on
346 outer loop counter. This works backwards taking
347 8 bits off the argument being encoded at a time
348 until all bits from uNumber have been encoded
349 and the minimum encoding size is reached.
350 Minimum encoding size is for floating point
351 numbers with zero bytes.
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800352 */
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800353 static const uint8_t aIterate[] = {1,1,2,4};
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000354
355 // The parameter passed in is unsigned, but goes negative in the loop
356 // so it must be converted to a signed value.
357 int nMinLen = (int)uMinLen;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800358 int i;
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000359 for(i = 0; uArgument || nMinLen > 0; i++) {
360 const int nIterations = (int)aIterate[i];
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800361 for(int j = 0; j < nIterations; j++) {
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000362 *--pByte = (uint8_t)(uArgument & 0xff);
363 uArgument = uArgument >> 8;
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800364 }
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800365 nMinLen -= nIterations;
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800366 }
Laurence Lundbladeee851742020-01-08 08:37:05 -0800367 // Additional info is the encoding of the number of additional
368 // bytes to encode argument.
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800369 nAdditionalInfo = LEN_IS_ONE_BYTE-1 + i;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700370 }
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800371
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800372 /*
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000373 This expression integer-promotes to type int. The code above in
374 function guarantees that nAdditionalInfo will never be larger than
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800375 0x1f. The caller may pass in a too-large uMajor type. The
376 conversion to unint8_t will cause an integer wrap around and
377 incorrect CBOR will be generated, but no security issue will
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000378 occur.
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800379 */
380 *--pByte = (uint8_t)((uMajorType << 5) + nAdditionalInfo);
381
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000382#ifdef EXTRA_ENCODE_HEAD_CHECK
383 /* This is a sanity check that can be turned on to verify the pointer
384 * math in this function is not going wrong. Turn it on and run the
385 * whole test suite to perform the check.
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800386 */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000387 if(pBufferEnd - pByte > 9 || pBufferEnd - pByte < 1 || pByte < (uint8_t *)buffer.ptr) {
388 return NULLUsefulBufC;
389 }
390#endif
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800391
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000392 // Length will not go negative because the loops run for at most 8 decrements
393 // of pByte, only one other decrement is made, and the array is sized
394 // for this.
395 return (UsefulBufC){pByte, (size_t)(pBufferEnd - pByte)};
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700396}
397
398
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000399/**
400 @brief Append the CBOR head, the major type and argument
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800401
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000402 @param me Encoder context.
403 @param uMajorType Major type to insert.
404 @param uArgument The argument (an integer value or a length).
405 @param uMinLen The minimum number of bytes for encoding the CBOR argument.
406
407 This formats the CBOR "head" and appends it to the output.
408 */
409static void AppendCBORHead(QCBOREncodeContext *me, uint8_t uMajorType, uint64_t uArgument, uint8_t uMinLen)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700410{
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000411 // A stack buffer large enough for a CBOR head
412 UsefulBuf_MAKE_STACK_UB (pBufferForEncodedHead, QCBOR_HEAD_BUFFER_SIZE);
413
414 UsefulBufC EncodedHead = QCBOREncode_EncodeHead(pBufferForEncodedHead,
415 uMajorType,
416 uMinLen,
417 uArgument);
418
419 /* No check for EncodedHead == NULLUsefulBufC is performed here to
420 * save object code. It is very clear that pBufferForEncodedHead
421 * is the correct size. If EncodedHead == NULLUsefulBufC then
422 * UsefulOutBuf_AppendUsefulBuf() will do nothing so there is
423 * no security hole introduced.
424 */
425
426 UsefulOutBuf_AppendUsefulBuf(&(me->OutBuf), EncodedHead);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700427}
428
429
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000430/**
431 @brief Insert the CBOR head for a map, array or wrapped bstr
432
433 @param me QCBOR encoding context.
434 @param uMajorType One of CBOR_MAJOR_TYPE_XXXX.
435 @param uLen The length of the data item.
436
437 When an array, map or bstr was opened, nothing was done but note
438 the position. This function goes back to that position and inserts
439 the CBOR Head with the major type and length.
440 */
441static void InsertCBORHead(QCBOREncodeContext *me, uint8_t uMajorType, size_t uLen)
442{
443 if(me->uError == QCBOR_SUCCESS) {
444 if(!Nesting_IsInNest(&(me->nesting))) {
445 me->uError = QCBOR_ERR_TOO_MANY_CLOSES;
446 } else if(Nesting_GetMajorType(&(me->nesting)) != uMajorType) {
447 me->uError = QCBOR_ERR_CLOSE_MISMATCH;
448 } else {
449 // A stack buffer large enough for a CBOR head
450 UsefulBuf_MAKE_STACK_UB (pBufferForEncodedHead,QCBOR_HEAD_BUFFER_SIZE);
451
452 UsefulBufC EncodedHead = QCBOREncode_EncodeHead(pBufferForEncodedHead,
453 uMajorType,
454 0,
455 uLen);
456
457 /* No check for EncodedHead == NULLUsefulBufC is performed here to
458 * save object code. It is very clear that pBufferForEncodedHead
459 * is the correct size. If EncodedHead == NULLUsefulBufC then
460 * UsefulOutBuf_InsertUsefulBuf() will do nothing so there is
461 * no security whole introduced.
462 */
463 UsefulOutBuf_InsertUsefulBuf(&(me->OutBuf), EncodedHead, Nesting_GetStartPos(&(me->nesting)) );
464
465 Nesting_Decrease(&(me->nesting));
466 }
467 }
468}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700469
Laurence Lundblade241705e2018-12-30 18:56:14 -0800470
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700471/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800472 Public functions for adding integers. See qcbor/qcbor_encode.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700473 */
Laurence Lundblade067035b2018-11-28 17:35:25 -0800474void QCBOREncode_AddUInt64(QCBOREncodeContext *me, uint64_t uValue)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700475{
Laurence Lundblade067035b2018-11-28 17:35:25 -0800476 if(me->uError == QCBOR_SUCCESS) {
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000477 AppendCBORHead(me, CBOR_MAJOR_TYPE_POSITIVE_INT, uValue, 0);
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800478 me->uError = Nesting_Increment(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700479 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700480}
481
Laurence Lundblade56230d12018-11-01 11:14:51 +0700482
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700483/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800484 Public functions for adding unsigned. See qcbor/qcbor_encode.h
Laurence Lundblade067035b2018-11-28 17:35:25 -0800485 */
486void QCBOREncode_AddInt64(QCBOREncodeContext *me, int64_t nNum)
487{
488 if(me->uError == QCBOR_SUCCESS) {
489 uint8_t uMajorType;
490 uint64_t uValue;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800491
Laurence Lundblade067035b2018-11-28 17:35:25 -0800492 if(nNum < 0) {
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800493 // In CBOR -1 encodes as 0x00 with major type negative int.
494 uValue = (uint64_t)(-nNum - 1);
Laurence Lundblade067035b2018-11-28 17:35:25 -0800495 uMajorType = CBOR_MAJOR_TYPE_NEGATIVE_INT;
496 } else {
497 uValue = (uint64_t)nNum;
498 uMajorType = CBOR_MAJOR_TYPE_POSITIVE_INT;
499 }
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000500 AppendCBORHead(me, uMajorType, uValue, 0);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800501
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800502 me->uError = Nesting_Increment(&(me->nesting));
Laurence Lundblade067035b2018-11-28 17:35:25 -0800503 }
504}
505
506
507/*
Laurence Lundbladeda532272019-04-07 11:40:17 -0700508 Semi-private function. It is exposed to user of the interface, but
509 they will usually call one of the inline wrappers rather than this.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800510
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800511 See qcbor/qcbor_encode.h
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800512
Laurence Lundbladeda532272019-04-07 11:40:17 -0700513 Does the work of adding actual strings bytes to the CBOR output (as
514 opposed to numbers and opening / closing aggregate types).
515
516 There are four use cases:
517 CBOR_MAJOR_TYPE_BYTE_STRING -- Byte strings
518 CBOR_MAJOR_TYPE_TEXT_STRING -- Text strings
519 CBOR_MAJOR_NONE_TYPE_RAW -- Already-encoded CBOR
520 CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY -- Special case
521
522 The first two add the type and length plus the actual bytes. The
523 third just adds the bytes as the type and length are presumed to be
524 in the bytes. The fourth just adds the type and length for the very
525 special case of QCBOREncode_AddBytesLenOnly().
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700526 */
Laurence Lundblade067035b2018-11-28 17:35:25 -0800527void QCBOREncode_AddBuffer(QCBOREncodeContext *me, uint8_t uMajorType, UsefulBufC Bytes)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700528{
Laurence Lundblade241705e2018-12-30 18:56:14 -0800529 if(me->uError == QCBOR_SUCCESS) {
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800530 // If it is not Raw CBOR, add the type and the length
531 if(uMajorType != CBOR_MAJOR_NONE_TYPE_RAW) {
Laurence Lundbladeda532272019-04-07 11:40:17 -0700532 uint8_t uRealMajorType = uMajorType;
533 if(uRealMajorType == CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY) {
534 uRealMajorType = CBOR_MAJOR_TYPE_BYTE_STRING;
535 }
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000536 AppendCBORHead(me, uRealMajorType, Bytes.len, 0);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700537 }
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800538
Laurence Lundbladeda532272019-04-07 11:40:17 -0700539 if(uMajorType != CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY) {
540 // Actually add the bytes
541 UsefulOutBuf_AppendUsefulBuf(&(me->OutBuf), Bytes);
542 }
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800543
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800544 // Update the array counting if there is any nesting at all
545 me->uError = Nesting_Increment(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700546 }
547}
548
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700549
Laurence Lundblade55a24832018-10-30 04:35:08 +0700550/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800551 Public functions for adding a tag. See qcbor/qcbor_encode.h
Laurence Lundblade55a24832018-10-30 04:35:08 +0700552 */
553void QCBOREncode_AddTag(QCBOREncodeContext *me, uint64_t uTag)
554{
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000555 AppendCBORHead(me, CBOR_MAJOR_TYPE_OPTIONAL, uTag, 0);
Laurence Lundblade55a24832018-10-30 04:35:08 +0700556}
557
558
Laurence Lundblade56230d12018-11-01 11:14:51 +0700559/*
Laurence Lundblade487930f2018-11-30 11:01:45 -0800560 Semi-private function. It is exposed to user of the interface,
561 but they will usually call one of the inline wrappers rather than this.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800562
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800563 See header qcbor/qcbor_encode.h
Laurence Lundblade56230d12018-11-01 11:14:51 +0700564 */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000565void QCBOREncode_AddType7(QCBOREncodeContext *me, uint8_t uMinLen, uint64_t uNum)
Laurence Lundblade55a24832018-10-30 04:35:08 +0700566{
Laurence Lundblade487930f2018-11-30 11:01:45 -0800567 if(me->uError == QCBOR_SUCCESS) {
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700568 if(uNum >= CBOR_SIMPLEV_RESERVED_START && uNum <= CBOR_SIMPLEV_RESERVED_END) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -0700569 me->uError = QCBOR_ERR_ENCODE_UNSUPPORTED;
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700570 } else {
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000571 // AppendHead() does endian swapping for the float / double
572 AppendCBORHead(me, CBOR_MAJOR_TYPE_SIMPLE, uNum, uMinLen);
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700573 me->uError = Nesting_Increment(&(me->nesting));
574 }
Laurence Lundblade487930f2018-11-30 11:01:45 -0800575 }
Laurence Lundblade55a24832018-10-30 04:35:08 +0700576}
577
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700578
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700579/*
580 Public functions for adding a double. See qcbor/qcbor_encode.h
581*/
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -0700582void QCBOREncode_AddDoubleNoPreferred(QCBOREncodeContext *me, double dNum)
583{
Laurence Lundblade2feb1e12020-07-15 03:50:45 -0700584 QCBOREncode_AddType7(me,
585 sizeof(uint64_t),
586 UsefulBufUtil_CopyDoubleToUint64(dNum));
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -0700587}
588
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700589
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700590/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800591 Public functions for adding a double. See qcbor/qcbor_encode.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700592 */
Laurence Lundblade067035b2018-11-28 17:35:25 -0800593void QCBOREncode_AddDouble(QCBOREncodeContext *me, double dNum)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700594{
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -0700595#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade067035b2018-11-28 17:35:25 -0800596 const IEEE754_union uNum = IEEE754_DoubleToSmallest(dNum);
Laurence Lundblade2feb1e12020-07-15 03:50:45 -0700597
Laurence Lundblade487930f2018-11-30 11:01:45 -0800598 QCBOREncode_AddType7(me, uNum.uSize, uNum.uValue);
Laurence Lundblade9682a532020-06-06 18:33:04 -0700599#else
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -0700600 QCBOREncode_AddDoubleNoPreferred(me, dNum);
Laurence Lundblade9682a532020-06-06 18:33:04 -0700601#endif
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -0700602}
Laurence Lundblade9682a532020-06-06 18:33:04 -0700603
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -0700604
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700605/*
606 Public functions for adding a float. See qcbor/qcbor_encode.h
607*/
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -0700608void QCBOREncode_AddFloatNoPreferred(QCBOREncodeContext *me, float fNum)
609{
Laurence Lundblade2feb1e12020-07-15 03:50:45 -0700610 QCBOREncode_AddType7(me,
611 sizeof(uint32_t),
612 UsefulBufUtil_CopyFloatToUint32(fNum));
Laurence Lundblade9682a532020-06-06 18:33:04 -0700613}
614
615
616/*
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700617 Public functions for adding a float. See qcbor/qcbor_encode.h
Laurence Lundblade9682a532020-06-06 18:33:04 -0700618 */
619void QCBOREncode_AddFloat(QCBOREncodeContext *me, float fNum)
620{
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -0700621#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade9682a532020-06-06 18:33:04 -0700622 const IEEE754_union uNum = IEEE754_FloatToSmallest(fNum);
Laurence Lundblade2feb1e12020-07-15 03:50:45 -0700623
Laurence Lundblade9682a532020-06-06 18:33:04 -0700624 QCBOREncode_AddType7(me, uNum.uSize, uNum.uValue);
625#else
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -0700626 QCBOREncode_AddFloatNoPreferred(me, fNum);
Laurence Lundblade9682a532020-06-06 18:33:04 -0700627#endif
Laurence Lundblade067035b2018-11-28 17:35:25 -0800628}
629
630
Laurence Lundblade59289e52019-12-30 13:44:37 -0800631#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
632/*
633 Semi-public function. It is exposed to the user of the interface, but
634 one of the inline wrappers will usually be called rather than this.
635
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800636 See qcbor/qcbor_encode.h
Laurence Lundblade45d5e482020-09-15 21:15:15 -0700637
638 Improvement: create another version of this that only
639 takes a big number mantissa and converts the output to
640 a type 0 or 1 integer when mantissa is small enough.
Laurence Lundblade59289e52019-12-30 13:44:37 -0800641 */
642void QCBOREncode_AddExponentAndMantissa(QCBOREncodeContext *pMe,
643 uint64_t uTag,
644 UsefulBufC BigNumMantissa,
645 bool bBigNumIsNegative,
646 int64_t nMantissa,
647 int64_t nExponent)
648{
Laurence Lundbladeee851742020-01-08 08:37:05 -0800649 /*
650 This is for encoding either a big float or a decimal fraction,
651 both of which are an array of two items, an exponent and a
652 mantissa. The difference between the two is that the exponent is
653 base-2 for big floats and base-10 for decimal fractions, but that
654 has no effect on the code here.
655 */
Laurence Lundbladeae66d3f2020-09-14 18:12:08 -0700656 if(uTag != CBOR_TAG_INVALID64) {
657 QCBOREncode_AddTag(pMe, uTag);
658 }
Laurence Lundblade59289e52019-12-30 13:44:37 -0800659 QCBOREncode_OpenArray(pMe);
660 QCBOREncode_AddInt64(pMe, nExponent);
661 if(!UsefulBuf_IsNULLC(BigNumMantissa)) {
662 if(bBigNumIsNegative) {
663 QCBOREncode_AddNegativeBignum(pMe, BigNumMantissa);
664 } else {
665 QCBOREncode_AddPositiveBignum(pMe, BigNumMantissa);
666 }
667 } else {
668 QCBOREncode_AddInt64(pMe, nMantissa);
669 }
670 QCBOREncode_CloseArray(pMe);
671}
672#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
673
674
Laurence Lundblade067035b2018-11-28 17:35:25 -0800675/*
676 Semi-public function. It is exposed to user of the interface,
677 but they will usually call one of the inline wrappers rather than this.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800678
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800679 See qcbor/qcbor_encode.h
Laurence Lundblade067035b2018-11-28 17:35:25 -0800680*/
681void QCBOREncode_OpenMapOrArray(QCBOREncodeContext *me, uint8_t uMajorType)
682{
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800683 // Add one item to the nesting level we are in for the new map or array
684 me->uError = Nesting_Increment(&(me->nesting));
Laurence Lundblade241705e2018-12-30 18:56:14 -0800685 if(me->uError == QCBOR_SUCCESS) {
Laurence Lundbladeee851742020-01-08 08:37:05 -0800686 /*
687 The offset where the length of an array or map will get written
688 is stored in a uint32_t, not a size_t to keep stack usage
689 smaller. This checks to be sure there is no wrap around when
690 recording the offset. Note that on 64-bit machines CBOR larger
691 than 4GB can be encoded as long as no array / map offsets occur
692 past the 4GB mark, but the public interface says that the
693 maximum is 4GB to keep the discussion simpler.
694 */
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800695 size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf));
Laurence Lundbladed39cd392019-01-11 18:17:38 -0800696
Laurence Lundbladeee851742020-01-08 08:37:05 -0800697 /*
698 QCBOR_MAX_ARRAY_OFFSET is slightly less than UINT32_MAX so this
699 code can run on a 32-bit machine and tests can pass on a 32-bit
700 machine. If it was exactly UINT32_MAX, then this code would not
701 compile or run on a 32-bit machine and an #ifdef or some
702 machine size detection would be needed reducing portability.
703 */
Laurence Lundbladed39cd392019-01-11 18:17:38 -0800704 if(uEndPosition >= QCBOR_MAX_ARRAY_OFFSET) {
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800705 me->uError = QCBOR_ERR_BUFFER_TOO_LARGE;
Laurence Lundbladed39cd392019-01-11 18:17:38 -0800706
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800707 } else {
Laurence Lundbladeee851742020-01-08 08:37:05 -0800708 // Increase nesting level because this is a map or array. Cast
709 // from size_t to uin32_t is safe because of check above
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800710 me->uError = Nesting_Increase(&(me->nesting), uMajorType, (uint32_t)uEndPosition);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700711 }
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800712 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700713}
714
Laurence Lundblade59289e52019-12-30 13:44:37 -0800715
Jan Jongboom4a93a662019-07-25 08:44:58 +0200716/*
717 Semi-public function. It is exposed to user of the interface,
718 but they will usually call one of the inline wrappers rather than this.
719
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800720 See qcbor/qcbor_encode.h
Jan Jongboom4a93a662019-07-25 08:44:58 +0200721*/
722void QCBOREncode_OpenMapOrArrayIndefiniteLength(QCBOREncodeContext *me, uint8_t uMajorType)
723{
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000724 // Insert the indefinite length marker (0x9f for arrays, 0xbf for maps)
725 AppendCBORHead(me, uMajorType, 0, 0);
726 // Call the definite-length opener just to do the bookkeeping for
727 // nesting. It will record the position of the opening item in
728 // the encoded output but this is not used when closing this open.
Jan Jongboom4a93a662019-07-25 08:44:58 +0200729 QCBOREncode_OpenMapOrArray(me, uMajorType);
730}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700731
Laurence Lundbladeee851742020-01-08 08:37:05 -0800732
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700733/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800734 Public functions for closing arrays and maps. See qcbor/qcbor_encode.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700735 */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000736void QCBOREncode_CloseMapOrArray(QCBOREncodeContext *me, uint8_t uMajorType)
Laurence Lundbladea954db92018-09-28 19:27:31 -0700737{
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000738 InsertCBORHead(me, uMajorType, Nesting_GetCount(&(me->nesting)));
739}
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800740
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800741
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000742/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800743 Public functions for closing bstr wrapping. See qcbor/qcbor_encode.h
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000744 */
745void QCBOREncode_CloseBstrWrap2(QCBOREncodeContext *me, bool bIncludeCBORHead, UsefulBufC *pWrappedCBOR)
746{
747 const size_t uInsertPosition = Nesting_GetStartPos(&(me->nesting));
748 const size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800749
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000750 // This can't go negative because the UsefulOutBuf always only grows
751 // and never shrinks. UsefulOutBut itself also has defenses such that
752 // it won't write where it should not even if given hostile input lengths.
753 const size_t uBstrLen = uEndPosition - uInsertPosition;
754
755 // Actually insert
756 InsertCBORHead(me, CBOR_MAJOR_TYPE_BYTE_STRING, uBstrLen);
757
758 if(pWrappedCBOR) {
759 /*
760 Return pointer and length to the enclosed encoded CBOR. The
761 intended use is for it to be hashed (e.g., SHA-256) in a COSE
762 implementation. This must be used right away, as the pointer
763 and length go invalid on any subsequent calls to this function
764 because there might be calls to InsertEncodedTypeAndNumber()
765 that slides data to the right.
766 */
767 size_t uStartOfNew = uInsertPosition;
768 if(!bIncludeCBORHead) {
769 // Skip over the CBOR head to just get the inserted bstr
770 const size_t uNewEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf));
771 uStartOfNew += uNewEndPosition - uEndPosition;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700772 }
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000773 const UsefulBufC PartialResult = UsefulOutBuf_OutUBuf(&(me->OutBuf));
774 *pWrappedCBOR = UsefulBuf_Tail(PartialResult, uStartOfNew);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700775 }
776}
777
Laurence Lundbladeee851742020-01-08 08:37:05 -0800778
Jan Jongboom4a93a662019-07-25 08:44:58 +0200779/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800780 Public functions for closing arrays and maps. See qcbor/qcbor_encode.h
Jan Jongboom4a93a662019-07-25 08:44:58 +0200781 */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000782void QCBOREncode_CloseMapOrArrayIndefiniteLength(QCBOREncodeContext *me, uint8_t uMajorType)
Jan Jongboom4a93a662019-07-25 08:44:58 +0200783{
784 if(me->uError == QCBOR_SUCCESS) {
785 if(!Nesting_IsInNest(&(me->nesting))) {
786 me->uError = QCBOR_ERR_TOO_MANY_CLOSES;
787 } else if(Nesting_GetMajorType(&(me->nesting)) != uMajorType) {
788 me->uError = QCBOR_ERR_CLOSE_MISMATCH;
789 } else {
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000790 // Append the break marker (0xff for both arrays and maps)
Laurence Lundblade8c858ab2020-11-02 19:53:49 -0800791 AppendCBORHead(me, CBOR_MAJOR_NONE_TYPE_SIMPLE_BREAK, CBOR_SIMPLE_BREAK, 0);
Jan Jongboom4a93a662019-07-25 08:44:58 +0200792
Jan Jongboom4a93a662019-07-25 08:44:58 +0200793 Nesting_Decrease(&(me->nesting));
794 }
795 }
796}
797
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700798
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700799/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800800 Public functions to finish and get the encoded result. See qcbor/qcbor_encode.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700801 */
Laurence Lundblade30816f22018-11-10 13:40:22 +0700802QCBORError QCBOREncode_Finish(QCBOREncodeContext *me, UsefulBufC *pEncodedCBOR)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700803{
Laurence Lundbladef607a2a2019-07-05 21:25:25 -0700804 QCBORError uReturn = QCBOREncode_GetErrorState(me);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800805
Laurence Lundblade067035b2018-11-28 17:35:25 -0800806 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700807 goto Done;
Laurence Lundblade067035b2018-11-28 17:35:25 -0800808 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800809
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700810 if (Nesting_IsInNest(&(me->nesting))) {
Laurence Lundblade067035b2018-11-28 17:35:25 -0800811 uReturn = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700812 goto Done;
813 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800814
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700815 *pEncodedCBOR = UsefulOutBuf_OutUBuf(&(me->OutBuf));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800816
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700817Done:
Laurence Lundblade067035b2018-11-28 17:35:25 -0800818 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700819}
820
Laurence Lundblade0595e932018-11-02 22:22:47 +0700821
Laurence Lundblade067035b2018-11-28 17:35:25 -0800822/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800823 Public functions to finish and get the encoded result. See qcbor/qcbor_encode.h
Laurence Lundblade067035b2018-11-28 17:35:25 -0800824 */
Laurence Lundblade30816f22018-11-10 13:40:22 +0700825QCBORError QCBOREncode_FinishGetSize(QCBOREncodeContext *me, size_t *puEncodedLen)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700826{
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700827 UsefulBufC Enc;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800828
Laurence Lundblade30816f22018-11-10 13:40:22 +0700829 QCBORError nReturn = QCBOREncode_Finish(me, &Enc);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800830
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700831 if(nReturn == QCBOR_SUCCESS) {
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700832 *puEncodedLen = Enc.len;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700833 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800834
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700835 return nReturn;
836}
837
838
Laurence Lundblade067035b2018-11-28 17:35:25 -0800839
840
841/*
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000842Object code sizes on 64-bit x86 with GCC -Os Jan 2020. GCC compiles smaller
843than LLVM and optimizations have been made to decrease code size. Bigfloat,
844Decimal fractions and indefinite length encoding were added to increase code
845size. Bstr wrapping is now separate which means if you don't use it, it gets
846dead stripped.
847
848_QCBOREncode_EncodeHead 187
849_QCBOREncode_CloseBstrWrap2: 154
850_QCBOREncode_AddExponentAndMantissa: 144
851_QCBOREncode_AddBuffer 105
852_QCBOREncode_OpenMapOrArray 101
853_QCBOREncode_CloseMapOrArrayIndefiniteLength: 72
854_QCBOREncode_Finish 71
855_InsertCBORHead.part.0 66
856_QCBOREncode_CloseMapOrArray 64
857_QCBOREncode_AddType7 58
858_QCBOREncode_AddInt64 57
859_AppendCBORHead 54
860_QCBOREncode_AddUInt64 40
861_QCBOREncode_Init 38
862_Nesting_Increment.isra.0 36
863_QCBOREncode_FinishGetSize: 34
864_QCBOREncode_AddDouble: 26
865_QCBOREncode_AddTag: 15
866Total 1322
867Min_encode use case 776
868
869
Laurence Lundblade241705e2018-12-30 18:56:14 -0800870 Object code sizes on X86 with LLVM compiler and -Os (Dec 30, 2018)
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800871
Laurence Lundblade9c097392018-12-30 13:52:24 -0800872 _QCBOREncode_Init 69
Laurence Lundblade067035b2018-11-28 17:35:25 -0800873 _QCBOREncode_AddUInt64 76
874 _QCBOREncode_AddInt64 87
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800875 _QCBOREncode_AddBuffer 113
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800876 _QCBOREncode_AddTag 27
Laurence Lundblade9c097392018-12-30 13:52:24 -0800877 _QCBOREncode_AddType7 87
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800878 _QCBOREncode_AddDouble 36
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800879 _QCBOREncode_OpenMapOrArray 103
Laurence Lundblade067035b2018-11-28 17:35:25 -0800880 _QCBOREncode_CloseMapOrArray 181
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800881 _InsertEncodedTypeAndNumber 190
Laurence Lundblade067035b2018-11-28 17:35:25 -0800882 _QCBOREncode_Finish 72
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800883 _QCBOREncode_FinishGetSize 70
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800884
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800885 Total is about 1.1KB
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800886
Laurence Lundblade067035b2018-11-28 17:35:25 -0800887 _QCBOREncode_CloseMapOrArray is larger because it has a lot
888 of nesting tracking to do and much of Nesting_ inlines
889 into it. It probably can't be reduced much.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800890
Laurence Lundblade067035b2018-11-28 17:35:25 -0800891 If the error returned by Nesting_Increment() can be ignored
892 because the limit is so high and the consequence of exceeding
893 is proved to be inconsequential, then a lot of if(me->uError)
894 instance can be removed, saving some code.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800895
Laurence Lundblade067035b2018-11-28 17:35:25 -0800896 */