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 <stddef.h>
13 #include <stdbool.h>
14 #include <stdint.h>
15 #include <string.h>
16 #include "cbor_common.h"
17 
18 _Static_assert((sizeof(size_t) == sizeof(void *)),
19 	"This code needs size_t to be the same length as pointers.");
20 
new_backup(cbor_state_t * state,uint32_t new_elem_count)21 bool new_backup(cbor_state_t *state, uint32_t new_elem_count)
22 {
23 	if ((state->backups->current_backup + 1)
24 		>= state->backups->num_backups) {
25 		FAIL();
26 	}
27 
28 	uint32_t i = ++(state->backups->current_backup);
29 	memcpy(&state->backups->backup_list[i], state,
30 		sizeof(cbor_state_t));
31 
32 	state->elem_count = new_elem_count;
33 
34 	return true;
35 }
36 
37 
restore_backup(cbor_state_t * state,uint32_t flags,uint32_t max_elem_count)38 bool restore_backup(cbor_state_t *state, uint32_t flags,
39 		uint32_t max_elem_count)
40 {
41 	const uint8_t *payload = state->payload;
42 	const uint32_t elem_count = state->elem_count;
43 
44 	if (state->backups->current_backup == 0) {
45 		FAIL();
46 	}
47 
48 	if (flags & FLAG_RESTORE) {
49 		uint32_t i = state->backups->current_backup;
50 
51 		memcpy(state, &state->backups->backup_list[i],
52 			sizeof(cbor_state_t));
53 	}
54 
55 	if (flags & FLAG_DISCARD) {
56 		state->backups->current_backup--;
57 	}
58 
59 	if (elem_count > max_elem_count) {
60 		cbor_print("elem_count: %d (expected max %d)\r\n",
61 			elem_count, max_elem_count);
62 		FAIL();
63 	}
64 
65 	if (flags & FLAG_TRANSFER_PAYLOAD) {
66 		state->payload = payload;
67 	}
68 
69 	return true;
70 }
71 
72 
union_start_code(cbor_state_t * state)73 bool union_start_code(cbor_state_t *state)
74 {
75 	if (!new_backup(state, state->elem_count)) {
76 		FAIL();
77 	}
78 	return true;
79 }
80 
81 
union_elem_code(cbor_state_t * state)82 bool union_elem_code(cbor_state_t *state)
83 {
84 	if (!restore_backup(state, FLAG_RESTORE, state->elem_count)) {
85 		FAIL();
86 	}
87 	return true;
88 }
89 
union_end_code(cbor_state_t * state)90 bool union_end_code(cbor_state_t *state)
91 {
92 	if (!restore_backup(state, FLAG_DISCARD, state->elem_count)) {
93 		FAIL();
94 	}
95 	return true;
96 }
97 
entry_function(const uint8_t * payload,uint32_t payload_len,const void * struct_ptr,uint32_t * payload_len_out,cbor_encoder_t func,uint32_t elem_count,uint32_t num_backups)98 bool entry_function(const uint8_t *payload, uint32_t payload_len,
99 		const void *struct_ptr, uint32_t *payload_len_out,
100 		cbor_encoder_t func, uint32_t elem_count, uint32_t num_backups)
101 {
102 	cbor_state_t state = {
103 		.payload = payload,
104 		.payload_end = payload + payload_len,
105 		.elem_count = elem_count,
106 	};
107 
108 	cbor_state_t state_backups[num_backups + 1];
109 
110 	cbor_state_backups_t backups = {
111 		.backup_list = state_backups,
112 		.current_backup = 0,
113 		.num_backups = num_backups + 1,
114 	};
115 
116 	state.backups = &backups;
117 
118 	bool result = func(&state, struct_ptr);
119 
120 	if (result && (payload_len_out != NULL)) {
121 		*payload_len_out = MIN(payload_len,
122 				(size_t)state.payload - (size_t)payload);
123 	}
124 	return result;
125 }
126