blob: e1c63879da1a52a3437955ea3d32f7ea647e98c9 [file] [log] [blame]
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001/*==============================================================================
2Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
3
4Redistribution and use in source and binary forms, with or without
5modification, are permitted provided that the following conditions are
6met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above
10 copyright notice, this list of conditions and the following
11 disclaimer in the documentation and/or other materials provided
12 with the distribution.
13 * Neither the name of The Linux Foundation nor the names of its
14 contributors may be used to endorse or promote products derived
15 from this software without specific prior written permission.
16
17THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28==============================================================================*/
29
Laurence Lundblade624405d2018-09-18 20:10:47 -070030/*==============================================================================
31 Modifications beyond the version released on CAF are under the MIT license:
32
33 Copyright 2018 Laurence Lundblade
34
35 Permission is hereby granted, free of charge, to any person obtaining
36 a copy of this software and associated documentation files (the
37 "Software"), to deal in the Software without restriction, including
38 without limitation the rights to use, copy, modify, merge, publish,
39 distribute, sublicense, and/or sell copies of the Software, and to
40 permit persons to whom the Software is furnished to do so, subject to
41 the following conditions:
42
43 The above copyright notice and this permission notice shall be included
44 in all copies or substantial portions of the Software.
45
46 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
47 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
48 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
49 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
50 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
51 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
52 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
53 SOFTWARE.
54 ==============================================================================*/
55
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070056/*===================================================================================
57 FILE: qcbor_encode.c
58
59 DESCRIPTION: This file contains the implementation of QCBOR.
60
61 EDIT HISTORY FOR FILE:
62
63 This section contains comments describing changes made to the module.
64 Notice that changes are listed in reverse chronological order.
65
66 when who what, where, why
67 -------- ---- ---------------------------------------------------
68 02/05/18 llundbla Works on CPUs which require integer alignment.
69 Requires new version of UsefulBuf.
70 07/05/17 llundbla Add bstr wrapping of maps/arrays for COSE
71 03/01/17 llundbla More data types
72 11/13/16 llundbla Integrate most TZ changes back into github version.
73 09/30/16 gkanike Porting to TZ.
74 03/15/16 llundbla Initial Version.
75
76 =====================================================================================*/
77
78#include "qcbor.h"
Laurence Lundblade12d32c52018-09-19 11:25:27 -070079#include "ieee754.h"
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070080
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070081
82/*...... This is a ruler that is 80 characters long...........................*/
83
84
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070085/*
86 CBOR's two nesting types, arrays and maps, are tracked here. There is a
87 limit of QCBOR_MAX_ARRAY_NESTING to the number of arrays and maps
88 that can be nested in one encoding so the encoding context stays
89 small enough to fit on the stack.
90
91 When an array / map is opened, pCurrentNesting points to the element
92 in pArrays that records the type, start position and accumluates a
93 count of the number of items added. When closed the start position is
94 used to go back and fill in the type and number of items in the array
95 / map.
96
97 Encoded output be just items like ints and strings that are
98 not part of any array / map. That is, the first thing encoded
99 does not have to be an array or a map.
100 */
101inline static void Nesting_Init(QCBORTrackNesting *pNesting)
102{
103 // assumes pNesting has been zeroed
104 pNesting->pCurrentNesting = &pNesting->pArrays[0];
105 // Implied CBOR array at the top nesting level. This is never returned,
106 // but makes the item count work correctly.
107 pNesting->pCurrentNesting->uMajorType = CBOR_MAJOR_TYPE_ARRAY;
108}
109
Laurence Lundbladea954db92018-09-28 19:27:31 -0700110inline static int Nesting_Increase(QCBORTrackNesting *pNesting, uint8_t uMajorType, uint32_t uPos)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700111{
112 int nReturn = QCBOR_SUCCESS;
113
114 if(pNesting->pCurrentNesting == &pNesting->pArrays[QCBOR_MAX_ARRAY_NESTING]) {
115 // trying to open one too many
116 nReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
117 } else {
118 pNesting->pCurrentNesting++;
119 pNesting->pCurrentNesting->uCount = 0;
120 pNesting->pCurrentNesting->uStart = uPos;
121 pNesting->pCurrentNesting->uMajorType = uMajorType;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700122 }
123 return nReturn;
124}
125
126inline static void Nesting_Decrease(QCBORTrackNesting *pNesting)
127{
128 pNesting->pCurrentNesting--;
129}
130
131inline static int Nesting_Increment(QCBORTrackNesting *pNesting, uint16_t uAmount)
132{
133 if(uAmount >= QCBOR_MAX_ITEMS_IN_ARRAY - pNesting->pCurrentNesting->uCount) {
134 return QCBOR_ERR_ARRAY_TOO_LONG;
135 }
136
137 pNesting->pCurrentNesting->uCount += uAmount;
138 return QCBOR_SUCCESS;
139}
140
141inline static uint16_t Nesting_GetCount(QCBORTrackNesting *pNesting)
142{
143 // The nesting count recorded is always the actual number of individiual
144 // data items in the array or map. For arrays CBOR uses the actual item
145 // count. For maps, CBOR uses the number of pairs. This function returns
146 // the number needed for the CBOR encoding, so it divides the number of
147 // items by two for maps to get the number of pairs. This implementation
148 // takes advantage of the map major type being one larger the array major
149 // type, hence the subtraction returns either 1 or 2.
150 return pNesting->pCurrentNesting->uCount / (pNesting->pCurrentNesting->uMajorType - CBOR_MAJOR_TYPE_ARRAY+1);
151}
152
153inline static uint32_t Nesting_GetStartPos(QCBORTrackNesting *pNesting)
154{
155 return pNesting->pCurrentNesting->uStart;
156}
157
158inline static uint8_t Nesting_GetMajorType(QCBORTrackNesting *pNesting)
159{
160 return pNesting->pCurrentNesting->uMajorType;
161}
162
163inline static int Nesting_IsInNest(QCBORTrackNesting *pNesting)
164{
165 return pNesting->pCurrentNesting == &pNesting->pArrays[0] ? 0 : 1;
166}
167
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700168
169
170
171/*
172 Error tracking plan -- Errors are tracked internally and not returned
173 until Finish is called. The CBOR errors are in me->uError.
174 UsefulOutBuf also tracks whether the the buffer is full or not in its
175 context. Once either of these errors is set they are never
176 cleared. Only Init() resets them. Or said another way, they must
177 never be cleared or we'll tell the caller all is good when it is not.
178
179 Only one error code is reported by Finish() even if there are
180 multiple errors. The last one set wins. The caller might have to fix
181 one error to reveal the next one they have to fix. This is OK.
182
183 The buffer full error tracked by UsefulBuf is only pulled out of
184 UsefulBuf in Finish() so it is the one that usually wins. UsefulBuf
185 will never go off the end of the buffer even if it is called again
186 and again when full.
187
188 It is really tempting to not check for overflow on the count in the
189 number of items in an array. It would save a lot of code, it is
190 extremely unlikely that any one will every put 65,000 items in an
191 array, and the only bad thing that would happen is the CBOR would be
192 bogus. Once we prove that is the only consequence, then we can make
193 the change.
194
195 Since this does not parse any input, you could in theory remove all
196 error checks in this code if you knew the caller called it
197 correctly. Maybe someday CDDL or some such language will be able to
198 generate the code to call this and the calling code would always be
199 correct. This could also make automatically size some of the data
200 structures like array/map nesting resulting in some good memory
201 savings.
202 */
203
204
205
206
207/*
208 Public function for initialization. See header qcbor.h
209 */
Laurence Lundblade2296db52018-09-14 18:08:39 -0700210void QCBOREncode_Init(QCBOREncodeContext *me, UsefulBuf Storage)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700211{
212 memset(me, 0, sizeof(QCBOREncodeContext));
Laurence Lundblade2296db52018-09-14 18:08:39 -0700213 if(Storage.len > UINT32_MAX) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700214 me->uError = QCBOR_ERR_BUFFER_TOO_LARGE;
215 } else {
Laurence Lundblade2296db52018-09-14 18:08:39 -0700216 UsefulOutBuf_Init(&(me->OutBuf), Storage);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700217 Nesting_Init(&(me->nesting));
218 }
219}
220
221
222
223
224/*
225 All CBOR data items have a type and a number. The number is either
226 the value of the item for integer types, the length of the content
227 for string, byte, array and map types, a tag for major type 6, and
228 has serveral uses for major type 7.
229
230 This function encodes the type and the number. There are several
231 encodings for the number depending on how large it is and how it is
232 used.
233
234 Every encoding of the type and number has at least one byte, the
235 "initial byte".
236
237 The top three bits of the initial byte are the major type for the
238 CBOR data item. The eight major types defined by the standard are
239 defined as CBOR_MAJOR_TYPE_xxxx in qcbor.h.
240
241 The remaining five bits, known as "additional information", and
242 possibly more bytes encode the number. If the number is less than 24,
243 then it is encoded entirely in the five bits. This is neat because it
244 allows you to encode an entire CBOR data item in 1 byte for many
245 values and types (integers 0-23, true, false, and tags).
246
247 If the number is larger than 24, then it is encoded in 1,2,4 or 8
248 additional bytes, with the number of these bytes indicated by the
249 values of the 5 bits 24, 25, 25 and 27.
250
251 It is possible to encode a particular number in many ways with this
252 representation. This implementation always uses the smallest
253 possible representation. This is also the suggestion made in the RFC
254 for cannonical CBOR.
255
256 This function inserts them into the output buffer at the specified
257 position. AppendEncodedTypeAndNumber() appends to the end.
258
259 This function takes care of converting to network byte order.
260
261 This function is also used to insert floats and doubles. Before this
262 function is called the float or double must be copied into a
263 uint64_t. That is how they are passed in. They are then converted to
264 network byte order correctly. The uMinLen param makes sure that even
265 if all the digits of a float or double are 0 it is still correctly
266 encoded in 4 or 8 bytes.
267
268 */
269static void InsertEncodedTypeAndNumber(QCBOREncodeContext *me, uint8_t uMajorType, size_t uMinLen, uint64_t uNumber, size_t uPos)
270{
271 // No need to worry about integer overflow here because a) uMajorType is
272 // always generated internally, not by the caller, b) this is for CBOR
273 // _generation_, not parsing c) a mistake will result in bad CBOR generation,
274 // not a security vulnerability.
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700275 uMajorType <<= 5; // TODO: make this a constant
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700276
277 if(uNumber > 0xffffffff || uMinLen >= 8) {
278 UsefulOutBuf_InsertByte(&(me->OutBuf), uMajorType + LEN_IS_EIGHT_BYTES, uPos);
279 UsefulOutBuf_InsertUint64(&(me->OutBuf), (uint64_t)uNumber, uPos+1);
280
281 } else if(uNumber > 0xffff || uMinLen >= 4) {
282 UsefulOutBuf_InsertByte(&(me->OutBuf), uMajorType + LEN_IS_FOUR_BYTES, uPos);
283 UsefulOutBuf_InsertUint32(&(me->OutBuf), (uint32_t)uNumber, uPos+1);
284
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700285 } else if (uNumber > 0xff || uMinLen>= 2) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700286 // Between 0 and 65535
287 UsefulOutBuf_InsertByte(&(me->OutBuf), uMajorType + LEN_IS_TWO_BYTES, uPos);
288 UsefulOutBuf_InsertUint16(&(me->OutBuf), (uint16_t)uNumber, uPos+1);
289
290 } else if(uNumber >= 24) {
291 // Between 0 and 255, but only between 24 and 255 is ever encoded here
292 UsefulOutBuf_InsertByte(&(me->OutBuf), uMajorType + LEN_IS_ONE_BYTE, uPos);
293 UsefulOutBuf_InsertByte(&(me->OutBuf), (uint8_t)uNumber, uPos+1);
294
295 } else {
296 // Between 0 and 23
297 UsefulOutBuf_InsertByte(&(me->OutBuf), uMajorType + (uint8_t)uNumber, uPos);
298 }
299}
300
301
302/*
303 Append the type and number info to the end of the buffer.
304
305 See InsertEncodedTypeAndNumber() function above for details
306*/
307inline static void AppendEncodedTypeAndNumber(QCBOREncodeContext *me, uint8_t uMajorType, uint64_t uNumber)
308{
309 // An append is an insert at the end.
310 InsertEncodedTypeAndNumber(me, uMajorType, 0, uNumber, UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
311}
312
313
Laurence Lundblade55a24832018-10-30 04:35:08 +0700314
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700315
316
317/*
Laurence Lundblade55a24832018-10-30 04:35:08 +0700318 Internal function for adding positive and negative integers of all different sizes
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700319 */
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700320void InsertInt64(QCBOREncodeContext *me, int64_t nNum, size_t uPos)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700321{
Laurence Lundblade55a24832018-10-30 04:35:08 +0700322 uint8_t uMajorType;
323 uint64_t uValue;
324
325 if(nNum < 0) {
326 uValue = (uint64_t)(-nNum - 1); // This is the way negative ints work in CBOR. -1 encodes as 0x00 with major type negative int.
327 uMajorType = CBOR_MAJOR_TYPE_NEGATIVE_INT;
328 } else {
329 uValue = (uint64_t)nNum;
330 uMajorType = CBOR_MAJOR_TYPE_POSITIVE_INT;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700331 }
Laurence Lundblade55a24832018-10-30 04:35:08 +0700332
333 InsertEncodedTypeAndNumber(me, uMajorType, 0, uValue, uPos);
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700334 me->uError = Nesting_Increment(&(me->nesting), 1);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700335}
336
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700337/*
338 Does the work of adding some bytes to the CBOR output. Works for a
339 byte and text strings, which are the same in in CBOR though they have
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700340 different major types. This is also used to insert raw
341 pre-encoded CBOR.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700342 */
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700343static void AddBytesInternal2(QCBOREncodeContext *me, UsefulBufC Bytes, uint8_t uMajorType, size_t uPos)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700344{
345 if(Bytes.len >= UINT32_MAX) {
346 // This implementation doesn't allow buffers larger than UINT32_MAX. This is
347 // primarily because QCBORTrackNesting.pArrays[].uStart is an uint32 rather
348 // than size_t to keep the stack usage down. Also it is entirely impractical
349 // to create tokens bigger than 4GB in contiguous RAM
350 me->uError = QCBOR_ERR_BUFFER_TOO_LARGE;
351
352 } else {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700353 if(!me->uError) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700354 // If it is not Raw CBOR, add the type and the length
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700355 const size_t uPosBeforeInsert = UsefulOutBuf_GetEndPosition(&(me->OutBuf));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700356 if(uMajorType != CBOR_MAJOR_NONE_TYPE_RAW) {
Laurence Lundblade55a24832018-10-30 04:35:08 +0700357 InsertEncodedTypeAndNumber(me, uMajorType, 0, Bytes.len, uPos);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700358 }
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700359 uPos += UsefulOutBuf_GetEndPosition(&(me->OutBuf)) - uPosBeforeInsert;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700360
361 // Actually add the bytes
Laurence Lundblade55a24832018-10-30 04:35:08 +0700362 UsefulOutBuf_InsertUsefulBuf(&(me->OutBuf), Bytes, uPos);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700363
364 // Update the array counting if there is any nesting at all
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700365 me->uError = Nesting_Increment(&(me->nesting), 1);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700366 }
367 }
368}
369
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700370
Laurence Lundblade55a24832018-10-30 04:35:08 +0700371/*
372 Add an optional label. It will go in front of a real data item.
373 */
Laurence Lundblade55a24832018-10-30 04:35:08 +0700374static void AddLabel(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel)
375{
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700376 size_t uPos = UsefulOutBuf_GetEndPosition(&(me->OutBuf));
377 if(Nesting_GetMajorType(&(me->nesting)) == CBOR_MAJOR_NONE_TAG_LABEL_REORDER) {
378 // Have to insert the label rather than just appen if a tag
379 // has been added. This is so the tag ends up on the value, not
380 // on the label.
Laurence Lundblade55a24832018-10-30 04:35:08 +0700381 uPos = Nesting_GetStartPos(&(me->nesting));
382 Nesting_Decrease(&(me->nesting));
383 }
384
385 if(szLabel) {
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700386 const UsefulBufC SZText = UsefulBuf_FromSZ(szLabel);
Laurence Lundblade55a24832018-10-30 04:35:08 +0700387 AddBytesInternal2(me, SZText, CBOR_MAJOR_TYPE_TEXT_STRING, uPos);
388 } else if (QCBOR_NO_INT_LABEL != nLabel) {
389 InsertInt64(me, nLabel, uPos);
390 }
391}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700392
393
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700394/*
Laurence Lundblade55a24832018-10-30 04:35:08 +0700395 Public Function
396 */
397void QCBOREncode_AddTag(QCBOREncodeContext *me, uint64_t uTag)
398{
399 uint8_t uNestingType = Nesting_GetMajorType(&(me->nesting));
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700400 if(uNestingType == CBOR_MAJOR_TYPE_MAP || uNestingType == CBOR_MAJOR_TYPE_ARRAY) { // TODO: really do this for arrays?
Laurence Lundblade55a24832018-10-30 04:35:08 +0700401 // Remember where the first tag is for this item
402 // So we can go back and insert the label in front of it.
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700403 // Cast to uint32_t here is OK all sizes are limited to 4GB by other checks
404 const uint32_t uPos = (uint32_t)UsefulOutBuf_GetEndPosition(&(me->OutBuf));
405 me->uError = Nesting_Increase(&(me->nesting), CBOR_MAJOR_NONE_TAG_LABEL_REORDER, uPos);
Laurence Lundblade55a24832018-10-30 04:35:08 +0700406 }
407
408 AppendEncodedTypeAndNumber(me, CBOR_MAJOR_TYPE_OPTIONAL, uTag);
409}
410
411
412
413void QCBOREncode_AddBytes_2(QCBOREncodeContext *me, uint8_t uMajorType, const char *szLabel, int64_t nLabel, UsefulBufC Bytes)
414{
415 AddLabel(me, szLabel, nLabel);
416 if(!me->uError) {
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700417 AddBytesInternal2(me, Bytes, uMajorType, UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
Laurence Lundblade55a24832018-10-30 04:35:08 +0700418 }
419}
420
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700421
422
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700423/*
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700424 TODO: fix docu
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700425 Internal function common to opening an array or a map
426
427 QCBOR_MAX_ARRAY_NESTING is the number of times Open can be called
428 successfully. Call it one more time gives an error.
429
430 */
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700431void OpenMapOrArray_2(QCBOREncodeContext *me, uint8_t uMajorType, const char *szLabel, uint64_t nLabel)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700432{
Laurence Lundblade55a24832018-10-30 04:35:08 +0700433 AddLabel(me, szLabel, nLabel);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700434
435 if(!me->uError) {
436 // Add one item to the nesting level we are in for the new map or array
437 me->uError = Nesting_Increment(&(me->nesting), 1);
438 if(!me->uError) {
439 // Increase nesting level because this is a map or array
440 // Cast from size_t to uin32_t is safe because the UsefulOutBuf
441 // size is limited to UINT32_MAX in QCBOR_Init().
Laurence Lundbladea954db92018-09-28 19:27:31 -0700442 me->uError = Nesting_Increase(&(me->nesting), uMajorType, (uint32_t)UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700443 }
444 }
445}
446
447
448/*
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700449 Public functions for closing arrays and maps. See header qcbor.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700450 */
Laurence Lundbladea954db92018-09-28 19:27:31 -0700451
452void QCBOREncode_Close(QCBOREncodeContext *me, uint8_t uMajorType, UsefulBufC *pWrappedCBOR)
453{
454 if(!me->uError) {
455 if(!Nesting_IsInNest(&(me->nesting))) {
456 me->uError = QCBOR_ERR_TOO_MANY_CLOSES;
457 } else if( Nesting_GetMajorType(&(me->nesting)) != uMajorType) {
458 me->uError = QCBOR_ERR_CLOSE_MISMATCH;
459 } else {
460 const uint32_t uInsertPosition = Nesting_GetStartPos(&(me->nesting));
461 // When the array, map or bstr wrap was started, nothing was done except
462 // note the position of the start of it. This code goes back and inserts
463 // the actual CBOR array, map or bstr and its length. That means all the
464 // data that is in the array, map or wrapped needs to be slid to the
465 // right. This is done by UsefulOutBuf's insert function that is called
466 // from inside InsertEncodedTypeAndNumber()
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700467
468 // Cast from size_t to uin32_t is safe because the UsefulOutBuf
469 // size is limited to UINT32_MAX in QCBOR_Init().
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700470 // TODO: can these be size_t? Check them for over/underflow
Laurence Lundbladea954db92018-09-28 19:27:31 -0700471 const uint32_t uEndPosition = (uint32_t)UsefulOutBuf_GetEndPosition(&(me->OutBuf));
472 const uint32_t uLenOfEncodedMapOrArray = uEndPosition - uInsertPosition;
473
474 // Length is number of bytes for a bstr and number of items for map & array
475 const uint32_t uLength = uMajorType == CBOR_MAJOR_TYPE_BYTE_STRING ?
476 uLenOfEncodedMapOrArray : Nesting_GetCount(&(me->nesting));
477
478 // Actually insert
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700479 InsertEncodedTypeAndNumber(me,
Laurence Lundbladea954db92018-09-28 19:27:31 -0700480 uMajorType, // major type bstr, array or map
481 0, // no minimum length for encoding
482 uLength, // either len of bstr or num items in array or map
483 uInsertPosition); // position in out buffer
484
485 // Return pointer and length to the enclosed encoded CBOR. The intended
486 // use is for it to be hashed (e.g., SHA-256) in a COSE implementation.
487 // This must be used right away, as the pointer and length go invalid
488 // on any subsequent calls to this function because of the
489 // InsertEncodedTypeAndNumber() call that slides data to the right.
490 if(pWrappedCBOR) {
491 UsefulBufC PartialResult = UsefulOutBuf_OutUBuf(&(me->OutBuf));
492 uint32_t uBstrLen = (uint32_t)UsefulOutBuf_GetEndPosition(&(me->OutBuf)) - uEndPosition;
493 *pWrappedCBOR = UsefulBuf_Tail(PartialResult, uInsertPosition+uBstrLen);
494 }
495 Nesting_Decrease(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700496 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700497 }
498}
499
500
501
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700502/*
Laurence Lundblade55a24832018-10-30 04:35:08 +0700503 Public functions for adding integers. See header qcbor.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700504 */
Laurence Lundblade55a24832018-10-30 04:35:08 +0700505
506void QCBOREncode_AddUInt64_2(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uNum)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700507{
Laurence Lundblade55a24832018-10-30 04:35:08 +0700508 AddLabel(me, szLabel, nLabel);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700509 if(!me->uError) {
Laurence Lundblade55a24832018-10-30 04:35:08 +0700510 AppendEncodedTypeAndNumber(me, CBOR_MAJOR_TYPE_POSITIVE_INT, uNum);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700511 me->uError = Nesting_Increment(&(me->nesting), 1);
512 }
513}
514
Laurence Lundblade55a24832018-10-30 04:35:08 +0700515void QCBOREncode_AddInt64_2(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, int64_t nNum)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700516{
Laurence Lundblade55a24832018-10-30 04:35:08 +0700517 AddLabel(me, szLabel, nLabel);
518 if(!me->uError) {
519 InsertInt64(me, nNum, (uint32_t)UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700520 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700521}
522
523
524
525
526/*
527 Common code for adding floats and doubles and simple types like true and false
528
529 One way to look at simple values is that they are:
530 - type 7
531 - an additional integer from 0 to 255
532 - additional integer 0-19 are unassigned and could be used in an update to CBOR
533 - additional integers 20, 21, 22 and 23 are false, true, null and undef
534 - additional integer 24 is not available
535 - when the additional value is 25, 26, or 27 there is additionally a half, float or double in following bytes
536 - additional integers 28, 29 and 30 are unassigned / reserved
537 - additional integer 31 is a "break"
538 - additional integers 32-255 are unassigned and could be used in an update to CBOR
539 */
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700540static void AddSimpleInternal(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, size_t uSize, uint64_t uNum)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700541{
Laurence Lundblade55a24832018-10-30 04:35:08 +0700542 AddLabel(me, szLabel, nLabel);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700543 if(!me->uError) {
544 // This function call takes care of endian swapping for the float / double
545 InsertEncodedTypeAndNumber(me,
546 CBOR_MAJOR_TYPE_SIMPLE, // The major type for floats and doubles
547 uSize, // min size / tells encoder to do it right
548 uNum, // Bytes of the floating point number as a uint
549 UsefulOutBuf_GetEndPosition(&(me->OutBuf))); // end position for append
550
551 me->uError = Nesting_Increment(&(me->nesting), 1);
552 }
553}
554
555
556/*
557 Public function for adding simple values. See header qcbor.h
558 */
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700559void QCBOREncode_AddRawSimple_2(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint8_t uSimple)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700560{
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700561 AddSimpleInternal(me, szLabel, nLabel, 0, uSimple);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700562}
563
564
565/*
566 Public function for adding simple values. See header qcbor.h
567 */
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700568void QCBOREncode_AddSimple_2(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint8_t uSimple)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700569{
570 if(uSimple < CBOR_SIMPLEV_FALSE || uSimple > CBOR_SIMPLEV_UNDEF) {
571 me->uError = QCBOR_ERR_BAD_SIMPLE;
572 } else {
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700573 QCBOREncode_AddRawSimple_2(me, szLabel, nLabel, uSimple);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700574 }
575}
576
577
578/*
579 Public functions for floating point numbers. See header qcbor.h
580 */
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700581void QCBOREncode_AddFloat_2(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, float fNum)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700582{
583 // Convert the *type* of the data from a float to a uint so the
584 // standard integer encoding can work. This takes advantage
585 // of CBOR's indicator for a float being the same as for a 4
586 // byte integer too.
587 const float *pfNum = &fNum;
588 const uint32_t uNum = *(uint32_t *)pfNum;
589
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700590 AddSimpleInternal(me, szLabel, nLabel, sizeof(float), uNum);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700591}
592
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700593void QCBOREncode_AddDouble_2(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, double dNum)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700594{
595 // see how it is done for floats above
596 const double *pdNum = &dNum;
597 const uint64_t uNum = *(uint64_t *)pdNum;
598
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700599 AddSimpleInternal(me, szLabel, nLabel, sizeof(double), uNum);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700600}
601
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700602void QCBOREncode_AddFloatAsHalf_2(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, float fNum)
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700603{
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700604 AddSimpleInternal(me, szLabel, nLabel, sizeof(uint16_t), IEEE754_FloatToHalf(fNum));
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700605}
606
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700607static void QCBOREncode_AddFUnionAsSmallest_2(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, IEEE754_union uNum)
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700608{
609 switch(uNum.uTag) {
610 case IEEE754_UNION_IS_HALF:
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700611 AddSimpleInternal(me, szLabel, nLabel, sizeof(uint16_t), uNum.u16);
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700612 break;
613 case IEEE754_UNION_IS_SINGLE:
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700614 AddSimpleInternal(me, szLabel, nLabel, sizeof(uint32_t), uNum.u32);
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700615 break;
616 case IEEE754_UNION_IS_DOUBLE:
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700617 AddSimpleInternal(me, szLabel, nLabel, sizeof(uint64_t), uNum.u64);
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700618 break;
619 }
620}
621
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700622void QCBOREncode_AddFloatAsSmallest_2(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, float fNum)
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700623{
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700624 QCBOREncode_AddFUnionAsSmallest_2(me, szLabel, nLabel, IEEE754_FloatToSmallest(fNum));
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700625}
626
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700627void QCBOREncode_AddDoubleAsSmallest_2(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, double dNum)
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700628{
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700629 QCBOREncode_AddFUnionAsSmallest_2(me, szLabel, nLabel, IEEE754_DoubleToSmallest(dNum));
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700630}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700631
632
633
634/*
635 Public functions to finish and get the encoded result. See header qcbor.h
636 */
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700637int QCBOREncode_Finish2(QCBOREncodeContext *me, UsefulBufC *pEncodedCBOR)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700638{
639 if(me->uError)
640 goto Done;
641
642 if (Nesting_IsInNest(&(me->nesting))) {
643 me->uError = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
644 goto Done;
645 }
646
647 if(UsefulOutBuf_GetError(&(me->OutBuf))) {
648 // Stuff didn't fit in the buffer.
649 // This check catches this condition for all the appends and inserts so checks aren't needed
650 // when the appends and inserts are performed. And of course UsefulBuf will never
651 // overrun the input buffer given to it. No complex analysis of the error handling
652 // in this file is needed to know that is true. Just read the UsefulBuf code.
653 me->uError = QCBOR_ERR_BUFFER_TOO_SMALL;
654 goto Done;
655 }
Laurence Lundblade2296db52018-09-14 18:08:39 -0700656
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700657 *pEncodedCBOR = UsefulOutBuf_OutUBuf(&(me->OutBuf));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700658
659Done:
660 return me->uError;
661}
662
663int QCBOREncode_Finish(QCBOREncodeContext *me, size_t *puEncodedLen)
664{
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700665 UsefulBufC Enc;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700666
667 int nReturn = QCBOREncode_Finish2(me, &Enc);
668
669 if(nReturn == QCBOR_SUCCESS) {
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700670 *puEncodedLen = Enc.len;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700671 }
672
673 return nReturn;
674}
675
676