blob: 05e376b660cfd271d5c4378e26529c49d0b9f36a [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 Lundblade3aee3a32018-12-17 16:17:45 -08005
Laurence Lundblade0dbc9172018-11-01 14:17:21 +07006Redistribution and use in source and binary forms, with or without
7modification, are permitted provided that the following conditions are
8met:
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 Lundblade3aee3a32018-12-17 16:17:45 -080019
Laurence Lundblade0dbc9172018-11-01 14:17:21 +070020THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
21WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
23ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
24BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
27BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
29OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
30IF 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
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080035
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070036 DESCRIPTION: This file contains the implementation of QCBOR.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080037
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070038 EDIT HISTORY FOR FILE:
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080039
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070040 This section contains comments describing changes made to the module.
41 Notice that changes are listed in reverse chronological order.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080042
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070043 when who what, where, why
44 -------- ---- ---------------------------------------------------
Laurence Lundblade9c097392018-12-30 13:52:24 -080045 12/30/18 llundblade Small efficient clever encode of type & argument.
Laurence Lundblade067035b2018-11-28 17:35:25 -080046 11/29/18 llundblade Rework to simpler handling of tags and labels.
47 11/9/18 llundblade Error codes are now enums.
48 11/1/18 llundblade Floating support.
49 10/31/18 llundblade Switch to one license that is almost BSD-3.
50 09/28/18 llundblade Added bstr wrapping feature for COSE implementation.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080051 02/05/18 llundbla Works on CPUs which require integer alignment.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070052 Requires new version of UsefulBuf.
53 07/05/17 llundbla Add bstr wrapping of maps/arrays for COSE
54 03/01/17 llundbla More data types
55 11/13/16 llundbla Integrate most TZ changes back into github version.
56 09/30/16 gkanike Porting to TZ.
57 03/15/16 llundbla Initial Version.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080058
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070059 =====================================================================================*/
60
61#include "qcbor.h"
Laurence Lundblade12d32c52018-09-19 11:25:27 -070062#include "ieee754.h"
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070063
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070064
65/*...... This is a ruler that is 80 characters long...........................*/
66
67
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070068/*
69 CBOR's two nesting types, arrays and maps, are tracked here. There is a
70 limit of QCBOR_MAX_ARRAY_NESTING to the number of arrays and maps
71 that can be nested in one encoding so the encoding context stays
72 small enough to fit on the stack.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080073
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070074 When an array / map is opened, pCurrentNesting points to the element
75 in pArrays that records the type, start position and accumluates a
76 count of the number of items added. When closed the start position is
77 used to go back and fill in the type and number of items in the array
78 / map.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080079
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070080 Encoded output be just items like ints and strings that are
81 not part of any array / map. That is, the first thing encoded
82 does not have to be an array or a map.
83 */
84inline static void Nesting_Init(QCBORTrackNesting *pNesting)
85{
86 // assumes pNesting has been zeroed
87 pNesting->pCurrentNesting = &pNesting->pArrays[0];
88 // Implied CBOR array at the top nesting level. This is never returned,
89 // but makes the item count work correctly.
90 pNesting->pCurrentNesting->uMajorType = CBOR_MAJOR_TYPE_ARRAY;
91}
92
Laurence Lundblade30816f22018-11-10 13:40:22 +070093inline static QCBORError Nesting_Increase(QCBORTrackNesting *pNesting, uint8_t uMajorType, uint32_t uPos)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070094{
Laurence Lundblade30816f22018-11-10 13:40:22 +070095 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080096
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070097 if(pNesting->pCurrentNesting == &pNesting->pArrays[QCBOR_MAX_ARRAY_NESTING]) {
98 // trying to open one too many
99 nReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
100 } else {
101 pNesting->pCurrentNesting++;
102 pNesting->pCurrentNesting->uCount = 0;
103 pNesting->pCurrentNesting->uStart = uPos;
104 pNesting->pCurrentNesting->uMajorType = uMajorType;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700105 }
106 return nReturn;
107}
108
109inline static void Nesting_Decrease(QCBORTrackNesting *pNesting)
110{
111 pNesting->pCurrentNesting--;
112}
113
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800114inline static QCBORError Nesting_Increment(QCBORTrackNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700115{
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800116 if(1 >= QCBOR_MAX_ITEMS_IN_ARRAY - pNesting->pCurrentNesting->uCount) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700117 return QCBOR_ERR_ARRAY_TOO_LONG;
118 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800119
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800120 pNesting->pCurrentNesting->uCount += 1;
Laurence Lundblade16619232018-12-30 14:02:24 -0800121
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700122 return QCBOR_SUCCESS;
123}
124
125inline static uint16_t Nesting_GetCount(QCBORTrackNesting *pNesting)
126{
127 // The nesting count recorded is always the actual number of individiual
128 // data items in the array or map. For arrays CBOR uses the actual item
129 // count. For maps, CBOR uses the number of pairs. This function returns
130 // the number needed for the CBOR encoding, so it divides the number of
131 // items by two for maps to get the number of pairs. This implementation
132 // takes advantage of the map major type being one larger the array major
133 // type, hence the subtraction returns either 1 or 2.
134 return pNesting->pCurrentNesting->uCount / (pNesting->pCurrentNesting->uMajorType - CBOR_MAJOR_TYPE_ARRAY+1);
135}
136
137inline static uint32_t Nesting_GetStartPos(QCBORTrackNesting *pNesting)
138{
139 return pNesting->pCurrentNesting->uStart;
140}
141
142inline static uint8_t Nesting_GetMajorType(QCBORTrackNesting *pNesting)
143{
144 return pNesting->pCurrentNesting->uMajorType;
145}
146
147inline static int Nesting_IsInNest(QCBORTrackNesting *pNesting)
148{
149 return pNesting->pCurrentNesting == &pNesting->pArrays[0] ? 0 : 1;
150}
151
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700152
153
154
155/*
156 Error tracking plan -- Errors are tracked internally and not returned
157 until Finish is called. The CBOR errors are in me->uError.
Laurence Lundblade067035b2018-11-28 17:35:25 -0800158 UsefulOutBuf also tracks whether the buffer is full or not in its
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700159 context. Once either of these errors is set they are never
160 cleared. Only Init() resets them. Or said another way, they must
161 never be cleared or we'll tell the caller all is good when it is not.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800162
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700163 Only one error code is reported by Finish() even if there are
164 multiple errors. The last one set wins. The caller might have to fix
165 one error to reveal the next one they have to fix. This is OK.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800166
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700167 The buffer full error tracked by UsefulBuf is only pulled out of
168 UsefulBuf in Finish() so it is the one that usually wins. UsefulBuf
169 will never go off the end of the buffer even if it is called again
170 and again when full.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800171
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700172 It is really tempting to not check for overflow on the count in the
173 number of items in an array. It would save a lot of code, it is
174 extremely unlikely that any one will every put 65,000 items in an
175 array, and the only bad thing that would happen is the CBOR would be
176 bogus. Once we prove that is the only consequence, then we can make
177 the change.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800178
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700179 Since this does not parse any input, you could in theory remove all
180 error checks in this code if you knew the caller called it
181 correctly. Maybe someday CDDL or some such language will be able to
182 generate the code to call this and the calling code would always be
Laurence Lundblade56230d12018-11-01 11:14:51 +0700183 correct. This could also automatically size some of the data
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700184 structures like array/map nesting resulting in some good memory
185 savings.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800186
Laurence Lundblade067035b2018-11-28 17:35:25 -0800187 Errors returned here fall into three categories:
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800188
Laurence Lundblade067035b2018-11-28 17:35:25 -0800189 Sizes
190 QCBOR_ERR_BUFFER_TOO_LARGE -- A buffer passed in > UINT32_MAX
191 QCBOR_ERR_BUFFER_TOO_SMALL -- output buffer too small
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800192
Laurence Lundblade067035b2018-11-28 17:35:25 -0800193 QCBOR_ERR_ARRAY_NESTING_TOO_DEEP -- Too many opens without closes
194 QCBOR_ERR_ARRAY_TOO_LONG -- Too many things added to an array/map
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800195
Laurence Lundblade067035b2018-11-28 17:35:25 -0800196 Nesting constructed incorrectly
197 QCBOR_ERR_TOO_MANY_CLOSES -- more close calls than opens
198 QCBOR_ERR_CLOSE_MISMATCH -- Type of close does not match open
199 QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN -- Finish called without enough closes
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800200
Laurence Lundblade067035b2018-11-28 17:35:25 -0800201 Bad data
202 QCBOR_ERR_BAD_SIMPLE -- Simple value integer not valid
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800203
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700204 */
205
206
207
208
209/*
210 Public function for initialization. See header qcbor.h
211 */
Laurence Lundblade2296db52018-09-14 18:08:39 -0700212void QCBOREncode_Init(QCBOREncodeContext *me, UsefulBuf Storage)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700213{
214 memset(me, 0, sizeof(QCBOREncodeContext));
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800215 UsefulOutBuf_Init(&(me->OutBuf), Storage);
216 Nesting_Init(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700217}
218
219
220
221
222/*
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800223 All CBOR data items have a type and an "argument". The argument is
224 either the value of the item for integer types, the length of the
225 content for string, byte, array and map types, a tag for major type
226 6, and has several uses for major type 7.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700227
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800228 This function encodes the type and the argument. There are several
229 encodings for the argument depending on how large it is and how it is
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700230 used.
231
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800232 Every encoding of the type and argument has at least one byte, the
Laurence Lundblade16619232018-12-30 14:02:24 -0800233>>>>>>> origin/smallinsert
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700234 "initial byte".
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800235
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700236 The top three bits of the initial byte are the major type for the
237 CBOR data item. The eight major types defined by the standard are
238 defined as CBOR_MAJOR_TYPE_xxxx in qcbor.h.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800239
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700240 The remaining five bits, known as "additional information", and
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800241 possibly more bytes encode the argument. If the argument is less than
242 24, then it is encoded entirely in the five bits. This is neat
243 because it allows you to encode an entire CBOR data item in 1 byte
244 for many values and types (integers 0-23, true, false, and tags).
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700245
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800246 If the argument is larger than 24, then it is encoded in 1,2,4 or 8
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700247 additional bytes, with the number of these bytes indicated by the
248 values of the 5 bits 24, 25, 25 and 27.
249
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800250 It is possible to encode a particular argument in many ways with this
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700251 representation. This implementation always uses the smallest
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800252 possible representation. This conforms with CBOR preferred encoding.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700253
254 This function inserts them into the output buffer at the specified
Laurence Lundblade067035b2018-11-28 17:35:25 -0800255 position. AppendEncodedTypeAndNumber() appends to the end.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800256
257 This function takes care of converting to network byte order.
258
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700259 This function is also used to insert floats and doubles. Before this
260 function is called the float or double must be copied into a
261 uint64_t. That is how they are passed in. They are then converted to
262 network byte order correctly. The uMinLen param makes sure that even
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800263
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800264 if all the digits of a half, float or double are 0 it is still
265 correctly encoded in 2, 4 or 8 bytes.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700266 */
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800267
268static void InsertEncodedTypeAndNumber(QCBOREncodeContext *me,
269 uint8_t uMajorType,
270 int nMinLen,
271 uint64_t uNumber,
272 size_t uPos)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700273{
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800274 /*
275 This code does endian conversion without hton or knowing the
276 endianness of the machine using masks and shifts. this avoids the
277 dependency on hton and the mess of figuring out how to find the
278 machine's endianness.
279
280 This is a good efficient implementation on little-endian machines.
281 A faster and small implementation is possible on big-endian
282 machines because CBOR/network byte order is big endian. However
283 big endian machines are uncommon.
284
285 On x86, it is about 200 bytes instead of 500 bytes for the more
286 formal unoptimized code.
287
288 This also does the CBOR preferred shortest encoding for integers
289 and is called to do endian conversion for floats.
290
291 It works backwards from the LSB to the MSB as needed.
292
293 Code Reviewers: THIS FUNCTION DOES POINTER MATH
294 */
295 // Holds up to 9 bytes of type and argument
296 // plus one extra so pointer always points to
297 // valid bytes.
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800298 uint8_t bytes[sizeof(uint64_t)+2];
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800299 // Point to the last bytes and work backwards
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800300 uint8_t *pByte = &bytes[sizeof(bytes)-1];
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800301 // This is the 5 bits in the initial byte that is not the major type
302 uint8_t uAdditionalInfo;
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800303
304 if(uNumber < CBOR_TWENTY_FOUR && nMinLen == 0) {
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800305 // Simple case where argument is < 24
306 uAdditionalInfo = uNumber;
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800307 } else {
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800308 /*
309 Encode argument in 1,2,4 or 8 bytes. Outer loop
310 runs once for 1 byte and 4 times for 8 bytes.
311 Inner loop runs 1, 2 or 4 times depending on
312 outer loop counter. This works backwards taking
313 8 bits off the argument being encoded at a time
314 until all bits from uNumber have been encoded
315 and the minimum encoding size is reached.
316 Minimum encoding size is for floating point
317 numbers with zero bytes correctly.
318 */
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800319 static const uint8_t aIterate[] = {1,1,2,4};
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800320 uint8_t i;
321 for(i = 0; uNumber || nMinLen > 0; i++) {
322 const uint8_t uIterations = aIterate[i];
323 for(int j = 0; j < uIterations; j++) {
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800324 *--pByte = uNumber & 0xff;
325 uNumber = uNumber >> 8;
326 }
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800327 nMinLen -= uIterations;
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800328 }
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800329 // Additional info is the encoding of the
330 // number of additional bytes to encode
331 // argument.
332 uAdditionalInfo = LEN_IS_ONE_BYTE-1 + i;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700333 }
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800334 *--pByte = (uMajorType << 5) + uAdditionalInfo;
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800335
336 UsefulOutBuf_InsertData(&(me->OutBuf), pByte, &bytes[sizeof(bytes)-1] - pByte, uPos);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700337}
338
339
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700340
341
342/*
343 Append the type and number info to the end of the buffer.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800344
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700345 See InsertEncodedTypeAndNumber() function above for details
346*/
347inline static void AppendEncodedTypeAndNumber(QCBOREncodeContext *me, uint8_t uMajorType, uint64_t uNumber)
348{
349 // An append is an insert at the end.
350 InsertEncodedTypeAndNumber(me, uMajorType, 0, uNumber, UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
351}
352
353
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700354
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700355/*
Laurence Lundblade067035b2018-11-28 17:35:25 -0800356 Public functions for closing arrays and maps. See header qcbor.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700357 */
Laurence Lundblade067035b2018-11-28 17:35:25 -0800358void QCBOREncode_AddUInt64(QCBOREncodeContext *me, uint64_t uValue)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700359{
Laurence Lundblade067035b2018-11-28 17:35:25 -0800360 if(me->uError == QCBOR_SUCCESS) {
361 AppendEncodedTypeAndNumber(me, CBOR_MAJOR_TYPE_POSITIVE_INT, uValue);
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800362 me->uError = Nesting_Increment(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700363 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700364}
365
Laurence Lundblade56230d12018-11-01 11:14:51 +0700366
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700367/*
Laurence Lundblade067035b2018-11-28 17:35:25 -0800368 Public functions for closing arrays and maps. See header qcbor.h
369 */
370void QCBOREncode_AddInt64(QCBOREncodeContext *me, int64_t nNum)
371{
372 if(me->uError == QCBOR_SUCCESS) {
373 uint8_t uMajorType;
374 uint64_t uValue;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800375
Laurence Lundblade067035b2018-11-28 17:35:25 -0800376 if(nNum < 0) {
377 uValue = (uint64_t)(-nNum - 1); // This is the way negative ints work in CBOR. -1 encodes as 0x00 with major type negative int.
378 uMajorType = CBOR_MAJOR_TYPE_NEGATIVE_INT;
379 } else {
380 uValue = (uint64_t)nNum;
381 uMajorType = CBOR_MAJOR_TYPE_POSITIVE_INT;
382 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800383
Laurence Lundblade067035b2018-11-28 17:35:25 -0800384 AppendEncodedTypeAndNumber(me, uMajorType, uValue);
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800385 me->uError = Nesting_Increment(&(me->nesting));
Laurence Lundblade067035b2018-11-28 17:35:25 -0800386 }
387}
388
389
390/*
391 Semi-private function. It is exposed to user of the interface,
392 but they will usually call one of the inline wrappers rather than this.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800393
Laurence Lundblade067035b2018-11-28 17:35:25 -0800394 See header qcbor.h
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800395
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700396 Does the work of adding some bytes to the CBOR output. Works for a
397 byte and text strings, which are the same in in CBOR though they have
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700398 different major types. This is also used to insert raw
399 pre-encoded CBOR.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700400 */
Laurence Lundblade067035b2018-11-28 17:35:25 -0800401void QCBOREncode_AddBuffer(QCBOREncodeContext *me, uint8_t uMajorType, UsefulBufC Bytes)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700402{
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800403 if(!me->uError) {
404 // If it is not Raw CBOR, add the type and the length
405 if(uMajorType != CBOR_MAJOR_NONE_TYPE_RAW) {
406 AppendEncodedTypeAndNumber(me, uMajorType, Bytes.len);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700407 }
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800408
409 // Actually add the bytes
410 UsefulOutBuf_AppendUsefulBuf(&(me->OutBuf), Bytes);
411
412 // Update the array counting if there is any nesting at all
413 me->uError = Nesting_Increment(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700414 }
415}
416
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700417
Laurence Lundblade55a24832018-10-30 04:35:08 +0700418/*
Laurence Lundblade067035b2018-11-28 17:35:25 -0800419 Public functions for closing arrays and maps. See header qcbor.h
Laurence Lundblade55a24832018-10-30 04:35:08 +0700420 */
421void QCBOREncode_AddTag(QCBOREncodeContext *me, uint64_t uTag)
422{
Laurence Lundblade55a24832018-10-30 04:35:08 +0700423 AppendEncodedTypeAndNumber(me, CBOR_MAJOR_TYPE_OPTIONAL, uTag);
424}
425
426
Laurence Lundblade487930f2018-11-30 11:01:45 -0800427
428
Laurence Lundblade56230d12018-11-01 11:14:51 +0700429/*
Laurence Lundblade487930f2018-11-30 11:01:45 -0800430 Semi-private function. It is exposed to user of the interface,
431 but they will usually call one of the inline wrappers rather than this.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800432
Laurence Lundblade487930f2018-11-30 11:01:45 -0800433 See header qcbor.h
Laurence Lundblade56230d12018-11-01 11:14:51 +0700434 */
Laurence Lundblade487930f2018-11-30 11:01:45 -0800435void QCBOREncode_AddType7(QCBOREncodeContext *me, size_t uSize, uint64_t uNum)
Laurence Lundblade55a24832018-10-30 04:35:08 +0700436{
Laurence Lundblade487930f2018-11-30 11:01:45 -0800437 if(me->uError == QCBOR_SUCCESS) {
438 // This function call takes care of endian swapping for the float / double
439 InsertEncodedTypeAndNumber(me,
440 CBOR_MAJOR_TYPE_SIMPLE, // The major type for
441 // floats and doubles
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800442 (int)uSize, // min size / tells
Laurence Lundblade487930f2018-11-30 11:01:45 -0800443 // encoder to do it right
444 uNum, // Bytes of the floating
445 // point number as a uint
446 UsefulOutBuf_GetEndPosition(&(me->OutBuf))); // end position for append
447
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800448 me->uError = Nesting_Increment(&(me->nesting));
Laurence Lundblade487930f2018-11-30 11:01:45 -0800449 }
Laurence Lundblade55a24832018-10-30 04:35:08 +0700450}
451
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700452
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700453/*
Laurence Lundblade067035b2018-11-28 17:35:25 -0800454 Public functions for closing arrays and maps. See header qcbor.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700455 */
Laurence Lundblade067035b2018-11-28 17:35:25 -0800456void QCBOREncode_AddDouble(QCBOREncodeContext *me, double dNum)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700457{
Laurence Lundblade067035b2018-11-28 17:35:25 -0800458 const IEEE754_union uNum = IEEE754_DoubleToSmallest(dNum);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800459
Laurence Lundblade487930f2018-11-30 11:01:45 -0800460 QCBOREncode_AddType7(me, uNum.uSize, uNum.uValue);
Laurence Lundblade067035b2018-11-28 17:35:25 -0800461}
462
463
464/*
465 Semi-public function. It is exposed to user of the interface,
466 but they will usually call one of the inline wrappers rather than this.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800467
Laurence Lundblade067035b2018-11-28 17:35:25 -0800468 See header qcbor.h
469*/
470void QCBOREncode_OpenMapOrArray(QCBOREncodeContext *me, uint8_t uMajorType)
471{
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800472 // Add one item to the nesting level we are in for the new map or array
473 me->uError = Nesting_Increment(&(me->nesting));
474 if(!me->uError) {
475 size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf));
476 if(uEndPosition >= UINT32_MAX-sizeof(uint64_t)) {
477 me->uError = QCBOR_ERR_BUFFER_TOO_LARGE;
478 } else {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700479 // Increase nesting level because this is a map or array
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800480 // Cast from size_t to uin32_t is safe because of check above
481 me->uError = Nesting_Increase(&(me->nesting), uMajorType, (uint32_t)uEndPosition);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700482 }
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800483 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700484}
485
486
487/*
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700488 Public functions for closing arrays and maps. See header qcbor.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700489 */
Laurence Lundblade067035b2018-11-28 17:35:25 -0800490void QCBOREncode_CloseMapOrArray(QCBOREncodeContext *me, uint8_t uMajorType, UsefulBufC *pWrappedCBOR)
Laurence Lundbladea954db92018-09-28 19:27:31 -0700491{
492 if(!me->uError) {
493 if(!Nesting_IsInNest(&(me->nesting))) {
494 me->uError = QCBOR_ERR_TOO_MANY_CLOSES;
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800495 } else if(Nesting_GetMajorType(&(me->nesting)) != uMajorType) {
Laurence Lundblade067035b2018-11-28 17:35:25 -0800496 me->uError = QCBOR_ERR_CLOSE_MISMATCH;
Laurence Lundbladea954db92018-09-28 19:27:31 -0700497 } else {
Laurence Lundblade56230d12018-11-01 11:14:51 +0700498 // When the array, map or bstr wrap was started, nothing was done
499 // except note the position of the start of it. This code goes back
500 // and inserts the actual CBOR array, map or bstr and its length.
501 // That means all the data that is in the array, map or wrapped
502 // needs to be slid to the right. This is done by UsefulOutBuf's
503 // insert function that is called from inside
504 // InsertEncodedTypeAndNumber()
505 const size_t uInsertPosition = Nesting_GetStartPos(&(me->nesting));
506 const size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf));
507 // This can't go negative because the UsefulOutBuf always only grows
508 // and never shrinks. UsefulOutBut itself also has defenses such that
509 // it won't write were it should not even if given hostile input lengths
510 const size_t uLenOfEncodedMapOrArray = uEndPosition - uInsertPosition;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800511
Laurence Lundblade56230d12018-11-01 11:14:51 +0700512 // Length is number of bytes for a bstr and number of items a for map & array
513 const size_t uLength = uMajorType == CBOR_MAJOR_TYPE_BYTE_STRING ?
Laurence Lundbladea954db92018-09-28 19:27:31 -0700514 uLenOfEncodedMapOrArray : Nesting_GetCount(&(me->nesting));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800515
Laurence Lundbladea954db92018-09-28 19:27:31 -0700516 // Actually insert
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700517 InsertEncodedTypeAndNumber(me,
Laurence Lundbladea954db92018-09-28 19:27:31 -0700518 uMajorType, // major type bstr, array or map
519 0, // no minimum length for encoding
520 uLength, // either len of bstr or num items in array or map
521 uInsertPosition); // position in out buffer
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800522
Laurence Lundbladea954db92018-09-28 19:27:31 -0700523 // Return pointer and length to the enclosed encoded CBOR. The intended
524 // use is for it to be hashed (e.g., SHA-256) in a COSE implementation.
525 // This must be used right away, as the pointer and length go invalid
526 // on any subsequent calls to this function because of the
527 // InsertEncodedTypeAndNumber() call that slides data to the right.
528 if(pWrappedCBOR) {
Laurence Lundblade25c6c0a2018-12-17 13:21:59 -0800529 const UsefulBufC PartialResult = UsefulOutBuf_OutUBuf(&(me->OutBuf));
530 const size_t uBstrLen = UsefulOutBuf_GetEndPosition(&(me->OutBuf)) - uEndPosition;
Laurence Lundbladea954db92018-09-28 19:27:31 -0700531 *pWrappedCBOR = UsefulBuf_Tail(PartialResult, uInsertPosition+uBstrLen);
532 }
533 Nesting_Decrease(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700534 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700535 }
536}
537
538
Laurence Lundblade56230d12018-11-01 11:14:51 +0700539
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700540/*
541 Public functions to finish and get the encoded result. See header qcbor.h
542 */
Laurence Lundblade30816f22018-11-10 13:40:22 +0700543QCBORError QCBOREncode_Finish(QCBOREncodeContext *me, UsefulBufC *pEncodedCBOR)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700544{
Laurence Lundblade067035b2018-11-28 17:35:25 -0800545 QCBORError uReturn = me->uError;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800546
Laurence Lundblade067035b2018-11-28 17:35:25 -0800547 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700548 goto Done;
Laurence Lundblade067035b2018-11-28 17:35:25 -0800549 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800550
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700551 if (Nesting_IsInNest(&(me->nesting))) {
Laurence Lundblade067035b2018-11-28 17:35:25 -0800552 uReturn = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700553 goto Done;
554 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800555
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700556 if(UsefulOutBuf_GetError(&(me->OutBuf))) {
557 // Stuff didn't fit in the buffer.
Laurence Lundblade56230d12018-11-01 11:14:51 +0700558 // This check catches this condition for all the appends and inserts
559 // so checks aren't needed when the appends and inserts are performed.
560 // And of course UsefulBuf will never overrun the input buffer given
561 // to it. No complex analysis of the error handling in this file is
562 // needed to know that is true. Just read the UsefulBuf code.
Laurence Lundblade067035b2018-11-28 17:35:25 -0800563 uReturn = QCBOR_ERR_BUFFER_TOO_SMALL;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700564 goto Done;
565 }
Laurence Lundblade2296db52018-09-14 18:08:39 -0700566
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700567 *pEncodedCBOR = UsefulOutBuf_OutUBuf(&(me->OutBuf));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800568
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700569Done:
Laurence Lundblade067035b2018-11-28 17:35:25 -0800570 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700571}
572
Laurence Lundblade0595e932018-11-02 22:22:47 +0700573
Laurence Lundblade067035b2018-11-28 17:35:25 -0800574/*
575 Public functions to finish and get the encoded result. See header qcbor.h
576 */
Laurence Lundblade30816f22018-11-10 13:40:22 +0700577QCBORError QCBOREncode_FinishGetSize(QCBOREncodeContext *me, size_t *puEncodedLen)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700578{
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700579 UsefulBufC Enc;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800580
Laurence Lundblade30816f22018-11-10 13:40:22 +0700581 QCBORError nReturn = QCBOREncode_Finish(me, &Enc);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800582
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700583 if(nReturn == QCBOR_SUCCESS) {
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700584 *puEncodedLen = Enc.len;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700585 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800586
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700587 return nReturn;
588}
589
590
Laurence Lundblade067035b2018-11-28 17:35:25 -0800591
592
593/*
594 Notes on the code
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800595
Laurence Lundblade067035b2018-11-28 17:35:25 -0800596 CBOR Major Type Public Function
597 0 QCBOREncode_AddUInt64
598 0, 1 QCBOREncode_AddUInt64, QCBOREncode_AddInt64
599 2, 3 QCBOREncode_AddBuffer, Also QCBOREncode_OpenMapOrArray
600 4, 5 QCBOREncode_OpenMapOrArray
601 6 QCBOREncode_AddTag
Laurence Lundblade4e7bc682018-12-14 23:21:04 -0800602 7 QCBOREncode_AddDouble, QCBOREncode_AddType7
Laurence Lundblade067035b2018-11-28 17:35:25 -0800603
Laurence Lundblade4e7bc682018-12-14 23:21:04 -0800604 Object code sizes on X86 with LLVM compiler and -Os (Dec 14, 2018)
Laurence Lundblade067035b2018-11-28 17:35:25 -0800605
Laurence Lundblade9c097392018-12-30 13:52:24 -0800606 _QCBOREncode_Init 69
Laurence Lundblade067035b2018-11-28 17:35:25 -0800607 _QCBOREncode_AddUInt64 76
608 _QCBOREncode_AddInt64 87
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800609 _QCBOREncode_AddBuffer 113
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800610 _QCBOREncode_AddTag 27
Laurence Lundblade9c097392018-12-30 13:52:24 -0800611 _QCBOREncode_AddType7 87
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800612 _QCBOREncode_AddDouble 36
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800613 _QCBOREncode_OpenMapOrArray 103
Laurence Lundblade067035b2018-11-28 17:35:25 -0800614 _QCBOREncode_CloseMapOrArray 181
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800615 _InsertEncodedTypeAndNumber 190
Laurence Lundblade067035b2018-11-28 17:35:25 -0800616 _QCBOREncode_Finish 72
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800617 _QCBOREncode_FinishGetSize 70
Laurence Lundblade067035b2018-11-28 17:35:25 -0800618
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800619 Total is about 1.1KB
Laurence Lundblade067035b2018-11-28 17:35:25 -0800620
Laurence Lundblade067035b2018-11-28 17:35:25 -0800621 _QCBOREncode_CloseMapOrArray is larger because it has a lot
622 of nesting tracking to do and much of Nesting_ inlines
623 into it. It probably can't be reduced much.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800624
Laurence Lundblade067035b2018-11-28 17:35:25 -0800625 If the error returned by Nesting_Increment() can be ignored
626 because the limit is so high and the consequence of exceeding
627 is proved to be inconsequential, then a lot of if(me->uError)
628 instance can be removed, saving some code.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800629
Laurence Lundblade067035b2018-11-28 17:35:25 -0800630 */
631