blob: 3ad809ef522416ee66a513af0a9b766c3721cbf9 [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 Lundbladeb69cad72018-09-13 11:09:01 -070079
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070080
81/*...... This is a ruler that is 80 characters long...........................*/
82
83
84// Used internally in the impementation here
85// Must not conflict with any of the official CBOR types
86#define CBOR_MAJOR_NONE_TYPE_RAW 9
87
88
89
90
91
92/*
93 CBOR's two nesting types, arrays and maps, are tracked here. There is a
94 limit of QCBOR_MAX_ARRAY_NESTING to the number of arrays and maps
95 that can be nested in one encoding so the encoding context stays
96 small enough to fit on the stack.
97
98 When an array / map is opened, pCurrentNesting points to the element
99 in pArrays that records the type, start position and accumluates a
100 count of the number of items added. When closed the start position is
101 used to go back and fill in the type and number of items in the array
102 / map.
103
104 Encoded output be just items like ints and strings that are
105 not part of any array / map. That is, the first thing encoded
106 does not have to be an array or a map.
107 */
108inline static void Nesting_Init(QCBORTrackNesting *pNesting)
109{
110 // assumes pNesting has been zeroed
111 pNesting->pCurrentNesting = &pNesting->pArrays[0];
112 // Implied CBOR array at the top nesting level. This is never returned,
113 // but makes the item count work correctly.
114 pNesting->pCurrentNesting->uMajorType = CBOR_MAJOR_TYPE_ARRAY;
115}
116
Laurence Lundbladea954db92018-09-28 19:27:31 -0700117inline static int Nesting_Increase(QCBORTrackNesting *pNesting, uint8_t uMajorType, uint32_t uPos)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700118{
119 int nReturn = QCBOR_SUCCESS;
120
121 if(pNesting->pCurrentNesting == &pNesting->pArrays[QCBOR_MAX_ARRAY_NESTING]) {
122 // trying to open one too many
123 nReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
124 } else {
125 pNesting->pCurrentNesting++;
126 pNesting->pCurrentNesting->uCount = 0;
127 pNesting->pCurrentNesting->uStart = uPos;
128 pNesting->pCurrentNesting->uMajorType = uMajorType;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700129 }
130 return nReturn;
131}
132
133inline static void Nesting_Decrease(QCBORTrackNesting *pNesting)
134{
135 pNesting->pCurrentNesting--;
136}
137
138inline static int Nesting_Increment(QCBORTrackNesting *pNesting, uint16_t uAmount)
139{
140 if(uAmount >= QCBOR_MAX_ITEMS_IN_ARRAY - pNesting->pCurrentNesting->uCount) {
141 return QCBOR_ERR_ARRAY_TOO_LONG;
142 }
143
144 pNesting->pCurrentNesting->uCount += uAmount;
145 return QCBOR_SUCCESS;
146}
147
148inline static uint16_t Nesting_GetCount(QCBORTrackNesting *pNesting)
149{
150 // The nesting count recorded is always the actual number of individiual
151 // data items in the array or map. For arrays CBOR uses the actual item
152 // count. For maps, CBOR uses the number of pairs. This function returns
153 // the number needed for the CBOR encoding, so it divides the number of
154 // items by two for maps to get the number of pairs. This implementation
155 // takes advantage of the map major type being one larger the array major
156 // type, hence the subtraction returns either 1 or 2.
157 return pNesting->pCurrentNesting->uCount / (pNesting->pCurrentNesting->uMajorType - CBOR_MAJOR_TYPE_ARRAY+1);
158}
159
160inline static uint32_t Nesting_GetStartPos(QCBORTrackNesting *pNesting)
161{
162 return pNesting->pCurrentNesting->uStart;
163}
164
165inline static uint8_t Nesting_GetMajorType(QCBORTrackNesting *pNesting)
166{
167 return pNesting->pCurrentNesting->uMajorType;
168}
169
170inline static int Nesting_IsInNest(QCBORTrackNesting *pNesting)
171{
172 return pNesting->pCurrentNesting == &pNesting->pArrays[0] ? 0 : 1;
173}
174
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700175
176
177
178/*
179 Error tracking plan -- Errors are tracked internally and not returned
180 until Finish is called. The CBOR errors are in me->uError.
181 UsefulOutBuf also tracks whether the the buffer is full or not in its
182 context. Once either of these errors is set they are never
183 cleared. Only Init() resets them. Or said another way, they must
184 never be cleared or we'll tell the caller all is good when it is not.
185
186 Only one error code is reported by Finish() even if there are
187 multiple errors. The last one set wins. The caller might have to fix
188 one error to reveal the next one they have to fix. This is OK.
189
190 The buffer full error tracked by UsefulBuf is only pulled out of
191 UsefulBuf in Finish() so it is the one that usually wins. UsefulBuf
192 will never go off the end of the buffer even if it is called again
193 and again when full.
194
195 It is really tempting to not check for overflow on the count in the
196 number of items in an array. It would save a lot of code, it is
197 extremely unlikely that any one will every put 65,000 items in an
198 array, and the only bad thing that would happen is the CBOR would be
199 bogus. Once we prove that is the only consequence, then we can make
200 the change.
201
202 Since this does not parse any input, you could in theory remove all
203 error checks in this code if you knew the caller called it
204 correctly. Maybe someday CDDL or some such language will be able to
205 generate the code to call this and the calling code would always be
206 correct. This could also make automatically size some of the data
207 structures like array/map nesting resulting in some good memory
208 savings.
209 */
210
211
212
213
214/*
215 Public function for initialization. See header qcbor.h
216 */
Laurence Lundblade2296db52018-09-14 18:08:39 -0700217void QCBOREncode_Init(QCBOREncodeContext *me, UsefulBuf Storage)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700218{
219 memset(me, 0, sizeof(QCBOREncodeContext));
Laurence Lundblade2296db52018-09-14 18:08:39 -0700220 if(Storage.len > UINT32_MAX) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700221 me->uError = QCBOR_ERR_BUFFER_TOO_LARGE;
222 } else {
Laurence Lundblade2296db52018-09-14 18:08:39 -0700223 UsefulOutBuf_Init(&(me->OutBuf), Storage);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700224 Nesting_Init(&(me->nesting));
225 }
226}
227
228
229
230
231/*
232 All CBOR data items have a type and a number. The number is either
233 the value of the item for integer types, the length of the content
234 for string, byte, array and map types, a tag for major type 6, and
235 has serveral uses for major type 7.
236
237 This function encodes the type and the number. There are several
238 encodings for the number depending on how large it is and how it is
239 used.
240
241 Every encoding of the type and number has at least one byte, the
242 "initial byte".
243
244 The top three bits of the initial byte are the major type for the
245 CBOR data item. The eight major types defined by the standard are
246 defined as CBOR_MAJOR_TYPE_xxxx in qcbor.h.
247
248 The remaining five bits, known as "additional information", and
249 possibly more bytes encode the number. If the number is less than 24,
250 then it is encoded entirely in the five bits. This is neat because it
251 allows you to encode an entire CBOR data item in 1 byte for many
252 values and types (integers 0-23, true, false, and tags).
253
254 If the number is larger than 24, then it is encoded in 1,2,4 or 8
255 additional bytes, with the number of these bytes indicated by the
256 values of the 5 bits 24, 25, 25 and 27.
257
258 It is possible to encode a particular number in many ways with this
259 representation. This implementation always uses the smallest
260 possible representation. This is also the suggestion made in the RFC
261 for cannonical CBOR.
262
263 This function inserts them into the output buffer at the specified
264 position. AppendEncodedTypeAndNumber() appends to the end.
265
266 This function takes care of converting to network byte order.
267
268 This function is also used to insert floats and doubles. Before this
269 function is called the float or double must be copied into a
270 uint64_t. That is how they are passed in. They are then converted to
271 network byte order correctly. The uMinLen param makes sure that even
272 if all the digits of a float or double are 0 it is still correctly
273 encoded in 4 or 8 bytes.
274
275 */
276static void InsertEncodedTypeAndNumber(QCBOREncodeContext *me, uint8_t uMajorType, size_t uMinLen, uint64_t uNumber, size_t uPos)
277{
278 // No need to worry about integer overflow here because a) uMajorType is
279 // always generated internally, not by the caller, b) this is for CBOR
280 // _generation_, not parsing c) a mistake will result in bad CBOR generation,
281 // not a security vulnerability.
282 uMajorType <<= 5;
283
284 if(uNumber > 0xffffffff || uMinLen >= 8) {
285 UsefulOutBuf_InsertByte(&(me->OutBuf), uMajorType + LEN_IS_EIGHT_BYTES, uPos);
286 UsefulOutBuf_InsertUint64(&(me->OutBuf), (uint64_t)uNumber, uPos+1);
287
288 } else if(uNumber > 0xffff || uMinLen >= 4) {
289 UsefulOutBuf_InsertByte(&(me->OutBuf), uMajorType + LEN_IS_FOUR_BYTES, uPos);
290 UsefulOutBuf_InsertUint32(&(me->OutBuf), (uint32_t)uNumber, uPos+1);
291
292 } else if (uNumber > 0xff) {
293 // Between 0 and 65535
294 UsefulOutBuf_InsertByte(&(me->OutBuf), uMajorType + LEN_IS_TWO_BYTES, uPos);
295 UsefulOutBuf_InsertUint16(&(me->OutBuf), (uint16_t)uNumber, uPos+1);
296
297 } else if(uNumber >= 24) {
298 // Between 0 and 255, but only between 24 and 255 is ever encoded here
299 UsefulOutBuf_InsertByte(&(me->OutBuf), uMajorType + LEN_IS_ONE_BYTE, uPos);
300 UsefulOutBuf_InsertByte(&(me->OutBuf), (uint8_t)uNumber, uPos+1);
301
302 } else {
303 // Between 0 and 23
304 UsefulOutBuf_InsertByte(&(me->OutBuf), uMajorType + (uint8_t)uNumber, uPos);
305 }
306}
307
308
309/*
310 Append the type and number info to the end of the buffer.
311
312 See InsertEncodedTypeAndNumber() function above for details
313*/
314inline static void AppendEncodedTypeAndNumber(QCBOREncodeContext *me, uint8_t uMajorType, uint64_t uNumber)
315{
316 // An append is an insert at the end.
317 InsertEncodedTypeAndNumber(me, uMajorType, 0, uNumber, UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
318}
319
320
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700321static 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 -0700322
323
324/*
325 Add an optional label and optional tag. It will go in front of a real data item.
326 */
327static void AddLabelAndOptionalTag(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag)
328{
329 if(szLabel) {
330 UsefulBufC SZText = {szLabel, strlen(szLabel)};
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700331 AddBytesInternal(me, NULL, nLabel, CBOR_TAG_NONE, SZText, CBOR_MAJOR_TYPE_TEXT_STRING);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700332 } else if (QCBOR_NO_INT_LABEL != nLabel) {
333 // Add an integer label. This is just adding an integer at this point
334 // This will result in a call right back to here, but the call won't do anything
335 // because of the params NULL, QCBOR_NO_INT_LABEL and CBOR_TAG_NONE
336 QCBOREncode_AddInt64_3(me, NULL, QCBOR_NO_INT_LABEL, CBOR_TAG_NONE, nLabel);
337 }
338 if(uTag != CBOR_TAG_NONE) {
339 AppendEncodedTypeAndNumber(me, CBOR_MAJOR_TYPE_OPTIONAL, uTag);
340 }
341}
342
343
344/*
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 Lundbladeda3f0822018-09-18 19:49:02 -0700350static 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 -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
361 AddLabelAndOptionalTag(me, szLabel, nLabel, uTag);
362
363 if(!me->uError) {
364
365 // If it is not Raw CBOR, add the type and the length
366 if(uMajorType != CBOR_MAJOR_NONE_TYPE_RAW) {
367 AppendEncodedTypeAndNumber(me, uMajorType, Bytes.len);
368 }
369
370 // Actually add the bytes
371 UsefulOutBuf_AppendUsefulBuf(&(me->OutBuf), Bytes);
372
373 // Update the array counting if there is any nesting at all
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700374 me->uError = Nesting_Increment(&(me->nesting), 1);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700375 }
376 }
377}
378
379
380
381
382/*
383 Public functions for adding strings and raw encoded CBOR. See header qcbor.h
384 */
385void QCBOREncode_AddBytes_3(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, UsefulBufC Bytes)
386{
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700387 AddBytesInternal(me, szLabel, nLabel, uTag, Bytes, CBOR_MAJOR_TYPE_BYTE_STRING);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700388}
389
390void QCBOREncode_AddText_3(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, UsefulBufC Bytes)
391{
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700392 AddBytesInternal(me, szLabel, nLabel, uTag, Bytes, CBOR_MAJOR_TYPE_TEXT_STRING);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700393}
394
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700395void QCBOREncode_AddEncodedToMap_3(QCBOREncodeContext *me, const char *szLabel, uint64_t nLabel, uint64_t uTag, UsefulBufC Encoded)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700396{
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700397 AddBytesInternal(me, szLabel, nLabel, uTag, Encoded, CBOR_MAJOR_NONE_TYPE_RAW);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700398}
399
400
401
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700402/*
403 Internal function common to opening an array or a map
404
405 QCBOR_MAX_ARRAY_NESTING is the number of times Open can be called
406 successfully. Call it one more time gives an error.
407
408 */
Laurence Lundbladea954db92018-09-28 19:27:31 -0700409static void OpenMapOrArrayInternal(QCBOREncodeContext *me, uint8_t uMajorType, const char *szLabel, uint64_t nLabel, uint64_t uTag)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700410{
411 AddLabelAndOptionalTag(me, szLabel, nLabel, uTag);
412
413 if(!me->uError) {
414 // Add one item to the nesting level we are in for the new map or array
415 me->uError = Nesting_Increment(&(me->nesting), 1);
416 if(!me->uError) {
417 // Increase nesting level because this is a map or array
418 // Cast from size_t to uin32_t is safe because the UsefulOutBuf
419 // size is limited to UINT32_MAX in QCBOR_Init().
Laurence Lundbladea954db92018-09-28 19:27:31 -0700420 me->uError = Nesting_Increase(&(me->nesting), uMajorType, (uint32_t)UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700421 }
422 }
423}
424
425
426/*
427 Public functions for opening / closing arrays and maps. See header qcbor.h
428 */
Laurence Lundbladea954db92018-09-28 19:27:31 -0700429void QCBOREncode_OpenArray_3(QCBOREncodeContext *me, const char *szLabel, uint64_t nLabel, uint64_t uTag)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700430{
Laurence Lundbladea954db92018-09-28 19:27:31 -0700431 OpenMapOrArrayInternal(me, CBOR_MAJOR_TYPE_ARRAY, szLabel, nLabel, uTag);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700432}
433
Laurence Lundbladea954db92018-09-28 19:27:31 -0700434void QCBOREncode_OpenMap_3(QCBOREncodeContext *me, const char *szLabel, uint64_t nLabel, uint64_t uTag)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700435{
Laurence Lundbladea954db92018-09-28 19:27:31 -0700436 OpenMapOrArrayInternal(me, CBOR_MAJOR_TYPE_MAP, szLabel, nLabel, uTag);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700437}
438
Laurence Lundbladea954db92018-09-28 19:27:31 -0700439void QCBOREncode_OpenBstrWrap_3(QCBOREncodeContext *me, const char *szLabel, uint64_t nLabel, uint64_t uTag)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700440{
Laurence Lundbladea954db92018-09-28 19:27:31 -0700441 OpenMapOrArrayInternal(me, CBOR_MAJOR_TYPE_BYTE_STRING, szLabel, nLabel, uTag);
442}
443
444void QCBOREncode_Close(QCBOREncodeContext *me, uint8_t uMajorType, UsefulBufC *pWrappedCBOR)
445{
446 if(!me->uError) {
447 if(!Nesting_IsInNest(&(me->nesting))) {
448 me->uError = QCBOR_ERR_TOO_MANY_CLOSES;
449 } else if( Nesting_GetMajorType(&(me->nesting)) != uMajorType) {
450 me->uError = QCBOR_ERR_CLOSE_MISMATCH;
451 } else {
452 const uint32_t uInsertPosition = Nesting_GetStartPos(&(me->nesting));
453 // When the array, map or bstr wrap was started, nothing was done except
454 // note the position of the start of it. This code goes back and inserts
455 // the actual CBOR array, map or bstr and its length. That means all the
456 // data that is in the array, map or wrapped needs to be slid to the
457 // right. This is done by UsefulOutBuf's insert function that is called
458 // from inside InsertEncodedTypeAndNumber()
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700459
460 // Cast from size_t to uin32_t is safe because the UsefulOutBuf
461 // size is limited to UINT32_MAX in QCBOR_Init().
Laurence Lundbladea954db92018-09-28 19:27:31 -0700462 const uint32_t uEndPosition = (uint32_t)UsefulOutBuf_GetEndPosition(&(me->OutBuf));
463 const uint32_t uLenOfEncodedMapOrArray = uEndPosition - uInsertPosition;
464
465 // Length is number of bytes for a bstr and number of items for map & array
466 const uint32_t uLength = uMajorType == CBOR_MAJOR_TYPE_BYTE_STRING ?
467 uLenOfEncodedMapOrArray : Nesting_GetCount(&(me->nesting));
468
469 // Actually insert
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700470 InsertEncodedTypeAndNumber(me,
Laurence Lundbladea954db92018-09-28 19:27:31 -0700471 uMajorType, // major type bstr, array or map
472 0, // no minimum length for encoding
473 uLength, // either len of bstr or num items in array or map
474 uInsertPosition); // position in out buffer
475
476 // Return pointer and length to the enclosed encoded CBOR. The intended
477 // use is for it to be hashed (e.g., SHA-256) in a COSE implementation.
478 // This must be used right away, as the pointer and length go invalid
479 // on any subsequent calls to this function because of the
480 // InsertEncodedTypeAndNumber() call that slides data to the right.
481 if(pWrappedCBOR) {
482 UsefulBufC PartialResult = UsefulOutBuf_OutUBuf(&(me->OutBuf));
483 uint32_t uBstrLen = (uint32_t)UsefulOutBuf_GetEndPosition(&(me->OutBuf)) - uEndPosition;
484 *pWrappedCBOR = UsefulBuf_Tail(PartialResult, uInsertPosition+uBstrLen);
485 }
486 Nesting_Decrease(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700487 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700488 }
489}
490
491
492
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700493/*
494 Internal function for adding positive and negative integers of all different sizes
495 */
496static void AddUInt64Internal(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, uint8_t uMajorType, uint64_t n)
497{
498 AddLabelAndOptionalTag(me, szLabel, nLabel, uTag);
499 if(!me->uError) {
500 AppendEncodedTypeAndNumber(me, uMajorType, n);
501 me->uError = Nesting_Increment(&(me->nesting), 1);
502 }
503}
504
505
506/*
507 Public functions for adding integers. See header qcbor.h
508 */
509void QCBOREncode_AddUInt64_3(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, uint64_t uNum)
510{
511 AddUInt64Internal(me, szLabel, nLabel, uTag, CBOR_MAJOR_TYPE_POSITIVE_INT, uNum);
512}
513
514void QCBOREncode_AddInt64_3(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, int64_t nNum)
515{
516 uint8_t uMajorType;
517 uint64_t uValue;
518
519 // Handle CBOR's particular format for positive and negative integers
520 if(nNum < 0) {
521 uValue = (uint64_t)(-nNum - 1); // This is the way negative ints work in CBOR. -1 encodes as 0x00 with major type negative int.
522 uMajorType = CBOR_MAJOR_TYPE_NEGATIVE_INT;
523 } else {
524 uValue = (uint64_t)nNum;
525 uMajorType = CBOR_MAJOR_TYPE_POSITIVE_INT;
526 }
527 AddUInt64Internal(me, szLabel, nLabel, uTag, uMajorType, uValue);
528}
529
530
531
532
533/*
534 Common code for adding floats and doubles and simple types like true and false
535
536 One way to look at simple values is that they are:
537 - type 7
538 - an additional integer from 0 to 255
539 - additional integer 0-19 are unassigned and could be used in an update to CBOR
540 - additional integers 20, 21, 22 and 23 are false, true, null and undef
541 - additional integer 24 is not available
542 - when the additional value is 25, 26, or 27 there is additionally a half, float or double in following bytes
543 - additional integers 28, 29 and 30 are unassigned / reserved
544 - additional integer 31 is a "break"
545 - additional integers 32-255 are unassigned and could be used in an update to CBOR
546 */
547static void AddSimpleInternal(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, size_t uSize, uint64_t uNum)
548{
549 AddLabelAndOptionalTag(me, szLabel, nLabel, uTag);
550 if(!me->uError) {
551 // This function call takes care of endian swapping for the float / double
552 InsertEncodedTypeAndNumber(me,
553 CBOR_MAJOR_TYPE_SIMPLE, // The major type for floats and doubles
554 uSize, // min size / tells encoder to do it right
555 uNum, // Bytes of the floating point number as a uint
556 UsefulOutBuf_GetEndPosition(&(me->OutBuf))); // end position for append
557
558 me->uError = Nesting_Increment(&(me->nesting), 1);
559 }
560}
561
562
563/*
564 Public function for adding simple values. See header qcbor.h
565 */
566void QCBOREncode_AddRawSimple_3(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, uint8_t uSimple)
567{
568 AddSimpleInternal(me, szLabel, nLabel, uTag, 0, uSimple);
569}
570
571
572/*
573 Public function for adding simple values. See header qcbor.h
574 */
575void QCBOREncode_AddSimple_3(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, uint8_t uSimple)
576{
577 if(uSimple < CBOR_SIMPLEV_FALSE || uSimple > CBOR_SIMPLEV_UNDEF) {
578 me->uError = QCBOR_ERR_BAD_SIMPLE;
579 } else {
580 QCBOREncode_AddRawSimple_3(me, szLabel, nLabel, uTag, uSimple);
581 }
582}
583
584
585/*
586 Public functions for floating point numbers. See header qcbor.h
587 */
588void QCBOREncode_AddFloat_3(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, float fNum)
589{
590 // Convert the *type* of the data from a float to a uint so the
591 // standard integer encoding can work. This takes advantage
592 // of CBOR's indicator for a float being the same as for a 4
593 // byte integer too.
594 const float *pfNum = &fNum;
595 const uint32_t uNum = *(uint32_t *)pfNum;
596
597 AddSimpleInternal(me, szLabel, nLabel, uTag, sizeof(float), uNum);
598}
599
600void QCBOREncode_AddDouble_3(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, double dNum)
601{
602 // see how it is done for floats above
603 const double *pdNum = &dNum;
604 const uint64_t uNum = *(uint64_t *)pdNum;
605
606 AddSimpleInternal(me, szLabel, nLabel, uTag, sizeof(double), uNum);
607}
608
609
610
611
612/*
613 Public functions to finish and get the encoded result. See header qcbor.h
614 */
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700615int QCBOREncode_Finish2(QCBOREncodeContext *me, UsefulBufC *pEncodedCBOR)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700616{
617 if(me->uError)
618 goto Done;
619
620 if (Nesting_IsInNest(&(me->nesting))) {
621 me->uError = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
622 goto Done;
623 }
624
625 if(UsefulOutBuf_GetError(&(me->OutBuf))) {
626 // Stuff didn't fit in the buffer.
627 // This check catches this condition for all the appends and inserts so checks aren't needed
628 // when the appends and inserts are performed. And of course UsefulBuf will never
629 // overrun the input buffer given to it. No complex analysis of the error handling
630 // in this file is needed to know that is true. Just read the UsefulBuf code.
631 me->uError = QCBOR_ERR_BUFFER_TOO_SMALL;
632 goto Done;
633 }
Laurence Lundblade2296db52018-09-14 18:08:39 -0700634
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700635 *pEncodedCBOR = UsefulOutBuf_OutUBuf(&(me->OutBuf));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700636
637Done:
638 return me->uError;
639}
640
641int QCBOREncode_Finish(QCBOREncodeContext *me, size_t *puEncodedLen)
642{
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700643 UsefulBufC Enc;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700644
645 int nReturn = QCBOREncode_Finish2(me, &Enc);
646
647 if(nReturn == QCBOR_SUCCESS) {
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700648 *puEncodedLen = Enc.len;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700649 }
650
651 return nReturn;
652}
653
654