1 /*
2 * This file has been copied from the cddl-gen submodule.
3 * Commit 9f77837f9950da1633d22abf6181a830521a6688
4 */
5
6 /*
7 * Copyright (c) 2020 Nordic Semiconductor ASA
8 *
9 * SPDX-License-Identifier: Apache-2.0
10 */
11
12 #include <stdint.h>
13 #include <stdbool.h>
14 #include <stddef.h>
15 #include <string.h>
16 #include "cbor_encode.h"
17 #include "cbor_common.h"
18
19 _Static_assert((sizeof(size_t) == sizeof(void *)),
20 "This code needs size_t to be the same length as pointers.");
21
get_additional(uint32_t len,uint8_t value0)22 uint8_t get_additional(uint32_t len, uint8_t value0)
23 {
24 switch(len) {
25 case 0: return value0;
26 case 1: return 24;
27 case 2: return 25;
28 case 3: return 25;
29 case 4: return 26;
30 case 5: return 26;
31 case 6: return 26;
32 case 7: return 26;
33 case 8: return 27;
34 }
35
36 cbor_assert(false, NULL);
37 return 0;
38 }
39
encode_header_byte(cbor_state_t * state,cbor_major_type_t major_type,uint8_t additional)40 static bool encode_header_byte(cbor_state_t *state,
41 cbor_major_type_t major_type, uint8_t additional)
42 {
43 if ((state->payload + 1) > state->payload_end) {
44 FAIL();
45 }
46
47 cbor_assert(additional < 32, NULL);
48
49 *(state->payload_mut++) = (major_type << 5) | (additional & 0x1F);
50 return true;
51 }
52
53 /** Encode a single value.
54 */
value_encode_len(cbor_state_t * state,cbor_major_type_t major_type,const void * const input,uint32_t result_len)55 static bool value_encode_len(cbor_state_t *state, cbor_major_type_t major_type,
56 const void *const input, uint32_t result_len)
57 {
58 uint8_t *u8_result = (uint8_t *)input;
59
60 if ((state->payload + 1 + result_len) > state->payload_end) {
61 FAIL();
62 }
63
64 if (!encode_header_byte(state, major_type,
65 get_additional(result_len, u8_result[0]))) {
66 FAIL();
67 }
68 state->payload_mut--;
69 cbor_trace();
70 state->payload_mut++;
71
72 #ifdef CONFIG_BIG_ENDIAN
73 memcpy(state->payload_mut, u8_result, result_len);
74 state->payload_mut += result_len;
75 #else
76 for (; result_len > 0; result_len--) {
77 *(state->payload_mut++) = u8_result[result_len - 1];
78 }
79 #endif
80
81 state->elem_count++;
82 return true;
83 }
84
85
get_result_len(const void * const input,uint32_t max_result_len)86 static uint32_t get_result_len(const void *const input, uint32_t max_result_len)
87 {
88 uint8_t *u8_result = (uint8_t *)input;
89 size_t i;
90
91 for (i = 0; i < max_result_len; i++) {
92 #ifdef CONFIG_BIG_ENDIAN
93 size_t idx = i;
94 #else
95 size_t idx = max_result_len - 1 - i;
96 #endif
97 if (u8_result[idx] != 0) {
98 break;
99 }
100 }
101 max_result_len -= i;
102
103 /* According to specification result length can be encoded on 1, 2, 4
104 * or 8 bytes.
105 */
106 cbor_assert(max_result_len <= 8, "Up to 8 bytes can be used to encode length.\n");
107 size_t encode_byte_cnt = 1;
108
109 for (size_t i = 0; i <= 3; i++) {
110 if (max_result_len <= encode_byte_cnt) {
111 max_result_len = encode_byte_cnt;
112 break;
113 }
114
115 encode_byte_cnt *= 2;
116 }
117
118 if ((max_result_len == 1) && (u8_result[0] <= VALUE_IN_HEADER)) {
119 max_result_len = 0;
120 }
121
122 return max_result_len;
123 }
124
125
value_encode(cbor_state_t * state,cbor_major_type_t major_type,const void * const input,uint32_t max_result_len)126 static bool value_encode(cbor_state_t *state, cbor_major_type_t major_type,
127 const void *const input, uint32_t max_result_len)
128 {
129 cbor_assert(max_result_len != 0, "0-length result not supported.\n");
130 return value_encode_len(state, major_type, input,
131 get_result_len(input, max_result_len));
132 }
133
134
intx32_put(cbor_state_t * state,int32_t input)135 bool intx32_put(cbor_state_t *state, int32_t input)
136 {
137 cbor_major_type_t major_type;
138
139 if (input < 0) {
140 major_type = CBOR_MAJOR_TYPE_NINT;
141 /* Convert from CBOR's representation. */
142 input = -1 - input;
143 } else {
144 major_type = CBOR_MAJOR_TYPE_PINT;
145 input = input;
146 }
147
148 if (!value_encode(state, major_type, &input, 4)) {
149 FAIL();
150 }
151
152 return true;
153 }
154
intx32_encode(cbor_state_t * state,const int32_t * input)155 bool intx32_encode(cbor_state_t *state, const int32_t *input)
156 {
157 return intx32_put(state, *input);
158 }
159
160
uint32_encode(cbor_state_t * state,const uint32_t * input,cbor_major_type_t major_type)161 static bool uint32_encode(cbor_state_t *state, const uint32_t *input,
162 cbor_major_type_t major_type)
163 {
164 if (!value_encode(state, major_type, input, 4)) {
165 FAIL();
166 }
167 return true;
168 }
169
170
uintx32_encode(cbor_state_t * state,const uint32_t * input)171 bool uintx32_encode(cbor_state_t *state, const uint32_t *input)
172 {
173 if (!uint32_encode(state, input, CBOR_MAJOR_TYPE_PINT)) {
174 FAIL();
175 }
176 return true;
177 }
178
179
uintx32_put(cbor_state_t * state,uint32_t input)180 bool uintx32_put(cbor_state_t *state, uint32_t input)
181 {
182 if (!uint32_encode(state, &input, CBOR_MAJOR_TYPE_PINT)) {
183 FAIL();
184 }
185 return true;
186 }
187
188
strx_start_encode(cbor_state_t * state,const cbor_string_type_t * input,cbor_major_type_t major_type)189 static bool strx_start_encode(cbor_state_t *state,
190 const cbor_string_type_t *input, cbor_major_type_t major_type)
191 {
192 if (input->value && ((get_result_len(&input->len, sizeof(input->len))
193 + 1 + input->len + (size_t)state->payload)
194 > (size_t)state->payload_end)) {
195 FAIL();
196 }
197 if (!uint32_encode(state, &input->len, major_type)) {
198 FAIL();
199 }
200
201 return true;
202 }
203
204
primx_encode(cbor_state_t * state,uint32_t input)205 static bool primx_encode(cbor_state_t *state, uint32_t input)
206 {
207 if (!uint32_encode(state, &input, CBOR_MAJOR_TYPE_PRIM)) {
208 FAIL();
209 }
210 return true;
211 }
212
213
remaining_str_len(cbor_state_t * state)214 static uint32_t remaining_str_len(cbor_state_t *state)
215 {
216 uint32_t max_len = (size_t)state->payload_end - (size_t)state->payload;
217 uint32_t result_len = get_result_len(&max_len, sizeof(uint32_t));
218 return max_len - result_len - 1;
219 }
220
221
bstrx_cbor_start_encode(cbor_state_t * state,const cbor_string_type_t * result)222 bool bstrx_cbor_start_encode(cbor_state_t *state, const cbor_string_type_t *result)
223 {
224 if (!new_backup(state, 0)) {
225 FAIL();
226 }
227
228 uint32_t max_len = remaining_str_len(state);
229
230 /* Encode a dummy header */
231 if (!uint32_encode(state, &max_len,
232 CBOR_MAJOR_TYPE_BSTR)) {
233 FAIL();
234 }
235 return true;
236 }
237
238
bstrx_cbor_end_encode(cbor_state_t * state)239 bool bstrx_cbor_end_encode(cbor_state_t *state)
240 {
241 const uint8_t *payload = state->payload;
242
243 if (!restore_backup(state, FLAG_RESTORE | FLAG_DISCARD, 0xFFFFFFFF)) {
244 FAIL();
245 }
246 cbor_string_type_t value;
247
248 value.value = state->payload_end - remaining_str_len(state);
249 value.len = (size_t)payload - (size_t)value.value;
250
251 /* Reencode header of list now that we know the number of elements. */
252 if (!bstrx_encode(state, &value)) {
253 FAIL();
254 }
255 return true;
256 }
257
258
strx_encode(cbor_state_t * state,const cbor_string_type_t * input,cbor_major_type_t major_type)259 static bool strx_encode(cbor_state_t *state,
260 const cbor_string_type_t *input, cbor_major_type_t major_type)
261 {
262 if (!strx_start_encode(state, input, major_type)) {
263 FAIL();
264 }
265 if (input->len > (state->payload_end - state->payload)) {
266 FAIL();
267 }
268 if (state->payload_mut != input->value) {
269 memmove(state->payload_mut, input->value, input->len);
270 }
271 state->payload += input->len;
272 return true;
273 }
274
275
bstrx_encode(cbor_state_t * state,const cbor_string_type_t * input)276 bool bstrx_encode(cbor_state_t *state, const cbor_string_type_t *input)
277 {
278 return strx_encode(state, input, CBOR_MAJOR_TYPE_BSTR);
279 }
280
281
tstrx_encode(cbor_state_t * state,const cbor_string_type_t * input)282 bool tstrx_encode(cbor_state_t *state, const cbor_string_type_t *input)
283 {
284 return strx_encode(state, input, CBOR_MAJOR_TYPE_TSTR);
285 }
286
287
list_map_start_encode(cbor_state_t * state,uint32_t max_num,cbor_major_type_t major_type)288 static bool list_map_start_encode(cbor_state_t *state, uint32_t max_num,
289 cbor_major_type_t major_type)
290 {
291 #ifdef CDDL_CBOR_CANONICAL
292 if (!new_backup(state, 0)) {
293 FAIL();
294 }
295
296 /* Encode dummy header with max number of elements. */
297 if (!uint32_encode(state, &max_num, major_type)) {
298 FAIL();
299 }
300 state->elem_count--; /* Because of dummy header. */
301 #else
302 if (!encode_header_byte(state, major_type, 31)) {
303 FAIL();
304 }
305 #endif
306 return true;
307 }
308
309
list_start_encode(cbor_state_t * state,uint32_t max_num)310 bool list_start_encode(cbor_state_t *state, uint32_t max_num)
311 {
312 return list_map_start_encode(state, max_num, CBOR_MAJOR_TYPE_LIST);
313 }
314
315
map_start_encode(cbor_state_t * state,uint32_t max_num)316 bool map_start_encode(cbor_state_t *state, uint32_t max_num)
317 {
318 return list_map_start_encode(state, max_num, CBOR_MAJOR_TYPE_MAP);
319 }
320
321
list_map_end_encode(cbor_state_t * state,uint32_t max_num,cbor_major_type_t major_type)322 bool list_map_end_encode(cbor_state_t *state, uint32_t max_num,
323 cbor_major_type_t major_type)
324 {
325 #ifdef CDDL_CBOR_CANONICAL
326 uint32_t list_count = ((major_type == CBOR_MAJOR_TYPE_LIST) ?
327 state->elem_count
328 : (state->elem_count / 2));
329
330 const uint8_t *payload = state->payload;
331 uint32_t max_header_len = get_result_len(&max_num, 4);
332 uint32_t header_len = get_result_len(&list_count, 4);
333
334 if (!restore_backup(state, FLAG_RESTORE | FLAG_DISCARD, 0xFFFFFFFF)) {
335 FAIL();
336 }
337
338 cbor_print("list_count: %d\r\n", list_count);
339
340 /* Reencode header of list now that we know the number of elements. */
341 if (!(uint32_encode(state, &list_count, major_type))) {
342 FAIL();
343 }
344
345 if (max_header_len != header_len) {
346 const uint8_t *start = state->payload + max_header_len - header_len;
347 uint32_t body_size = payload - start;
348 memmove(state->payload_mut,
349 state->payload + max_header_len - header_len,
350 body_size);
351 /* Reset payload pointer to end of list */
352 state->payload += body_size;
353 } else {
354 /* Reset payload pointer to end of list */
355 state->payload = payload;
356 }
357 #else
358 if (!encode_header_byte(state, CBOR_MAJOR_TYPE_PRIM, 31)) {
359 FAIL();
360 }
361 #endif
362 return true;
363 }
364
365
list_end_encode(cbor_state_t * state,uint32_t max_num)366 bool list_end_encode(cbor_state_t *state, uint32_t max_num)
367 {
368 return list_map_end_encode(state, max_num, CBOR_MAJOR_TYPE_LIST);
369 }
370
371
map_end_encode(cbor_state_t * state,uint32_t max_num)372 bool map_end_encode(cbor_state_t *state, uint32_t max_num)
373 {
374 return list_map_end_encode(state, max_num, CBOR_MAJOR_TYPE_MAP);
375 }
376
377
nilx_put(cbor_state_t * state,const void * input)378 bool nilx_put(cbor_state_t *state, const void *input)
379 {
380 (void)input;
381 return primx_encode(state, 22);
382 }
383
384
boolx_encode(cbor_state_t * state,const bool * input)385 bool boolx_encode(cbor_state_t *state, const bool *input)
386 {
387 if (!primx_encode(state, *input + BOOL_TO_PRIM)) {
388 FAIL();
389 }
390 return true;
391 }
392
393
boolx_put(cbor_state_t * state,bool input)394 bool boolx_put(cbor_state_t *state, bool input)
395 {
396 if (!primx_encode(state, input + BOOL_TO_PRIM)) {
397 FAIL();
398 }
399 return true;
400 }
401
402
double_encode(cbor_state_t * state,double * input)403 bool double_encode(cbor_state_t *state, double *input)
404 {
405 if (!value_encode(state, CBOR_MAJOR_TYPE_PRIM, input,
406 sizeof(*input))) {
407 FAIL();
408 }
409
410 return true;
411 }
412
413
double_put(cbor_state_t * state,double input)414 bool double_put(cbor_state_t *state, double input)
415 {
416 return double_encode(state, &input);
417 }
418
419
any_encode(cbor_state_t * state,void * input)420 bool any_encode(cbor_state_t *state, void *input)
421 {
422 return nilx_put(state, input);
423 }
424
425
tag_encode(cbor_state_t * state,uint32_t tag)426 bool tag_encode(cbor_state_t *state, uint32_t tag)
427 {
428 if (!value_encode(state, CBOR_MAJOR_TYPE_TAG, &tag, sizeof(tag))) {
429 FAIL();
430 }
431 state->elem_count--;
432
433 return true;
434 }
435
436
multi_encode(uint32_t min_encode,uint32_t max_encode,const uint32_t * num_encode,cbor_encoder_t encoder,cbor_state_t * state,const void * input,uint32_t result_len)437 bool multi_encode(uint32_t min_encode,
438 uint32_t max_encode,
439 const uint32_t *num_encode,
440 cbor_encoder_t encoder,
441 cbor_state_t *state,
442 const void *input,
443 uint32_t result_len)
444 {
445 if (!PTR_VALUE_IN_RANGE(uint32_t, num_encode, NULL, &max_encode)) {
446 FAIL();
447 }
448 for (uint32_t i = 0; i < *num_encode; i++) {
449 if (!encoder(state, (const uint8_t *)input + i*result_len)) {
450 FAIL();
451 }
452 }
453 cbor_print("Found %zu elements.\n", *num_encode);
454 return true;
455 }
456
457
present_encode(const uint32_t * present,cbor_encoder_t encoder,cbor_state_t * state,const void * input)458 bool present_encode(const uint32_t *present,
459 cbor_encoder_t encoder,
460 cbor_state_t *state,
461 const void *input)
462 {
463 uint32_t num_encode = *present;
464 bool retval = multi_encode(0, 1, &num_encode, encoder, state, input, 0);
465 return retval;
466 }
467