blob: f627af64c23b61cbb3f437869720affc05c2ef45 [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.
3 Copyright (c) 2018, Laurence Lundblade.
4 All rights reserved.
Laurence Lundblade624405d2018-09-18 20:10:47 -07005
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 Lundblade624405d2018-09-18 20:10:47 -070019
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 Lundblade624405d2018-09-18 20:10:47 -070031 ==============================================================================*/
32
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070033/*===================================================================================
34 FILE: qcbor_encode.c
35
36 DESCRIPTION: This file contains the implementation of QCBOR.
37
38 EDIT HISTORY FOR FILE:
39
40 This section contains comments describing changes made to the module.
41 Notice that changes are listed in reverse chronological order.
42
43 when who what, where, why
44 -------- ---- ---------------------------------------------------
Laurence Lundblade067035b2018-11-28 17:35:25 -080045 11/29/18 llundblade Rework to simpler handling of tags and labels.
46 11/9/18 llundblade Error codes are now enums.
47 11/1/18 llundblade Floating support.
48 10/31/18 llundblade Switch to one license that is almost BSD-3.
49 09/28/18 llundblade Added bstr wrapping feature for COSE implementation.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070050 02/05/18 llundbla Works on CPUs which require integer alignment.
51 Requires new version of UsefulBuf.
52 07/05/17 llundbla Add bstr wrapping of maps/arrays for COSE
53 03/01/17 llundbla More data types
54 11/13/16 llundbla Integrate most TZ changes back into github version.
55 09/30/16 gkanike Porting to TZ.
56 03/15/16 llundbla Initial Version.
57
58 =====================================================================================*/
59
60#include "qcbor.h"
Laurence Lundblade12d32c52018-09-19 11:25:27 -070061#include "ieee754.h"
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070062
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070063
64/*...... This is a ruler that is 80 characters long...........................*/
65
66
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070067/*
68 CBOR's two nesting types, arrays and maps, are tracked here. There is a
69 limit of QCBOR_MAX_ARRAY_NESTING to the number of arrays and maps
70 that can be nested in one encoding so the encoding context stays
71 small enough to fit on the stack.
72
73 When an array / map is opened, pCurrentNesting points to the element
74 in pArrays that records the type, start position and accumluates a
75 count of the number of items added. When closed the start position is
76 used to go back and fill in the type and number of items in the array
77 / map.
78
79 Encoded output be just items like ints and strings that are
80 not part of any array / map. That is, the first thing encoded
81 does not have to be an array or a map.
82 */
83inline static void Nesting_Init(QCBORTrackNesting *pNesting)
84{
85 // assumes pNesting has been zeroed
86 pNesting->pCurrentNesting = &pNesting->pArrays[0];
87 // Implied CBOR array at the top nesting level. This is never returned,
88 // but makes the item count work correctly.
89 pNesting->pCurrentNesting->uMajorType = CBOR_MAJOR_TYPE_ARRAY;
90}
91
Laurence Lundblade30816f22018-11-10 13:40:22 +070092inline static QCBORError Nesting_Increase(QCBORTrackNesting *pNesting, uint8_t uMajorType, uint32_t uPos)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070093{
Laurence Lundblade30816f22018-11-10 13:40:22 +070094 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070095
96 if(pNesting->pCurrentNesting == &pNesting->pArrays[QCBOR_MAX_ARRAY_NESTING]) {
97 // trying to open one too many
98 nReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
99 } else {
100 pNesting->pCurrentNesting++;
101 pNesting->pCurrentNesting->uCount = 0;
102 pNesting->pCurrentNesting->uStart = uPos;
103 pNesting->pCurrentNesting->uMajorType = uMajorType;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700104 }
105 return nReturn;
106}
107
108inline static void Nesting_Decrease(QCBORTrackNesting *pNesting)
109{
110 pNesting->pCurrentNesting--;
111}
112
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800113inline static QCBORError Nesting_Increment(QCBORTrackNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700114{
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800115 if(1 >= QCBOR_MAX_ITEMS_IN_ARRAY - pNesting->pCurrentNesting->uCount) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700116 return QCBOR_ERR_ARRAY_TOO_LONG;
117 }
118
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800119 pNesting->pCurrentNesting->uCount += 1;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700120 return QCBOR_SUCCESS;
121}
122
123inline static uint16_t Nesting_GetCount(QCBORTrackNesting *pNesting)
124{
125 // The nesting count recorded is always the actual number of individiual
126 // data items in the array or map. For arrays CBOR uses the actual item
127 // count. For maps, CBOR uses the number of pairs. This function returns
128 // the number needed for the CBOR encoding, so it divides the number of
129 // items by two for maps to get the number of pairs. This implementation
130 // takes advantage of the map major type being one larger the array major
131 // type, hence the subtraction returns either 1 or 2.
132 return pNesting->pCurrentNesting->uCount / (pNesting->pCurrentNesting->uMajorType - CBOR_MAJOR_TYPE_ARRAY+1);
133}
134
135inline static uint32_t Nesting_GetStartPos(QCBORTrackNesting *pNesting)
136{
137 return pNesting->pCurrentNesting->uStart;
138}
139
140inline static uint8_t Nesting_GetMajorType(QCBORTrackNesting *pNesting)
141{
142 return pNesting->pCurrentNesting->uMajorType;
143}
144
145inline static int Nesting_IsInNest(QCBORTrackNesting *pNesting)
146{
147 return pNesting->pCurrentNesting == &pNesting->pArrays[0] ? 0 : 1;
148}
149
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700150
151
152
153/*
154 Error tracking plan -- Errors are tracked internally and not returned
155 until Finish is called. The CBOR errors are in me->uError.
Laurence Lundblade067035b2018-11-28 17:35:25 -0800156 UsefulOutBuf also tracks whether the buffer is full or not in its
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700157 context. Once either of these errors is set they are never
158 cleared. Only Init() resets them. Or said another way, they must
159 never be cleared or we'll tell the caller all is good when it is not.
160
161 Only one error code is reported by Finish() even if there are
162 multiple errors. The last one set wins. The caller might have to fix
163 one error to reveal the next one they have to fix. This is OK.
164
165 The buffer full error tracked by UsefulBuf is only pulled out of
166 UsefulBuf in Finish() so it is the one that usually wins. UsefulBuf
167 will never go off the end of the buffer even if it is called again
168 and again when full.
169
170 It is really tempting to not check for overflow on the count in the
171 number of items in an array. It would save a lot of code, it is
172 extremely unlikely that any one will every put 65,000 items in an
173 array, and the only bad thing that would happen is the CBOR would be
174 bogus. Once we prove that is the only consequence, then we can make
175 the change.
176
177 Since this does not parse any input, you could in theory remove all
178 error checks in this code if you knew the caller called it
179 correctly. Maybe someday CDDL or some such language will be able to
180 generate the code to call this and the calling code would always be
Laurence Lundblade56230d12018-11-01 11:14:51 +0700181 correct. This could also automatically size some of the data
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700182 structures like array/map nesting resulting in some good memory
183 savings.
Laurence Lundblade067035b2018-11-28 17:35:25 -0800184
185 Errors returned here fall into three categories:
186
187 Sizes
188 QCBOR_ERR_BUFFER_TOO_LARGE -- A buffer passed in > UINT32_MAX
189 QCBOR_ERR_BUFFER_TOO_SMALL -- output buffer too small
190
191 QCBOR_ERR_ARRAY_NESTING_TOO_DEEP -- Too many opens without closes
192 QCBOR_ERR_ARRAY_TOO_LONG -- Too many things added to an array/map
193
194 Nesting constructed incorrectly
195 QCBOR_ERR_TOO_MANY_CLOSES -- more close calls than opens
196 QCBOR_ERR_CLOSE_MISMATCH -- Type of close does not match open
197 QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN -- Finish called without enough closes
198
199 Bad data
200 QCBOR_ERR_BAD_SIMPLE -- Simple value integer not valid
201
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700202 */
203
204
205
206
207/*
208 Public function for initialization. See header qcbor.h
209 */
Laurence Lundblade2296db52018-09-14 18:08:39 -0700210void QCBOREncode_Init(QCBOREncodeContext *me, UsefulBuf Storage)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700211{
212 memset(me, 0, sizeof(QCBOREncodeContext));
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800213 UsefulOutBuf_Init(&(me->OutBuf), Storage);
214 Nesting_Init(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700215}
216
217
218
219
220/*
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800221 All CBOR data items have a type and an "argument". The argument is
222 either the value of the item for integer types, the length of the
223 content for string, byte, array and map types, a tag for major type
224 6, and has several uses for major type 7.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700225
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800226 This function encodes the type and the argument. There are several
227 encodings for the argument depending on how large it is and how it is
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700228 used.
229
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800230 Every encoding of the type and argument has at least one byte, the
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700231 "initial byte".
232
233 The top three bits of the initial byte are the major type for the
234 CBOR data item. The eight major types defined by the standard are
235 defined as CBOR_MAJOR_TYPE_xxxx in qcbor.h.
236
237 The remaining five bits, known as "additional information", and
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800238 possibly more bytes encode the argument. If the argument is less than
239 24, then it is encoded entirely in the five bits. This is neat
240 because it allows you to encode an entire CBOR data item in 1 byte
241 for many values and types (integers 0-23, true, false, and tags).
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700242
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800243 If the argument is larger than 24, then it is encoded in 1,2,4 or 8
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700244 additional bytes, with the number of these bytes indicated by the
245 values of the 5 bits 24, 25, 25 and 27.
246
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800247 It is possible to encode a particular argument in many ways with this
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700248 representation. This implementation always uses the smallest
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800249 possible representation. This conforms with CBOR preferred encoding.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700250
251 This function inserts them into the output buffer at the specified
Laurence Lundblade067035b2018-11-28 17:35:25 -0800252 position. AppendEncodedTypeAndNumber() appends to the end.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700253
254 This function takes care of converting to network byte order.
255
256 This function is also used to insert floats and doubles. Before this
257 function is called the float or double must be copied into a
258 uint64_t. That is how they are passed in. They are then converted to
259 network byte order correctly. The uMinLen param makes sure that even
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800260 if all the digits of a half, float or double are 0 it is still
261 correctly encoded in 2, 4 or 8 bytes.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700262 */
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800263
264static void InsertEncodedTypeAndNumber(QCBOREncodeContext *me,
265 uint8_t uMajorType,
266 int nMinLen,
267 uint64_t uNumber,
268 size_t uPos)
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800269{
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800270 /*
271 This code does endian conversion without hton or knowing the
272 endianness of the machine using masks and shifts. this avoids the
273 dependency on hton and the mess of figuring out how to find the
274 machine's endianness.
275
276 This is a good efficient implementation on little-endian machines.
277 A faster and small implementation is possible on big-endian
278 machines because CBOR/network byte order is big endian. However
279 big endian machines are uncommon.
280
281 On x86, it is about 200 bytes instead of 500 bytes for the more
282 formal unoptimized code.
283
284 This also does the CBOR preferred shortest encoding for integers
285 and is called to do endian conversion for floats.
286
287 It works backwards from the LSB to the MSB as needed.
288
289 Code Reviewers: THIS FUNCTION DOES POINTER MATH
290 */
291 // Holds up to 9 bytes of type and argument
292 // plus one extra so pointer always points to
293 // valid bytes.
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800294 uint8_t bytes[sizeof(uint64_t)+2];
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800295 // Point to the last bytes and work backwards
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800296 uint8_t *pByte = &bytes[sizeof(bytes)-1];
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800297 // This is the 5 bits in the initial byte that is not the major type
298 uint8_t uAdditionalInfo;
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800299
300 if(uNumber < CBOR_TWENTY_FOUR && nMinLen == 0) {
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800301 // Simple case where argument is < 24
302 uAdditionalInfo = uNumber;
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800303 } else {
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800304 /*
305 Encode argument in 1,2,4 or 8 bytes. Outer loop
306 runs once for 1 byte and 4 times for 8 bytes.
307 Inner loop runs 1, 2 or 4 times depending on
308 outer loop counter. This works backwards taking
309 8 bits off the argument being encoded at a time
310 until all bits from uNumber have been encoded
311 and the minimum encoding size is reached.
312 Minimum encoding size is for floating point
313 numbers with zero bytes correctly.
314 */
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800315 static const uint8_t aIterate[] = {1,1,2,4};
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800316 uint8_t i;
317 for(i = 0; uNumber || nMinLen > 0; i++) {
318 const uint8_t uIterations = aIterate[i];
319 for(int j = 0; j < uIterations; j++) {
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800320 *--pByte = uNumber & 0xff;
321 uNumber = uNumber >> 8;
322 }
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800323 nMinLen -= uIterations;
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800324 }
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800325 // Additional info is the encoding of the
326 // number of additional bytes to encode
327 // argument.
328 uAdditionalInfo = LEN_IS_ONE_BYTE-1 + i;
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800329 }
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800330 *--pByte = (uMajorType << 5) + uAdditionalInfo;
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800331
332 UsefulOutBuf_InsertData(&(me->OutBuf), pByte, &bytes[sizeof(bytes)-1] - pByte, uPos);
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800333}
334
Laurence Lundblade351bfea2018-12-07 21:34:31 +0900335
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700336
337
338/*
339 Append the type and number info to the end of the buffer.
340
341 See InsertEncodedTypeAndNumber() function above for details
342*/
343inline static void AppendEncodedTypeAndNumber(QCBOREncodeContext *me, uint8_t uMajorType, uint64_t uNumber)
344{
345 // An append is an insert at the end.
346 InsertEncodedTypeAndNumber(me, uMajorType, 0, uNumber, UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
347}
348
349
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700350
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700351/*
Laurence Lundblade067035b2018-11-28 17:35:25 -0800352 Public functions for closing arrays and maps. See header qcbor.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700353 */
Laurence Lundblade067035b2018-11-28 17:35:25 -0800354void QCBOREncode_AddUInt64(QCBOREncodeContext *me, uint64_t uValue)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700355{
Laurence Lundblade067035b2018-11-28 17:35:25 -0800356 if(me->uError == QCBOR_SUCCESS) {
357 AppendEncodedTypeAndNumber(me, CBOR_MAJOR_TYPE_POSITIVE_INT, uValue);
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800358 me->uError = Nesting_Increment(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700359 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700360}
361
Laurence Lundblade56230d12018-11-01 11:14:51 +0700362
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700363/*
Laurence Lundblade067035b2018-11-28 17:35:25 -0800364 Public functions for closing arrays and maps. See header qcbor.h
365 */
366void QCBOREncode_AddInt64(QCBOREncodeContext *me, int64_t nNum)
367{
368 if(me->uError == QCBOR_SUCCESS) {
369 uint8_t uMajorType;
370 uint64_t uValue;
371
372 if(nNum < 0) {
373 uValue = (uint64_t)(-nNum - 1); // This is the way negative ints work in CBOR. -1 encodes as 0x00 with major type negative int.
374 uMajorType = CBOR_MAJOR_TYPE_NEGATIVE_INT;
375 } else {
376 uValue = (uint64_t)nNum;
377 uMajorType = CBOR_MAJOR_TYPE_POSITIVE_INT;
378 }
379
380 AppendEncodedTypeAndNumber(me, uMajorType, uValue);
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800381 me->uError = Nesting_Increment(&(me->nesting));
Laurence Lundblade067035b2018-11-28 17:35:25 -0800382 }
383}
384
385
386/*
387 Semi-private function. It is exposed to user of the interface,
388 but they will usually call one of the inline wrappers rather than this.
389
390 See header qcbor.h
391
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700392 Does the work of adding some bytes to the CBOR output. Works for a
393 byte and text strings, which are the same in in CBOR though they have
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700394 different major types. This is also used to insert raw
395 pre-encoded CBOR.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700396 */
Laurence Lundblade067035b2018-11-28 17:35:25 -0800397void QCBOREncode_AddBuffer(QCBOREncodeContext *me, uint8_t uMajorType, UsefulBufC Bytes)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700398{
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800399 if(!me->uError) {
400 // If it is not Raw CBOR, add the type and the length
401 if(uMajorType != CBOR_MAJOR_NONE_TYPE_RAW) {
402 AppendEncodedTypeAndNumber(me, uMajorType, Bytes.len);
403 // The increment in uPos is to account for bytes added for
404 // type and number so the buffer being added goes to the
405 // right place
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700406 }
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800407
408 // Actually add the bytes
409 UsefulOutBuf_AppendUsefulBuf(&(me->OutBuf), Bytes);
410
411 // Update the array counting if there is any nesting at all
412 me->uError = Nesting_Increment(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700413 }
414}
415
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700416
Laurence Lundblade55a24832018-10-30 04:35:08 +0700417/*
Laurence Lundblade067035b2018-11-28 17:35:25 -0800418 Public functions for closing arrays and maps. See header qcbor.h
Laurence Lundblade55a24832018-10-30 04:35:08 +0700419 */
420void QCBOREncode_AddTag(QCBOREncodeContext *me, uint64_t uTag)
421{
Laurence Lundblade55a24832018-10-30 04:35:08 +0700422 AppendEncodedTypeAndNumber(me, CBOR_MAJOR_TYPE_OPTIONAL, uTag);
423}
424
425
Laurence Lundblade487930f2018-11-30 11:01:45 -0800426
427
Laurence Lundblade56230d12018-11-01 11:14:51 +0700428/*
Laurence Lundblade487930f2018-11-30 11:01:45 -0800429 Semi-private function. It is exposed to user of the interface,
430 but they will usually call one of the inline wrappers rather than this.
431
432 See header qcbor.h
Laurence Lundblade56230d12018-11-01 11:14:51 +0700433 */
Laurence Lundblade487930f2018-11-30 11:01:45 -0800434void QCBOREncode_AddType7(QCBOREncodeContext *me, size_t uSize, uint64_t uNum)
Laurence Lundblade55a24832018-10-30 04:35:08 +0700435{
Laurence Lundblade487930f2018-11-30 11:01:45 -0800436 if(me->uError == QCBOR_SUCCESS) {
437 // This function call takes care of endian swapping for the float / double
438 InsertEncodedTypeAndNumber(me,
439 CBOR_MAJOR_TYPE_SIMPLE, // The major type for
440 // floats and doubles
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800441 (int)uSize, // min size / tells
Laurence Lundblade487930f2018-11-30 11:01:45 -0800442 // encoder to do it right
443 uNum, // Bytes of the floating
444 // point number as a uint
445 UsefulOutBuf_GetEndPosition(&(me->OutBuf))); // end position for append
446
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800447 me->uError = Nesting_Increment(&(me->nesting));
Laurence Lundblade487930f2018-11-30 11:01:45 -0800448 }
Laurence Lundblade55a24832018-10-30 04:35:08 +0700449}
450
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700451
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700452/*
Laurence Lundblade067035b2018-11-28 17:35:25 -0800453 Public functions for closing arrays and maps. See header qcbor.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700454 */
Laurence Lundblade067035b2018-11-28 17:35:25 -0800455void QCBOREncode_AddDouble(QCBOREncodeContext *me, double dNum)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700456{
Laurence Lundblade067035b2018-11-28 17:35:25 -0800457 const IEEE754_union uNum = IEEE754_DoubleToSmallest(dNum);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700458
Laurence Lundblade487930f2018-11-30 11:01:45 -0800459 QCBOREncode_AddType7(me, uNum.uSize, uNum.uValue);
Laurence Lundblade067035b2018-11-28 17:35:25 -0800460}
461
462
463/*
464 Semi-public function. It is exposed to user of the interface,
465 but they will usually call one of the inline wrappers rather than this.
466
467 See header qcbor.h
468*/
469void QCBOREncode_OpenMapOrArray(QCBOREncodeContext *me, uint8_t uMajorType)
470{
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800471 // Add one item to the nesting level we are in for the new map or array
472 me->uError = Nesting_Increment(&(me->nesting));
473 if(!me->uError) {
474 size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf));
475 if(uEndPosition >= UINT32_MAX-sizeof(uint64_t)) {
476 me->uError = QCBOR_ERR_BUFFER_TOO_LARGE;
477 } else {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700478 // Increase nesting level because this is a map or array
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800479 // Cast from size_t to uin32_t is safe because of check above
480 me->uError = Nesting_Increase(&(me->nesting), uMajorType, (uint32_t)uEndPosition);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700481 }
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800482 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700483}
484
485
486/*
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700487 Public functions for closing arrays and maps. See header qcbor.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700488 */
Laurence Lundblade067035b2018-11-28 17:35:25 -0800489void QCBOREncode_CloseMapOrArray(QCBOREncodeContext *me, uint8_t uMajorType, UsefulBufC *pWrappedCBOR)
Laurence Lundbladea954db92018-09-28 19:27:31 -0700490{
491 if(!me->uError) {
492 if(!Nesting_IsInNest(&(me->nesting))) {
493 me->uError = QCBOR_ERR_TOO_MANY_CLOSES;
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800494 } else if(Nesting_GetMajorType(&(me->nesting)) != uMajorType) {
Laurence Lundblade067035b2018-11-28 17:35:25 -0800495 me->uError = QCBOR_ERR_CLOSE_MISMATCH;
Laurence Lundbladea954db92018-09-28 19:27:31 -0700496 } else {
Laurence Lundblade56230d12018-11-01 11:14:51 +0700497 // When the array, map or bstr wrap was started, nothing was done
498 // except note the position of the start of it. This code goes back
499 // and inserts the actual CBOR array, map or bstr and its length.
500 // That means all the data that is in the array, map or wrapped
501 // needs to be slid to the right. This is done by UsefulOutBuf's
502 // insert function that is called from inside
503 // InsertEncodedTypeAndNumber()
504 const size_t uInsertPosition = Nesting_GetStartPos(&(me->nesting));
505 const size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf));
506 // This can't go negative because the UsefulOutBuf always only grows
507 // and never shrinks. UsefulOutBut itself also has defenses such that
508 // it won't write were it should not even if given hostile input lengths
509 const size_t uLenOfEncodedMapOrArray = uEndPosition - uInsertPosition;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700510
Laurence Lundblade56230d12018-11-01 11:14:51 +0700511 // Length is number of bytes for a bstr and number of items a for map & array
512 const size_t uLength = uMajorType == CBOR_MAJOR_TYPE_BYTE_STRING ?
Laurence Lundbladea954db92018-09-28 19:27:31 -0700513 uLenOfEncodedMapOrArray : Nesting_GetCount(&(me->nesting));
514
515 // Actually insert
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700516 InsertEncodedTypeAndNumber(me,
Laurence Lundbladea954db92018-09-28 19:27:31 -0700517 uMajorType, // major type bstr, array or map
518 0, // no minimum length for encoding
519 uLength, // either len of bstr or num items in array or map
520 uInsertPosition); // position in out buffer
521
522 // Return pointer and length to the enclosed encoded CBOR. The intended
523 // use is for it to be hashed (e.g., SHA-256) in a COSE implementation.
524 // This must be used right away, as the pointer and length go invalid
525 // on any subsequent calls to this function because of the
526 // InsertEncodedTypeAndNumber() call that slides data to the right.
527 if(pWrappedCBOR) {
528 UsefulBufC PartialResult = UsefulOutBuf_OutUBuf(&(me->OutBuf));
Laurence Lundblade56230d12018-11-01 11:14:51 +0700529 size_t uBstrLen = UsefulOutBuf_GetEndPosition(&(me->OutBuf)) - uEndPosition;
Laurence Lundbladea954db92018-09-28 19:27:31 -0700530 *pWrappedCBOR = UsefulBuf_Tail(PartialResult, uInsertPosition+uBstrLen);
531 }
532 Nesting_Decrease(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700533 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700534 }
535}
536
537
Laurence Lundblade56230d12018-11-01 11:14:51 +0700538
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700539/*
540 Public functions to finish and get the encoded result. See header qcbor.h
541 */
Laurence Lundblade30816f22018-11-10 13:40:22 +0700542QCBORError QCBOREncode_Finish(QCBOREncodeContext *me, UsefulBufC *pEncodedCBOR)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700543{
Laurence Lundblade067035b2018-11-28 17:35:25 -0800544 QCBORError uReturn = me->uError;
545
546 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700547 goto Done;
Laurence Lundblade067035b2018-11-28 17:35:25 -0800548 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700549
550 if (Nesting_IsInNest(&(me->nesting))) {
Laurence Lundblade067035b2018-11-28 17:35:25 -0800551 uReturn = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700552 goto Done;
553 }
554
555 if(UsefulOutBuf_GetError(&(me->OutBuf))) {
556 // Stuff didn't fit in the buffer.
Laurence Lundblade56230d12018-11-01 11:14:51 +0700557 // This check catches this condition for all the appends and inserts
558 // so checks aren't needed when the appends and inserts are performed.
559 // And of course UsefulBuf will never overrun the input buffer given
560 // to it. No complex analysis of the error handling in this file is
561 // needed to know that is true. Just read the UsefulBuf code.
Laurence Lundblade067035b2018-11-28 17:35:25 -0800562 uReturn = QCBOR_ERR_BUFFER_TOO_SMALL;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700563 goto Done;
564 }
Laurence Lundblade2296db52018-09-14 18:08:39 -0700565
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700566 *pEncodedCBOR = UsefulOutBuf_OutUBuf(&(me->OutBuf));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700567
568Done:
Laurence Lundblade067035b2018-11-28 17:35:25 -0800569 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700570}
571
Laurence Lundblade0595e932018-11-02 22:22:47 +0700572
Laurence Lundblade067035b2018-11-28 17:35:25 -0800573/*
574 Public functions to finish and get the encoded result. See header qcbor.h
575 */
Laurence Lundblade30816f22018-11-10 13:40:22 +0700576QCBORError QCBOREncode_FinishGetSize(QCBOREncodeContext *me, size_t *puEncodedLen)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700577{
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700578 UsefulBufC Enc;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700579
Laurence Lundblade30816f22018-11-10 13:40:22 +0700580 QCBORError nReturn = QCBOREncode_Finish(me, &Enc);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700581
582 if(nReturn == QCBOR_SUCCESS) {
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700583 *puEncodedLen = Enc.len;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700584 }
585
586 return nReturn;
587}
588
589
Laurence Lundblade067035b2018-11-28 17:35:25 -0800590
591
592/*
593 Notes on the code
594
595 CBOR Major Type Public Function
596 0 QCBOREncode_AddUInt64
597 0, 1 QCBOREncode_AddUInt64, QCBOREncode_AddInt64
598 2, 3 QCBOREncode_AddBuffer, Also QCBOREncode_OpenMapOrArray
599 4, 5 QCBOREncode_OpenMapOrArray
600 6 QCBOREncode_AddTag
Laurence Lundblade4e7bc682018-12-14 23:21:04 -0800601 7 QCBOREncode_AddDouble, QCBOREncode_AddType7
Laurence Lundblade067035b2018-11-28 17:35:25 -0800602
Laurence Lundblade4e7bc682018-12-14 23:21:04 -0800603 Object code sizes on X86 with LLVM compiler and -Os (Dec 14, 2018)
Laurence Lundblade067035b2018-11-28 17:35:25 -0800604
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800605 _QCBOREncode_Init 71
Laurence Lundblade067035b2018-11-28 17:35:25 -0800606 _QCBOREncode_AddUInt64 76
607 _QCBOREncode_AddInt64 87
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800608 _QCBOREncode_AddBuffer 113
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800609 _QCBOREncode_AddTag 27
Laurence Lundblade4e7bc682018-12-14 23:21:04 -0800610 _QCBOREncode_AddType7 83
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800611 _QCBOREncode_AddDouble 36
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800612 _QCBOREncode_OpenMapOrArray 103
Laurence Lundblade067035b2018-11-28 17:35:25 -0800613 _QCBOREncode_CloseMapOrArray 181
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800614 _InsertEncodedTypeAndNumber 190
Laurence Lundblade067035b2018-11-28 17:35:25 -0800615 _QCBOREncode_Finish 72
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800616 _QCBOREncode_FinishGetSize 70
Laurence Lundblade067035b2018-11-28 17:35:25 -0800617
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800618 Total is about 1.1KB
Laurence Lundblade067035b2018-11-28 17:35:25 -0800619
Laurence Lundblade067035b2018-11-28 17:35:25 -0800620 _QCBOREncode_CloseMapOrArray is larger because it has a lot
621 of nesting tracking to do and much of Nesting_ inlines
622 into it. It probably can't be reduced much.
623
624 If the error returned by Nesting_Increment() can be ignored
625 because the limit is so high and the consequence of exceeding
626 is proved to be inconsequential, then a lot of if(me->uError)
627 instance can be removed, saving some code.
628
629 */
630
631
Laurence Lundblade067035b2018-11-28 17:35:25 -0800632
633