blob: 7b53ac1f70cdffb280607642dc6e87433b64802f [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
30/*===================================================================================
31 FILE: qcbor_encode.c
32
33 DESCRIPTION: This file contains the implementation of QCBOR.
34
35 EDIT HISTORY FOR FILE:
36
37 This section contains comments describing changes made to the module.
38 Notice that changes are listed in reverse chronological order.
39
40 when who what, where, why
41 -------- ---- ---------------------------------------------------
42 02/05/18 llundbla Works on CPUs which require integer alignment.
43 Requires new version of UsefulBuf.
44 07/05/17 llundbla Add bstr wrapping of maps/arrays for COSE
45 03/01/17 llundbla More data types
46 11/13/16 llundbla Integrate most TZ changes back into github version.
47 09/30/16 gkanike Porting to TZ.
48 03/15/16 llundbla Initial Version.
49
50 =====================================================================================*/
51
52#include "qcbor.h"
53#include <stdint.h>
54
55#ifdef QSEE
56#include "stringl.h"
57#endif
58
59/*...... This is a ruler that is 80 characters long...........................*/
60
61
62// Used internally in the impementation here
63// Must not conflict with any of the official CBOR types
64#define CBOR_MAJOR_NONE_TYPE_RAW 9
65
66
67
68
69
70/*
71 CBOR's two nesting types, arrays and maps, are tracked here. There is a
72 limit of QCBOR_MAX_ARRAY_NESTING to the number of arrays and maps
73 that can be nested in one encoding so the encoding context stays
74 small enough to fit on the stack.
75
76 When an array / map is opened, pCurrentNesting points to the element
77 in pArrays that records the type, start position and accumluates a
78 count of the number of items added. When closed the start position is
79 used to go back and fill in the type and number of items in the array
80 / map.
81
82 Encoded output be just items like ints and strings that are
83 not part of any array / map. That is, the first thing encoded
84 does not have to be an array or a map.
85 */
86inline static void Nesting_Init(QCBORTrackNesting *pNesting)
87{
88 // assumes pNesting has been zeroed
89 pNesting->pCurrentNesting = &pNesting->pArrays[0];
90 // Implied CBOR array at the top nesting level. This is never returned,
91 // but makes the item count work correctly.
92 pNesting->pCurrentNesting->uMajorType = CBOR_MAJOR_TYPE_ARRAY;
93}
94
95inline static int Nesting_Increase(QCBORTrackNesting *pNesting, uint8_t uMajorType, uint32_t uPos, bool bBstWrap)
96{
97 int nReturn = QCBOR_SUCCESS;
98
99 if(pNesting->pCurrentNesting == &pNesting->pArrays[QCBOR_MAX_ARRAY_NESTING]) {
100 // trying to open one too many
101 nReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
102 } else {
103 pNesting->pCurrentNesting++;
104 pNesting->pCurrentNesting->uCount = 0;
105 pNesting->pCurrentNesting->uStart = uPos;
106 pNesting->pCurrentNesting->uMajorType = uMajorType;
107 pNesting->pCurrentNesting->bBstrWrap = bBstWrap;
108 }
109 return nReturn;
110}
111
112inline static void Nesting_Decrease(QCBORTrackNesting *pNesting)
113{
114 pNesting->pCurrentNesting--;
115}
116
117inline static int Nesting_Increment(QCBORTrackNesting *pNesting, uint16_t uAmount)
118{
119 if(uAmount >= QCBOR_MAX_ITEMS_IN_ARRAY - pNesting->pCurrentNesting->uCount) {
120 return QCBOR_ERR_ARRAY_TOO_LONG;
121 }
122
123 pNesting->pCurrentNesting->uCount += uAmount;
124 return QCBOR_SUCCESS;
125}
126
127inline static uint16_t Nesting_GetCount(QCBORTrackNesting *pNesting)
128{
129 // The nesting count recorded is always the actual number of individiual
130 // data items in the array or map. For arrays CBOR uses the actual item
131 // count. For maps, CBOR uses the number of pairs. This function returns
132 // the number needed for the CBOR encoding, so it divides the number of
133 // items by two for maps to get the number of pairs. This implementation
134 // takes advantage of the map major type being one larger the array major
135 // type, hence the subtraction returns either 1 or 2.
136 return pNesting->pCurrentNesting->uCount / (pNesting->pCurrentNesting->uMajorType - CBOR_MAJOR_TYPE_ARRAY+1);
137}
138
139inline static uint32_t Nesting_GetStartPos(QCBORTrackNesting *pNesting)
140{
141 return pNesting->pCurrentNesting->uStart;
142}
143
144inline static uint8_t Nesting_GetMajorType(QCBORTrackNesting *pNesting)
145{
146 return pNesting->pCurrentNesting->uMajorType;
147}
148
149inline static int Nesting_IsInNest(QCBORTrackNesting *pNesting)
150{
151 return pNesting->pCurrentNesting == &pNesting->pArrays[0] ? 0 : 1;
152}
153
154inline static bool Nesting_IsBstrWrapped(QCBORTrackNesting *pNesting)
155{
156 return pNesting->pCurrentNesting->bBstrWrap;
157}
158
159
160
161/*
162 Error tracking plan -- Errors are tracked internally and not returned
163 until Finish is called. The CBOR errors are in me->uError.
164 UsefulOutBuf also tracks whether the the buffer is full or not in its
165 context. Once either of these errors is set they are never
166 cleared. Only Init() resets them. Or said another way, they must
167 never be cleared or we'll tell the caller all is good when it is not.
168
169 Only one error code is reported by Finish() even if there are
170 multiple errors. The last one set wins. The caller might have to fix
171 one error to reveal the next one they have to fix. This is OK.
172
173 The buffer full error tracked by UsefulBuf is only pulled out of
174 UsefulBuf in Finish() so it is the one that usually wins. UsefulBuf
175 will never go off the end of the buffer even if it is called again
176 and again when full.
177
178 It is really tempting to not check for overflow on the count in the
179 number of items in an array. It would save a lot of code, it is
180 extremely unlikely that any one will every put 65,000 items in an
181 array, and the only bad thing that would happen is the CBOR would be
182 bogus. Once we prove that is the only consequence, then we can make
183 the change.
184
185 Since this does not parse any input, you could in theory remove all
186 error checks in this code if you knew the caller called it
187 correctly. Maybe someday CDDL or some such language will be able to
188 generate the code to call this and the calling code would always be
189 correct. This could also make automatically size some of the data
190 structures like array/map nesting resulting in some good memory
191 savings.
192 */
193
194
195
196
197/*
198 Public function for initialization. See header qcbor.h
199 */
200void QCBOREncode_Init(QCBOREncodeContext *me, void *pBuf, size_t uBufLen)
201{
202 memset(me, 0, sizeof(QCBOREncodeContext));
203 if(uBufLen > UINT32_MAX) {
204 me->uError = QCBOR_ERR_BUFFER_TOO_LARGE;
205 } else {
206 UsefulOutBuf_Init(&(me->OutBuf), pBuf, uBufLen);
207 Nesting_Init(&(me->nesting));
208 }
209}
210
211
212
213
214/*
215 All CBOR data items have a type and a number. The number is either
216 the value of the item for integer types, the length of the content
217 for string, byte, array and map types, a tag for major type 6, and
218 has serveral uses for major type 7.
219
220 This function encodes the type and the number. There are several
221 encodings for the number depending on how large it is and how it is
222 used.
223
224 Every encoding of the type and number has at least one byte, the
225 "initial byte".
226
227 The top three bits of the initial byte are the major type for the
228 CBOR data item. The eight major types defined by the standard are
229 defined as CBOR_MAJOR_TYPE_xxxx in qcbor.h.
230
231 The remaining five bits, known as "additional information", and
232 possibly more bytes encode the number. If the number is less than 24,
233 then it is encoded entirely in the five bits. This is neat because it
234 allows you to encode an entire CBOR data item in 1 byte for many
235 values and types (integers 0-23, true, false, and tags).
236
237 If the number is larger than 24, then it is encoded in 1,2,4 or 8
238 additional bytes, with the number of these bytes indicated by the
239 values of the 5 bits 24, 25, 25 and 27.
240
241 It is possible to encode a particular number in many ways with this
242 representation. This implementation always uses the smallest
243 possible representation. This is also the suggestion made in the RFC
244 for cannonical CBOR.
245
246 This function inserts them into the output buffer at the specified
247 position. AppendEncodedTypeAndNumber() appends to the end.
248
249 This function takes care of converting to network byte order.
250
251 This function is also used to insert floats and doubles. Before this
252 function is called the float or double must be copied into a
253 uint64_t. That is how they are passed in. They are then converted to
254 network byte order correctly. The uMinLen param makes sure that even
255 if all the digits of a float or double are 0 it is still correctly
256 encoded in 4 or 8 bytes.
257
258 */
259static void InsertEncodedTypeAndNumber(QCBOREncodeContext *me, uint8_t uMajorType, size_t uMinLen, uint64_t uNumber, size_t uPos)
260{
261 // No need to worry about integer overflow here because a) uMajorType is
262 // always generated internally, not by the caller, b) this is for CBOR
263 // _generation_, not parsing c) a mistake will result in bad CBOR generation,
264 // not a security vulnerability.
265 uMajorType <<= 5;
266
267 if(uNumber > 0xffffffff || uMinLen >= 8) {
268 UsefulOutBuf_InsertByte(&(me->OutBuf), uMajorType + LEN_IS_EIGHT_BYTES, uPos);
269 UsefulOutBuf_InsertUint64(&(me->OutBuf), (uint64_t)uNumber, uPos+1);
270
271 } else if(uNumber > 0xffff || uMinLen >= 4) {
272 UsefulOutBuf_InsertByte(&(me->OutBuf), uMajorType + LEN_IS_FOUR_BYTES, uPos);
273 UsefulOutBuf_InsertUint32(&(me->OutBuf), (uint32_t)uNumber, uPos+1);
274
275 } else if (uNumber > 0xff) {
276 // Between 0 and 65535
277 UsefulOutBuf_InsertByte(&(me->OutBuf), uMajorType + LEN_IS_TWO_BYTES, uPos);
278 UsefulOutBuf_InsertUint16(&(me->OutBuf), (uint16_t)uNumber, uPos+1);
279
280 } else if(uNumber >= 24) {
281 // Between 0 and 255, but only between 24 and 255 is ever encoded here
282 UsefulOutBuf_InsertByte(&(me->OutBuf), uMajorType + LEN_IS_ONE_BYTE, uPos);
283 UsefulOutBuf_InsertByte(&(me->OutBuf), (uint8_t)uNumber, uPos+1);
284
285 } else {
286 // Between 0 and 23
287 UsefulOutBuf_InsertByte(&(me->OutBuf), uMajorType + (uint8_t)uNumber, uPos);
288 }
289}
290
291
292/*
293 Append the type and number info to the end of the buffer.
294
295 See InsertEncodedTypeAndNumber() function above for details
296*/
297inline static void AppendEncodedTypeAndNumber(QCBOREncodeContext *me, uint8_t uMajorType, uint64_t uNumber)
298{
299 // An append is an insert at the end.
300 InsertEncodedTypeAndNumber(me, uMajorType, 0, uNumber, UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
301}
302
303
304static void AddBytesInternal(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, UsefulBufC Bytes, uint8_t uMajorType, uint16_t uItems);
305
306
307/*
308 Add an optional label and optional tag. It will go in front of a real data item.
309 */
310static void AddLabelAndOptionalTag(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag)
311{
312 if(szLabel) {
313 UsefulBufC SZText = {szLabel, strlen(szLabel)};
314 AddBytesInternal(me, NULL, nLabel, CBOR_TAG_NONE, SZText, CBOR_MAJOR_TYPE_TEXT_STRING, 0);
315 } else if (QCBOR_NO_INT_LABEL != nLabel) {
316 // Add an integer label. This is just adding an integer at this point
317 // This will result in a call right back to here, but the call won't do anything
318 // because of the params NULL, QCBOR_NO_INT_LABEL and CBOR_TAG_NONE
319 QCBOREncode_AddInt64_3(me, NULL, QCBOR_NO_INT_LABEL, CBOR_TAG_NONE, nLabel);
320 }
321 if(uTag != CBOR_TAG_NONE) {
322 AppendEncodedTypeAndNumber(me, CBOR_MAJOR_TYPE_OPTIONAL, uTag);
323 }
324}
325
326
327/*
328 Does the work of adding some bytes to the CBOR output. Works for a
329 byte and text strings, which are the same in in CBOR though they have
330 different major types. This is also used to insert raw or
331 pre-formatted CBOR.
332 */
333static void AddBytesInternal(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, UsefulBufC Bytes, uint8_t uMajorType, uint16_t uItems)
334{
335 if(Bytes.len >= UINT32_MAX) {
336 // This implementation doesn't allow buffers larger than UINT32_MAX. This is
337 // primarily because QCBORTrackNesting.pArrays[].uStart is an uint32 rather
338 // than size_t to keep the stack usage down. Also it is entirely impractical
339 // to create tokens bigger than 4GB in contiguous RAM
340 me->uError = QCBOR_ERR_BUFFER_TOO_LARGE;
341
342 } else {
343
344 AddLabelAndOptionalTag(me, szLabel, nLabel, uTag);
345
346 if(!me->uError) {
347
348 // If it is not Raw CBOR, add the type and the length
349 if(uMajorType != CBOR_MAJOR_NONE_TYPE_RAW) {
350 AppendEncodedTypeAndNumber(me, uMajorType, Bytes.len);
351 }
352
353 // Actually add the bytes
354 UsefulOutBuf_AppendUsefulBuf(&(me->OutBuf), Bytes);
355
356 // Update the array counting if there is any nesting at all
357 me->uError = Nesting_Increment(&(me->nesting), uMajorType == CBOR_MAJOR_NONE_TYPE_RAW ? uItems : 1);
358 }
359 }
360}
361
362
363
364
365/*
366 Public functions for adding strings and raw encoded CBOR. See header qcbor.h
367 */
368void QCBOREncode_AddBytes_3(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, UsefulBufC Bytes)
369{
370 AddBytesInternal(me, szLabel, nLabel, uTag, Bytes, CBOR_MAJOR_TYPE_BYTE_STRING, 0);
371}
372
373void QCBOREncode_AddText_3(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, UsefulBufC Bytes)
374{
375 AddBytesInternal(me, szLabel, nLabel, uTag, Bytes, CBOR_MAJOR_TYPE_TEXT_STRING, 0);
376}
377
378void QCBOREncode_AddRaw(QCBOREncodeContext *me, EncodedCBORC Raw)
379{
380 AddBytesInternal(me, NULL, QCBOR_NO_INT_LABEL, CBOR_TAG_NONE, Raw.Bytes, CBOR_MAJOR_NONE_TYPE_RAW, Raw.uItems);
381}
382
383
384
385
386/*
387 Internal function common to opening an array or a map
388
389 QCBOR_MAX_ARRAY_NESTING is the number of times Open can be called
390 successfully. Call it one more time gives an error.
391
392 */
393static void OpenMapOrArrayInternal(QCBOREncodeContext *me, uint8_t uMajorType, const char *szLabel, uint64_t nLabel, uint64_t uTag, bool bBstrWrap)
394{
395 AddLabelAndOptionalTag(me, szLabel, nLabel, uTag);
396
397 if(!me->uError) {
398 // Add one item to the nesting level we are in for the new map or array
399 me->uError = Nesting_Increment(&(me->nesting), 1);
400 if(!me->uError) {
401 // Increase nesting level because this is a map or array
402 // Cast from size_t to uin32_t is safe because the UsefulOutBuf
403 // size is limited to UINT32_MAX in QCBOR_Init().
404 me->uError = Nesting_Increase(&(me->nesting),
405 uMajorType, (uint32_t)UsefulOutBuf_GetEndPosition(&(me->OutBuf)),
406 bBstrWrap);
407 }
408 }
409}
410
411
412/*
413 Public functions for opening / closing arrays and maps. See header qcbor.h
414 */
415void QCBOREncode_OpenArray_3(QCBOREncodeContext *me, const char *szLabel, uint64_t nLabel, uint64_t uTag, bool bBstrWrap)
416{
417 OpenMapOrArrayInternal(me, CBOR_MAJOR_TYPE_ARRAY, szLabel, nLabel, uTag, bBstrWrap);
418}
419
420void QCBOREncode_OpenMap_3(QCBOREncodeContext *me, const char *szLabel, uint64_t nLabel, uint64_t uTag, uint8_t bBstrWrap)
421{
422 OpenMapOrArrayInternal(me, CBOR_MAJOR_TYPE_MAP, szLabel, nLabel, uTag, bBstrWrap);
423}
424
425void QCBOREncode_CloseArray(QCBOREncodeContext *me)
426{
427 if(!Nesting_IsInNest(&(me->nesting))) {
428 me->uError = QCBOR_ERR_TOO_MANY_CLOSES;
429
430 } else {
431 // When the array was opened, nothing was done except note the position
432 // of the start of the array. This code goes back and inserts the type
433 // (array or map) and length. That means all the data in the array or map
434 // and any nested arrays or maps have to be slid right. This is done
435 // by UsefulOutBuf's insert function that is called from inside
436 // InsertEncodedTypeAndNumber()
437
438 const uint32_t uInsertPosition = Nesting_GetStartPos(&(me->nesting));
439
440 InsertEncodedTypeAndNumber(me,
441 Nesting_GetMajorType(&(me->nesting)), // the major type (array or map)
442 0, // no minimum length for encoding
443 Nesting_GetCount(&(me->nesting)), // number of items in array or map
444 uInsertPosition); // position in output buffer
445
446 if(Nesting_IsBstrWrapped(&(me->nesting))) {
447 // This map or array is to be wrapped in a byte string. This is typically because
448 // the data is to be hashed or cryprographically signed. This is what COSE
449 // signing does.
450
451 // Cast from size_t to uin32_t is safe because the UsefulOutBuf
452 // size is limited to UINT32_MAX in QCBOR_Init().
453 uint32_t uLenOfEncodedMapOrArray = (uint32_t)UsefulOutBuf_GetEndPosition(&(me->OutBuf)) - uInsertPosition;
454
455 // Insert the bstring wrapping
456 InsertEncodedTypeAndNumber(me,
457 CBOR_MAJOR_TYPE_BYTE_STRING, // major type bstring
458 0, // no minimum length for encoding
459 uLenOfEncodedMapOrArray, // length of the map
460 uInsertPosition); // position in out buffer
461 }
462
463 Nesting_Decrease(&(me->nesting));
464 }
465}
466
467
468
469
470/*
471 Internal function for adding positive and negative integers of all different sizes
472 */
473static void AddUInt64Internal(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, uint8_t uMajorType, uint64_t n)
474{
475 AddLabelAndOptionalTag(me, szLabel, nLabel, uTag);
476 if(!me->uError) {
477 AppendEncodedTypeAndNumber(me, uMajorType, n);
478 me->uError = Nesting_Increment(&(me->nesting), 1);
479 }
480}
481
482
483/*
484 Public functions for adding integers. See header qcbor.h
485 */
486void QCBOREncode_AddUInt64_3(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, uint64_t uNum)
487{
488 AddUInt64Internal(me, szLabel, nLabel, uTag, CBOR_MAJOR_TYPE_POSITIVE_INT, uNum);
489}
490
491void QCBOREncode_AddInt64_3(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, int64_t nNum)
492{
493 uint8_t uMajorType;
494 uint64_t uValue;
495
496 // Handle CBOR's particular format for positive and negative integers
497 if(nNum < 0) {
498 uValue = (uint64_t)(-nNum - 1); // This is the way negative ints work in CBOR. -1 encodes as 0x00 with major type negative int.
499 uMajorType = CBOR_MAJOR_TYPE_NEGATIVE_INT;
500 } else {
501 uValue = (uint64_t)nNum;
502 uMajorType = CBOR_MAJOR_TYPE_POSITIVE_INT;
503 }
504 AddUInt64Internal(me, szLabel, nLabel, uTag, uMajorType, uValue);
505}
506
507
508
509
510/*
511 Common code for adding floats and doubles and simple types like true and false
512
513 One way to look at simple values is that they are:
514 - type 7
515 - an additional integer from 0 to 255
516 - additional integer 0-19 are unassigned and could be used in an update to CBOR
517 - additional integers 20, 21, 22 and 23 are false, true, null and undef
518 - additional integer 24 is not available
519 - when the additional value is 25, 26, or 27 there is additionally a half, float or double in following bytes
520 - additional integers 28, 29 and 30 are unassigned / reserved
521 - additional integer 31 is a "break"
522 - additional integers 32-255 are unassigned and could be used in an update to CBOR
523 */
524static void AddSimpleInternal(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, size_t uSize, uint64_t uNum)
525{
526 AddLabelAndOptionalTag(me, szLabel, nLabel, uTag);
527 if(!me->uError) {
528 // This function call takes care of endian swapping for the float / double
529 InsertEncodedTypeAndNumber(me,
530 CBOR_MAJOR_TYPE_SIMPLE, // The major type for floats and doubles
531 uSize, // min size / tells encoder to do it right
532 uNum, // Bytes of the floating point number as a uint
533 UsefulOutBuf_GetEndPosition(&(me->OutBuf))); // end position for append
534
535 me->uError = Nesting_Increment(&(me->nesting), 1);
536 }
537}
538
539
540/*
541 Public function for adding simple values. See header qcbor.h
542 */
543void QCBOREncode_AddRawSimple_3(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, uint8_t uSimple)
544{
545 AddSimpleInternal(me, szLabel, nLabel, uTag, 0, uSimple);
546}
547
548
549/*
550 Public function for adding simple values. See header qcbor.h
551 */
552void QCBOREncode_AddSimple_3(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, uint8_t uSimple)
553{
554 if(uSimple < CBOR_SIMPLEV_FALSE || uSimple > CBOR_SIMPLEV_UNDEF) {
555 me->uError = QCBOR_ERR_BAD_SIMPLE;
556 } else {
557 QCBOREncode_AddRawSimple_3(me, szLabel, nLabel, uTag, uSimple);
558 }
559}
560
561
562/*
563 Public functions for floating point numbers. See header qcbor.h
564 */
565void QCBOREncode_AddFloat_3(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, float fNum)
566{
567 // Convert the *type* of the data from a float to a uint so the
568 // standard integer encoding can work. This takes advantage
569 // of CBOR's indicator for a float being the same as for a 4
570 // byte integer too.
571 const float *pfNum = &fNum;
572 const uint32_t uNum = *(uint32_t *)pfNum;
573
574 AddSimpleInternal(me, szLabel, nLabel, uTag, sizeof(float), uNum);
575}
576
577void QCBOREncode_AddDouble_3(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, double dNum)
578{
579 // see how it is done for floats above
580 const double *pdNum = &dNum;
581 const uint64_t uNum = *(uint64_t *)pdNum;
582
583 AddSimpleInternal(me, szLabel, nLabel, uTag, sizeof(double), uNum);
584}
585
586
587
588
589/*
590 Public functions to finish and get the encoded result. See header qcbor.h
591 */
592int QCBOREncode_Finish2(QCBOREncodeContext *me, EncodedCBOR *pEncodedCBOR)
593{
594 if(me->uError)
595 goto Done;
596
597 if (Nesting_IsInNest(&(me->nesting))) {
598 me->uError = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
599 goto Done;
600 }
601
602 if(UsefulOutBuf_GetError(&(me->OutBuf))) {
603 // Stuff didn't fit in the buffer.
604 // This check catches this condition for all the appends and inserts so checks aren't needed
605 // when the appends and inserts are performed. And of course UsefulBuf will never
606 // overrun the input buffer given to it. No complex analysis of the error handling
607 // in this file is needed to know that is true. Just read the UsefulBuf code.
608 me->uError = QCBOR_ERR_BUFFER_TOO_SMALL;
609 goto Done;
610 }
611
612 UsefulOutBuf_OutUBuf(&(me->OutBuf), &(pEncodedCBOR->Bytes));
613 pEncodedCBOR->uItems = Nesting_GetCount(&(me->nesting));
614
615Done:
616 return me->uError;
617}
618
619int QCBOREncode_Finish(QCBOREncodeContext *me, size_t *puEncodedLen)
620{
621 EncodedCBOR Enc;
622
623 int nReturn = QCBOREncode_Finish2(me, &Enc);
624
625 if(nReturn == QCBOR_SUCCESS) {
626 *puEncodedLen = Enc.Bytes.len;
627 }
628
629 return nReturn;
630}
631
632