blob: e8401cac30f6625fd42353dcc9c01847b0c39e60 [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
Laurence Lundblade56230d12018-11-01 11:14:51 +0700199 correct. This could also automatically size some of the data
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700200 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 Lundblade56230d12018-11-01 11:14:51 +0700275 uMajorType <<= 5;
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
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700316/*
Laurence Lundblade55a24832018-10-30 04:35:08 +0700317 Internal function for adding positive and negative integers of all different sizes
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700318 */
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700319void InsertInt64(QCBOREncodeContext *me, int64_t nNum, size_t uPos)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700320{
Laurence Lundblade55a24832018-10-30 04:35:08 +0700321 uint8_t uMajorType;
322 uint64_t uValue;
323
324 if(nNum < 0) {
325 uValue = (uint64_t)(-nNum - 1); // This is the way negative ints work in CBOR. -1 encodes as 0x00 with major type negative int.
326 uMajorType = CBOR_MAJOR_TYPE_NEGATIVE_INT;
327 } else {
328 uValue = (uint64_t)nNum;
329 uMajorType = CBOR_MAJOR_TYPE_POSITIVE_INT;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700330 }
Laurence Lundblade55a24832018-10-30 04:35:08 +0700331
332 InsertEncodedTypeAndNumber(me, uMajorType, 0, uValue, uPos);
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700333 me->uError = Nesting_Increment(&(me->nesting), 1);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700334}
335
Laurence Lundblade56230d12018-11-01 11:14:51 +0700336
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 Lundblade56230d12018-11-01 11:14:51 +0700343static void AddBufferInternal(QCBOREncodeContext *me, UsefulBufC Bytes, uint8_t uMajorType, size_t uPos)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700344{
345 if(Bytes.len >= UINT32_MAX) {
Laurence Lundblade56230d12018-11-01 11:14:51 +0700346 // This implementation doesn't allow buffers larger than UINT32_MAX.
347 // This is primarily because QCBORTrackNesting.pArrays[].uStart is
348 // an uint32 rather than size_t to keep the stack usage down. Also
349 // it is entirely impractical to create tokens bigger than 4GB in
350 // contiguous RAM
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700351 me->uError = QCBOR_ERR_BUFFER_TOO_LARGE;
352
353 } else {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700354 if(!me->uError) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700355 // If it is not Raw CBOR, add the type and the length
356 if(uMajorType != CBOR_MAJOR_NONE_TYPE_RAW) {
Laurence Lundblade56230d12018-11-01 11:14:51 +0700357 const size_t uPosBeforeInsert = UsefulOutBuf_GetEndPosition(&(me->OutBuf));
Laurence Lundblade55a24832018-10-30 04:35:08 +0700358 InsertEncodedTypeAndNumber(me, uMajorType, 0, Bytes.len, uPos);
Laurence Lundblade56230d12018-11-01 11:14:51 +0700359 // The increment in uPos is to account for bytes added for
360 // type and number so the buffer being added goes to the
361 // right place
362 uPos += UsefulOutBuf_GetEndPosition(&(me->OutBuf)) - uPosBeforeInsert;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700363 }
364
365 // Actually add the bytes
Laurence Lundblade55a24832018-10-30 04:35:08 +0700366 UsefulOutBuf_InsertUsefulBuf(&(me->OutBuf), Bytes, uPos);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700367
368 // Update the array counting if there is any nesting at all
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700369 me->uError = Nesting_Increment(&(me->nesting), 1);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700370 }
371 }
372}
373
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700374
Laurence Lundblade55a24832018-10-30 04:35:08 +0700375/*
376 Add an optional label. It will go in front of a real data item.
377 */
Laurence Lundblade55a24832018-10-30 04:35:08 +0700378static void AddLabel(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel)
379{
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700380 size_t uPos = UsefulOutBuf_GetEndPosition(&(me->OutBuf));
381 if(Nesting_GetMajorType(&(me->nesting)) == CBOR_MAJOR_NONE_TAG_LABEL_REORDER) {
382 // Have to insert the label rather than just appen if a tag
383 // has been added. This is so the tag ends up on the value, not
384 // on the label.
Laurence Lundblade55a24832018-10-30 04:35:08 +0700385 uPos = Nesting_GetStartPos(&(me->nesting));
386 Nesting_Decrease(&(me->nesting));
387 }
388
389 if(szLabel) {
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700390 const UsefulBufC SZText = UsefulBuf_FromSZ(szLabel);
Laurence Lundblade56230d12018-11-01 11:14:51 +0700391 AddBufferInternal(me, SZText, CBOR_MAJOR_TYPE_TEXT_STRING, uPos);
Laurence Lundblade55a24832018-10-30 04:35:08 +0700392 } else if (QCBOR_NO_INT_LABEL != nLabel) {
393 InsertInt64(me, nLabel, uPos);
394 }
395}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700396
397
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700398/*
Laurence Lundblade55a24832018-10-30 04:35:08 +0700399 Public Function
400 */
401void QCBOREncode_AddTag(QCBOREncodeContext *me, uint64_t uTag)
402{
403 uint8_t uNestingType = Nesting_GetMajorType(&(me->nesting));
Laurence Lundblade56230d12018-11-01 11:14:51 +0700404 if(uNestingType == CBOR_MAJOR_TYPE_MAP || uNestingType == CBOR_MAJOR_TYPE_ARRAY) {
Laurence Lundblade55a24832018-10-30 04:35:08 +0700405 // Remember where the first tag is for this item
406 // So we can go back and insert the label in front of it.
Laurence Lundblade56230d12018-11-01 11:14:51 +0700407 // Cast to uint32_t here OK as all inputs are limited to 4GB
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700408 const uint32_t uPos = (uint32_t)UsefulOutBuf_GetEndPosition(&(me->OutBuf));
409 me->uError = Nesting_Increase(&(me->nesting), CBOR_MAJOR_NONE_TAG_LABEL_REORDER, uPos);
Laurence Lundblade55a24832018-10-30 04:35:08 +0700410 }
411
412 AppendEncodedTypeAndNumber(me, CBOR_MAJOR_TYPE_OPTIONAL, uTag);
413}
414
415
Laurence Lundblade56230d12018-11-01 11:14:51 +0700416/*
417 Semi-public interface. Called by inline functions to add text and byte strings
418 and already-encoded CBOR. They are the real public interface, even though this
419 is the main entry point. The code is structured like this to reduce code size.
420 */
421void QCBOREncode_AddBuffer_2(QCBOREncodeContext *me, uint8_t uMajorType, const char *szLabel, int64_t nLabel, UsefulBufC Bytes)
Laurence Lundblade55a24832018-10-30 04:35:08 +0700422{
423 AddLabel(me, szLabel, nLabel);
424 if(!me->uError) {
Laurence Lundblade56230d12018-11-01 11:14:51 +0700425 AddBufferInternal(me, Bytes, uMajorType, UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
Laurence Lundblade55a24832018-10-30 04:35:08 +0700426 }
427}
428
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700429
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700430/*
Laurence Lundblade56230d12018-11-01 11:14:51 +0700431 Semi-public interfaced. Called by inline functions to open arrays, maps and
432 bstr wrapped CBOR. They are the real public interface, even though this is the
433 main entry point. This code is structured like this to reduce code size.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700434 */
Laurence Lundblade56230d12018-11-01 11:14:51 +0700435void QCBOREncode_OpenMapOrArray_2(QCBOREncodeContext *me, uint8_t uMajorType, const char *szLabel, uint64_t nLabel)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700436{
Laurence Lundblade55a24832018-10-30 04:35:08 +0700437 AddLabel(me, szLabel, nLabel);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700438
439 if(!me->uError) {
440 // Add one item to the nesting level we are in for the new map or array
441 me->uError = Nesting_Increment(&(me->nesting), 1);
442 if(!me->uError) {
443 // Increase nesting level because this is a map or array
444 // Cast from size_t to uin32_t is safe because the UsefulOutBuf
445 // size is limited to UINT32_MAX in QCBOR_Init().
Laurence Lundbladea954db92018-09-28 19:27:31 -0700446 me->uError = Nesting_Increase(&(me->nesting), uMajorType, (uint32_t)UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700447 }
448 }
449}
450
451
452/*
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700453 Public functions for closing arrays and maps. See header qcbor.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700454 */
Laurence Lundbladea954db92018-09-28 19:27:31 -0700455void QCBOREncode_Close(QCBOREncodeContext *me, uint8_t uMajorType, UsefulBufC *pWrappedCBOR)
456{
457 if(!me->uError) {
458 if(!Nesting_IsInNest(&(me->nesting))) {
459 me->uError = QCBOR_ERR_TOO_MANY_CLOSES;
460 } else if( Nesting_GetMajorType(&(me->nesting)) != uMajorType) {
461 me->uError = QCBOR_ERR_CLOSE_MISMATCH;
462 } else {
Laurence Lundblade56230d12018-11-01 11:14:51 +0700463 // When the array, map or bstr wrap was started, nothing was done
464 // except note the position of the start of it. This code goes back
465 // and inserts the actual CBOR array, map or bstr and its length.
466 // That means all the data that is in the array, map or wrapped
467 // needs to be slid to the right. This is done by UsefulOutBuf's
468 // insert function that is called from inside
469 // InsertEncodedTypeAndNumber()
470 const size_t uInsertPosition = Nesting_GetStartPos(&(me->nesting));
471 const size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf));
472 // This can't go negative because the UsefulOutBuf always only grows
473 // and never shrinks. UsefulOutBut itself also has defenses such that
474 // it won't write were it should not even if given hostile input lengths
475 const size_t uLenOfEncodedMapOrArray = uEndPosition - uInsertPosition;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700476
Laurence Lundblade56230d12018-11-01 11:14:51 +0700477 // Length is number of bytes for a bstr and number of items a for map & array
478 const size_t uLength = uMajorType == CBOR_MAJOR_TYPE_BYTE_STRING ?
Laurence Lundbladea954db92018-09-28 19:27:31 -0700479 uLenOfEncodedMapOrArray : Nesting_GetCount(&(me->nesting));
480
481 // Actually insert
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700482 InsertEncodedTypeAndNumber(me,
Laurence Lundbladea954db92018-09-28 19:27:31 -0700483 uMajorType, // major type bstr, array or map
484 0, // no minimum length for encoding
485 uLength, // either len of bstr or num items in array or map
486 uInsertPosition); // position in out buffer
487
488 // Return pointer and length to the enclosed encoded CBOR. The intended
489 // use is for it to be hashed (e.g., SHA-256) in a COSE implementation.
490 // This must be used right away, as the pointer and length go invalid
491 // on any subsequent calls to this function because of the
492 // InsertEncodedTypeAndNumber() call that slides data to the right.
493 if(pWrappedCBOR) {
494 UsefulBufC PartialResult = UsefulOutBuf_OutUBuf(&(me->OutBuf));
Laurence Lundblade56230d12018-11-01 11:14:51 +0700495 size_t uBstrLen = UsefulOutBuf_GetEndPosition(&(me->OutBuf)) - uEndPosition;
Laurence Lundbladea954db92018-09-28 19:27:31 -0700496 *pWrappedCBOR = UsefulBuf_Tail(PartialResult, uInsertPosition+uBstrLen);
497 }
498 Nesting_Decrease(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700499 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700500 }
501}
502
503
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700504/*
Laurence Lundblade55a24832018-10-30 04:35:08 +0700505 Public functions for adding integers. See header qcbor.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700506 */
Laurence Lundblade55a24832018-10-30 04:35:08 +0700507void QCBOREncode_AddUInt64_2(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uNum)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700508{
Laurence Lundblade55a24832018-10-30 04:35:08 +0700509 AddLabel(me, szLabel, nLabel);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700510 if(!me->uError) {
Laurence Lundblade55a24832018-10-30 04:35:08 +0700511 AppendEncodedTypeAndNumber(me, CBOR_MAJOR_TYPE_POSITIVE_INT, uNum);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700512 me->uError = Nesting_Increment(&(me->nesting), 1);
513 }
514}
515
Laurence Lundblade56230d12018-11-01 11:14:51 +0700516
517/*
518 Public functions for adding integers. See header qcbor.h
519 */
Laurence Lundblade55a24832018-10-30 04:35:08 +0700520void QCBOREncode_AddInt64_2(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, int64_t nNum)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700521{
Laurence Lundblade55a24832018-10-30 04:35:08 +0700522 AddLabel(me, szLabel, nLabel);
523 if(!me->uError) {
Laurence Lundblade56230d12018-11-01 11:14:51 +0700524 // Cast is OK here because the output buffer is limited to 4GB in Init().
Laurence Lundblade55a24832018-10-30 04:35:08 +0700525 InsertInt64(me, nNum, (uint32_t)UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700526 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700527}
528
529
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700530/*
Laurence Lundblade56230d12018-11-01 11:14:51 +0700531 Semi-public interfaced. Called by inline functions to add simple and float
532 types. They are the real public interface, even though this is the
533 main entry point. This code is structured like this to reduce code size.
534
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700535 Common code for adding floats and doubles and simple types like true and false
536
537 One way to look at simple values is that they are:
538 - type 7
539 - an additional integer from 0 to 255
540 - additional integer 0-19 are unassigned and could be used in an update to CBOR
541 - additional integers 20, 21, 22 and 23 are false, true, null and undef
542 - additional integer 24 is not available
543 - when the additional value is 25, 26, or 27 there is additionally a half, float or double in following bytes
544 - additional integers 28, 29 and 30 are unassigned / reserved
545 - additional integer 31 is a "break"
546 - additional integers 32-255 are unassigned and could be used in an update to CBOR
547 */
Laurence Lundblade56230d12018-11-01 11:14:51 +0700548void QCBOREncode_AddType7_2(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, size_t uSize, uint64_t uNum)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700549{
Laurence Lundblade55a24832018-10-30 04:35:08 +0700550 AddLabel(me, szLabel, nLabel);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700551 if(!me->uError) {
552 // This function call takes care of endian swapping for the float / double
553 InsertEncodedTypeAndNumber(me,
Laurence Lundblade56230d12018-11-01 11:14:51 +0700554 CBOR_MAJOR_TYPE_SIMPLE, // The major type for
555 // floats and doubles
556 uSize, // min size / tells
557 // encoder to do it right
558 uNum, // Bytes of the floating
559 // point number as a uint
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700560 UsefulOutBuf_GetEndPosition(&(me->OutBuf))); // end position for append
561
562 me->uError = Nesting_Increment(&(me->nesting), 1);
563 }
564}
565
566
567/*
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700568 Public functions for floating point numbers. See header qcbor.h
569 */
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700570void QCBOREncode_AddFloat_2(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, float fNum)
Laurence Lundblade56230d12018-11-01 11:14:51 +0700571{
572 QCBOREncode_AddType7_2(me, szLabel, nLabel, sizeof(float), UsefulBufUtil_CopyFloatToUint32(fNum));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700573}
574
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700575void QCBOREncode_AddDouble_2(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, double dNum)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700576{
Laurence Lundblade56230d12018-11-01 11:14:51 +0700577 QCBOREncode_AddType7_2(me, szLabel, nLabel, sizeof(double), UsefulBufUtil_CopyDoubleToUint64(dNum));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700578}
579
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700580void QCBOREncode_AddFloatAsHalf_2(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, float fNum)
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700581{
Laurence Lundblade56230d12018-11-01 11:14:51 +0700582 QCBOREncode_AddType7_2(me, szLabel, nLabel, sizeof(uint16_t), IEEE754_FloatToHalf(fNum));
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700583}
584
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700585static void QCBOREncode_AddFUnionAsSmallest_2(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, IEEE754_union uNum)
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700586{
587 switch(uNum.uTag) {
588 case IEEE754_UNION_IS_HALF:
Laurence Lundblade56230d12018-11-01 11:14:51 +0700589 QCBOREncode_AddType7_2(me, szLabel, nLabel, sizeof(uint16_t), uNum.u16);
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700590 break;
591 case IEEE754_UNION_IS_SINGLE:
Laurence Lundblade56230d12018-11-01 11:14:51 +0700592 QCBOREncode_AddType7_2(me, szLabel, nLabel, sizeof(uint32_t), uNum.u32);
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700593 break;
594 case IEEE754_UNION_IS_DOUBLE:
Laurence Lundblade56230d12018-11-01 11:14:51 +0700595 QCBOREncode_AddType7_2(me, szLabel, nLabel, sizeof(uint64_t), uNum.u64);
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700596 break;
597 }
598}
599
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700600void QCBOREncode_AddFloatAsSmallest_2(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, float fNum)
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700601{
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700602 QCBOREncode_AddFUnionAsSmallest_2(me, szLabel, nLabel, IEEE754_FloatToSmallest(fNum));
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700603}
604
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700605void QCBOREncode_AddDoubleAsSmallest_2(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, double dNum)
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700606{
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700607 QCBOREncode_AddFUnionAsSmallest_2(me, szLabel, nLabel, IEEE754_DoubleToSmallest(dNum));
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700608}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700609
610
611
Laurence Lundblade56230d12018-11-01 11:14:51 +0700612
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700613/*
614 Public functions to finish and get the encoded result. See header qcbor.h
615 */
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700616int QCBOREncode_Finish2(QCBOREncodeContext *me, UsefulBufC *pEncodedCBOR)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700617{
618 if(me->uError)
619 goto Done;
620
621 if (Nesting_IsInNest(&(me->nesting))) {
622 me->uError = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
623 goto Done;
624 }
625
626 if(UsefulOutBuf_GetError(&(me->OutBuf))) {
627 // Stuff didn't fit in the buffer.
Laurence Lundblade56230d12018-11-01 11:14:51 +0700628 // This check catches this condition for all the appends and inserts
629 // so checks aren't needed when the appends and inserts are performed.
630 // And of course UsefulBuf will never overrun the input buffer given
631 // to it. No complex analysis of the error handling in this file is
632 // needed to know that is true. Just read the UsefulBuf code.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700633 me->uError = QCBOR_ERR_BUFFER_TOO_SMALL;
634 goto Done;
635 }
Laurence Lundblade2296db52018-09-14 18:08:39 -0700636
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700637 *pEncodedCBOR = UsefulOutBuf_OutUBuf(&(me->OutBuf));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700638
639Done:
640 return me->uError;
641}
642
643int QCBOREncode_Finish(QCBOREncodeContext *me, size_t *puEncodedLen)
644{
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700645 UsefulBufC Enc;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700646
647 int nReturn = QCBOREncode_Finish2(me, &Enc);
648
649 if(nReturn == QCBOR_SUCCESS) {
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700650 *puEncodedLen = Enc.len;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700651 }
652
653 return nReturn;
654}
655
656