blob: 93f7203d67639b2b338b6c63df5aff94126f1b59 [file] [log] [blame]
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001/*==============================================================================
Laurence Lundbladed92a6162018-11-01 11:38:35 +07002 Copyright (c) 2016-2018, The Linux Foundation.
3 Copyright (c) 2018, Laurence Lundblade.
4 All rights reserved.
Laurence Lundblade624405d2018-09-18 20:10:47 -07005
Laurence Lundbladed92a6162018-11-01 11:38:35 +07006 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are
8 met:
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of The Linux Foundation nor the names of its
16 contributors, nor the name "Laurence Lundblade" may be used to
17 endorse or promote products derived from this software without
18 specific prior written permission.
Laurence Lundblade624405d2018-09-18 20:10:47 -070019
Laurence Lundbladed92a6162018-11-01 11:38:35 +070020 THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
21 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
23 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
24 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
27 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
29 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
30 IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Laurence Lundblade624405d2018-09-18 20:10:47 -070031 ==============================================================================*/
32
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070033/*===================================================================================
34 FILE: qcbor_encode.c
35
36 DESCRIPTION: This file contains the implementation of QCBOR.
37
38 EDIT HISTORY FOR FILE:
39
40 This section contains comments describing changes made to the module.
41 Notice that changes are listed in reverse chronological order.
42
43 when who what, where, why
44 -------- ---- ---------------------------------------------------
45 02/05/18 llundbla Works on CPUs which require integer alignment.
46 Requires new version of UsefulBuf.
47 07/05/17 llundbla Add bstr wrapping of maps/arrays for COSE
48 03/01/17 llundbla More data types
49 11/13/16 llundbla Integrate most TZ changes back into github version.
50 09/30/16 gkanike Porting to TZ.
51 03/15/16 llundbla Initial Version.
52
53 =====================================================================================*/
54
55#include "qcbor.h"
Laurence Lundblade12d32c52018-09-19 11:25:27 -070056#include "ieee754.h"
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070057
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070058
59/*...... This is a ruler that is 80 characters long...........................*/
60
61
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070062/*
63 CBOR's two nesting types, arrays and maps, are tracked here. There is a
64 limit of QCBOR_MAX_ARRAY_NESTING to the number of arrays and maps
65 that can be nested in one encoding so the encoding context stays
66 small enough to fit on the stack.
67
68 When an array / map is opened, pCurrentNesting points to the element
69 in pArrays that records the type, start position and accumluates a
70 count of the number of items added. When closed the start position is
71 used to go back and fill in the type and number of items in the array
72 / map.
73
74 Encoded output be just items like ints and strings that are
75 not part of any array / map. That is, the first thing encoded
76 does not have to be an array or a map.
77 */
78inline static void Nesting_Init(QCBORTrackNesting *pNesting)
79{
80 // assumes pNesting has been zeroed
81 pNesting->pCurrentNesting = &pNesting->pArrays[0];
82 // Implied CBOR array at the top nesting level. This is never returned,
83 // but makes the item count work correctly.
84 pNesting->pCurrentNesting->uMajorType = CBOR_MAJOR_TYPE_ARRAY;
85}
86
Laurence Lundbladea954db92018-09-28 19:27:31 -070087inline static int Nesting_Increase(QCBORTrackNesting *pNesting, uint8_t uMajorType, uint32_t uPos)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070088{
89 int nReturn = QCBOR_SUCCESS;
90
91 if(pNesting->pCurrentNesting == &pNesting->pArrays[QCBOR_MAX_ARRAY_NESTING]) {
92 // trying to open one too many
93 nReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
94 } else {
95 pNesting->pCurrentNesting++;
96 pNesting->pCurrentNesting->uCount = 0;
97 pNesting->pCurrentNesting->uStart = uPos;
98 pNesting->pCurrentNesting->uMajorType = uMajorType;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070099 }
100 return nReturn;
101}
102
103inline static void Nesting_Decrease(QCBORTrackNesting *pNesting)
104{
105 pNesting->pCurrentNesting--;
106}
107
108inline static int Nesting_Increment(QCBORTrackNesting *pNesting, uint16_t uAmount)
109{
110 if(uAmount >= QCBOR_MAX_ITEMS_IN_ARRAY - pNesting->pCurrentNesting->uCount) {
111 return QCBOR_ERR_ARRAY_TOO_LONG;
112 }
113
114 pNesting->pCurrentNesting->uCount += uAmount;
115 return QCBOR_SUCCESS;
116}
117
118inline static uint16_t Nesting_GetCount(QCBORTrackNesting *pNesting)
119{
120 // The nesting count recorded is always the actual number of individiual
121 // data items in the array or map. For arrays CBOR uses the actual item
122 // count. For maps, CBOR uses the number of pairs. This function returns
123 // the number needed for the CBOR encoding, so it divides the number of
124 // items by two for maps to get the number of pairs. This implementation
125 // takes advantage of the map major type being one larger the array major
126 // type, hence the subtraction returns either 1 or 2.
127 return pNesting->pCurrentNesting->uCount / (pNesting->pCurrentNesting->uMajorType - CBOR_MAJOR_TYPE_ARRAY+1);
128}
129
130inline static uint32_t Nesting_GetStartPos(QCBORTrackNesting *pNesting)
131{
132 return pNesting->pCurrentNesting->uStart;
133}
134
135inline static uint8_t Nesting_GetMajorType(QCBORTrackNesting *pNesting)
136{
137 return pNesting->pCurrentNesting->uMajorType;
138}
139
140inline static int Nesting_IsInNest(QCBORTrackNesting *pNesting)
141{
142 return pNesting->pCurrentNesting == &pNesting->pArrays[0] ? 0 : 1;
143}
144
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700145
146
147
148/*
149 Error tracking plan -- Errors are tracked internally and not returned
150 until Finish is called. The CBOR errors are in me->uError.
151 UsefulOutBuf also tracks whether the the buffer is full or not in its
152 context. Once either of these errors is set they are never
153 cleared. Only Init() resets them. Or said another way, they must
154 never be cleared or we'll tell the caller all is good when it is not.
155
156 Only one error code is reported by Finish() even if there are
157 multiple errors. The last one set wins. The caller might have to fix
158 one error to reveal the next one they have to fix. This is OK.
159
160 The buffer full error tracked by UsefulBuf is only pulled out of
161 UsefulBuf in Finish() so it is the one that usually wins. UsefulBuf
162 will never go off the end of the buffer even if it is called again
163 and again when full.
164
165 It is really tempting to not check for overflow on the count in the
166 number of items in an array. It would save a lot of code, it is
167 extremely unlikely that any one will every put 65,000 items in an
168 array, and the only bad thing that would happen is the CBOR would be
169 bogus. Once we prove that is the only consequence, then we can make
170 the change.
171
172 Since this does not parse any input, you could in theory remove all
173 error checks in this code if you knew the caller called it
174 correctly. Maybe someday CDDL or some such language will be able to
175 generate the code to call this and the calling code would always be
Laurence Lundblade56230d12018-11-01 11:14:51 +0700176 correct. This could also automatically size some of the data
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700177 structures like array/map nesting resulting in some good memory
178 savings.
179 */
180
181
182
183
184/*
185 Public function for initialization. See header qcbor.h
186 */
Laurence Lundblade2296db52018-09-14 18:08:39 -0700187void QCBOREncode_Init(QCBOREncodeContext *me, UsefulBuf Storage)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700188{
189 memset(me, 0, sizeof(QCBOREncodeContext));
Laurence Lundblade2296db52018-09-14 18:08:39 -0700190 if(Storage.len > UINT32_MAX) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700191 me->uError = QCBOR_ERR_BUFFER_TOO_LARGE;
192 } else {
Laurence Lundblade2296db52018-09-14 18:08:39 -0700193 UsefulOutBuf_Init(&(me->OutBuf), Storage);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700194 Nesting_Init(&(me->nesting));
195 }
196}
197
198
199
200
201/*
202 All CBOR data items have a type and a number. The number is either
203 the value of the item for integer types, the length of the content
204 for string, byte, array and map types, a tag for major type 6, and
205 has serveral uses for major type 7.
206
207 This function encodes the type and the number. There are several
208 encodings for the number depending on how large it is and how it is
209 used.
210
211 Every encoding of the type and number has at least one byte, the
212 "initial byte".
213
214 The top three bits of the initial byte are the major type for the
215 CBOR data item. The eight major types defined by the standard are
216 defined as CBOR_MAJOR_TYPE_xxxx in qcbor.h.
217
218 The remaining five bits, known as "additional information", and
219 possibly more bytes encode the number. If the number is less than 24,
220 then it is encoded entirely in the five bits. This is neat because it
221 allows you to encode an entire CBOR data item in 1 byte for many
222 values and types (integers 0-23, true, false, and tags).
223
224 If the number is larger than 24, then it is encoded in 1,2,4 or 8
225 additional bytes, with the number of these bytes indicated by the
226 values of the 5 bits 24, 25, 25 and 27.
227
228 It is possible to encode a particular number in many ways with this
229 representation. This implementation always uses the smallest
230 possible representation. This is also the suggestion made in the RFC
231 for cannonical CBOR.
232
233 This function inserts them into the output buffer at the specified
234 position. AppendEncodedTypeAndNumber() appends to the end.
235
236 This function takes care of converting to network byte order.
237
238 This function is also used to insert floats and doubles. Before this
239 function is called the float or double must be copied into a
240 uint64_t. That is how they are passed in. They are then converted to
241 network byte order correctly. The uMinLen param makes sure that even
242 if all the digits of a float or double are 0 it is still correctly
243 encoded in 4 or 8 bytes.
244
245 */
246static void InsertEncodedTypeAndNumber(QCBOREncodeContext *me, uint8_t uMajorType, size_t uMinLen, uint64_t uNumber, size_t uPos)
247{
248 // No need to worry about integer overflow here because a) uMajorType is
249 // always generated internally, not by the caller, b) this is for CBOR
250 // _generation_, not parsing c) a mistake will result in bad CBOR generation,
251 // not a security vulnerability.
Laurence Lundblade56230d12018-11-01 11:14:51 +0700252 uMajorType <<= 5;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700253
254 if(uNumber > 0xffffffff || uMinLen >= 8) {
255 UsefulOutBuf_InsertByte(&(me->OutBuf), uMajorType + LEN_IS_EIGHT_BYTES, uPos);
256 UsefulOutBuf_InsertUint64(&(me->OutBuf), (uint64_t)uNumber, uPos+1);
257
258 } else if(uNumber > 0xffff || uMinLen >= 4) {
259 UsefulOutBuf_InsertByte(&(me->OutBuf), uMajorType + LEN_IS_FOUR_BYTES, uPos);
260 UsefulOutBuf_InsertUint32(&(me->OutBuf), (uint32_t)uNumber, uPos+1);
261
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700262 } else if (uNumber > 0xff || uMinLen>= 2) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700263 // Between 0 and 65535
264 UsefulOutBuf_InsertByte(&(me->OutBuf), uMajorType + LEN_IS_TWO_BYTES, uPos);
265 UsefulOutBuf_InsertUint16(&(me->OutBuf), (uint16_t)uNumber, uPos+1);
266
267 } else if(uNumber >= 24) {
268 // Between 0 and 255, but only between 24 and 255 is ever encoded here
269 UsefulOutBuf_InsertByte(&(me->OutBuf), uMajorType + LEN_IS_ONE_BYTE, uPos);
270 UsefulOutBuf_InsertByte(&(me->OutBuf), (uint8_t)uNumber, uPos+1);
271
272 } else {
273 // Between 0 and 23
274 UsefulOutBuf_InsertByte(&(me->OutBuf), uMajorType + (uint8_t)uNumber, uPos);
275 }
276}
277
278
279/*
280 Append the type and number info to the end of the buffer.
281
282 See InsertEncodedTypeAndNumber() function above for details
283*/
284inline static void AppendEncodedTypeAndNumber(QCBOREncodeContext *me, uint8_t uMajorType, uint64_t uNumber)
285{
286 // An append is an insert at the end.
287 InsertEncodedTypeAndNumber(me, uMajorType, 0, uNumber, UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
288}
289
290
Laurence Lundblade55a24832018-10-30 04:35:08 +0700291
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700292
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700293/*
Laurence Lundblade55a24832018-10-30 04:35:08 +0700294 Internal function for adding positive and negative integers of all different sizes
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700295 */
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700296void InsertInt64(QCBOREncodeContext *me, int64_t nNum, size_t uPos)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700297{
Laurence Lundblade55a24832018-10-30 04:35:08 +0700298 uint8_t uMajorType;
299 uint64_t uValue;
300
301 if(nNum < 0) {
302 uValue = (uint64_t)(-nNum - 1); // This is the way negative ints work in CBOR. -1 encodes as 0x00 with major type negative int.
303 uMajorType = CBOR_MAJOR_TYPE_NEGATIVE_INT;
304 } else {
305 uValue = (uint64_t)nNum;
306 uMajorType = CBOR_MAJOR_TYPE_POSITIVE_INT;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700307 }
Laurence Lundblade55a24832018-10-30 04:35:08 +0700308
309 InsertEncodedTypeAndNumber(me, uMajorType, 0, uValue, uPos);
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700310 me->uError = Nesting_Increment(&(me->nesting), 1);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700311}
312
Laurence Lundblade56230d12018-11-01 11:14:51 +0700313
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700314/*
315 Does the work of adding some bytes to the CBOR output. Works for a
316 byte and text strings, which are the same in in CBOR though they have
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700317 different major types. This is also used to insert raw
318 pre-encoded CBOR.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700319 */
Laurence Lundblade56230d12018-11-01 11:14:51 +0700320static void AddBufferInternal(QCBOREncodeContext *me, UsefulBufC Bytes, uint8_t uMajorType, size_t uPos)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700321{
322 if(Bytes.len >= UINT32_MAX) {
Laurence Lundblade56230d12018-11-01 11:14:51 +0700323 // This implementation doesn't allow buffers larger than UINT32_MAX.
324 // This is primarily because QCBORTrackNesting.pArrays[].uStart is
325 // an uint32 rather than size_t to keep the stack usage down. Also
326 // it is entirely impractical to create tokens bigger than 4GB in
327 // contiguous RAM
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700328 me->uError = QCBOR_ERR_BUFFER_TOO_LARGE;
329
330 } else {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700331 if(!me->uError) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700332 // If it is not Raw CBOR, add the type and the length
333 if(uMajorType != CBOR_MAJOR_NONE_TYPE_RAW) {
Laurence Lundblade56230d12018-11-01 11:14:51 +0700334 const size_t uPosBeforeInsert = UsefulOutBuf_GetEndPosition(&(me->OutBuf));
Laurence Lundblade55a24832018-10-30 04:35:08 +0700335 InsertEncodedTypeAndNumber(me, uMajorType, 0, Bytes.len, uPos);
Laurence Lundblade56230d12018-11-01 11:14:51 +0700336 // The increment in uPos is to account for bytes added for
337 // type and number so the buffer being added goes to the
338 // right place
339 uPos += UsefulOutBuf_GetEndPosition(&(me->OutBuf)) - uPosBeforeInsert;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700340 }
341
342 // Actually add the bytes
Laurence Lundblade55a24832018-10-30 04:35:08 +0700343 UsefulOutBuf_InsertUsefulBuf(&(me->OutBuf), Bytes, uPos);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700344
345 // Update the array counting if there is any nesting at all
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700346 me->uError = Nesting_Increment(&(me->nesting), 1);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700347 }
348 }
349}
350
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700351
Laurence Lundblade55a24832018-10-30 04:35:08 +0700352/*
353 Add an optional label. It will go in front of a real data item.
354 */
Laurence Lundblade55a24832018-10-30 04:35:08 +0700355static void AddLabel(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel)
356{
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700357 size_t uPos = UsefulOutBuf_GetEndPosition(&(me->OutBuf));
358 if(Nesting_GetMajorType(&(me->nesting)) == CBOR_MAJOR_NONE_TAG_LABEL_REORDER) {
359 // Have to insert the label rather than just appen if a tag
360 // has been added. This is so the tag ends up on the value, not
361 // on the label.
Laurence Lundblade55a24832018-10-30 04:35:08 +0700362 uPos = Nesting_GetStartPos(&(me->nesting));
363 Nesting_Decrease(&(me->nesting));
364 }
365
366 if(szLabel) {
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700367 const UsefulBufC SZText = UsefulBuf_FromSZ(szLabel);
Laurence Lundblade56230d12018-11-01 11:14:51 +0700368 AddBufferInternal(me, SZText, CBOR_MAJOR_TYPE_TEXT_STRING, uPos);
Laurence Lundblade55a24832018-10-30 04:35:08 +0700369 } else if (QCBOR_NO_INT_LABEL != nLabel) {
370 InsertInt64(me, nLabel, uPos);
371 }
372}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700373
374
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700375/*
Laurence Lundblade55a24832018-10-30 04:35:08 +0700376 Public Function
377 */
378void QCBOREncode_AddTag(QCBOREncodeContext *me, uint64_t uTag)
379{
380 uint8_t uNestingType = Nesting_GetMajorType(&(me->nesting));
Laurence Lundblade56230d12018-11-01 11:14:51 +0700381 if(uNestingType == CBOR_MAJOR_TYPE_MAP || uNestingType == CBOR_MAJOR_TYPE_ARRAY) {
Laurence Lundblade55a24832018-10-30 04:35:08 +0700382 // Remember where the first tag is for this item
383 // So we can go back and insert the label in front of it.
Laurence Lundblade56230d12018-11-01 11:14:51 +0700384 // Cast to uint32_t here OK as all inputs are limited to 4GB
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700385 const uint32_t uPos = (uint32_t)UsefulOutBuf_GetEndPosition(&(me->OutBuf));
386 me->uError = Nesting_Increase(&(me->nesting), CBOR_MAJOR_NONE_TAG_LABEL_REORDER, uPos);
Laurence Lundblade55a24832018-10-30 04:35:08 +0700387 }
388
389 AppendEncodedTypeAndNumber(me, CBOR_MAJOR_TYPE_OPTIONAL, uTag);
390}
391
392
Laurence Lundblade56230d12018-11-01 11:14:51 +0700393/*
394 Semi-public interface. Called by inline functions to add text and byte strings
395 and already-encoded CBOR. They are the real public interface, even though this
396 is the main entry point. The code is structured like this to reduce code size.
397 */
398void QCBOREncode_AddBuffer_2(QCBOREncodeContext *me, uint8_t uMajorType, const char *szLabel, int64_t nLabel, UsefulBufC Bytes)
Laurence Lundblade55a24832018-10-30 04:35:08 +0700399{
400 AddLabel(me, szLabel, nLabel);
401 if(!me->uError) {
Laurence Lundblade56230d12018-11-01 11:14:51 +0700402 AddBufferInternal(me, Bytes, uMajorType, UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
Laurence Lundblade55a24832018-10-30 04:35:08 +0700403 }
404}
405
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700406
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700407/*
Laurence Lundblade56230d12018-11-01 11:14:51 +0700408 Semi-public interfaced. Called by inline functions to open arrays, maps and
409 bstr wrapped CBOR. They are the real public interface, even though this is the
410 main entry point. This code is structured like this to reduce code size.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700411 */
Laurence Lundblade56230d12018-11-01 11:14:51 +0700412void QCBOREncode_OpenMapOrArray_2(QCBOREncodeContext *me, uint8_t uMajorType, const char *szLabel, uint64_t nLabel)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700413{
Laurence Lundblade55a24832018-10-30 04:35:08 +0700414 AddLabel(me, szLabel, nLabel);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700415
416 if(!me->uError) {
417 // Add one item to the nesting level we are in for the new map or array
418 me->uError = Nesting_Increment(&(me->nesting), 1);
419 if(!me->uError) {
420 // Increase nesting level because this is a map or array
421 // Cast from size_t to uin32_t is safe because the UsefulOutBuf
422 // size is limited to UINT32_MAX in QCBOR_Init().
Laurence Lundbladea954db92018-09-28 19:27:31 -0700423 me->uError = Nesting_Increase(&(me->nesting), uMajorType, (uint32_t)UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700424 }
425 }
426}
427
428
429/*
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700430 Public functions for closing arrays and maps. See header qcbor.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700431 */
Laurence Lundbladea954db92018-09-28 19:27:31 -0700432void QCBOREncode_Close(QCBOREncodeContext *me, uint8_t uMajorType, UsefulBufC *pWrappedCBOR)
433{
434 if(!me->uError) {
435 if(!Nesting_IsInNest(&(me->nesting))) {
436 me->uError = QCBOR_ERR_TOO_MANY_CLOSES;
437 } else if( Nesting_GetMajorType(&(me->nesting)) != uMajorType) {
438 me->uError = QCBOR_ERR_CLOSE_MISMATCH;
439 } else {
Laurence Lundblade56230d12018-11-01 11:14:51 +0700440 // When the array, map or bstr wrap was started, nothing was done
441 // except note the position of the start of it. This code goes back
442 // and inserts the actual CBOR array, map or bstr and its length.
443 // That means all the data that is in the array, map or wrapped
444 // needs to be slid to the right. This is done by UsefulOutBuf's
445 // insert function that is called from inside
446 // InsertEncodedTypeAndNumber()
447 const size_t uInsertPosition = Nesting_GetStartPos(&(me->nesting));
448 const size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf));
449 // This can't go negative because the UsefulOutBuf always only grows
450 // and never shrinks. UsefulOutBut itself also has defenses such that
451 // it won't write were it should not even if given hostile input lengths
452 const size_t uLenOfEncodedMapOrArray = uEndPosition - uInsertPosition;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700453
Laurence Lundblade56230d12018-11-01 11:14:51 +0700454 // Length is number of bytes for a bstr and number of items a for map & array
455 const size_t uLength = uMajorType == CBOR_MAJOR_TYPE_BYTE_STRING ?
Laurence Lundbladea954db92018-09-28 19:27:31 -0700456 uLenOfEncodedMapOrArray : Nesting_GetCount(&(me->nesting));
457
458 // Actually insert
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700459 InsertEncodedTypeAndNumber(me,
Laurence Lundbladea954db92018-09-28 19:27:31 -0700460 uMajorType, // major type bstr, array or map
461 0, // no minimum length for encoding
462 uLength, // either len of bstr or num items in array or map
463 uInsertPosition); // position in out buffer
464
465 // Return pointer and length to the enclosed encoded CBOR. The intended
466 // use is for it to be hashed (e.g., SHA-256) in a COSE implementation.
467 // This must be used right away, as the pointer and length go invalid
468 // on any subsequent calls to this function because of the
469 // InsertEncodedTypeAndNumber() call that slides data to the right.
470 if(pWrappedCBOR) {
471 UsefulBufC PartialResult = UsefulOutBuf_OutUBuf(&(me->OutBuf));
Laurence Lundblade56230d12018-11-01 11:14:51 +0700472 size_t uBstrLen = UsefulOutBuf_GetEndPosition(&(me->OutBuf)) - uEndPosition;
Laurence Lundbladea954db92018-09-28 19:27:31 -0700473 *pWrappedCBOR = UsefulBuf_Tail(PartialResult, uInsertPosition+uBstrLen);
474 }
475 Nesting_Decrease(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700476 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700477 }
478}
479
480
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700481/*
Laurence Lundblade55a24832018-10-30 04:35:08 +0700482 Public functions for adding integers. See header qcbor.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700483 */
Laurence Lundblade55a24832018-10-30 04:35:08 +0700484void QCBOREncode_AddUInt64_2(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uNum)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700485{
Laurence Lundblade55a24832018-10-30 04:35:08 +0700486 AddLabel(me, szLabel, nLabel);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700487 if(!me->uError) {
Laurence Lundblade55a24832018-10-30 04:35:08 +0700488 AppendEncodedTypeAndNumber(me, CBOR_MAJOR_TYPE_POSITIVE_INT, uNum);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700489 me->uError = Nesting_Increment(&(me->nesting), 1);
490 }
491}
492
Laurence Lundblade56230d12018-11-01 11:14:51 +0700493
494/*
495 Public functions for adding integers. See header qcbor.h
496 */
Laurence Lundblade55a24832018-10-30 04:35:08 +0700497void QCBOREncode_AddInt64_2(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, int64_t nNum)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700498{
Laurence Lundblade55a24832018-10-30 04:35:08 +0700499 AddLabel(me, szLabel, nLabel);
500 if(!me->uError) {
Laurence Lundblade56230d12018-11-01 11:14:51 +0700501 // Cast is OK here because the output buffer is limited to 4GB in Init().
Laurence Lundblade55a24832018-10-30 04:35:08 +0700502 InsertInt64(me, nNum, (uint32_t)UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700503 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700504}
505
506
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700507/*
Laurence Lundblade56230d12018-11-01 11:14:51 +0700508 Semi-public interfaced. Called by inline functions to add simple and float
509 types. They are the real public interface, even though this is the
510 main entry point. This code is structured like this to reduce code size.
511
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700512 Common code for adding floats and doubles and simple types like true and false
513
514 One way to look at simple values is that they are:
515 - type 7
516 - an additional integer from 0 to 255
517 - additional integer 0-19 are unassigned and could be used in an update to CBOR
518 - additional integers 20, 21, 22 and 23 are false, true, null and undef
519 - additional integer 24 is not available
520 - when the additional value is 25, 26, or 27 there is additionally a half, float or double in following bytes
521 - additional integers 28, 29 and 30 are unassigned / reserved
522 - additional integer 31 is a "break"
523 - additional integers 32-255 are unassigned and could be used in an update to CBOR
524 */
Laurence Lundblade56230d12018-11-01 11:14:51 +0700525void QCBOREncode_AddType7_2(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, size_t uSize, uint64_t uNum)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700526{
Laurence Lundblade55a24832018-10-30 04:35:08 +0700527 AddLabel(me, szLabel, nLabel);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700528 if(!me->uError) {
529 // This function call takes care of endian swapping for the float / double
530 InsertEncodedTypeAndNumber(me,
Laurence Lundblade56230d12018-11-01 11:14:51 +0700531 CBOR_MAJOR_TYPE_SIMPLE, // The major type for
532 // floats and doubles
533 uSize, // min size / tells
534 // encoder to do it right
535 uNum, // Bytes of the floating
536 // point number as a uint
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700537 UsefulOutBuf_GetEndPosition(&(me->OutBuf))); // end position for append
538
539 me->uError = Nesting_Increment(&(me->nesting), 1);
540 }
541}
542
543
544/*
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700545 Public functions for floating point numbers. See header qcbor.h
546 */
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700547void QCBOREncode_AddFloat_2(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, float fNum)
Laurence Lundblade56230d12018-11-01 11:14:51 +0700548{
549 QCBOREncode_AddType7_2(me, szLabel, nLabel, sizeof(float), UsefulBufUtil_CopyFloatToUint32(fNum));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700550}
551
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700552void QCBOREncode_AddDouble_2(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, double dNum)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700553{
Laurence Lundblade56230d12018-11-01 11:14:51 +0700554 QCBOREncode_AddType7_2(me, szLabel, nLabel, sizeof(double), UsefulBufUtil_CopyDoubleToUint64(dNum));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700555}
556
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700557void QCBOREncode_AddFloatAsHalf_2(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, float fNum)
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700558{
Laurence Lundblade56230d12018-11-01 11:14:51 +0700559 QCBOREncode_AddType7_2(me, szLabel, nLabel, sizeof(uint16_t), IEEE754_FloatToHalf(fNum));
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700560}
561
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700562static void QCBOREncode_AddFUnionAsSmallest_2(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, IEEE754_union uNum)
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700563{
564 switch(uNum.uTag) {
565 case IEEE754_UNION_IS_HALF:
Laurence Lundblade56230d12018-11-01 11:14:51 +0700566 QCBOREncode_AddType7_2(me, szLabel, nLabel, sizeof(uint16_t), uNum.u16);
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700567 break;
568 case IEEE754_UNION_IS_SINGLE:
Laurence Lundblade56230d12018-11-01 11:14:51 +0700569 QCBOREncode_AddType7_2(me, szLabel, nLabel, sizeof(uint32_t), uNum.u32);
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700570 break;
571 case IEEE754_UNION_IS_DOUBLE:
Laurence Lundblade56230d12018-11-01 11:14:51 +0700572 QCBOREncode_AddType7_2(me, szLabel, nLabel, sizeof(uint64_t), uNum.u64);
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700573 break;
574 }
575}
576
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700577void QCBOREncode_AddFloatAsSmallest_2(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, float fNum)
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700578{
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700579 QCBOREncode_AddFUnionAsSmallest_2(me, szLabel, nLabel, IEEE754_FloatToSmallest(fNum));
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700580}
581
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700582void QCBOREncode_AddDoubleAsSmallest_2(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, double dNum)
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700583{
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700584 QCBOREncode_AddFUnionAsSmallest_2(me, szLabel, nLabel, IEEE754_DoubleToSmallest(dNum));
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700585}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700586
587
588
Laurence Lundblade56230d12018-11-01 11:14:51 +0700589
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700590/*
591 Public functions to finish and get the encoded result. See header qcbor.h
592 */
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700593int QCBOREncode_Finish2(QCBOREncodeContext *me, UsefulBufC *pEncodedCBOR)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700594{
595 if(me->uError)
596 goto Done;
597
598 if (Nesting_IsInNest(&(me->nesting))) {
599 me->uError = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
600 goto Done;
601 }
602
603 if(UsefulOutBuf_GetError(&(me->OutBuf))) {
604 // Stuff didn't fit in the buffer.
Laurence Lundblade56230d12018-11-01 11:14:51 +0700605 // This check catches this condition for all the appends and inserts
606 // so checks aren't needed when the appends and inserts are performed.
607 // And of course UsefulBuf will never overrun the input buffer given
608 // to it. No complex analysis of the error handling in this file is
609 // needed to know that is true. Just read the UsefulBuf code.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700610 me->uError = QCBOR_ERR_BUFFER_TOO_SMALL;
611 goto Done;
612 }
Laurence Lundblade2296db52018-09-14 18:08:39 -0700613
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700614 *pEncodedCBOR = UsefulOutBuf_OutUBuf(&(me->OutBuf));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700615
616Done:
617 return me->uError;
618}
619
620int QCBOREncode_Finish(QCBOREncodeContext *me, size_t *puEncodedLen)
621{
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700622 UsefulBufC Enc;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700623
624 int nReturn = QCBOREncode_Finish2(me, &Enc);
625
626 if(nReturn == QCBOR_SUCCESS) {
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700627 *puEncodedLen = Enc.len;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700628 }
629
630 return nReturn;
631}
632
633