Contiki-NG
Loading...
Searching...
No Matches
cbor.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2018, SICS, RISE AB
3 * Copyright (c) 2023, Uppsala universitet
4 * Copyright (c) 2024, Siemens AG
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the Institute nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32/**
33 * \addtogroup cbor
34 * @{
35 * \file
36 * CBOR implementation.
37 */
38
39#include "lib/cbor.h"
40#include <string.h>
41
42/*---------------------------------------------------------------------------*/
43void
45 uint8_t *buffer, size_t buffer_size)
46{
47 state->buffer_head = buffer;
48 state->buffer = buffer;
49 state->buffer_size = buffer_size;
50 state->nesting_depth = CBOR_MAX_NESTING;
51}
52/*---------------------------------------------------------------------------*/
53size_t
55{
56 return (state->nesting_depth == CBOR_MAX_NESTING) && state->buffer
57 ? (size_t)(state->buffer - state->buffer_head)
58 : 0;
59}
60/*---------------------------------------------------------------------------*/
61void
63{
64 state->buffer = NULL;
65 state->buffer_size = 0;
66}
67/*---------------------------------------------------------------------------*/
68static void
69increment(cbor_writer_state_t *state)
70{
71 if(state->nesting_depth == CBOR_MAX_NESTING) {
72 return;
73 }
74 state->records[state->nesting_depth].objects++;
75}
76/*---------------------------------------------------------------------------*/
77static void
78write_first_byte(cbor_writer_state_t *state, uint_fast8_t value)
79{
80 if(!state->buffer_size) {
81 cbor_break_writer(state);
82 return;
83 }
84 *state->buffer++ = value;
85 state->buffer_size--;
86 increment(state);
87}
88/*---------------------------------------------------------------------------*/
89static void
90write_object(cbor_writer_state_t *state,
91 const void *object, size_t object_size)
92{
93 if(!object_size) {
94 return;
95 }
96 if(state->buffer_size < object_size) {
97 cbor_break_writer(state);
98 return;
99 }
100 memcpy(state->buffer, object, object_size);
101 state->buffer += object_size;
102 state->buffer_size -= object_size;
103}
104/*---------------------------------------------------------------------------*/
105void
107 const void *object, size_t object_size)
108{
109 if(!object_size) {
110 return;
111 }
112 write_object(state, object, object_size);
113 increment(state);
114}
115/*---------------------------------------------------------------------------*/
116static void
117insert_unsigned(cbor_writer_state_t *state,
118 uint8_t *const destination,
119 uint64_t value)
120{
121 size_t length_to_copy;
122
123 if(!state->buffer) {
124 return;
125 }
126
127 /* update additional information */
128 if(value < CBOR_SIZE_1) {
129 destination[-1] |= value;
130 return;
131 }
132 if(value <= UINT8_MAX) {
133 length_to_copy = 1;
134 destination[-1] |= CBOR_SIZE_1;
135 } else if(value <= UINT16_MAX) {
136 length_to_copy = 2;
137 destination[-1] |= CBOR_SIZE_2;
138 } else if(value <= UINT32_MAX) {
139 length_to_copy = 4;
140 destination[-1] |= CBOR_SIZE_4;
141 } else {
142 length_to_copy = 8;
143 destination[-1] |= CBOR_SIZE_8;
144 }
145
146 /* check if there is enough space left */
147 if(state->buffer_size < length_to_copy) {
148 cbor_break_writer(state);
149 return;
150 }
151
152 /* move when inserting */
153 memmove(destination + length_to_copy,
154 destination,
155 state->buffer - destination);
156
157 /* update buffer variables */
158 state->buffer += length_to_copy;
159 state->buffer_size -= length_to_copy;
160
161 /* serialize value */
162 while(length_to_copy--) {
163 destination[length_to_copy] = value;
164 value >>= 8;
165 }
166}
167/*---------------------------------------------------------------------------*/
168void
170{
171 write_first_byte(state, CBOR_MAJOR_TYPE_UNSIGNED);
172 insert_unsigned(state, state->buffer, value);
173}
174/*---------------------------------------------------------------------------*/
175void
177{
178 if(value >= 0) {
179 cbor_write_unsigned(state, (uint64_t)value);
180 } else {
181 write_first_byte(state, CBOR_MAJOR_TYPE_SIGNED);
182 insert_unsigned(state, state->buffer, (uint64_t)(-1 - value));
183 }
184}
185/*---------------------------------------------------------------------------*/
186void
188 const uint8_t *data, size_t data_size)
189{
190 write_first_byte(state, CBOR_MAJOR_TYPE_BYTE_STRING);
191 insert_unsigned(state, state->buffer, data_size);
192 write_object(state, data, data_size);
193}
194/*---------------------------------------------------------------------------*/
195void
197 const char *text, size_t text_size)
198{
199 write_first_byte(state, CBOR_MAJOR_TYPE_TEXT_STRING);
200 insert_unsigned(state, state->buffer, text_size);
201 write_object(state, text, text_size);
202}
203/*---------------------------------------------------------------------------*/
204void
206{
207 write_first_byte(state, CBOR_SIMPLE_VALUE_NULL);
208}
209/*---------------------------------------------------------------------------*/
210void
212{
213 write_first_byte(state, CBOR_SIMPLE_VALUE_UNDEFINED);
214}
215/*---------------------------------------------------------------------------*/
216void
218{
219 write_first_byte(state,
220 boolean ? CBOR_SIMPLE_VALUE_TRUE : CBOR_SIMPLE_VALUE_FALSE);
221}
222/*---------------------------------------------------------------------------*/
223static void
224generic_open(cbor_writer_state_t *state, cbor_major_type_t major_type)
225{
226 if(!state->nesting_depth) {
227 cbor_break_writer(state);
228 return;
229 }
230 write_first_byte(state, major_type);
231 state->records[--state->nesting_depth].start = state->buffer;
232 state->records[state->nesting_depth].objects = 0;
233}
234/*---------------------------------------------------------------------------*/
235static void
236generic_close(cbor_writer_state_t *state, size_t value)
237{
238 insert_unsigned(state, state->records[state->nesting_depth].start, value);
239 state->nesting_depth++;
240}
241/*---------------------------------------------------------------------------*/
242void
244{
245 generic_open(state, CBOR_MAJOR_TYPE_BYTE_STRING);
246}
247/*---------------------------------------------------------------------------*/
248void
250{
251 if(state->nesting_depth == CBOR_MAX_NESTING) {
252 cbor_break_writer(state);
253 return;
254 }
255 generic_close(state,
256 state->buffer - state->records[state->nesting_depth].start);
257}
258/*---------------------------------------------------------------------------*/
259void
261{
262 generic_open(state, CBOR_MAJOR_TYPE_ARRAY);
263}
264/*---------------------------------------------------------------------------*/
265void
267{
268 if(state->nesting_depth == CBOR_MAX_NESTING) {
269 cbor_break_writer(state);
270 return;
271 }
272 generic_close(state, state->records[state->nesting_depth].objects);
273}
274/*---------------------------------------------------------------------------*/
275void
277{
278 generic_open(state, CBOR_MAJOR_TYPE_MAP);
279}
280/*---------------------------------------------------------------------------*/
281void
283{
284 if((state->nesting_depth == CBOR_MAX_NESTING)
285 || (state->records[state->nesting_depth].objects & 1)) {
286 cbor_break_writer(state);
287 return;
288 }
289 generic_close(state, state->records[state->nesting_depth].objects >> 1);
290}
291/*---------------------------------------------------------------------------*/
292void
294 const uint8_t *cbor, size_t cbor_size)
295{
296 state->cbor = cbor;
297 state->cbor_size = cbor_size;
298}
299/*---------------------------------------------------------------------------*/
302{
303 if(!state->cbor_size) {
304 return CBOR_MAJOR_TYPE_NONE;
305 }
306 return *state->cbor & 0xE0;
307}
308/*---------------------------------------------------------------------------*/
309bool
311{
312 return state->cbor_size == 0;
313}
314/*---------------------------------------------------------------------------*/
317{
318 size_t bytes_to_read;
319
320 if(!state->cbor_size) {
321 return CBOR_SIZE_NONE;
322 }
323 cbor_size_t size = *state->cbor & ~0xE0;
324 state->cbor++;
325 state->cbor_size--;
326
327 if(size < CBOR_SIZE_1) {
328 *value = size;
329 return CBOR_SIZE_1;
330 }
331
332 switch(size) {
333 case CBOR_SIZE_1:
334 bytes_to_read = 1;
335 break;
336 case CBOR_SIZE_2:
337 bytes_to_read = 2;
338 break;
339 case CBOR_SIZE_4:
340 bytes_to_read = 4;
341 break;
342 case CBOR_SIZE_8:
343 bytes_to_read = 8;
344 break;
345 case CBOR_SIZE_NONE:
346 default:
347 return CBOR_SIZE_NONE;
348 }
349
350 if(bytes_to_read > state->cbor_size) {
351 return CBOR_SIZE_NONE;
352 }
353 state->cbor_size -= bytes_to_read;
354
355 *value = 0;
356 while(bytes_to_read--) {
357 *value <<= 8;
358 *value += *state->cbor++;
359 }
360 return size;
361}
362/*---------------------------------------------------------------------------*/
365{
366 uint64_t unsigned_value;
367 cbor_major_type_t type = cbor_peek_next(state);
368 cbor_size_t size = cbor_read_unsigned(state, &unsigned_value);
369 if(size == CBOR_SIZE_NONE || unsigned_value > INT64_MAX) {
370 return CBOR_SIZE_NONE;
371 }
372
373 switch(type) {
374 case CBOR_MAJOR_TYPE_UNSIGNED:
375 *value = (int64_t)unsigned_value;
376 return size;
377 case CBOR_MAJOR_TYPE_SIGNED:
378 *value = -(int64_t)(unsigned_value + 1);
379 return size;
380 default:
381 return CBOR_SIZE_NONE;
382 }
383}
384/*---------------------------------------------------------------------------*/
385static const uint8_t *
386read_byte_or_text_string(cbor_reader_state_t *state, size_t *size)
387{
388 uint64_t value;
389
390 if((CBOR_SIZE_NONE == cbor_read_unsigned(state, &value))
391 || (state->cbor_size < value)) {
392 return NULL;
393 }
394 *size = value;
395 const uint8_t *beginning = state->cbor;
396 state->cbor += *size;
397 state->cbor_size -= *size;
398 return beginning;
399}
400/*---------------------------------------------------------------------------*/
401const uint8_t *
402cbor_read_data(cbor_reader_state_t *state, size_t *data_size)
403{
404 if(cbor_peek_next(state) != CBOR_MAJOR_TYPE_BYTE_STRING) {
405 return NULL;
406 }
407 return read_byte_or_text_string(state, data_size);
408}
409/*---------------------------------------------------------------------------*/
410const char *
411cbor_read_text(cbor_reader_state_t *state, size_t *text_size)
412{
413 if(cbor_peek_next(state) != CBOR_MAJOR_TYPE_TEXT_STRING) {
414 return NULL;
415 }
416 return (const char *)read_byte_or_text_string(state, text_size);
417}
418/*---------------------------------------------------------------------------*/
421{
422 if(!state->cbor_size) {
423 return CBOR_SIMPLE_VALUE_NONE;
424 }
425 state->cbor_size--;
426 return *state->cbor++;
427}
428/*---------------------------------------------------------------------------*/
429static size_t
430read_array_or_map(cbor_reader_state_t *state)
431{
432 uint64_t value;
433
434 if((CBOR_SIZE_NONE == cbor_read_unsigned(state, &value))
435 || (value >= SIZE_MAX)) {
436 return SIZE_MAX;
437 }
438 return value;
439}
440/*---------------------------------------------------------------------------*/
441size_t
443{
444 if(cbor_peek_next(state) != CBOR_MAJOR_TYPE_ARRAY) {
445 return SIZE_MAX;
446 }
447 return read_array_or_map(state);
448}
449/*---------------------------------------------------------------------------*/
450size_t
452{
453 if(cbor_peek_next(state) != CBOR_MAJOR_TYPE_MAP) {
454 return SIZE_MAX;
455 }
456 return read_array_or_map(state);
457}
458/*---------------------------------------------------------------------------*/
459
460/** @} */
CBOR API.
size_t cbor_end_writer(cbor_writer_state_t *state)
Finishes writing CBOR output.
Definition cbor.c:54
void cbor_close_data(cbor_writer_state_t *state)
Stops enclosing subsequent CBOR objects in the innermost byte string.
Definition cbor.c:249
void cbor_open_map(cbor_writer_state_t *state)
Adds subsequent entries to a map.
Definition cbor.c:276
cbor_size_t cbor_read_signed(cbor_reader_state_t *state, int64_t *value)
Reads a signed integer.
Definition cbor.c:364
void cbor_break_writer(cbor_writer_state_t *state)
Marks the CBOR output as erroneous.
Definition cbor.c:62
size_t cbor_read_array(cbor_reader_state_t *state)
Reads the number of elements of an array.
Definition cbor.c:442
cbor_major_type_t
Enumeration of major types.
Definition cbor.h:75
bool cbor_end_reader(cbor_reader_state_t *state)
Ensures that no bytes remain unread.
Definition cbor.c:310
cbor_simple_value_t
Enumeration of simple values.
Definition cbor.h:89
cbor_size_t cbor_read_unsigned(cbor_reader_state_t *state, uint64_t *value)
Reads an unsigned integer.
Definition cbor.c:316
cbor_simple_value_t cbor_read_simple(cbor_reader_state_t *state)
Reads a simple value.
Definition cbor.c:420
void cbor_write_text(cbor_writer_state_t *state, const char *text, size_t text_size)
Appends a text string.
Definition cbor.c:196
void cbor_write_unsigned(cbor_writer_state_t *state, uint64_t value)
Appends an unsigned integer.
Definition cbor.c:169
cbor_major_type_t cbor_peek_next(cbor_reader_state_t *state)
Inspects the next major type.
Definition cbor.c:301
void cbor_write_null(cbor_writer_state_t *state)
Appends the simple value null.
Definition cbor.c:205
void cbor_open_data(cbor_writer_state_t *state)
Encloses subsequent CBOR objects in a byte string.
Definition cbor.c:243
void cbor_write_bool(cbor_writer_state_t *state, bool boolean)
Appends a boolean simple value.
Definition cbor.c:217
void cbor_open_array(cbor_writer_state_t *state)
Adds subsequent CBOR objects to an array.
Definition cbor.c:260
const uint8_t * cbor_read_data(cbor_reader_state_t *state, size_t *data_size)
Reads a byte string.
Definition cbor.c:402
void cbor_close_map(cbor_writer_state_t *state)
Stops adding subsequent entries to the innermost map.
Definition cbor.c:282
void cbor_write_object(cbor_writer_state_t *state, const void *object, size_t object_size)
Appends an arbitrary CBOR object.
Definition cbor.c:106
#define CBOR_MAX_NESTING
Defines how many arrays and maps can be open simultaneously while writing.
Definition cbor.h:58
void cbor_init_writer(cbor_writer_state_t *state, uint8_t *buffer, size_t buffer_size)
Prepares for writing CBOR output.
Definition cbor.c:44
cbor_size_t
Enumeration of size information in various major types.
Definition cbor.h:100
void cbor_close_array(cbor_writer_state_t *state)
Stops adding subsequent CBOR objects to the innermost array.
Definition cbor.c:266
void cbor_init_reader(cbor_reader_state_t *state, const uint8_t *cbor, size_t cbor_size)
Prepares for reading CBOR input.
Definition cbor.c:293
void cbor_write_data(cbor_writer_state_t *state, const uint8_t *data, size_t data_size)
Appends a byte string.
Definition cbor.c:187
void cbor_write_signed(cbor_writer_state_t *state, int64_t value)
Appends a signed integer.
Definition cbor.c:176
size_t cbor_read_map(cbor_reader_state_t *state)
Reads the number of entries of a map.
Definition cbor.c:451
void cbor_write_undefined(cbor_writer_state_t *state)
Appends the simple value undefined.
Definition cbor.c:211
const char * cbor_read_text(cbor_reader_state_t *state, size_t *text_size)
Reads a text string.
Definition cbor.c:411
@ CBOR_SIZE_NONE
error condition
Definition cbor.h:101
@ CBOR_SIZE_4
4 bytes
Definition cbor.h:104
@ CBOR_SIZE_2
2 bytes
Definition cbor.h:103
@ CBOR_SIZE_8
8 bytes
Definition cbor.h:105
@ CBOR_SIZE_1
1 byte
Definition cbor.h:102
Structure of the internal state of a CBOR reader.
Definition cbor.h:130
Structure of the internal state of a CBOR writer.
Definition cbor.h:119