blob: 460dd8520db3d025b57388f129b8416d03834186 [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.
Laurence Lundbladed39cd392019-01-11 18:17:38 -08003 Copyright (c) 2018-2019, Laurence Lundblade.
Laurence Lundbladed92a6162018-11-01 11:38:35 +07004 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 Lundblade2c40ab82018-12-30 14:20:29 -080093inline static QCBORError Nesting_Increase(QCBORTrackNesting *pNesting,
94 uint8_t uMajorType,
95 uint32_t uPos)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070096{
Laurence Lundblade30816f22018-11-10 13:40:22 +070097 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080098
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070099 if(pNesting->pCurrentNesting == &pNesting->pArrays[QCBOR_MAX_ARRAY_NESTING]) {
100 // trying to open one too many
101 nReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
102 } else {
103 pNesting->pCurrentNesting++;
104 pNesting->pCurrentNesting->uCount = 0;
105 pNesting->pCurrentNesting->uStart = uPos;
106 pNesting->pCurrentNesting->uMajorType = uMajorType;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700107 }
108 return nReturn;
109}
110
111inline static void Nesting_Decrease(QCBORTrackNesting *pNesting)
112{
113 pNesting->pCurrentNesting--;
114}
115
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800116inline static QCBORError Nesting_Increment(QCBORTrackNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700117{
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800118 if(1 >= QCBOR_MAX_ITEMS_IN_ARRAY - pNesting->pCurrentNesting->uCount) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700119 return QCBOR_ERR_ARRAY_TOO_LONG;
120 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800121
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800122 pNesting->pCurrentNesting->uCount += 1;
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800123
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700124 return QCBOR_SUCCESS;
125}
126
127inline static uint16_t Nesting_GetCount(QCBORTrackNesting *pNesting)
128{
129 // The nesting count recorded is always the actual number of individiual
130 // data items in the array or map. For arrays CBOR uses the actual item
131 // count. For maps, CBOR uses the number of pairs. This function returns
132 // the number needed for the CBOR encoding, so it divides the number of
133 // items by two for maps to get the number of pairs. This implementation
134 // takes advantage of the map major type being one larger the array major
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800135 // type, hence uDivisor is either 1 or 2.
136 const uint16_t uDivisor = pNesting->pCurrentNesting->uMajorType - CBOR_MAJOR_TYPE_ARRAY+1;
137
138 return pNesting->pCurrentNesting->uCount / uDivisor;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700139}
140
141inline static uint32_t Nesting_GetStartPos(QCBORTrackNesting *pNesting)
142{
143 return pNesting->pCurrentNesting->uStart;
144}
145
146inline static uint8_t Nesting_GetMajorType(QCBORTrackNesting *pNesting)
147{
148 return pNesting->pCurrentNesting->uMajorType;
149}
150
151inline static int Nesting_IsInNest(QCBORTrackNesting *pNesting)
152{
153 return pNesting->pCurrentNesting == &pNesting->pArrays[0] ? 0 : 1;
154}
155
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700156
157
158
159/*
160 Error tracking plan -- Errors are tracked internally and not returned
161 until Finish is called. The CBOR errors are in me->uError.
Laurence Lundblade067035b2018-11-28 17:35:25 -0800162 UsefulOutBuf also tracks whether the buffer is full or not in its
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700163 context. Once either of these errors is set they are never
Laurence Lundblade241705e2018-12-30 18:56:14 -0800164 cleared. Only QCBOREncode_Init() resets them. Or said another way, they must
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700165 never be cleared or we'll tell the caller all is good when it is not.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800166
Laurence Lundblade241705e2018-12-30 18:56:14 -0800167 Only one error code is reported by QCBOREncode_Finish() even if there are
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700168 multiple errors. The last one set wins. The caller might have to fix
169 one error to reveal the next one they have to fix. This is OK.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800170
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700171 The buffer full error tracked by UsefulBuf is only pulled out of
172 UsefulBuf in Finish() so it is the one that usually wins. UsefulBuf
173 will never go off the end of the buffer even if it is called again
174 and again when full.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800175
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700176 It is really tempting to not check for overflow on the count in the
177 number of items in an array. It would save a lot of code, it is
178 extremely unlikely that any one will every put 65,000 items in an
179 array, and the only bad thing that would happen is the CBOR would be
Laurence Lundblade241705e2018-12-30 18:56:14 -0800180 bogus.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800181
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700182 Since this does not parse any input, you could in theory remove all
183 error checks in this code if you knew the caller called it
184 correctly. Maybe someday CDDL or some such language will be able to
185 generate the code to call this and the calling code would always be
Laurence Lundblade56230d12018-11-01 11:14:51 +0700186 correct. This could also automatically size some of the data
Laurence Lundblade241705e2018-12-30 18:56:14 -0800187 structures like array/map nesting resulting in some stack memory
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700188 savings.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800189
Laurence Lundblade241705e2018-12-30 18:56:14 -0800190 Errors returned here fall into two categories:
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800191
Laurence Lundblade067035b2018-11-28 17:35:25 -0800192 Sizes
Laurence Lundblade241705e2018-12-30 18:56:14 -0800193 QCBOR_ERR_BUFFER_TOO_LARGE -- Encoded output exceeded UINT32_MAX
Laurence Lundblade067035b2018-11-28 17:35:25 -0800194 QCBOR_ERR_BUFFER_TOO_SMALL -- output buffer too small
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800195
Laurence Lundblade241705e2018-12-30 18:56:14 -0800196 QCBOR_ERR_ARRAY_NESTING_TOO_DEEP -- Array/map nesting > QCBOR_MAX_ARRAY_NESTING1
Laurence Lundblade067035b2018-11-28 17:35:25 -0800197 QCBOR_ERR_ARRAY_TOO_LONG -- Too many things added to an array/map
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800198
Laurence Lundblade067035b2018-11-28 17:35:25 -0800199 Nesting constructed incorrectly
200 QCBOR_ERR_TOO_MANY_CLOSES -- more close calls than opens
201 QCBOR_ERR_CLOSE_MISMATCH -- Type of close does not match open
202 QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN -- Finish called without enough closes
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700203 */
204
205
206
207
208/*
209 Public function for initialization. See header qcbor.h
210 */
Laurence Lundblade2296db52018-09-14 18:08:39 -0700211void QCBOREncode_Init(QCBOREncodeContext *me, UsefulBuf Storage)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700212{
213 memset(me, 0, sizeof(QCBOREncodeContext));
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800214 UsefulOutBuf_Init(&(me->OutBuf), Storage);
215 Nesting_Init(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700216}
217
218
219
220
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800221/*
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800222 All CBOR data items have a type and an "argument". The argument is
223 either the value of the item for integer types, the length of the
224 content for string, byte, array and map types, a tag for major type
225 6, and has several uses for major type 7.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800226
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800227 This function encodes the type and the argument. There are several
228 encodings for the argument depending on how large it is and how it is
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700229 used.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800230
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800231 Every encoding of the type and argument has at least one byte, the
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700232 "initial byte".
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800233
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700234 The top three bits of the initial byte are the major type for the
235 CBOR data item. The eight major types defined by the standard are
236 defined as CBOR_MAJOR_TYPE_xxxx in qcbor.h.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800237
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700238 The remaining five bits, known as "additional information", and
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800239 possibly more bytes encode the argument. If the argument is less than
240 24, then it is encoded entirely in the five bits. This is neat
241 because it allows you to encode an entire CBOR data item in 1 byte
242 for many values and types (integers 0-23, true, false, and tags).
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800243
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800244 If the argument is larger than 24, then it is encoded in 1,2,4 or 8
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700245 additional bytes, with the number of these bytes indicated by the
246 values of the 5 bits 24, 25, 25 and 27.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800247
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800248 It is possible to encode a particular argument in many ways with this
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700249 representation. This implementation always uses the smallest
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800250 possible representation. This conforms with CBOR preferred encoding.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800251
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700252 This function inserts them into the output buffer at the specified
Laurence Lundblade067035b2018-11-28 17:35:25 -0800253 position. AppendEncodedTypeAndNumber() appends to the end.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800254
255 This function takes care of converting to network byte order.
256
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700257 This function is also used to insert floats and doubles. Before this
258 function is called the float or double must be copied into a
259 uint64_t. That is how they are passed in. They are then converted to
260 network byte order correctly. The uMinLen param makes sure that even
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800261
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800262 if all the digits of a half, float or double are 0 it is still
263 correctly encoded in 2, 4 or 8 bytes.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700264 */
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800265
266static void InsertEncodedTypeAndNumber(QCBOREncodeContext *me,
267 uint8_t uMajorType,
268 int nMinLen,
269 uint64_t uNumber,
270 size_t uPos)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700271{
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800272 /*
273 This code does endian conversion without hton or knowing the
Laurence Lundblade241705e2018-12-30 18:56:14 -0800274 endianness of the machine using masks and shifts. This avoids the
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800275 dependency on hton and the mess of figuring out how to find the
276 machine's endianness.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800277
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800278 This is a good efficient implementation on little-endian machines.
279 A faster and small implementation is possible on big-endian
280 machines because CBOR/network byte order is big endian. However
281 big endian machines are uncommon.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800282
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800283 On x86, it is about 200 bytes instead of 500 bytes for the more
284 formal unoptimized code.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800285
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800286 This also does the CBOR preferred shortest encoding for integers
287 and is called to do endian conversion for floats.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800288
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800289 It works backwards from the LSB to the MSB as needed.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800290
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800291 Code Reviewers: THIS FUNCTION DOES POINTER MATH
292 */
293 // Holds up to 9 bytes of type and argument
294 // plus one extra so pointer always points to
295 // valid bytes.
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800296 uint8_t bytes[sizeof(uint64_t)+2];
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800297 // Point to the last bytes and work backwards
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800298 uint8_t *pByte = &bytes[sizeof(bytes)-1];
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800299 // This is the 5 bits in the initial byte that is not the major type
300 uint8_t uAdditionalInfo;
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800301
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800302 if(uNumber < CBOR_TWENTY_FOUR && nMinLen == 0) {
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800303 // Simple case where argument is < 24
304 uAdditionalInfo = uNumber;
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800305 } else {
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800306 /*
307 Encode argument in 1,2,4 or 8 bytes. Outer loop
308 runs once for 1 byte and 4 times for 8 bytes.
309 Inner loop runs 1, 2 or 4 times depending on
310 outer loop counter. This works backwards taking
311 8 bits off the argument being encoded at a time
312 until all bits from uNumber have been encoded
313 and the minimum encoding size is reached.
314 Minimum encoding size is for floating point
Laurence Lundblade241705e2018-12-30 18:56:14 -0800315 numbers with zero bytes.
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800316 */
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800317 static const uint8_t aIterate[] = {1,1,2,4};
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800318 uint8_t i;
319 for(i = 0; uNumber || nMinLen > 0; i++) {
320 const uint8_t uIterations = aIterate[i];
321 for(int j = 0; j < uIterations; j++) {
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800322 *--pByte = uNumber & 0xff;
323 uNumber = uNumber >> 8;
324 }
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800325 nMinLen -= uIterations;
Laurence Lundblade04a859b2018-12-11 12:13:02 -0800326 }
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800327 // Additional info is the encoding of the
328 // number of additional bytes to encode
329 // argument.
330 uAdditionalInfo = LEN_IS_ONE_BYTE-1 + i;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700331 }
Laurence Lundbladee9b00322018-12-30 10:33:26 -0800332 *--pByte = (uMajorType << 5) + uAdditionalInfo;
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800333
334 UsefulOutBuf_InsertData(&(me->OutBuf), pByte, &bytes[sizeof(bytes)-1] - pByte, uPos);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700335}
336
337
338/*
339 Append the type and number info to the end of the buffer.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800340
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700341 See InsertEncodedTypeAndNumber() function above for details
342*/
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800343inline static void AppendEncodedTypeAndNumber(QCBOREncodeContext *me,
344 uint8_t uMajorType,
345 uint64_t uNumber)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700346{
347 // An append is an insert at the end.
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800348 InsertEncodedTypeAndNumber(me,
349 uMajorType,
350 0,
351 uNumber,
352 UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700353}
354
355
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700356
Laurence Lundblade241705e2018-12-30 18:56:14 -0800357
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700358/*
Laurence Lundblade067035b2018-11-28 17:35:25 -0800359 Public functions for closing arrays and maps. See header qcbor.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700360 */
Laurence Lundblade067035b2018-11-28 17:35:25 -0800361void QCBOREncode_AddUInt64(QCBOREncodeContext *me, uint64_t uValue)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700362{
Laurence Lundblade067035b2018-11-28 17:35:25 -0800363 if(me->uError == QCBOR_SUCCESS) {
364 AppendEncodedTypeAndNumber(me, CBOR_MAJOR_TYPE_POSITIVE_INT, uValue);
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800365 me->uError = Nesting_Increment(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700366 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700367}
368
Laurence Lundblade56230d12018-11-01 11:14:51 +0700369
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700370/*
Laurence Lundblade067035b2018-11-28 17:35:25 -0800371 Public functions for closing arrays and maps. See header qcbor.h
372 */
373void QCBOREncode_AddInt64(QCBOREncodeContext *me, int64_t nNum)
374{
375 if(me->uError == QCBOR_SUCCESS) {
376 uint8_t uMajorType;
377 uint64_t uValue;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800378
Laurence Lundblade067035b2018-11-28 17:35:25 -0800379 if(nNum < 0) {
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800380 // In CBOR -1 encodes as 0x00 with major type negative int.
381 uValue = (uint64_t)(-nNum - 1);
Laurence Lundblade067035b2018-11-28 17:35:25 -0800382 uMajorType = CBOR_MAJOR_TYPE_NEGATIVE_INT;
383 } else {
384 uValue = (uint64_t)nNum;
385 uMajorType = CBOR_MAJOR_TYPE_POSITIVE_INT;
386 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800387
Laurence Lundblade067035b2018-11-28 17:35:25 -0800388 AppendEncodedTypeAndNumber(me, uMajorType, uValue);
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800389 me->uError = Nesting_Increment(&(me->nesting));
Laurence Lundblade067035b2018-11-28 17:35:25 -0800390 }
391}
392
393
394/*
395 Semi-private function. It is exposed to user of the interface,
396 but they will usually call one of the inline wrappers rather than this.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800397
Laurence Lundblade067035b2018-11-28 17:35:25 -0800398 See header qcbor.h
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800399
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700400 Does the work of adding some bytes to the CBOR output. Works for a
401 byte and text strings, which are the same in in CBOR though they have
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700402 different major types. This is also used to insert raw
403 pre-encoded CBOR.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700404 */
Laurence Lundblade067035b2018-11-28 17:35:25 -0800405void QCBOREncode_AddBuffer(QCBOREncodeContext *me, uint8_t uMajorType, UsefulBufC Bytes)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700406{
Laurence Lundblade241705e2018-12-30 18:56:14 -0800407 if(me->uError == QCBOR_SUCCESS) {
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800408 // If it is not Raw CBOR, add the type and the length
409 if(uMajorType != CBOR_MAJOR_NONE_TYPE_RAW) {
410 AppendEncodedTypeAndNumber(me, uMajorType, Bytes.len);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700411 }
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800412
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800413 // Actually add the bytes
414 UsefulOutBuf_AppendUsefulBuf(&(me->OutBuf), Bytes);
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800415
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800416 // Update the array counting if there is any nesting at all
417 me->uError = Nesting_Increment(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700418 }
419}
420
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700421
Laurence Lundblade55a24832018-10-30 04:35:08 +0700422/*
Laurence Lundblade067035b2018-11-28 17:35:25 -0800423 Public functions for closing arrays and maps. See header qcbor.h
Laurence Lundblade55a24832018-10-30 04:35:08 +0700424 */
425void QCBOREncode_AddTag(QCBOREncodeContext *me, uint64_t uTag)
426{
Laurence Lundblade55a24832018-10-30 04:35:08 +0700427 AppendEncodedTypeAndNumber(me, CBOR_MAJOR_TYPE_OPTIONAL, uTag);
428}
429
430
Laurence Lundblade56230d12018-11-01 11:14:51 +0700431/*
Laurence Lundblade487930f2018-11-30 11:01:45 -0800432 Semi-private function. It is exposed to user of the interface,
433 but they will usually call one of the inline wrappers rather than this.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800434
Laurence Lundblade487930f2018-11-30 11:01:45 -0800435 See header qcbor.h
Laurence Lundblade56230d12018-11-01 11:14:51 +0700436 */
Laurence Lundblade487930f2018-11-30 11:01:45 -0800437void QCBOREncode_AddType7(QCBOREncodeContext *me, size_t uSize, uint64_t uNum)
Laurence Lundblade55a24832018-10-30 04:35:08 +0700438{
Laurence Lundblade487930f2018-11-30 11:01:45 -0800439 if(me->uError == QCBOR_SUCCESS) {
440 // This function call takes care of endian swapping for the float / double
441 InsertEncodedTypeAndNumber(me,
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800442 // The major type for floats and doubles
443 CBOR_MAJOR_TYPE_SIMPLE,
444 // size makes sure floats with zeros encode correctly
445 (int)uSize,
446 // Bytes of the floating point number as a uint
447 uNum,
448 // end position because this is append
449 UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
450
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800451 me->uError = Nesting_Increment(&(me->nesting));
Laurence Lundblade487930f2018-11-30 11:01:45 -0800452 }
Laurence Lundblade55a24832018-10-30 04:35:08 +0700453}
454
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700455
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700456/*
Laurence Lundblade067035b2018-11-28 17:35:25 -0800457 Public functions for closing arrays and maps. See header qcbor.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700458 */
Laurence Lundblade067035b2018-11-28 17:35:25 -0800459void QCBOREncode_AddDouble(QCBOREncodeContext *me, double dNum)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700460{
Laurence Lundblade067035b2018-11-28 17:35:25 -0800461 const IEEE754_union uNum = IEEE754_DoubleToSmallest(dNum);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800462
Laurence Lundblade487930f2018-11-30 11:01:45 -0800463 QCBOREncode_AddType7(me, uNum.uSize, uNum.uValue);
Laurence Lundblade067035b2018-11-28 17:35:25 -0800464}
465
466
467/*
468 Semi-public function. It is exposed to user of the interface,
469 but they will usually call one of the inline wrappers rather than this.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800470
Laurence Lundblade067035b2018-11-28 17:35:25 -0800471 See header qcbor.h
472*/
473void QCBOREncode_OpenMapOrArray(QCBOREncodeContext *me, uint8_t uMajorType)
474{
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800475 // Add one item to the nesting level we are in for the new map or array
476 me->uError = Nesting_Increment(&(me->nesting));
Laurence Lundblade241705e2018-12-30 18:56:14 -0800477 if(me->uError == QCBOR_SUCCESS) {
Laurence Lundbladed39cd392019-01-11 18:17:38 -0800478 // The offset where the length of an array or map will get written
479 // is stored in a uint32_t, not a size_t to keep stack usage smaller. This
480 // checks to be sure there is no wrap around when recording the offset.
481 // Note that on 64-bit machines CBOR larger than 4GB can be encoded as long as no
482 // array / map offsets occur past the 4GB mark, but the public interface
483 // says that the maximum is 4GB to keep the discussion simpler.
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800484 size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf));
Laurence Lundbladed39cd392019-01-11 18:17:38 -0800485
486 // QCBOR_MAX_ARRAY_OFFSET is slightly less than UINT32_MAX so this
487 // code can run on a 32-bit machine and tests can pass on a 32-bit
488 // machine. If it was exactly UINT32_MAX, then this code would
489 // not compile or run on a 32-bit machine and an #ifdef or some
490 // machine size detection would be needed reducing portability.
491 if(uEndPosition >= QCBOR_MAX_ARRAY_OFFSET) {
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800492 me->uError = QCBOR_ERR_BUFFER_TOO_LARGE;
Laurence Lundbladed39cd392019-01-11 18:17:38 -0800493
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800494 } else {
Laurence Lundbladed39cd392019-01-11 18:17:38 -0800495 // Increase nesting level because this is a map or array.
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800496 // Cast from size_t to uin32_t is safe because of check above
497 me->uError = Nesting_Increase(&(me->nesting), uMajorType, (uint32_t)uEndPosition);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700498 }
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800499 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700500}
501
502
503/*
Laurence Lundbladecafcfe12018-10-31 21:59:50 +0700504 Public functions for closing arrays and maps. See header qcbor.h
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700505 */
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800506void QCBOREncode_CloseMapOrArray(QCBOREncodeContext *me,
507 uint8_t uMajorType,
508 UsefulBufC *pWrappedCBOR)
Laurence Lundbladea954db92018-09-28 19:27:31 -0700509{
Laurence Lundblade241705e2018-12-30 18:56:14 -0800510 if(me->uError == QCBOR_SUCCESS) {
Laurence Lundbladea954db92018-09-28 19:27:31 -0700511 if(!Nesting_IsInNest(&(me->nesting))) {
512 me->uError = QCBOR_ERR_TOO_MANY_CLOSES;
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800513 } else if(Nesting_GetMajorType(&(me->nesting)) != uMajorType) {
Laurence Lundblade067035b2018-11-28 17:35:25 -0800514 me->uError = QCBOR_ERR_CLOSE_MISMATCH;
Laurence Lundbladea954db92018-09-28 19:27:31 -0700515 } else {
Laurence Lundblade56230d12018-11-01 11:14:51 +0700516 // When the array, map or bstr wrap was started, nothing was done
517 // except note the position of the start of it. This code goes back
518 // and inserts the actual CBOR array, map or bstr and its length.
519 // That means all the data that is in the array, map or wrapped
520 // needs to be slid to the right. This is done by UsefulOutBuf's
521 // insert function that is called from inside
522 // InsertEncodedTypeAndNumber()
523 const size_t uInsertPosition = Nesting_GetStartPos(&(me->nesting));
524 const size_t uEndPosition = UsefulOutBuf_GetEndPosition(&(me->OutBuf));
525 // This can't go negative because the UsefulOutBuf always only grows
526 // and never shrinks. UsefulOutBut itself also has defenses such that
527 // it won't write were it should not even if given hostile input lengths
528 const size_t uLenOfEncodedMapOrArray = uEndPosition - uInsertPosition;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800529
Laurence Lundblade56230d12018-11-01 11:14:51 +0700530 // Length is number of bytes for a bstr and number of items a for map & array
531 const size_t uLength = uMajorType == CBOR_MAJOR_TYPE_BYTE_STRING ?
Laurence Lundbladea954db92018-09-28 19:27:31 -0700532 uLenOfEncodedMapOrArray : Nesting_GetCount(&(me->nesting));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800533
Laurence Lundbladea954db92018-09-28 19:27:31 -0700534 // Actually insert
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700535 InsertEncodedTypeAndNumber(me,
Laurence Lundbladea954db92018-09-28 19:27:31 -0700536 uMajorType, // major type bstr, array or map
537 0, // no minimum length for encoding
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800538 uLength, // either len of bstr or num map / array items
Laurence Lundbladea954db92018-09-28 19:27:31 -0700539 uInsertPosition); // position in out buffer
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800540
Laurence Lundbladea954db92018-09-28 19:27:31 -0700541 // Return pointer and length to the enclosed encoded CBOR. The intended
542 // use is for it to be hashed (e.g., SHA-256) in a COSE implementation.
543 // This must be used right away, as the pointer and length go invalid
544 // on any subsequent calls to this function because of the
545 // InsertEncodedTypeAndNumber() call that slides data to the right.
546 if(pWrappedCBOR) {
Laurence Lundblade25c6c0a2018-12-17 13:21:59 -0800547 const UsefulBufC PartialResult = UsefulOutBuf_OutUBuf(&(me->OutBuf));
548 const size_t uBstrLen = UsefulOutBuf_GetEndPosition(&(me->OutBuf)) - uEndPosition;
Laurence Lundbladea954db92018-09-28 19:27:31 -0700549 *pWrappedCBOR = UsefulBuf_Tail(PartialResult, uInsertPosition+uBstrLen);
550 }
551 Nesting_Decrease(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700552 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700553 }
554}
555
556
Laurence Lundblade56230d12018-11-01 11:14:51 +0700557
Laurence Lundblade241705e2018-12-30 18:56:14 -0800558
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700559/*
560 Public functions to finish and get the encoded result. See header qcbor.h
561 */
Laurence Lundblade30816f22018-11-10 13:40:22 +0700562QCBORError QCBOREncode_Finish(QCBOREncodeContext *me, UsefulBufC *pEncodedCBOR)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700563{
Laurence Lundblade067035b2018-11-28 17:35:25 -0800564 QCBORError uReturn = me->uError;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800565
Laurence Lundblade067035b2018-11-28 17:35:25 -0800566 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700567 goto Done;
Laurence Lundblade067035b2018-11-28 17:35:25 -0800568 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800569
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700570 if (Nesting_IsInNest(&(me->nesting))) {
Laurence Lundblade067035b2018-11-28 17:35:25 -0800571 uReturn = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700572 goto Done;
573 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800574
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700575 if(UsefulOutBuf_GetError(&(me->OutBuf))) {
576 // Stuff didn't fit in the buffer.
Laurence Lundblade56230d12018-11-01 11:14:51 +0700577 // This check catches this condition for all the appends and inserts
578 // so checks aren't needed when the appends and inserts are performed.
579 // And of course UsefulBuf will never overrun the input buffer given
580 // to it. No complex analysis of the error handling in this file is
581 // needed to know that is true. Just read the UsefulBuf code.
Laurence Lundblade067035b2018-11-28 17:35:25 -0800582 uReturn = QCBOR_ERR_BUFFER_TOO_SMALL;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700583 goto Done;
584 }
Laurence Lundblade2296db52018-09-14 18:08:39 -0700585
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700586 *pEncodedCBOR = UsefulOutBuf_OutUBuf(&(me->OutBuf));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800587
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700588Done:
Laurence Lundblade067035b2018-11-28 17:35:25 -0800589 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700590}
591
Laurence Lundblade0595e932018-11-02 22:22:47 +0700592
Laurence Lundblade067035b2018-11-28 17:35:25 -0800593/*
594 Public functions to finish and get the encoded result. See header qcbor.h
595 */
Laurence Lundblade30816f22018-11-10 13:40:22 +0700596QCBORError QCBOREncode_FinishGetSize(QCBOREncodeContext *me, size_t *puEncodedLen)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700597{
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700598 UsefulBufC Enc;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800599
Laurence Lundblade30816f22018-11-10 13:40:22 +0700600 QCBORError nReturn = QCBOREncode_Finish(me, &Enc);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800601
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700602 if(nReturn == QCBOR_SUCCESS) {
Laurence Lundbladeda3f0822018-09-18 19:49:02 -0700603 *puEncodedLen = Enc.len;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700604 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800605
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700606 return nReturn;
607}
608
609
Laurence Lundblade067035b2018-11-28 17:35:25 -0800610
611
612/*
613 Notes on the code
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800614
Laurence Lundblade067035b2018-11-28 17:35:25 -0800615 CBOR Major Type Public Function
616 0 QCBOREncode_AddUInt64
617 0, 1 QCBOREncode_AddUInt64, QCBOREncode_AddInt64
618 2, 3 QCBOREncode_AddBuffer, Also QCBOREncode_OpenMapOrArray
619 4, 5 QCBOREncode_OpenMapOrArray
620 6 QCBOREncode_AddTag
Laurence Lundblade4e7bc682018-12-14 23:21:04 -0800621 7 QCBOREncode_AddDouble, QCBOREncode_AddType7
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800622
Laurence Lundblade241705e2018-12-30 18:56:14 -0800623 Object code sizes on X86 with LLVM compiler and -Os (Dec 30, 2018)
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800624
Laurence Lundblade9c097392018-12-30 13:52:24 -0800625 _QCBOREncode_Init 69
Laurence Lundblade067035b2018-11-28 17:35:25 -0800626 _QCBOREncode_AddUInt64 76
627 _QCBOREncode_AddInt64 87
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800628 _QCBOREncode_AddBuffer 113
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800629 _QCBOREncode_AddTag 27
Laurence Lundblade9c097392018-12-30 13:52:24 -0800630 _QCBOREncode_AddType7 87
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800631 _QCBOREncode_AddDouble 36
Laurence Lundblade1ef8b2d2018-12-14 23:13:34 -0800632 _QCBOREncode_OpenMapOrArray 103
Laurence Lundblade067035b2018-11-28 17:35:25 -0800633 _QCBOREncode_CloseMapOrArray 181
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800634 _InsertEncodedTypeAndNumber 190
Laurence Lundblade067035b2018-11-28 17:35:25 -0800635 _QCBOREncode_Finish 72
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800636 _QCBOREncode_FinishGetSize 70
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800637
Laurence Lundbladef970f1d2018-12-14 01:44:23 -0800638 Total is about 1.1KB
Laurence Lundblade2c40ab82018-12-30 14:20:29 -0800639
Laurence Lundblade067035b2018-11-28 17:35:25 -0800640 _QCBOREncode_CloseMapOrArray is larger because it has a lot
641 of nesting tracking to do and much of Nesting_ inlines
642 into it. It probably can't be reduced much.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800643
Laurence Lundblade067035b2018-11-28 17:35:25 -0800644 If the error returned by Nesting_Increment() can be ignored
645 because the limit is so high and the consequence of exceeding
646 is proved to be inconsequential, then a lot of if(me->uError)
647 instance can be removed, saving some code.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800648
Laurence Lundblade067035b2018-11-28 17:35:25 -0800649 */
650