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