blob: be72cd5bb4dcc67ed7b711763a0c04394ed066e7 [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 Lundblade2c40ab82018-12-30 14:20:29 -080075inline static QCBORError Nesting_Increase(QCBORTrackNesting *pNesting,
76 uint8_t uMajorType,
77 uint32_t uPos)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070078{
Laurence Lundblade30816f22018-11-10 13:40:22 +070079 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080080
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070081 if(pNesting->pCurrentNesting == &pNesting->pArrays[QCBOR_MAX_ARRAY_NESTING]) {
Laurence Lundbladeee851742020-01-08 08:37:05 -080082 // Trying to open one too many
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070083 nReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
84 } else {
85 pNesting->pCurrentNesting++;
86 pNesting->pCurrentNesting->uCount = 0;
87 pNesting->pCurrentNesting->uStart = uPos;
88 pNesting->pCurrentNesting->uMajorType = uMajorType;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070089 }
90 return nReturn;
91}
92
93inline static void Nesting_Decrease(QCBORTrackNesting *pNesting)
94{
95 pNesting->pCurrentNesting--;
96}
97
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -080098inline static QCBORError Nesting_Increment(QCBORTrackNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070099{
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800100 if(1 >= QCBOR_MAX_ITEMS_IN_ARRAY - pNesting->pCurrentNesting->uCount) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700101 return QCBOR_ERR_ARRAY_TOO_LONG;
102 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800103
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800104 pNesting->pCurrentNesting->uCount += 1;
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
132inline static uint8_t Nesting_GetMajorType(QCBORTrackNesting *pNesting)
133{
134 return pNesting->pCurrentNesting->uMajorType;
135}
136
Laurence Lundbladeee851742020-01-08 08:37:05 -0800137inline static bool Nesting_IsInNest(QCBORTrackNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700138{
Laurence Lundbladeee851742020-01-08 08:37:05 -0800139 return pNesting->pCurrentNesting == &pNesting->pArrays[0] ? false : true;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700140}
141
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700142
143
144
145/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800146 Encoding of the major CBOR types is by these functions:
147
148 CBOR Major Type Public Function
149 0 QCBOREncode_AddUInt64()
150 0, 1 QCBOREncode_AddUInt64(), QCBOREncode_AddInt64()
151 2, 3 QCBOREncode_AddBuffer(), Also QCBOREncode_OpenMapOrArray(),
152 QCBOREncode_CloseMapOrArray()
153 4, 5 QCBOREncode_OpenMapOrArray(), QCBOREncode_CloseMapOrArray(),
154 QCBOREncode_OpenMapOrArrayIndefiniteLength(),
155 QCBOREncode_CloseMapOrArrayIndefiniteLength()
156 6 QCBOREncode_AddTag()
157 7 QCBOREncode_AddDouble(), QCBOREncode_AddType7()
158
159 Additionally, encoding of decimal fractions and bigfloats is by
160 QCBOREncode_AddExponentAndMantissa()
161*/
162
163/*
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700164 Error tracking plan -- Errors are tracked internally and not returned
Laurence Lundbladeee851742020-01-08 08:37:05 -0800165 until QCBOREncode_Finish is called. The CBOR errors are in me->uError.
Laurence Lundblade067035b2018-11-28 17:35:25 -0800166 UsefulOutBuf also tracks whether the buffer is full or not in its
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700167 context. Once either of these errors is set they are never
Laurence Lundblade241705e2018-12-30 18:56:14 -0800168 cleared. Only QCBOREncode_Init() resets them. Or said another way, they must
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700169 never be cleared or we'll tell the caller all is good when it is not.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800170
Laurence Lundblade241705e2018-12-30 18:56:14 -0800171 Only one error code is reported by QCBOREncode_Finish() even if there are
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700172 multiple errors. The last one set wins. The caller might have to fix
173 one error to reveal the next one they have to fix. This is OK.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800174
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700175 The buffer full error tracked by UsefulBuf is only pulled out of
176 UsefulBuf in Finish() so it is the one that usually wins. UsefulBuf
177 will never go off the end of the buffer even if it is called again
178 and again when full.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800179
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700180 It is really tempting to not check for overflow on the count in the
181 number of items in an array. It would save a lot of code, it is
182 extremely unlikely that any one will every put 65,000 items in an
183 array, and the only bad thing that would happen is the CBOR would be
Laurence Lundblade241705e2018-12-30 18:56:14 -0800184 bogus.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800185
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700186 Since this does not parse any input, you could in theory remove all
187 error checks in this code if you knew the caller called it
188 correctly. Maybe someday CDDL or some such language will be able to
189 generate the code to call this and the calling code would always be
Laurence Lundblade56230d12018-11-01 11:14:51 +0700190 correct. This could also automatically size some of the data
Laurence Lundblade241705e2018-12-30 18:56:14 -0800191 structures like array/map nesting resulting in some stack memory
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700192 savings.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800193
Laurence Lundbladeee851742020-01-08 08:37:05 -0800194 The 8 errors returned here fall into three categories:
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800195
Laurence Lundblade067035b2018-11-28 17:35:25 -0800196 Sizes
Laurence Lundbladeee851742020-01-08 08:37:05 -0800197 QCBOR_ERR_BUFFER_TOO_LARGE -- Encoded output exceeded UINT32_MAX
198 QCBOR_ERR_BUFFER_TOO_SMALL -- Output buffer too small
199 QCBOR_ERR_ARRAY_NESTING_TOO_DEEP -- Nesting > QCBOR_MAX_ARRAY_NESTING1
200 QCBOR_ERR_ARRAY_TOO_LONG -- Too many things added to an array/map
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800201
Laurence Lundblade067035b2018-11-28 17:35:25 -0800202 Nesting constructed incorrectly
Laurence Lundbladeee851742020-01-08 08:37:05 -0800203 QCBOR_ERR_TOO_MANY_CLOSES -- More close calls than opens
204 QCBOR_ERR_CLOSE_MISMATCH -- Type of close does not match open
Laurence Lundblade067035b2018-11-28 17:35:25 -0800205 QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN -- Finish called without enough closes
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700206
207 Would generate not-well-formed CBOR
Laurence Lundbladeee851742020-01-08 08:37:05 -0800208 QCBOR_ERR_UNSUPPORTED -- Simple type between 24 and 31
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700209 */
210
211
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700212/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800213 Public function for initialization. See qcbor/qcbor_encode.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700214 */
Laurence Lundblade2296db52018-09-14 18:08:39 -0700215void QCBOREncode_Init(QCBOREncodeContext *me, UsefulBuf Storage)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700216{
217 memset(me, 0, sizeof(QCBOREncodeContext));
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800218 UsefulOutBuf_Init(&(me->OutBuf), Storage);
219 Nesting_Init(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700220}
221
222
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000223/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800224 Public function to encode a CBOR head. See qcbor/qcbor_encode.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700225 */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000226UsefulBufC QCBOREncode_EncodeHead(UsefulBuf buffer,
227 uint8_t uMajorType,
228 uint8_t uMinLen,
229 uint64_t uArgument)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700230{
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000231 /**
232 All CBOR data items have a type and an "argument". The argument is
233 either the value of the item for integer types, the length of the
234 content for string, byte, array and map types, a tag for major type
235 6, and has several uses for major type 7.
236
237 This function encodes the type and the argument. There are several
238 encodings for the argument depending on how large it is and how it is
239 used.
240
241 Every encoding of the type and argument has at least one byte, the
242 "initial byte".
243
244 The top three bits of the initial byte are the major type for the
245 CBOR data item. The eight major types defined by the standard are
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800246 defined as CBOR_MAJOR_TYPE_xxxx in qcbor/qcbor_common.h.
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000247
248 The remaining five bits, known as "additional information", and
249 possibly more bytes encode the argument. If the argument is less than
250 24, then it is encoded entirely in the five bits. This is neat
251 because it allows you to encode an entire CBOR data item in 1 byte
252 for many values and types (integers 0-23, true, false, and tags).
253
254 If the argument is larger than 24, then it is encoded in 1,2,4 or 8
255 additional bytes, with the number of these bytes indicated by the
256 values of the 5 bits 24, 25, 25 and 27.
257
258 It is possible to encode a particular argument in many ways with this
259 representation. This implementation always uses the smallest
260 possible representation. This conforms with CBOR preferred encoding.
261
262 This function inserts them into the output buffer at the specified
263 position. AppendEncodedTypeAndNumber() appends to the end.
264
265 This function takes care of converting to network byte order.
266
267 This function is also used to insert floats and doubles. Before this
268 function is called the float or double must be copied into a
269 uint64_t. That is how they are passed in. They are then converted to
270 network byte order correctly. The uMinLen parameter makes sure that
271 even if all the digits of a half, float or double are 0 it is still
272 correctly encoded in 2, 4 or 8 bytes.
273 */
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800274 /*
275 This code does endian conversion without hton or knowing the
Laurence Lundblade241705e2018-12-30 18:56:14 -0800276 endianness of the machine using masks and shifts. This avoids the
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800277 dependency on hton and the mess of figuring out how to find the
278 machine's endianness.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800279
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800280 This is a good efficient implementation on little-endian machines.
281 A faster and small implementation is possible on big-endian
282 machines because CBOR/network byte order is big endian. However
283 big endian machines are uncommon.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800284
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800285 On x86, it is about 200 bytes instead of 500 bytes for the more
286 formal unoptimized code.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800287
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800288 This also does the CBOR preferred shortest encoding for integers
289 and is called to do endian conversion for floats.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800290
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800291 It works backwards from the LSB to the MSB as needed.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800292
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800293 Code Reviewers: THIS FUNCTION DOES POINTER MATH
294 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800295 /*
296 The type int is used here for several variables because of the way
297 integer promotion works in C for integer variables that are
298 uint8_t or uint16_t. The basic rule is that they will always be
299 promoted to int if they will fit. All of these integer variables
300 need only hold values less than 255 or are promoted from uint8_t,
301 so they will always fit into an int. Note that promotion is only
302 to unsigned int if the value won't fit into an int even if the
303 promotion is for an unsigned like uint8_t.
304
305 By declaring them int, there are few implicit conversions and fewer
306 casts needed. Code size is reduced a little. It also makes static
307 analyzers happier.
308
309 Note also that declaring them uint8_t won't stop integer wrap
310 around if the code is wrong. It won't make the code more correct.
311
312 https://stackoverflow.com/questions/46073295/implicit-type-promotion-rules
313 https://stackoverflow.com/questions/589575/what-does-the-c-standard-state-the-size-of-int-long-type-to-be
314 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800315
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000316 // Buffer must have room for the largest CBOR HEAD + one extra as the
317 // one extra is needed for this code to work as it does a pre-decrement.
318 if(buffer.len < QCBOR_HEAD_BUFFER_SIZE) {
319 return NULLUsefulBufC;
320 }
321
322 // Pointer to last valid byte in the buffer
323 uint8_t * const pBufferEnd = &((uint8_t *)buffer.ptr)[QCBOR_HEAD_BUFFER_SIZE-1];
324
325 // Point to the last byte and work backwards
326 uint8_t *pByte = pBufferEnd;
327 // The 5 bits in the initial byte that are not the major type
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800328 int nAdditionalInfo;
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800329
Jan Jongboom5d827882019-08-07 12:51:15 +0200330 if (uMajorType == CBOR_MAJOR_NONE_TYPE_ARRAY_INDEFINITE_LEN) {
331 uMajorType = CBOR_MAJOR_TYPE_ARRAY;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800332 nAdditionalInfo = LEN_IS_INDEFINITE;
Jan Jongboom5d827882019-08-07 12:51:15 +0200333 } else if (uMajorType == CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN) {
334 uMajorType = CBOR_MAJOR_TYPE_MAP;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800335 nAdditionalInfo = LEN_IS_INDEFINITE;
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000336 } else if (uArgument < CBOR_TWENTY_FOUR && uMinLen == 0) {
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800337 // Simple case where argument is < 24
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000338 nAdditionalInfo = (int)uArgument;
339 } else if (uMajorType == CBOR_MAJOR_TYPE_SIMPLE && uArgument == CBOR_SIMPLE_BREAK) {
Jan Jongboom4a93a662019-07-25 08:44:58 +0200340 // Break statement can be encoded in single byte too (0xff)
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000341 nAdditionalInfo = (int)uArgument;
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800342 } else {
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800343 /*
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000344 Encode argument in 1,2,4 or 8 bytes. Outer loop
345 runs once for 1 byte and 4 times for 8 bytes.
346 Inner loop runs 1, 2 or 4 times depending on
347 outer loop counter. This works backwards taking
348 8 bits off the argument being encoded at a time
349 until all bits from uNumber have been encoded
350 and the minimum encoding size is reached.
351 Minimum encoding size is for floating point
352 numbers with zero bytes.
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800353 */
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800354 static const uint8_t aIterate[] = {1,1,2,4};
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000355
356 // The parameter passed in is unsigned, but goes negative in the loop
357 // so it must be converted to a signed value.
358 int nMinLen = (int)uMinLen;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800359 int i;
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000360 for(i = 0; uArgument || nMinLen > 0; i++) {
361 const int nIterations = (int)aIterate[i];
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800362 for(int j = 0; j < nIterations; j++) {
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000363 *--pByte = (uint8_t)(uArgument & 0xff);
364 uArgument = uArgument >> 8;
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800365 }
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800366 nMinLen -= nIterations;
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800367 }
Laurence Lundbladeee851742020-01-08 08:37:05 -0800368 // Additional info is the encoding of the number of additional
369 // bytes to encode argument.
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800370 nAdditionalInfo = LEN_IS_ONE_BYTE-1 + i;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700371 }
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800372
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800373 /*
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000374 This expression integer-promotes to type int. The code above in
375 function guarantees that nAdditionalInfo will never be larger than
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800376 0x1f. The caller may pass in a too-large uMajor type. The
377 conversion to unint8_t will cause an integer wrap around and
378 incorrect CBOR will be generated, but no security issue will
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000379 occur.
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800380 */
381 *--pByte = (uint8_t)((uMajorType << 5) + nAdditionalInfo);
382
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000383#ifdef EXTRA_ENCODE_HEAD_CHECK
384 /* This is a sanity check that can be turned on to verify the pointer
385 * math in this function is not going wrong. Turn it on and run the
386 * whole test suite to perform the check.
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800387 */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000388 if(pBufferEnd - pByte > 9 || pBufferEnd - pByte < 1 || pByte < (uint8_t *)buffer.ptr) {
389 return NULLUsefulBufC;
390 }
391#endif
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800392
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000393 // Length will not go negative because the loops run for at most 8 decrements
394 // of pByte, only one other decrement is made, and the array is sized
395 // for this.
396 return (UsefulBufC){pByte, (size_t)(pBufferEnd - pByte)};
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700397}
398
399
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000400/**
401 @brief Append the CBOR head, the major type and argument
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800402
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000403 @param me Encoder context.
404 @param uMajorType Major type to insert.
405 @param uArgument The argument (an integer value or a length).
406 @param uMinLen The minimum number of bytes for encoding the CBOR argument.
407
408 This formats the CBOR "head" and appends it to the output.
409 */
410static void AppendCBORHead(QCBOREncodeContext *me, uint8_t uMajorType, uint64_t uArgument, uint8_t uMinLen)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700411{
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000412 // A stack buffer large enough for a CBOR head
413 UsefulBuf_MAKE_STACK_UB (pBufferForEncodedHead, QCBOR_HEAD_BUFFER_SIZE);
414
415 UsefulBufC EncodedHead = QCBOREncode_EncodeHead(pBufferForEncodedHead,
416 uMajorType,
417 uMinLen,
418 uArgument);
419
420 /* No check for EncodedHead == NULLUsefulBufC is performed here to
421 * save object code. It is very clear that pBufferForEncodedHead
422 * is the correct size. If EncodedHead == NULLUsefulBufC then
423 * UsefulOutBuf_AppendUsefulBuf() will do nothing so there is
424 * no security hole introduced.
425 */
426
427 UsefulOutBuf_AppendUsefulBuf(&(me->OutBuf), EncodedHead);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700428}
429
430
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000431/**
432 @brief Insert the CBOR head for a map, array or wrapped bstr
433
434 @param me QCBOR encoding context.
435 @param uMajorType One of CBOR_MAJOR_TYPE_XXXX.
436 @param uLen The length of the data item.
437
438 When an array, map or bstr was opened, nothing was done but note
439 the position. This function goes back to that position and inserts
440 the CBOR Head with the major type and length.
441 */
442static void InsertCBORHead(QCBOREncodeContext *me, uint8_t uMajorType, size_t uLen)
443{
444 if(me->uError == QCBOR_SUCCESS) {
445 if(!Nesting_IsInNest(&(me->nesting))) {
446 me->uError = QCBOR_ERR_TOO_MANY_CLOSES;
447 } else if(Nesting_GetMajorType(&(me->nesting)) != uMajorType) {
448 me->uError = QCBOR_ERR_CLOSE_MISMATCH;
449 } else {
450 // A stack buffer large enough for a CBOR head
451 UsefulBuf_MAKE_STACK_UB (pBufferForEncodedHead,QCBOR_HEAD_BUFFER_SIZE);
452
453 UsefulBufC EncodedHead = QCBOREncode_EncodeHead(pBufferForEncodedHead,
454 uMajorType,
455 0,
456 uLen);
457
458 /* No check for EncodedHead == NULLUsefulBufC is performed here to
459 * save object code. It is very clear that pBufferForEncodedHead
460 * is the correct size. If EncodedHead == NULLUsefulBufC then
461 * UsefulOutBuf_InsertUsefulBuf() will do nothing so there is
462 * no security whole introduced.
463 */
464 UsefulOutBuf_InsertUsefulBuf(&(me->OutBuf), EncodedHead, Nesting_GetStartPos(&(me->nesting)) );
465
466 Nesting_Decrease(&(me->nesting));
467 }
468 }
469}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700470
Laurence Lundblade241705e2018-12-30 18:56:14 -0800471
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700472/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800473 Public functions for adding integers. See qcbor/qcbor_encode.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700474 */
Laurence Lundblade067035b2018-11-28 17:35:25 -0800475void QCBOREncode_AddUInt64(QCBOREncodeContext *me, uint64_t uValue)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700476{
Laurence Lundblade067035b2018-11-28 17:35:25 -0800477 if(me->uError == QCBOR_SUCCESS) {
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000478 AppendCBORHead(me, CBOR_MAJOR_TYPE_POSITIVE_INT, uValue, 0);
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800479 me->uError = Nesting_Increment(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700480 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700481}
482
Laurence Lundblade56230d12018-11-01 11:14:51 +0700483
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700484/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800485 Public functions for adding unsigned. See qcbor/qcbor_encode.h
Laurence Lundblade067035b2018-11-28 17:35:25 -0800486 */
487void QCBOREncode_AddInt64(QCBOREncodeContext *me, int64_t nNum)
488{
489 if(me->uError == QCBOR_SUCCESS) {
490 uint8_t uMajorType;
491 uint64_t uValue;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800492
Laurence Lundblade067035b2018-11-28 17:35:25 -0800493 if(nNum < 0) {
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800494 // In CBOR -1 encodes as 0x00 with major type negative int.
495 uValue = (uint64_t)(-nNum - 1);
Laurence Lundblade067035b2018-11-28 17:35:25 -0800496 uMajorType = CBOR_MAJOR_TYPE_NEGATIVE_INT;
497 } else {
498 uValue = (uint64_t)nNum;
499 uMajorType = CBOR_MAJOR_TYPE_POSITIVE_INT;
500 }
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000501 AppendCBORHead(me, uMajorType, uValue, 0);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800502
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800503 me->uError = Nesting_Increment(&(me->nesting));
Laurence Lundblade067035b2018-11-28 17:35:25 -0800504 }
505}
506
507
508/*
Laurence Lundbladeda532272019-04-07 11:40:17 -0700509 Semi-private function. It is exposed to user of the interface, but
510 they will usually call one of the inline wrappers rather than this.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800511
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800512 See qcbor/qcbor_encode.h
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800513
Laurence Lundbladeda532272019-04-07 11:40:17 -0700514 Does the work of adding actual strings bytes to the CBOR output (as
515 opposed to numbers and opening / closing aggregate types).
516
517 There are four use cases:
518 CBOR_MAJOR_TYPE_BYTE_STRING -- Byte strings
519 CBOR_MAJOR_TYPE_TEXT_STRING -- Text strings
520 CBOR_MAJOR_NONE_TYPE_RAW -- Already-encoded CBOR
521 CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY -- Special case
522
523 The first two add the type and length plus the actual bytes. The
524 third just adds the bytes as the type and length are presumed to be
525 in the bytes. The fourth just adds the type and length for the very
526 special case of QCBOREncode_AddBytesLenOnly().
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700527 */
Laurence Lundblade067035b2018-11-28 17:35:25 -0800528void QCBOREncode_AddBuffer(QCBOREncodeContext *me, uint8_t uMajorType, UsefulBufC Bytes)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700529{
Laurence Lundblade241705e2018-12-30 18:56:14 -0800530 if(me->uError == QCBOR_SUCCESS) {
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800531 // If it is not Raw CBOR, add the type and the length
532 if(uMajorType != CBOR_MAJOR_NONE_TYPE_RAW) {
Laurence Lundbladeda532272019-04-07 11:40:17 -0700533 uint8_t uRealMajorType = uMajorType;
534 if(uRealMajorType == CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY) {
535 uRealMajorType = CBOR_MAJOR_TYPE_BYTE_STRING;
536 }
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000537 AppendCBORHead(me, uRealMajorType, Bytes.len, 0);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700538 }
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800539
Laurence Lundbladeda532272019-04-07 11:40:17 -0700540 if(uMajorType != CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY) {
541 // Actually add the bytes
542 UsefulOutBuf_AppendUsefulBuf(&(me->OutBuf), Bytes);
543 }
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800544
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800545 // Update the array counting if there is any nesting at all
546 me->uError = Nesting_Increment(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700547 }
548}
549
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700550
Laurence Lundblade55a24832018-10-30 04:35:08 +0700551/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800552 Public functions for adding a tag. See qcbor/qcbor_encode.h
Laurence Lundblade55a24832018-10-30 04:35:08 +0700553 */
554void QCBOREncode_AddTag(QCBOREncodeContext *me, uint64_t uTag)
555{
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000556 AppendCBORHead(me, CBOR_MAJOR_TYPE_OPTIONAL, uTag, 0);
Laurence Lundblade55a24832018-10-30 04:35:08 +0700557}
558
559
Laurence Lundblade56230d12018-11-01 11:14:51 +0700560/*
Laurence Lundblade487930f2018-11-30 11:01:45 -0800561 Semi-private function. It is exposed to user of the interface,
562 but they will usually call one of the inline wrappers rather than this.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800563
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800564 See header qcbor/qcbor_encode.h
Laurence Lundblade56230d12018-11-01 11:14:51 +0700565 */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000566void QCBOREncode_AddType7(QCBOREncodeContext *me, uint8_t uMinLen, uint64_t uNum)
Laurence Lundblade55a24832018-10-30 04:35:08 +0700567{
Laurence Lundblade487930f2018-11-30 11:01:45 -0800568 if(me->uError == QCBOR_SUCCESS) {
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700569 if(uNum >= CBOR_SIMPLEV_RESERVED_START && uNum <= CBOR_SIMPLEV_RESERVED_END) {
570 me->uError = QCBOR_ERR_UNSUPPORTED;
571 } else {
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000572 // AppendHead() does endian swapping for the float / double
573 AppendCBORHead(me, CBOR_MAJOR_TYPE_SIMPLE, uNum, uMinLen);
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700574 me->uError = Nesting_Increment(&(me->nesting));
575 }
Laurence Lundblade487930f2018-11-30 11:01:45 -0800576 }
Laurence Lundblade55a24832018-10-30 04:35:08 +0700577}
578
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700579
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700580/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800581 Public functions for adding a double. See qcbor/qcbor_encode.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700582 */
Laurence Lundblade067035b2018-11-28 17:35:25 -0800583void QCBOREncode_AddDouble(QCBOREncodeContext *me, double dNum)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700584{
Laurence Lundblade067035b2018-11-28 17:35:25 -0800585 const IEEE754_union uNum = IEEE754_DoubleToSmallest(dNum);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800586
Laurence Lundblade487930f2018-11-30 11:01:45 -0800587 QCBOREncode_AddType7(me, uNum.uSize, uNum.uValue);
Laurence Lundblade067035b2018-11-28 17:35:25 -0800588}
589
590
Laurence Lundblade59289e52019-12-30 13:44:37 -0800591#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
592/*
593 Semi-public function. It is exposed to the user of the interface, but
594 one of the inline wrappers will usually be called rather than this.
595
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800596 See qcbor/qcbor_encode.h
Laurence Lundblade59289e52019-12-30 13:44:37 -0800597 */
598void QCBOREncode_AddExponentAndMantissa(QCBOREncodeContext *pMe,
599 uint64_t uTag,
600 UsefulBufC BigNumMantissa,
601 bool bBigNumIsNegative,
602 int64_t nMantissa,
603 int64_t nExponent)
604{
Laurence Lundbladeee851742020-01-08 08:37:05 -0800605 /*
606 This is for encoding either a big float or a decimal fraction,
607 both of which are an array of two items, an exponent and a
608 mantissa. The difference between the two is that the exponent is
609 base-2 for big floats and base-10 for decimal fractions, but that
610 has no effect on the code here.
611 */
Laurence Lundblade59289e52019-12-30 13:44:37 -0800612 QCBOREncode_AddTag(pMe, uTag);
613 QCBOREncode_OpenArray(pMe);
614 QCBOREncode_AddInt64(pMe, nExponent);
615 if(!UsefulBuf_IsNULLC(BigNumMantissa)) {
616 if(bBigNumIsNegative) {
617 QCBOREncode_AddNegativeBignum(pMe, BigNumMantissa);
618 } else {
619 QCBOREncode_AddPositiveBignum(pMe, BigNumMantissa);
620 }
621 } else {
622 QCBOREncode_AddInt64(pMe, nMantissa);
623 }
624 QCBOREncode_CloseArray(pMe);
625}
626#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
627
628
Laurence Lundblade067035b2018-11-28 17:35:25 -0800629/*
630 Semi-public function. It is exposed to user of the interface,
631 but they will usually call one of the inline wrappers rather than this.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800632
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800633 See qcbor/qcbor_encode.h
Laurence Lundblade067035b2018-11-28 17:35:25 -0800634*/
635void QCBOREncode_OpenMapOrArray(QCBOREncodeContext *me, uint8_t uMajorType)
636{
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800637 // Add one item to the nesting level we are in for the new map or array
638 me->uError = Nesting_Increment(&(me->nesting));
Laurence Lundblade241705e2018-12-30 18:56:14 -0800639 if(me->uError == QCBOR_SUCCESS) {
Laurence Lundbladeee851742020-01-08 08:37:05 -0800640 /*
641 The offset where the length of an array or map will get written
642 is stored in a uint32_t, not a size_t to keep stack usage
643 smaller. This checks to be sure there is no wrap around when
644 recording the offset. Note that on 64-bit machines CBOR larger
645 than 4GB can be encoded as long as no array / map offsets occur
646 past the 4GB mark, but the public interface says that the
647 maximum is 4GB to keep the discussion simpler.
648 */
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800649 size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf));
Laurence Lundbladed39cd392019-01-11 18:17:38 -0800650
Laurence Lundbladeee851742020-01-08 08:37:05 -0800651 /*
652 QCBOR_MAX_ARRAY_OFFSET is slightly less than UINT32_MAX so this
653 code can run on a 32-bit machine and tests can pass on a 32-bit
654 machine. If it was exactly UINT32_MAX, then this code would not
655 compile or run on a 32-bit machine and an #ifdef or some
656 machine size detection would be needed reducing portability.
657 */
Laurence Lundbladed39cd392019-01-11 18:17:38 -0800658 if(uEndPosition >= QCBOR_MAX_ARRAY_OFFSET) {
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800659 me->uError = QCBOR_ERR_BUFFER_TOO_LARGE;
Laurence Lundbladed39cd392019-01-11 18:17:38 -0800660
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800661 } else {
Laurence Lundbladeee851742020-01-08 08:37:05 -0800662 // Increase nesting level because this is a map or array. Cast
663 // from size_t to uin32_t is safe because of check above
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800664 me->uError = Nesting_Increase(&(me->nesting), uMajorType, (uint32_t)uEndPosition);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700665 }
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800666 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700667}
668
Laurence Lundblade59289e52019-12-30 13:44:37 -0800669
Jan Jongboom4a93a662019-07-25 08:44:58 +0200670/*
671 Semi-public function. It is exposed to user of the interface,
672 but they will usually call one of the inline wrappers rather than this.
673
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800674 See qcbor/qcbor_encode.h
Jan Jongboom4a93a662019-07-25 08:44:58 +0200675*/
676void QCBOREncode_OpenMapOrArrayIndefiniteLength(QCBOREncodeContext *me, uint8_t uMajorType)
677{
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000678 // Insert the indefinite length marker (0x9f for arrays, 0xbf for maps)
679 AppendCBORHead(me, uMajorType, 0, 0);
680 // Call the definite-length opener just to do the bookkeeping for
681 // nesting. It will record the position of the opening item in
682 // the encoded output but this is not used when closing this open.
Jan Jongboom4a93a662019-07-25 08:44:58 +0200683 QCBOREncode_OpenMapOrArray(me, uMajorType);
684}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700685
Laurence Lundbladeee851742020-01-08 08:37:05 -0800686
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700687/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800688 Public functions for closing arrays and maps. See qcbor/qcbor_encode.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700689 */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000690void QCBOREncode_CloseMapOrArray(QCBOREncodeContext *me, uint8_t uMajorType)
Laurence Lundbladea954db92018-09-28 19:27:31 -0700691{
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000692 InsertCBORHead(me, uMajorType, Nesting_GetCount(&(me->nesting)));
693}
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800694
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800695
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000696/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800697 Public functions for closing bstr wrapping. See qcbor/qcbor_encode.h
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000698 */
699void QCBOREncode_CloseBstrWrap2(QCBOREncodeContext *me, bool bIncludeCBORHead, UsefulBufC *pWrappedCBOR)
700{
701 const size_t uInsertPosition = Nesting_GetStartPos(&(me->nesting));
702 const size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800703
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000704 // This can't go negative because the UsefulOutBuf always only grows
705 // and never shrinks. UsefulOutBut itself also has defenses such that
706 // it won't write where it should not even if given hostile input lengths.
707 const size_t uBstrLen = uEndPosition - uInsertPosition;
708
709 // Actually insert
710 InsertCBORHead(me, CBOR_MAJOR_TYPE_BYTE_STRING, uBstrLen);
711
712 if(pWrappedCBOR) {
713 /*
714 Return pointer and length to the enclosed encoded CBOR. The
715 intended use is for it to be hashed (e.g., SHA-256) in a COSE
716 implementation. This must be used right away, as the pointer
717 and length go invalid on any subsequent calls to this function
718 because there might be calls to InsertEncodedTypeAndNumber()
719 that slides data to the right.
720 */
721 size_t uStartOfNew = uInsertPosition;
722 if(!bIncludeCBORHead) {
723 // Skip over the CBOR head to just get the inserted bstr
724 const size_t uNewEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf));
725 uStartOfNew += uNewEndPosition - uEndPosition;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700726 }
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000727 const UsefulBufC PartialResult = UsefulOutBuf_OutUBuf(&(me->OutBuf));
728 *pWrappedCBOR = UsefulBuf_Tail(PartialResult, uStartOfNew);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700729 }
730}
731
Laurence Lundbladeee851742020-01-08 08:37:05 -0800732
Jan Jongboom4a93a662019-07-25 08:44:58 +0200733/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800734 Public functions for closing arrays and maps. See qcbor/qcbor_encode.h
Jan Jongboom4a93a662019-07-25 08:44:58 +0200735 */
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000736void QCBOREncode_CloseMapOrArrayIndefiniteLength(QCBOREncodeContext *me, uint8_t uMajorType)
Jan Jongboom4a93a662019-07-25 08:44:58 +0200737{
738 if(me->uError == QCBOR_SUCCESS) {
739 if(!Nesting_IsInNest(&(me->nesting))) {
740 me->uError = QCBOR_ERR_TOO_MANY_CLOSES;
741 } else if(Nesting_GetMajorType(&(me->nesting)) != uMajorType) {
742 me->uError = QCBOR_ERR_CLOSE_MISMATCH;
743 } else {
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000744 // Append the break marker (0xff for both arrays and maps)
745 AppendCBORHead(me, CBOR_MAJOR_TYPE_SIMPLE, CBOR_SIMPLE_BREAK, 0);
Jan Jongboom4a93a662019-07-25 08:44:58 +0200746
Jan Jongboom4a93a662019-07-25 08:44:58 +0200747 Nesting_Decrease(&(me->nesting));
748 }
749 }
750}
751
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700752
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700753/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800754 Public functions to finish and get the encoded result. See qcbor/qcbor_encode.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700755 */
Laurence Lundblade30816f22018-11-10 13:40:22 +0700756QCBORError QCBOREncode_Finish(QCBOREncodeContext *me, UsefulBufC *pEncodedCBOR)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700757{
Laurence Lundbladef607a2a2019-07-05 21:25:25 -0700758 QCBORError uReturn = QCBOREncode_GetErrorState(me);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800759
Laurence Lundblade067035b2018-11-28 17:35:25 -0800760 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700761 goto Done;
Laurence Lundblade067035b2018-11-28 17:35:25 -0800762 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800763
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700764 if (Nesting_IsInNest(&(me->nesting))) {
Laurence Lundblade067035b2018-11-28 17:35:25 -0800765 uReturn = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700766 goto Done;
767 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800768
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700769 *pEncodedCBOR = UsefulOutBuf_OutUBuf(&(me->OutBuf));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800770
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700771Done:
Laurence Lundblade067035b2018-11-28 17:35:25 -0800772 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700773}
774
Laurence Lundblade0595e932018-11-02 22:22:47 +0700775
Laurence Lundblade067035b2018-11-28 17:35:25 -0800776/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800777 Public functions to finish and get the encoded result. See qcbor/qcbor_encode.h
Laurence Lundblade067035b2018-11-28 17:35:25 -0800778 */
Laurence Lundblade30816f22018-11-10 13:40:22 +0700779QCBORError QCBOREncode_FinishGetSize(QCBOREncodeContext *me, size_t *puEncodedLen)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700780{
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700781 UsefulBufC Enc;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800782
Laurence Lundblade30816f22018-11-10 13:40:22 +0700783 QCBORError nReturn = QCBOREncode_Finish(me, &Enc);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800784
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700785 if(nReturn == QCBOR_SUCCESS) {
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700786 *puEncodedLen = Enc.len;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700787 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800788
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700789 return nReturn;
790}
791
792
Laurence Lundblade067035b2018-11-28 17:35:25 -0800793
794
795/*
Laurence Lundbladec9f0fbc2020-02-07 10:48:33 +0000796Object code sizes on 64-bit x86 with GCC -Os Jan 2020. GCC compiles smaller
797than LLVM and optimizations have been made to decrease code size. Bigfloat,
798Decimal fractions and indefinite length encoding were added to increase code
799size. Bstr wrapping is now separate which means if you don't use it, it gets
800dead stripped.
801
802_QCBOREncode_EncodeHead 187
803_QCBOREncode_CloseBstrWrap2: 154
804_QCBOREncode_AddExponentAndMantissa: 144
805_QCBOREncode_AddBuffer 105
806_QCBOREncode_OpenMapOrArray 101
807_QCBOREncode_CloseMapOrArrayIndefiniteLength: 72
808_QCBOREncode_Finish 71
809_InsertCBORHead.part.0 66
810_QCBOREncode_CloseMapOrArray 64
811_QCBOREncode_AddType7 58
812_QCBOREncode_AddInt64 57
813_AppendCBORHead 54
814_QCBOREncode_AddUInt64 40
815_QCBOREncode_Init 38
816_Nesting_Increment.isra.0 36
817_QCBOREncode_FinishGetSize: 34
818_QCBOREncode_AddDouble: 26
819_QCBOREncode_AddTag: 15
820Total 1322
821Min_encode use case 776
822
823
Laurence Lundblade241705e2018-12-30 18:56:14 -0800824 Object code sizes on X86 with LLVM compiler and -Os (Dec 30, 2018)
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800825
Laurence Lundblade9c097392018-12-30 13:52:24 -0800826 _QCBOREncode_Init 69
Laurence Lundblade067035b2018-11-28 17:35:25 -0800827 _QCBOREncode_AddUInt64 76
828 _QCBOREncode_AddInt64 87
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800829 _QCBOREncode_AddBuffer 113
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800830 _QCBOREncode_AddTag 27
Laurence Lundblade9c097392018-12-30 13:52:24 -0800831 _QCBOREncode_AddType7 87
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800832 _QCBOREncode_AddDouble 36
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800833 _QCBOREncode_OpenMapOrArray 103
Laurence Lundblade067035b2018-11-28 17:35:25 -0800834 _QCBOREncode_CloseMapOrArray 181
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800835 _InsertEncodedTypeAndNumber 190
Laurence Lundblade067035b2018-11-28 17:35:25 -0800836 _QCBOREncode_Finish 72
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800837 _QCBOREncode_FinishGetSize 70
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800838
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800839 Total is about 1.1KB
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800840
Laurence Lundblade067035b2018-11-28 17:35:25 -0800841 _QCBOREncode_CloseMapOrArray is larger because it has a lot
842 of nesting tracking to do and much of Nesting_ inlines
843 into it. It probably can't be reduced much.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800844
Laurence Lundblade067035b2018-11-28 17:35:25 -0800845 If the error returned by Nesting_Increment() can be ignored
846 because the limit is so high and the consequence of exceeding
847 is proved to be inconsequential, then a lot of if(me->uError)
848 instance can be removed, saving some code.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800849
Laurence Lundblade067035b2018-11-28 17:35:25 -0800850 */