blob: 7a93614460c1583678464ab6fa5880f85393a5c9 [file] [log] [blame]
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001/*==============================================================================
2Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
3
4Redistribution and use in source and binary forms, with or without
5modification, are permitted provided that the following conditions are
6met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above
10 copyright notice, this list of conditions and the following
11 disclaimer in the documentation and/or other materials provided
12 with the distribution.
13 * Neither the name of The Linux Foundation nor the names of its
14 contributors may be used to endorse or promote products derived
15 from this software without specific prior written permission.
16
17THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28==============================================================================*/
29
Laurence Lundblade624405d2018-09-18 20:10:47 -070030/*==============================================================================
31 Modifications beyond the version released on CAF are under the MIT license:
32
33 Copyright 2018 Laurence Lundblade
34
35 Permission is hereby granted, free of charge, to any person obtaining
36 a copy of this software and associated documentation files (the
37 "Software"), to deal in the Software without restriction, including
38 without limitation the rights to use, copy, modify, merge, publish,
39 distribute, sublicense, and/or sell copies of the Software, and to
40 permit persons to whom the Software is furnished to do so, subject to
41 the following conditions:
42
43 The above copyright notice and this permission notice shall be included
44 in all copies or substantial portions of the Software.
45
46 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
47 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
48 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
49 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
50 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
51 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
52 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
53 SOFTWARE.
54 ==============================================================================*/
55
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070056/*===================================================================================
57 FILE: qcbor_encode.c
58
59 DESCRIPTION: This file contains the implementation of QCBOR.
60
61 EDIT HISTORY FOR FILE:
62
63 This section contains comments describing changes made to the module.
64 Notice that changes are listed in reverse chronological order.
65
66 when who what, where, why
67 -------- ---- ---------------------------------------------------
68 02/05/18 llundbla Works on CPUs which require integer alignment.
69 Requires new version of UsefulBuf.
70 07/05/17 llundbla Add bstr wrapping of maps/arrays for COSE
71 03/01/17 llundbla More data types
72 11/13/16 llundbla Integrate most TZ changes back into github version.
73 09/30/16 gkanike Porting to TZ.
74 03/15/16 llundbla Initial Version.
75
76 =====================================================================================*/
77
78#include "qcbor.h"
Laurence Lundblade12d32c52018-09-19 11:25:27 -070079#include "ieee754.h"
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070080
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070081
82/*...... This is a ruler that is 80 characters long...........................*/
83
84
85// Used internally in the impementation here
86// Must not conflict with any of the official CBOR types
87#define CBOR_MAJOR_NONE_TYPE_RAW 9
88
89
90
91
92
93/*
94 CBOR's two nesting types, arrays and maps, are tracked here. There is a
95 limit of QCBOR_MAX_ARRAY_NESTING to the number of arrays and maps
96 that can be nested in one encoding so the encoding context stays
97 small enough to fit on the stack.
98
99 When an array / map is opened, pCurrentNesting points to the element
100 in pArrays that records the type, start position and accumluates a
101 count of the number of items added. When closed the start position is
102 used to go back and fill in the type and number of items in the array
103 / map.
104
105 Encoded output be just items like ints and strings that are
106 not part of any array / map. That is, the first thing encoded
107 does not have to be an array or a map.
108 */
109inline static void Nesting_Init(QCBORTrackNesting *pNesting)
110{
111 // assumes pNesting has been zeroed
112 pNesting->pCurrentNesting = &pNesting->pArrays[0];
113 // Implied CBOR array at the top nesting level. This is never returned,
114 // but makes the item count work correctly.
115 pNesting->pCurrentNesting->uMajorType = CBOR_MAJOR_TYPE_ARRAY;
116}
117
Laurence Lundbladea954db92018-09-28 19:27:31 -0700118inline static int Nesting_Increase(QCBORTrackNesting *pNesting, uint8_t uMajorType, uint32_t uPos)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700119{
120 int nReturn = QCBOR_SUCCESS;
121
122 if(pNesting->pCurrentNesting == &pNesting->pArrays[QCBOR_MAX_ARRAY_NESTING]) {
123 // trying to open one too many
124 nReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
125 } else {
126 pNesting->pCurrentNesting++;
127 pNesting->pCurrentNesting->uCount = 0;
128 pNesting->pCurrentNesting->uStart = uPos;
129 pNesting->pCurrentNesting->uMajorType = uMajorType;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700130 }
131 return nReturn;
132}
133
134inline static void Nesting_Decrease(QCBORTrackNesting *pNesting)
135{
136 pNesting->pCurrentNesting--;
137}
138
139inline static int Nesting_Increment(QCBORTrackNesting *pNesting, uint16_t uAmount)
140{
141 if(uAmount >= QCBOR_MAX_ITEMS_IN_ARRAY - pNesting->pCurrentNesting->uCount) {
142 return QCBOR_ERR_ARRAY_TOO_LONG;
143 }
144
145 pNesting->pCurrentNesting->uCount += uAmount;
146 return QCBOR_SUCCESS;
147}
148
149inline static uint16_t Nesting_GetCount(QCBORTrackNesting *pNesting)
150{
151 // The nesting count recorded is always the actual number of individiual
152 // data items in the array or map. For arrays CBOR uses the actual item
153 // count. For maps, CBOR uses the number of pairs. This function returns
154 // the number needed for the CBOR encoding, so it divides the number of
155 // items by two for maps to get the number of pairs. This implementation
156 // takes advantage of the map major type being one larger the array major
157 // type, hence the subtraction returns either 1 or 2.
158 return pNesting->pCurrentNesting->uCount / (pNesting->pCurrentNesting->uMajorType - CBOR_MAJOR_TYPE_ARRAY+1);
159}
160
161inline static uint32_t Nesting_GetStartPos(QCBORTrackNesting *pNesting)
162{
163 return pNesting->pCurrentNesting->uStart;
164}
165
166inline static uint8_t Nesting_GetMajorType(QCBORTrackNesting *pNesting)
167{
168 return pNesting->pCurrentNesting->uMajorType;
169}
170
171inline static int Nesting_IsInNest(QCBORTrackNesting *pNesting)
172{
173 return pNesting->pCurrentNesting == &pNesting->pArrays[0] ? 0 : 1;
174}
175
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700176
177
178
179/*
180 Error tracking plan -- Errors are tracked internally and not returned
181 until Finish is called. The CBOR errors are in me->uError.
182 UsefulOutBuf also tracks whether the the buffer is full or not in its
183 context. Once either of these errors is set they are never
184 cleared. Only Init() resets them. Or said another way, they must
185 never be cleared or we'll tell the caller all is good when it is not.
186
187 Only one error code is reported by Finish() even if there are
188 multiple errors. The last one set wins. The caller might have to fix
189 one error to reveal the next one they have to fix. This is OK.
190
191 The buffer full error tracked by UsefulBuf is only pulled out of
192 UsefulBuf in Finish() so it is the one that usually wins. UsefulBuf
193 will never go off the end of the buffer even if it is called again
194 and again when full.
195
196 It is really tempting to not check for overflow on the count in the
197 number of items in an array. It would save a lot of code, it is
198 extremely unlikely that any one will every put 65,000 items in an
199 array, and the only bad thing that would happen is the CBOR would be
200 bogus. Once we prove that is the only consequence, then we can make
201 the change.
202
203 Since this does not parse any input, you could in theory remove all
204 error checks in this code if you knew the caller called it
205 correctly. Maybe someday CDDL or some such language will be able to
206 generate the code to call this and the calling code would always be
207 correct. This could also make automatically size some of the data
208 structures like array/map nesting resulting in some good memory
209 savings.
210 */
211
212
213
214
215/*
216 Public function for initialization. See header qcbor.h
217 */
Laurence Lundblade2296db52018-09-14 18:08:39 -0700218void QCBOREncode_Init(QCBOREncodeContext *me, UsefulBuf Storage)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700219{
220 memset(me, 0, sizeof(QCBOREncodeContext));
Laurence Lundblade2296db52018-09-14 18:08:39 -0700221 if(Storage.len > UINT32_MAX) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700222 me->uError = QCBOR_ERR_BUFFER_TOO_LARGE;
223 } else {
Laurence Lundblade2296db52018-09-14 18:08:39 -0700224 UsefulOutBuf_Init(&(me->OutBuf), Storage);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700225 Nesting_Init(&(me->nesting));
226 }
227}
228
229
230
231
232/*
233 All CBOR data items have a type and a number. The number is either
234 the value of the item for integer types, the length of the content
235 for string, byte, array and map types, a tag for major type 6, and
236 has serveral uses for major type 7.
237
238 This function encodes the type and the number. There are several
239 encodings for the number depending on how large it is and how it is
240 used.
241
242 Every encoding of the type and number has at least one byte, the
243 "initial byte".
244
245 The top three bits of the initial byte are the major type for the
246 CBOR data item. The eight major types defined by the standard are
247 defined as CBOR_MAJOR_TYPE_xxxx in qcbor.h.
248
249 The remaining five bits, known as "additional information", and
250 possibly more bytes encode the number. If the number is less than 24,
251 then it is encoded entirely in the five bits. This is neat because it
252 allows you to encode an entire CBOR data item in 1 byte for many
253 values and types (integers 0-23, true, false, and tags).
254
255 If the number is larger than 24, then it is encoded in 1,2,4 or 8
256 additional bytes, with the number of these bytes indicated by the
257 values of the 5 bits 24, 25, 25 and 27.
258
259 It is possible to encode a particular number in many ways with this
260 representation. This implementation always uses the smallest
261 possible representation. This is also the suggestion made in the RFC
262 for cannonical CBOR.
263
264 This function inserts them into the output buffer at the specified
265 position. AppendEncodedTypeAndNumber() appends to the end.
266
267 This function takes care of converting to network byte order.
268
269 This function is also used to insert floats and doubles. Before this
270 function is called the float or double must be copied into a
271 uint64_t. That is how they are passed in. They are then converted to
272 network byte order correctly. The uMinLen param makes sure that even
273 if all the digits of a float or double are 0 it is still correctly
274 encoded in 4 or 8 bytes.
275
276 */
277static void InsertEncodedTypeAndNumber(QCBOREncodeContext *me, uint8_t uMajorType, size_t uMinLen, uint64_t uNumber, size_t uPos)
278{
279 // No need to worry about integer overflow here because a) uMajorType is
280 // always generated internally, not by the caller, b) this is for CBOR
281 // _generation_, not parsing c) a mistake will result in bad CBOR generation,
282 // not a security vulnerability.
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700283 uMajorType <<= 5; // TODO: make this a constant
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700284
285 if(uNumber > 0xffffffff || uMinLen >= 8) {
286 UsefulOutBuf_InsertByte(&(me->OutBuf), uMajorType + LEN_IS_EIGHT_BYTES, uPos);
287 UsefulOutBuf_InsertUint64(&(me->OutBuf), (uint64_t)uNumber, uPos+1);
288
289 } else if(uNumber > 0xffff || uMinLen >= 4) {
290 UsefulOutBuf_InsertByte(&(me->OutBuf), uMajorType + LEN_IS_FOUR_BYTES, uPos);
291 UsefulOutBuf_InsertUint32(&(me->OutBuf), (uint32_t)uNumber, uPos+1);
292
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700293 } else if (uNumber > 0xff || uMinLen>= 2) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700294 // Between 0 and 65535
295 UsefulOutBuf_InsertByte(&(me->OutBuf), uMajorType + LEN_IS_TWO_BYTES, uPos);
296 UsefulOutBuf_InsertUint16(&(me->OutBuf), (uint16_t)uNumber, uPos+1);
297
298 } else if(uNumber >= 24) {
299 // Between 0 and 255, but only between 24 and 255 is ever encoded here
300 UsefulOutBuf_InsertByte(&(me->OutBuf), uMajorType + LEN_IS_ONE_BYTE, uPos);
301 UsefulOutBuf_InsertByte(&(me->OutBuf), (uint8_t)uNumber, uPos+1);
302
303 } else {
304 // Between 0 and 23
305 UsefulOutBuf_InsertByte(&(me->OutBuf), uMajorType + (uint8_t)uNumber, uPos);
306 }
307}
308
309
310/*
311 Append the type and number info to the end of the buffer.
312
313 See InsertEncodedTypeAndNumber() function above for details
314*/
315inline static void AppendEncodedTypeAndNumber(QCBOREncodeContext *me, uint8_t uMajorType, uint64_t uNumber)
316{
317 // An append is an insert at the end.
318 InsertEncodedTypeAndNumber(me, uMajorType, 0, uNumber, UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
319}
320
321
Laurence Lundblade55a24832018-10-30 04:35:08 +0700322
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700323
324
325/*
Laurence Lundblade55a24832018-10-30 04:35:08 +0700326 Internal function for adding positive and negative integers of all different sizes
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700327 */
Laurence Lundblade55a24832018-10-30 04:35:08 +0700328void InsertInt64(QCBOREncodeContext *me, int64_t nNum, uint32_t uPos)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700329{
Laurence Lundblade55a24832018-10-30 04:35:08 +0700330 uint8_t uMajorType;
331 uint64_t uValue;
332
333 if(nNum < 0) {
334 uValue = (uint64_t)(-nNum - 1); // This is the way negative ints work in CBOR. -1 encodes as 0x00 with major type negative int.
335 uMajorType = CBOR_MAJOR_TYPE_NEGATIVE_INT;
336 } else {
337 uValue = (uint64_t)nNum;
338 uMajorType = CBOR_MAJOR_TYPE_POSITIVE_INT;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700339 }
Laurence Lundblade55a24832018-10-30 04:35:08 +0700340
341 InsertEncodedTypeAndNumber(me, uMajorType, 0, uValue, uPos);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700342}
343
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700344/*
345 Does the work of adding some bytes to the CBOR output. Works for a
346 byte and text strings, which are the same in in CBOR though they have
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700347 different major types. This is also used to insert raw
348 pre-encoded CBOR.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700349 */
Laurence Lundblade55a24832018-10-30 04:35:08 +0700350static void AddBytesInternal2(QCBOREncodeContext *me, UsefulBufC Bytes, uint8_t uMajorType, uint32_t uPos)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700351{
352 if(Bytes.len >= UINT32_MAX) {
353 // This implementation doesn't allow buffers larger than UINT32_MAX. This is
354 // primarily because QCBORTrackNesting.pArrays[].uStart is an uint32 rather
355 // than size_t to keep the stack usage down. Also it is entirely impractical
356 // to create tokens bigger than 4GB in contiguous RAM
357 me->uError = QCBOR_ERR_BUFFER_TOO_LARGE;
358
359 } else {
360
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700361 if(!me->uError) {
Laurence Lundblade55a24832018-10-30 04:35:08 +0700362
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700363 // If it is not Raw CBOR, add the type and the length
Laurence Lundblade55a24832018-10-30 04:35:08 +0700364 uint32_t xx = (uint32_t)UsefulOutBuf_GetEndPosition(&(me->OutBuf));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700365 if(uMajorType != CBOR_MAJOR_NONE_TYPE_RAW) {
Laurence Lundblade55a24832018-10-30 04:35:08 +0700366 InsertEncodedTypeAndNumber(me, uMajorType, 0, Bytes.len, uPos);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700367 }
Laurence Lundblade55a24832018-10-30 04:35:08 +0700368 uint32_t yy = (uint32_t)UsefulOutBuf_GetEndPosition(&(me->OutBuf));
369 uPos += yy-xx;
370
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700371
372 // Actually add the bytes
Laurence Lundblade55a24832018-10-30 04:35:08 +0700373 // TODO: how do we know where to insert this?
374 UsefulOutBuf_InsertUsefulBuf(&(me->OutBuf), Bytes, uPos);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700375
376 // Update the array counting if there is any nesting at all
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700377 me->uError = Nesting_Increment(&(me->nesting), 1);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700378 }
379 }
380}
381
Laurence Lundblade55a24832018-10-30 04:35:08 +0700382/*
383 Add an optional label. It will go in front of a real data item.
384 */
385
386static void AddLabel(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel)
387{
388 uint32_t uPos = (uint32_t)UsefulOutBuf_GetEndPosition(&(me->OutBuf)); // TODO: justify cast
389 if(Nesting_GetMajorType(&(me->nesting)) == 0x1f) {
390 uPos = Nesting_GetStartPos(&(me->nesting));
391 Nesting_Decrease(&(me->nesting));
392 }
393
394 if(szLabel) {
395 UsefulBufC SZText = UsefulBuf_FromSZ(szLabel);
396 AddBytesInternal2(me, SZText, CBOR_MAJOR_TYPE_TEXT_STRING, uPos);
397 } else if (QCBOR_NO_INT_LABEL != nLabel) {
398 InsertInt64(me, nLabel, uPos);
399 }
400}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700401
402
403
404/*
Laurence Lundblade55a24832018-10-30 04:35:08 +0700405 Public Function
406 */
407void QCBOREncode_AddTag(QCBOREncodeContext *me, uint64_t uTag)
408{
409 uint8_t uNestingType = Nesting_GetMajorType(&(me->nesting));
410 if(uNestingType == CBOR_MAJOR_TYPE_MAP) {
411 // Remember where the first tag is for this item
412 // So we can go back and insert the label in front of it.
413 me->uError = Nesting_Increase(&(me->nesting), 0x1f, (uint32_t)UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
414 }
415
416 AppendEncodedTypeAndNumber(me, CBOR_MAJOR_TYPE_OPTIONAL, uTag);
417}
418
419
420
421void QCBOREncode_AddBytes_2(QCBOREncodeContext *me, uint8_t uMajorType, const char *szLabel, int64_t nLabel, UsefulBufC Bytes)
422{
423 AddLabel(me, szLabel, nLabel);
424 if(!me->uError) {
425 AddBytesInternal2(me, Bytes, uMajorType, (uint32_t)UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
426 }
427}
428
429/*
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700430 Public functions for adding strings and raw encoded CBOR. See header qcbor.h
431 */
432void QCBOREncode_AddBytes_3(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, UsefulBufC Bytes)
433{
Laurence Lundblade55a24832018-10-30 04:35:08 +0700434 QCBOREncode_AddBytes_2(me, CBOR_MAJOR_TYPE_BYTE_STRING, szLabel, nLabel, Bytes);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700435}
436
437void QCBOREncode_AddText_3(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, UsefulBufC Bytes)
438{
Laurence Lundblade55a24832018-10-30 04:35:08 +0700439 QCBOREncode_AddBytes_2(me, CBOR_MAJOR_TYPE_TEXT_STRING, szLabel, nLabel, Bytes);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700440}
441
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700442void QCBOREncode_AddEncodedToMap_3(QCBOREncodeContext *me, const char *szLabel, uint64_t nLabel, uint64_t uTag, UsefulBufC Encoded)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700443{
Laurence Lundblade55a24832018-10-30 04:35:08 +0700444 QCBOREncode_AddBytes_2(me, CBOR_MAJOR_NONE_TYPE_RAW, szLabel, nLabel, Encoded);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700445}
446
447
448
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700449/*
450 Internal function common to opening an array or a map
451
452 QCBOR_MAX_ARRAY_NESTING is the number of times Open can be called
453 successfully. Call it one more time gives an error.
454
455 */
Laurence Lundblade55a24832018-10-30 04:35:08 +0700456static void OpenMapOrArrayInternal(QCBOREncodeContext *me, uint8_t uMajorType, const char *szLabel, uint64_t nLabel)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700457{
Laurence Lundblade55a24832018-10-30 04:35:08 +0700458 AddLabel(me, szLabel, nLabel);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700459
460 if(!me->uError) {
461 // Add one item to the nesting level we are in for the new map or array
462 me->uError = Nesting_Increment(&(me->nesting), 1);
463 if(!me->uError) {
464 // Increase nesting level because this is a map or array
465 // Cast from size_t to uin32_t is safe because the UsefulOutBuf
466 // size is limited to UINT32_MAX in QCBOR_Init().
Laurence Lundbladea954db92018-09-28 19:27:31 -0700467 me->uError = Nesting_Increase(&(me->nesting), uMajorType, (uint32_t)UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700468 }
469 }
470}
471
472
473/*
474 Public functions for opening / closing arrays and maps. See header qcbor.h
475 */
Laurence Lundbladea954db92018-09-28 19:27:31 -0700476void QCBOREncode_OpenArray_3(QCBOREncodeContext *me, const char *szLabel, uint64_t nLabel, uint64_t uTag)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700477{
Laurence Lundblade55a24832018-10-30 04:35:08 +0700478 OpenMapOrArrayInternal(me, CBOR_MAJOR_TYPE_ARRAY, szLabel, nLabel);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700479}
480
Laurence Lundbladea954db92018-09-28 19:27:31 -0700481void QCBOREncode_OpenMap_3(QCBOREncodeContext *me, const char *szLabel, uint64_t nLabel, uint64_t uTag)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700482{
Laurence Lundblade55a24832018-10-30 04:35:08 +0700483 OpenMapOrArrayInternal(me, CBOR_MAJOR_TYPE_MAP, szLabel, nLabel);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700484}
485
Laurence Lundbladea954db92018-09-28 19:27:31 -0700486void QCBOREncode_OpenBstrWrap_3(QCBOREncodeContext *me, const char *szLabel, uint64_t nLabel, uint64_t uTag)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700487{
Laurence Lundblade55a24832018-10-30 04:35:08 +0700488 OpenMapOrArrayInternal(me, CBOR_MAJOR_TYPE_BYTE_STRING, szLabel, nLabel);
Laurence Lundbladea954db92018-09-28 19:27:31 -0700489}
490
491void QCBOREncode_Close(QCBOREncodeContext *me, uint8_t uMajorType, UsefulBufC *pWrappedCBOR)
492{
493 if(!me->uError) {
494 if(!Nesting_IsInNest(&(me->nesting))) {
495 me->uError = QCBOR_ERR_TOO_MANY_CLOSES;
496 } else if( Nesting_GetMajorType(&(me->nesting)) != uMajorType) {
497 me->uError = QCBOR_ERR_CLOSE_MISMATCH;
498 } else {
499 const uint32_t uInsertPosition = Nesting_GetStartPos(&(me->nesting));
500 // When the array, map or bstr wrap was started, nothing was done except
501 // note the position of the start of it. This code goes back and inserts
502 // the actual CBOR array, map or bstr and its length. That means all the
503 // data that is in the array, map or wrapped needs to be slid to the
504 // right. This is done by UsefulOutBuf's insert function that is called
505 // from inside InsertEncodedTypeAndNumber()
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700506
507 // Cast from size_t to uin32_t is safe because the UsefulOutBuf
508 // size is limited to UINT32_MAX in QCBOR_Init().
Laurence Lundbladea954db92018-09-28 19:27:31 -0700509 const uint32_t uEndPosition = (uint32_t)UsefulOutBuf_GetEndPosition(&(me->OutBuf));
510 const uint32_t uLenOfEncodedMapOrArray = uEndPosition - uInsertPosition;
511
512 // Length is number of bytes for a bstr and number of items for map & array
513 const uint32_t uLength = uMajorType == CBOR_MAJOR_TYPE_BYTE_STRING ?
514 uLenOfEncodedMapOrArray : Nesting_GetCount(&(me->nesting));
515
516 // Actually insert
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700517 InsertEncodedTypeAndNumber(me,
Laurence Lundbladea954db92018-09-28 19:27:31 -0700518 uMajorType, // major type bstr, array or map
519 0, // no minimum length for encoding
520 uLength, // either len of bstr or num items in array or map
521 uInsertPosition); // position in out buffer
522
523 // Return pointer and length to the enclosed encoded CBOR. The intended
524 // use is for it to be hashed (e.g., SHA-256) in a COSE implementation.
525 // This must be used right away, as the pointer and length go invalid
526 // on any subsequent calls to this function because of the
527 // InsertEncodedTypeAndNumber() call that slides data to the right.
528 if(pWrappedCBOR) {
529 UsefulBufC PartialResult = UsefulOutBuf_OutUBuf(&(me->OutBuf));
530 uint32_t uBstrLen = (uint32_t)UsefulOutBuf_GetEndPosition(&(me->OutBuf)) - uEndPosition;
531 *pWrappedCBOR = UsefulBuf_Tail(PartialResult, uInsertPosition+uBstrLen);
532 }
533 Nesting_Decrease(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700534 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700535 }
536}
537
538
539
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700540/*
Laurence Lundblade55a24832018-10-30 04:35:08 +0700541 Public functions for adding integers. See header qcbor.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700542 */
Laurence Lundblade55a24832018-10-30 04:35:08 +0700543
544void QCBOREncode_AddUInt64_2(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uNum)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700545{
Laurence Lundblade55a24832018-10-30 04:35:08 +0700546 AddLabel(me, szLabel, nLabel);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700547 if(!me->uError) {
Laurence Lundblade55a24832018-10-30 04:35:08 +0700548 AppendEncodedTypeAndNumber(me, CBOR_MAJOR_TYPE_POSITIVE_INT, uNum);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700549 me->uError = Nesting_Increment(&(me->nesting), 1);
550 }
551}
552
Laurence Lundblade55a24832018-10-30 04:35:08 +0700553void QCBOREncode_AddInt64_2(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, int64_t nNum)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700554{
Laurence Lundblade55a24832018-10-30 04:35:08 +0700555 AddLabel(me, szLabel, nLabel);
556 if(!me->uError) {
557 InsertInt64(me, nNum, (uint32_t)UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
558 me->uError = Nesting_Increment(&(me->nesting), 1);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700559 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700560}
561
562
563
564
565/*
566 Common code for adding floats and doubles and simple types like true and false
567
568 One way to look at simple values is that they are:
569 - type 7
570 - an additional integer from 0 to 255
571 - additional integer 0-19 are unassigned and could be used in an update to CBOR
572 - additional integers 20, 21, 22 and 23 are false, true, null and undef
573 - additional integer 24 is not available
574 - when the additional value is 25, 26, or 27 there is additionally a half, float or double in following bytes
575 - additional integers 28, 29 and 30 are unassigned / reserved
576 - additional integer 31 is a "break"
577 - additional integers 32-255 are unassigned and could be used in an update to CBOR
578 */
579static void AddSimpleInternal(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, size_t uSize, uint64_t uNum)
580{
Laurence Lundblade55a24832018-10-30 04:35:08 +0700581 AddLabel(me, szLabel, nLabel);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700582 if(!me->uError) {
583 // This function call takes care of endian swapping for the float / double
584 InsertEncodedTypeAndNumber(me,
585 CBOR_MAJOR_TYPE_SIMPLE, // The major type for floats and doubles
586 uSize, // min size / tells encoder to do it right
587 uNum, // Bytes of the floating point number as a uint
588 UsefulOutBuf_GetEndPosition(&(me->OutBuf))); // end position for append
589
590 me->uError = Nesting_Increment(&(me->nesting), 1);
591 }
592}
593
594
595/*
596 Public function for adding simple values. See header qcbor.h
597 */
598void QCBOREncode_AddRawSimple_3(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, uint8_t uSimple)
599{
600 AddSimpleInternal(me, szLabel, nLabel, uTag, 0, uSimple);
601}
602
603
604/*
605 Public function for adding simple values. See header qcbor.h
606 */
607void QCBOREncode_AddSimple_3(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, uint8_t uSimple)
608{
609 if(uSimple < CBOR_SIMPLEV_FALSE || uSimple > CBOR_SIMPLEV_UNDEF) {
610 me->uError = QCBOR_ERR_BAD_SIMPLE;
611 } else {
612 QCBOREncode_AddRawSimple_3(me, szLabel, nLabel, uTag, uSimple);
613 }
614}
615
616
617/*
618 Public functions for floating point numbers. See header qcbor.h
619 */
620void QCBOREncode_AddFloat_3(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, float fNum)
621{
622 // Convert the *type* of the data from a float to a uint so the
623 // standard integer encoding can work. This takes advantage
624 // of CBOR's indicator for a float being the same as for a 4
625 // byte integer too.
626 const float *pfNum = &fNum;
627 const uint32_t uNum = *(uint32_t *)pfNum;
628
629 AddSimpleInternal(me, szLabel, nLabel, uTag, sizeof(float), uNum);
630}
631
632void QCBOREncode_AddDouble_3(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, double dNum)
633{
634 // see how it is done for floats above
635 const double *pdNum = &dNum;
636 const uint64_t uNum = *(uint64_t *)pdNum;
637
638 AddSimpleInternal(me, szLabel, nLabel, uTag, sizeof(double), uNum);
639}
640
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700641void QCBOREncode_AddFloatAsHalf_3(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, float fNum)
642{
643 AddSimpleInternal(me, szLabel, nLabel, uTag, sizeof(uint16_t), IEEE754_FloatToHalf(fNum));
644}
645
646static void QCBOREncode_AddFUnionAsSmallest_3(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, IEEE754_union uNum)
647{
648 switch(uNum.uTag) {
649 case IEEE754_UNION_IS_HALF:
650 AddSimpleInternal(me, szLabel, nLabel, uTag, sizeof(uint16_t), uNum.u16);
651 break;
652 case IEEE754_UNION_IS_SINGLE:
653 AddSimpleInternal(me, szLabel, nLabel, uTag, sizeof(uint32_t), uNum.u32);
654 break;
655 case IEEE754_UNION_IS_DOUBLE:
656 AddSimpleInternal(me, szLabel, nLabel, uTag, sizeof(uint64_t), uNum.u64);
657 break;
658 }
659}
660
661void QCBOREncode_AddFloatAsSmallest_3(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, float fNum)
662{
663 QCBOREncode_AddFUnionAsSmallest_3(me, szLabel, nLabel, uTag, IEEE754_FloatToSmallest(fNum));
664}
665
666void QCBOREncode_AddDoubleAsSmallest_3(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, double dNum)
667{
668 QCBOREncode_AddFUnionAsSmallest_3(me, szLabel, nLabel, uTag, IEEE754_DoubleToSmallest(dNum));
669}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700670
671
672
673/*
674 Public functions to finish and get the encoded result. See header qcbor.h
675 */
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700676int QCBOREncode_Finish2(QCBOREncodeContext *me, UsefulBufC *pEncodedCBOR)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700677{
678 if(me->uError)
679 goto Done;
680
681 if (Nesting_IsInNest(&(me->nesting))) {
682 me->uError = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
683 goto Done;
684 }
685
686 if(UsefulOutBuf_GetError(&(me->OutBuf))) {
687 // Stuff didn't fit in the buffer.
688 // This check catches this condition for all the appends and inserts so checks aren't needed
689 // when the appends and inserts are performed. And of course UsefulBuf will never
690 // overrun the input buffer given to it. No complex analysis of the error handling
691 // in this file is needed to know that is true. Just read the UsefulBuf code.
692 me->uError = QCBOR_ERR_BUFFER_TOO_SMALL;
693 goto Done;
694 }
Laurence Lundblade2296db52018-09-14 18:08:39 -0700695
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700696 *pEncodedCBOR = UsefulOutBuf_OutUBuf(&(me->OutBuf));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700697
698Done:
699 return me->uError;
700}
701
702int QCBOREncode_Finish(QCBOREncodeContext *me, size_t *puEncodedLen)
703{
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700704 UsefulBufC Enc;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700705
706 int nReturn = QCBOREncode_Finish2(me, &Enc);
707
708 if(nReturn == QCBOR_SUCCESS) {
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700709 *puEncodedLen = Enc.len;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700710 }
711
712 return nReturn;
713}
714
715