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