blob: 7f752a46db30510431e726da9de56c1ada71082f [file] [log] [blame]
Thiago Macieiraf1cadf02015-05-08 17:19:17 -07001/****************************************************************************
2**
Thiago Macieira46a818e2015-10-08 15:13:05 +02003** Copyright (C) 2016 Intel Corporation
Thiago Macieiraf1cadf02015-05-08 17:19:17 -07004**
5** Permission is hereby granted, free of charge, to any person obtaining a copy
6** of this software and associated documentation files (the "Software"), to deal
7** in the Software without restriction, including without limitation the rights
8** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9** copies of the Software, and to permit persons to whom the Software is
10** furnished to do so, subject to the following conditions:
11**
12** The above copyright notice and this permission notice shall be included in
13** all copies or substantial portions of the Software.
14**
15** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21** THE SOFTWARE.
22**
23****************************************************************************/
24
Thiago Macieiraed5b57c2015-07-07 16:38:27 -070025#define _BSD_SOURCE 1
Thiago Macieiraf1cadf02015-05-08 17:19:17 -070026#include "cbor.h"
27#include "cborconstants_p.h"
28#include "compilersupport_p.h"
29
30#include <assert.h>
Thiago Macieiraf1cadf02015-05-08 17:19:17 -070031#include <stdlib.h>
32#include <string.h>
33
Thiago Macieira8f3fb782015-06-16 16:27:01 -070034#include "assert_p.h" /* Always include last */
35
Thiago Macieira46a818e2015-10-08 15:13:05 +020036/**
37 * \defgroup CborEncoding Encoding to CBOR
38 * \brief Group of functions used to encode data to CBOR.
39 *
40 * CborEncoder is used to encode data into a CBOR stream. The outermost
41 * CborEncoder is initialized by calling cbor_encoder_init(), with the buffer
42 * where the CBOR stream will be stored. The outermost CborEncoder is usually
43 * used to encode exactly one item, most often an array or map. It is possible
44 * to encode more than one item, but care must then be taken on the decoder
45 * side to ensure the state is reset after each item was decoded.
46 *
47 * Nested CborEncoder objects are created using cbor_encoder_create_array() and
48 * cbor_encoder_create_map(), later closed with cbor_encoder_close_container()
49 * or cbor_encoder_close_container_checked(). The pairs of creation and closing
50 * must be exactly matched and their parameters are always the same.
51 *
52 * CborEncoder writes directly to the user-supplied buffer, without extra
53 * buffering. CborEncoder does not allocate memory and CborEncoder objects are
54 * usually created on the stack of the encoding functions.
55 *
56 * The example below initializes a CborEncoder object with a buffer and encodes
57 * a single integer.
58 *
59 * \code
60 * uint8_t buf[16];
61 * CborEncoder encoder;
62 * cbor_encoder_init(&encoder, &buf, sizeof(buf), 0);
63 * cbor_encode_int(&encoder, some_value);
64 * \endcode
65 *
66 * As explained before, usually the outermost CborEncoder object is used to add
67 * one array or map, which in turn contains multiple elements. The example
68 * below creates a CBOR map with one element: a key "foo" and a boolean value.
69 *
70 * \code
71 * uint8_t buf[16];
72 * CborEncoder encoder, mapEncoder;
73 * cbor_encoder_init(&encoder, &buf, sizeof(buf), 0);
74 * cbor_encoder_create_map(&encoder, &mapEncoder, 1);
75 * cbor_encode_text_stringz(&mapEncoder, "foo");
76 * cbor_encode_boolean(&mapEncoder, some_value);
77 * cbor_encoder_close_container(&encoder, &mapEncoder);
78 * \endcode
79 *
80 * <h3 class="groupheader">Error checking and buffer size</h2>
81 *
82 * All functions operating on CborEncoder return a condition of type CborError.
83 * If the encoding was successful, they return CborNoError. Some functions do
84 * extra checking on the input provided and may return some other error
85 * conditions (for example, cbor_encode_simple_value() checks that the type is
86 * of the correct type).
87 *
88 * In addition, all functions check whether the buffer has enough bytes to
89 * encode the item being appended. If that is not possible, they return
90 * CborErrorOutOfMemory.
91 *
92 * It is possible to continue with the encoding of data past the first function
93 * that returns CborErrorOutOfMemory. CborEncoder functions will not overrun
94 * the buffer, but will instead count how many more bytes are needed to
Thiago Macieira7ae36a72015-10-28 16:19:23 -070095 * complete the encoding. At the end, you can obtain that count by calling
96 * cbor_encoder_get_extra_bytes_needed().
Thiago Macieira46a818e2015-10-08 15:13:05 +020097 *
98 * \section1 Finalizing the encoding
99 *
100 * Once all items have been appended and the containers have all been properly
101 * closed, the user-supplied buffer will contain the CBOR stream and may be
Thiago Macieira7ae36a72015-10-28 16:19:23 -0700102 * immediately used. To obtain the size of the buffer, call
103 * cbor_encoder_get_buffer_size() with the original buffer pointer.
Thiago Macieira46a818e2015-10-08 15:13:05 +0200104 *
105 * The example below illustrates how one can encode an item with error checking
106 * and then pass on the buffer for network sending.
107 *
108 * \code
109 * uint8_t buf[16];
110 * CborError err;
111 * CborEncoder encoder, mapEncoder;
112 * cbor_encoder_init(&encoder, &buf, sizeof(buf), 0);
113 * err = cbor_encoder_create_map(&encoder, &mapEncoder, 1);
114 * if (!err)
115 * return err;
116 * err = cbor_encode_text_stringz(&mapEncoder, "foo");
117 * if (!err)
118 * return err;
119 * err = cbor_encode_boolean(&mapEncoder, some_value);
120 * if (!err)
121 * return err;
122 * err = cbor_encoder_close_container_checked(&encoder, &mapEncoder);
123 * if (!err)
124 * return err;
125 *
Thiago Macieira7ae36a72015-10-28 16:19:23 -0700126 * size_t len = cbor_encoder_get_buffer_size(&encoder, buf);
Thiago Macieira46a818e2015-10-08 15:13:05 +0200127 * send_payload(buf, len);
128 * return CborNoError;
129 * \endcode
Thiago Macieira7ae36a72015-10-28 16:19:23 -0700130 *
131 * Finally, the example below illustrates expands on the one above and also
132 * deals with dynamically growing the buffer if the initial allocation wasn't
133 * big enough. Note the two places where the error checking was replaced with
134 * an assertion, showing where the author assumes no error can occur.
135 *
136 * \code
137 * uint8_t *encode_string_array(const char **strings, int n, size_t *bufsize)
138 * {
139 * CborError err;
140 * CborEncoder encoder, arrayEncoder;
141 * size_t size = 256;
142 * uint8_t *buf = NULL;
143 *
144 * while (1) {
145 * int i;
146 * size_t more_bytes;
147 * uint8_t *nbuf = realloc(buf, size);
148 * if (nbuf == NULL)
149 * goto error;
150 * buf = nbuf;
151 *
152 * cbor_encoder_init(&encoder, &buf, size, 0);
153 * err = cbor_encoder_create_array(&encoder, &arrayEncoder, n);
154 * assert(err); // can't fail, the buffer is always big enough
155 *
156 * for (i = 0; i < n; ++i) {
157 * err = cbor_encode_text_stringz(&arrayEncoder, strings[i]);
158 * if (err && err != CborErrorOutOfMemory)
159 * goto error;
160 * }
161 *
162 * err = cbor_encoder_close_container_checked(&encoder, &arrayEncoder);
163 * assert(err); // shouldn't fail!
164 *
165 * more_bytes = cbor_encoder_get_extra_bytes_needed(encoder);
166 * if (more_size) {
167 * // buffer wasn't big enough, try again
168 * size += more_bytes;
169 * continue;
170 * }
171 *
172 * *bufsize = cbor_encoder_get_buffer_size(encoder, buf);
173 * return buf;
174 * }
175 * error:
176 * free(buf);
177 * return NULL;
178 * }
179 * \endcode
Thiago Macieira46a818e2015-10-08 15:13:05 +0200180 */
181
182/**
183 * \addtogroup CborEncoding
184 * @{
185 */
186
187/**
188 * \struct CborEncoder
189 * Structure used to encode to CBOR.
190 */
191
192/**
193 * Initializes a CborEncoder structure \a encoder by pointing it to buffer \a
194 * buffer of size \a size. The \a flags field is currently unused and must be
195 * zero.
196 */
Thiago Macieira5752ce52015-06-16 12:10:03 -0700197void cbor_encoder_init(CborEncoder *encoder, uint8_t *buffer, size_t size, int flags)
Thiago Macieiraf1cadf02015-05-08 17:19:17 -0700198{
199 encoder->ptr = buffer;
200 encoder->end = buffer + size;
Thiago Macieira4e9626c2015-09-21 14:57:17 -0700201 encoder->added = 0;
Thiago Macieiraf1cadf02015-05-08 17:19:17 -0700202 encoder->flags = flags;
203}
204
Thiago Macieira5752ce52015-06-16 12:10:03 -0700205static inline void put16(void *where, uint16_t v)
Thiago Macieiraf1cadf02015-05-08 17:19:17 -0700206{
Thiago Macieira5934a9f2015-06-16 11:55:28 -0700207 v = cbor_htons(v);
Thiago Macieiraf1cadf02015-05-08 17:19:17 -0700208 memcpy(where, &v, sizeof(v));
209}
210
Thiago Macieiradbc01292016-06-06 17:02:25 -0700211/* Note: Since this is currently only used in situations where OOM is the only
212 * valid error, we KNOW this to be true. Thus, this function now returns just 'true',
213 * but if in the future, any function starts returning a non-OOM error, this will need
214 * to be changed to the test. At the moment, this is done to prevent more branches
215 * being created in the tinycbor output */
Erich Keane47a78562015-08-10 15:19:50 -0700216static inline bool isOomError(CborError err)
217{
218 (void) err;
219 return true;
220}
221
Thiago Macieira5752ce52015-06-16 12:10:03 -0700222static inline void put32(void *where, uint32_t v)
Thiago Macieiraf1cadf02015-05-08 17:19:17 -0700223{
Thiago Macieira5934a9f2015-06-16 11:55:28 -0700224 v = cbor_htonl(v);
Thiago Macieiraf1cadf02015-05-08 17:19:17 -0700225 memcpy(where, &v, sizeof(v));
226}
227
Thiago Macieira5752ce52015-06-16 12:10:03 -0700228static inline void put64(void *where, uint64_t v)
Thiago Macieiraf1cadf02015-05-08 17:19:17 -0700229{
Thiago Macieira5934a9f2015-06-16 11:55:28 -0700230 v = cbor_htonll(v);
Thiago Macieiraf1cadf02015-05-08 17:19:17 -0700231 memcpy(where, &v, sizeof(v));
232}
233
Thiago Macieira397f9792015-09-18 19:36:26 -0700234static inline bool would_overflow(CborEncoder *encoder, size_t len)
235{
236 ptrdiff_t remaining = (ptrdiff_t)encoder->end;
237 remaining -= remaining ? (ptrdiff_t)encoder->ptr : encoder->bytes_needed;
238 remaining -= (ptrdiff_t)len;
239 return unlikely(remaining < 0);
240}
241
242static inline void advance_ptr(CborEncoder *encoder, size_t n)
243{
244 if (encoder->end)
245 encoder->ptr += n;
246 else
247 encoder->bytes_needed += n;
248}
249
Thiago Macieira5752ce52015-06-16 12:10:03 -0700250static inline CborError append_to_buffer(CborEncoder *encoder, const void *data, size_t len)
Thiago Macieiraf1cadf02015-05-08 17:19:17 -0700251{
Thiago Macieira397f9792015-09-18 19:36:26 -0700252 if (would_overflow(encoder, len)) {
Erich Keane47a78562015-08-10 15:19:50 -0700253 if (encoder->end != NULL) {
254 len -= encoder->end - encoder->ptr;
Thiago Macieira397f9792015-09-18 19:36:26 -0700255 encoder->end = NULL;
256 encoder->bytes_needed = 0;
Erich Keane47a78562015-08-10 15:19:50 -0700257 }
258
Thiago Macieira397f9792015-09-18 19:36:26 -0700259 advance_ptr(encoder, len);
Thiago Macieiraf1cadf02015-05-08 17:19:17 -0700260 return CborErrorOutOfMemory;
Erich Keane47a78562015-08-10 15:19:50 -0700261 }
262
Thiago Macieiraf1cadf02015-05-08 17:19:17 -0700263 memcpy(encoder->ptr, data, len);
264 encoder->ptr += len;
265 return CborNoError;
266}
267
Thiago Macieira5752ce52015-06-16 12:10:03 -0700268static inline CborError append_byte_to_buffer(CborEncoder *encoder, uint8_t byte)
Thiago Macieira8f7bd9e2015-05-12 13:37:46 +0900269{
Thiago Macieira618d2f12015-09-22 09:14:29 -0700270 return append_to_buffer(encoder, &byte, 1);
Thiago Macieira8f7bd9e2015-05-12 13:37:46 +0900271}
272
Thiago Macieira4e9626c2015-09-21 14:57:17 -0700273static inline CborError encode_number_no_update(CborEncoder *encoder, uint64_t ui, uint8_t shiftedMajorType)
Thiago Macieiraf1cadf02015-05-08 17:19:17 -0700274{
Thiago Macieiraafa4ff62015-05-09 10:09:55 -0700275 /* Little-endian would have been so much more convenient here:
276 * We could just write at the beginning of buf but append_to_buffer
277 * only the necessary bytes.
278 * Since it has to be big endian, do it the other way around:
279 * write from the end. */
Thiago Macieira510e5b82015-09-21 16:05:02 -0700280 uint64_t buf[2];
281 uint8_t *const bufend = (uint8_t *)buf + sizeof(buf);
Thiago Macieira5752ce52015-06-16 12:10:03 -0700282 uint8_t *bufstart = bufend - 1;
Thiago Macieiradbc01292016-06-06 17:02:25 -0700283 put64(buf + 1, ui); /* we probably have a bunch of zeros in the beginning */
Thiago Macieiraf1cadf02015-05-08 17:19:17 -0700284
285 if (ui < Value8Bit) {
Thiago Macieiraafa4ff62015-05-09 10:09:55 -0700286 *bufstart += shiftedMajorType;
Thiago Macieiraf1cadf02015-05-08 17:19:17 -0700287 } else {
Thiago Macieiraafa4ff62015-05-09 10:09:55 -0700288 unsigned more = 0;
Thiago Macieira13c85792015-07-07 16:15:41 -0700289 if (ui > 0xffU)
Thiago Macieiraafa4ff62015-05-09 10:09:55 -0700290 ++more;
Thiago Macieira13c85792015-07-07 16:15:41 -0700291 if (ui > 0xffffU)
Thiago Macieiraafa4ff62015-05-09 10:09:55 -0700292 ++more;
Thiago Macieira13c85792015-07-07 16:15:41 -0700293 if (ui > 0xffffffffU)
Thiago Macieiraafa4ff62015-05-09 10:09:55 -0700294 ++more;
Thiago Macieirae12dfd02016-06-07 16:29:25 -0700295 bufstart -= (size_t)1 << more;
Thiago Macieiraafa4ff62015-05-09 10:09:55 -0700296 *bufstart = shiftedMajorType + Value8Bit + more;
Thiago Macieiraf1cadf02015-05-08 17:19:17 -0700297 }
298
Thiago Macieiraafa4ff62015-05-09 10:09:55 -0700299 return append_to_buffer(encoder, bufstart, bufend - bufstart);
Thiago Macieiraf1cadf02015-05-08 17:19:17 -0700300}
301
Thiago Macieira4e9626c2015-09-21 14:57:17 -0700302static inline CborError encode_number(CborEncoder *encoder, uint64_t ui, uint8_t shiftedMajorType)
303{
304 ++encoder->added;
305 return encode_number_no_update(encoder, ui, shiftedMajorType);
306}
307
Thiago Macieira46a818e2015-10-08 15:13:05 +0200308/**
309 * Appends the unsigned 64-bit integer \a value to the CBOR stream provided by
310 * \a encoder.
311 *
312 * \sa cbor_encode_negative_int, cbor_encode_int
313 */
Thiago Macieiraf1cadf02015-05-08 17:19:17 -0700314CborError cbor_encode_uint(CborEncoder *encoder, uint64_t value)
315{
316 return encode_number(encoder, value, UnsignedIntegerType << MajorTypeShift);
317}
318
Thiago Macieira46a818e2015-10-08 15:13:05 +0200319/**
320 * Appends the negative 64-bit integer whose absolute value is \a
321 * absolute_value to the CBOR stream provided by \a encoder.
322 *
323 * \sa cbor_encode_uint, cbor_encode_int
324 */
Thiago Macieira78632b32015-09-26 14:18:48 -0700325CborError cbor_encode_negative_int(CborEncoder *encoder, uint64_t absolute_value)
326{
327 return encode_number(encoder, absolute_value, NegativeIntegerType << MajorTypeShift);
328}
329
Thiago Macieira46a818e2015-10-08 15:13:05 +0200330/**
331 * Appends the signed 64-bit integer \a value to the CBOR stream provided by
332 * \a encoder.
333 *
334 * \sa cbor_encode_negative_int, cbor_encode_uint
335 */
Thiago Macieiraf1cadf02015-05-08 17:19:17 -0700336CborError cbor_encode_int(CborEncoder *encoder, int64_t value)
337{
Thiago Macieiradbc01292016-06-06 17:02:25 -0700338 /* adapted from code in RFC 7049 appendix C (pseudocode) */
339 uint64_t ui = value >> 63; /* extend sign to whole length */
340 uint8_t majorType = ui & 0x20; /* extract major type */
341 ui ^= value; /* complement negatives */
Thiago Macieiraf1cadf02015-05-08 17:19:17 -0700342 return encode_number(encoder, ui, majorType);
343}
344
Thiago Macieira46a818e2015-10-08 15:13:05 +0200345/**
346 * Appends the CBOR Simple Type of value \a value to the CBOR stream provided by
347 * \a encoder.
348 *
349 * This function may return error CborErrorIllegalSimpleType if the \a value
350 * variable contains a number that is not a valid simple type.
351 */
Thiago Macieiraf1cadf02015-05-08 17:19:17 -0700352CborError cbor_encode_simple_value(CborEncoder *encoder, uint8_t value)
353{
354#ifndef CBOR_ENCODER_NO_CHECK_USER
Thiago Macieiradbc01292016-06-06 17:02:25 -0700355 /* check if this is a valid simple type */
Thiago Macieiraf1cadf02015-05-08 17:19:17 -0700356 if (value >= HalfPrecisionFloat && value <= Break)
357 return CborErrorIllegalSimpleType;
358#endif
359 return encode_number(encoder, value, SimpleTypesType << MajorTypeShift);
360}
361
Thiago Macieira46a818e2015-10-08 15:13:05 +0200362/**
363 * Appends the floating-point value of type \a fpType and pointed to by \a
364 * value to the CBOR stream provided by \a encoder. The value of \a fpType must
365 * be one of CborHalfFloatType, CborFloatType or CborDoubleType, otherwise the
366 * behavior of this function is undefined.
367 *
368 * This function is useful for code that needs to pass through floating point
369 * values but does not wish to have the actual floating-point code.
370 *
371 * \sa cbor_encode_half_float, cbor_encode_float, cbor_encode_double
372 */
Thiago Macieira81f33432015-07-02 16:16:28 -0700373CborError cbor_encode_floating_point(CborEncoder *encoder, CborType fpType, const void *value)
Thiago Macieiraf1cadf02015-05-08 17:19:17 -0700374{
Thiago Macieira81f33432015-07-02 16:16:28 -0700375 uint8_t buf[1 + sizeof(uint64_t)];
376 assert(fpType == CborHalfFloatType || fpType == CborFloatType || fpType == CborDoubleType);
377 buf[0] = fpType;
Thiago Macieiraf1cadf02015-05-08 17:19:17 -0700378
Thiago Macieira81f33432015-07-02 16:16:28 -0700379 unsigned size = 2U << (fpType - CborHalfFloatType);
380 if (size == 8)
381 put64(buf + 1, *(const uint64_t*)value);
382 else if (size == 4)
383 put32(buf + 1, *(const uint32_t*)value);
384 else
385 put16(buf + 1, *(const uint16_t*)value);
Thiago Macieira4e9626c2015-09-21 14:57:17 -0700386 ++encoder->added;
Thiago Macieira81f33432015-07-02 16:16:28 -0700387 return append_to_buffer(encoder, buf, size + 1);
Thiago Macieiraf1cadf02015-05-08 17:19:17 -0700388}
Thiago Macieira8f98a112015-05-08 17:25:29 -0700389
Thiago Macieira46a818e2015-10-08 15:13:05 +0200390/**
391 * Appends the CBOR tag \a tag to the CBOR stream provided by \a encoder.
392 *
393 * \sa CborTag
394 */
Thiago Macieira8f98a112015-05-08 17:25:29 -0700395CborError cbor_encode_tag(CborEncoder *encoder, CborTag tag)
396{
Thiago Macieiradbc01292016-06-06 17:02:25 -0700397 /* tags don't count towards the number of elements in an array or map */
Thiago Macieira4e9626c2015-09-21 14:57:17 -0700398 return encode_number_no_update(encoder, tag, TagType << MajorTypeShift);
Thiago Macieira8f98a112015-05-08 17:25:29 -0700399}
Thiago Macieirab54debe2015-05-08 17:42:39 -0700400
Thiago Macieira5752ce52015-06-16 12:10:03 -0700401static CborError encode_string(CborEncoder *encoder, size_t length, uint8_t shiftedMajorType, const void *string)
Thiago Macieirab54debe2015-05-08 17:42:39 -0700402{
403 CborError err = encode_number(encoder, length, shiftedMajorType);
Erich Keane47a78562015-08-10 15:19:50 -0700404 if (err && !isOomError(err))
Thiago Macieirab54debe2015-05-08 17:42:39 -0700405 return err;
406 return append_to_buffer(encoder, string, length);
407}
408
Thiago Macieira46a818e2015-10-08 15:13:05 +0200409/**
410 * \fn CborError cbor_encode_text_stringz(CborEncoder *encoder, const char *string)
411 *
412 * Appends the null-terminated text string \a string to the CBOR stream
413 * provided by \a encoder. CBOR requires that \a string be valid UTF-8, but
414 * TinyCBOR makes no verification of correctness. The terminating null is not
415 * included in the stream.
416 *
417 * \sa cbor_encode_text_string, cbor_encode_byte_string
418 */
419
420/**
421 * Appends the text string \a string of length \a length to the CBOR stream
422 * provided by \a encoder. CBOR requires that \a string be valid UTF-8, but
423 * TinyCBOR makes no verification of correctness.
424 *
425 * \sa CborError cbor_encode_text_stringz, cbor_encode_byte_string
426 */
Thiago Macieira5752ce52015-06-16 12:10:03 -0700427CborError cbor_encode_byte_string(CborEncoder *encoder, const uint8_t *string, size_t length)
Thiago Macieirab54debe2015-05-08 17:42:39 -0700428{
429 return encode_string(encoder, length, ByteStringType << MajorTypeShift, string);
430}
431
Thiago Macieira46a818e2015-10-08 15:13:05 +0200432/**
433 * Appends the byte string \a string of length \a length to the CBOR stream
434 * provided by \a encoder. CBOR byte strings are arbitrary raw data.
435 *
436 * \sa cbor_encode_text_stringz, cbor_encode_text_string
437 */
Thiago Macieirab54debe2015-05-08 17:42:39 -0700438CborError cbor_encode_text_string(CborEncoder *encoder, const char *string, size_t length)
439{
440 return encode_string(encoder, length, TextStringType << MajorTypeShift, string);
441}
Thiago Macieira355817e2015-05-08 18:38:18 -0700442
Thiago Macieira56635242015-09-20 17:44:51 -0700443#ifdef __GNUC__
444__attribute__((noinline))
445#endif
446static CborError create_container(CborEncoder *encoder, CborEncoder *container, size_t length, uint8_t shiftedMajorType)
Thiago Macieira355817e2015-05-08 18:38:18 -0700447{
Thiago Macieira8f7bd9e2015-05-12 13:37:46 +0900448 CborError err;
Thiago Macieira4e9626c2015-09-21 14:57:17 -0700449 container->ptr = encoder->ptr;
450 container->end = encoder->end;
451 ++encoder->added;
452 container->added = 0;
453
454 cbor_static_assert(((MapType << MajorTypeShift) & CborIteratorFlag_ContainerIsMap) == CborIteratorFlag_ContainerIsMap);
455 cbor_static_assert(((ArrayType << MajorTypeShift) & CborIteratorFlag_ContainerIsMap) == 0);
456 container->flags = shiftedMajorType & CborIteratorFlag_ContainerIsMap;
457
458 if (length == CborIndefiniteLength) {
459 container->flags |= CborIteratorFlag_UnknownLength;
460 err = append_byte_to_buffer(container, shiftedMajorType + IndefiniteLength);
461 } else {
462 err = encode_number_no_update(container, length, shiftedMajorType);
463 }
Erich Keane47a78562015-08-10 15:19:50 -0700464 if (err && !isOomError(err))
Thiago Macieira355817e2015-05-08 18:38:18 -0700465 return err;
Thiago Macieira8f7bd9e2015-05-12 13:37:46 +0900466
Thiago Macieira355817e2015-05-08 18:38:18 -0700467 return CborNoError;
468}
469
Thiago Macieira46a818e2015-10-08 15:13:05 +0200470/**
471 * Creates a CBOR array in the CBOR stream provided by \a encoder and
472 * initializes \a arrayEncoder so that items can be added to the array using
473 * the CborEncoder functions. The array must be terminated by calling either
474 * cbor_encoder_close_container() or cbor_encoder_close_container_checked()
475 * with the same \a encoder and \a arrayEncoder parameters.
476 *
477 * The number of items inserted into the array must be exactly \a length items,
478 * otherwise the stream is invalid. If the number of items is not known when
479 * creating the array, the constant \ref CborIndefiniteLength may be passed as
480 * length instead.
481 *
482 * \sa cbor_encoder_create_map
483 */
Thiago Macieira355817e2015-05-08 18:38:18 -0700484CborError cbor_encoder_create_array(CborEncoder *encoder, CborEncoder *arrayEncoder, size_t length)
485{
Thiago Macieira56635242015-09-20 17:44:51 -0700486 return create_container(encoder, arrayEncoder, length, ArrayType << MajorTypeShift);
Thiago Macieira355817e2015-05-08 18:38:18 -0700487}
488
Thiago Macieira46a818e2015-10-08 15:13:05 +0200489/**
490 * Creates a CBOR map in the CBOR stream provided by \a encoder and
491 * initializes \a mapEncoder so that items can be added to the map using
492 * the CborEncoder functions. The map must be terminated by calling either
493 * cbor_encoder_close_container() or cbor_encoder_close_container_checked()
494 * with the same \a encoder and \a mapEncoder parameters.
495 *
496 * The number of pair of items inserted into the map must be exactly \a length
497 * items, otherwise the stream is invalid. If the number of items is not known
498 * when creating the map, the constant \ref CborIndefiniteLength may be passed as
499 * length instead.
500 *
501 * \b{Implementation limitation:} TinyCBOR cannot encode more than SIZE_MAX/2
502 * key-value pairs in the stream. If the length \a length is larger than this
503 * value, this function returns error CborErrorDataTooLarge.
504 *
505 * \sa cbor_encoder_create_array
506 */
Thiago Macieira355817e2015-05-08 18:38:18 -0700507CborError cbor_encoder_create_map(CborEncoder *encoder, CborEncoder *mapEncoder, size_t length)
508{
Thiago Macieira4e9626c2015-09-21 14:57:17 -0700509 if (length != CborIndefiniteLength && length > SIZE_MAX / 2)
510 return CborErrorDataTooLarge;
Thiago Macieira56635242015-09-20 17:44:51 -0700511 return create_container(encoder, mapEncoder, length, MapType << MajorTypeShift);
Thiago Macieira355817e2015-05-08 18:38:18 -0700512}
513
Thiago Macieira46a818e2015-10-08 15:13:05 +0200514/**
515 * Closes the CBOR container (array or map) provided by \a containerEncoder and
516 * updates the CBOR stream provided by \a encoder. Both parameters must be the
517 * same as were passed to cbor_encoder_create_array() or
518 * cbor_encoder_create_map().
519 *
520 * This function does not verify that the number of items (or pair of items, in
521 * the case of a map) was correct. To execute that verification, call
522 * cbor_encoder_close_container_checked() instead.
523 *
524 * \sa cbor_encoder_create_array(), cbor_encoder_create_map()
525 */
Thiago Macieira355817e2015-05-08 18:38:18 -0700526CborError cbor_encoder_close_container(CborEncoder *encoder, const CborEncoder *containerEncoder)
527{
Thiago Macieira397f9792015-09-18 19:36:26 -0700528 if (encoder->end)
529 encoder->ptr = containerEncoder->ptr;
530 else
531 encoder->bytes_needed = containerEncoder->bytes_needed;
Erich Keane47a78562015-08-10 15:19:50 -0700532 encoder->end = containerEncoder->end;
Thiago Macieira8f7bd9e2015-05-12 13:37:46 +0900533 if (containerEncoder->flags & CborIteratorFlag_UnknownLength)
534 return append_byte_to_buffer(encoder, BreakByte);
Thiago Macieira355817e2015-05-08 18:38:18 -0700535 return CborNoError;
536}
Thiago Macieira46a818e2015-10-08 15:13:05 +0200537
538/**
539 * \fn CborError cbor_encode_boolean(CborEncoder *encoder, bool value)
540 *
541 * Appends the boolean value \a value to the CBOR stream provided by \a encoder.
542 */
543
544/**
545 * \fn CborError cbor_encode_null(CborEncoder *encoder)
546 *
547 * Appends the CBOR type representing a null value to the CBOR stream provided
548 * by \a encoder.
549 *
550 * \sa cbor_encode_undefined()
551 */
552
553/**
554 * \fn CborError cbor_encode_undefined(CborEncoder *encoder)
555 *
556 * Appends the CBOR type representing an undefined value to the CBOR stream
557 * provided by \a encoder.
558 *
559 * \sa cbor_encode_null()
560 */
561
562/**
563 * \fn CborError cbor_encode_half_float(CborEncoder *encoder, const void *value)
564 *
565 * Appends the IEEE 754 half-precision (16-bit) floating point value pointed to
566 * by \a value to the CBOR stream provided by \a encoder.
567 *
568 * \sa cbor_encode_floating_point(), cbor_encode_float(), cbor_encode_double()
569 */
570
571/**
572 * \fn CborError cbor_encode_float(CborEncoder *encoder, float value)
573 *
574 * Appends the IEEE 754 single-precision (32-bit) floating point value \a value
575 * to the CBOR stream provided by \a encoder.
576 *
577 * \sa cbor_encode_floating_point(), cbor_encode_half_float(), cbor_encode_double()
578 */
579
580/**
581 * \fn CborError cbor_encode_double(CborEncoder *encoder, double value)
582 *
583 * Appends the IEEE 754 double-precision (64-bit) floating point value \a value
584 * to the CBOR stream provided by \a encoder.
585 *
586 * \sa cbor_encode_floating_point(), cbor_encode_half_float(), cbor_encode_float()
587 */
588
Thiago Macieira7ae36a72015-10-28 16:19:23 -0700589/**
590 * \fn size_t cbor_encoder_get_buffer_size(const CborEncoder *encoder, const uint8_t *buffer)
591 *
592 * Returns the total size of the buffer starting at \a buffer after the
593 * encoding finished without errors. The \a encoder and \a buffer arguments
594 * must be the same as supplied to cbor_encoder_init().
595 *
596 * If the encoding process had errors, the return value of this function is
597 * meaningless. If the only errors were CborErrorOutOfMemory, instead use
598 * cbor_encoder_get_extra_bytes_needed() to find out by how much to grow the
599 * buffer before encoding again.
600 *
601 * See \ref CborEncoding for an example of using this function.
602 *
603 * \sa cbor_encoder_init(), cbor_encoder_get_extra_bytes_needed(), CborEncoding
604 */
605
606/**
607 * \fn size_t cbor_encoder_get_extra_bytes_needed(const CborEncoder *encoder)
608 *
609 * Returns how many more bytes the original buffer supplied to
610 * cbor_encoder_init() needs to be extended by so that no CborErrorOutOfMemory
611 * condition will happen for the encoding. If the buffer was big enough, this
612 * function returns 0. The \a encoder must be the original argument as passed
613 * to cbor_encoder_init().
614 *
615 * This function is usually called after an encoding sequence ended with one or
616 * more CborErrorOutOfMemory errors, but no other error. If any other error
617 * happened, the return value of this function is meaningless.
618 *
619 * See \ref CborEncoding for an example of using this function.
620 *
621 * \sa cbor_encoder_init(), cbor_encoder_get_buffer_size(), CborEncoding
622 */
623
Thiago Macieira46a818e2015-10-08 15:13:05 +0200624/** @} */