1 /*
2 * Copyright (c) 2020 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <stddef.h>
8 #include <stdbool.h>
9 #include <stdint.h>
10 #include <string.h>
11 #include "zcbor_common.h"
12
13 _Static_assert((sizeof(size_t) == sizeof(void *)),
14 "This code needs size_t to be the same length as pointers.");
15
16 _Static_assert((sizeof(zcbor_state_t) >= sizeof(struct zcbor_state_constant)),
17 "This code needs zcbor_state_t to be at least as large as zcbor_backups_t.");
18
zcbor_new_backup(zcbor_state_t * state,size_t new_elem_count)19 bool zcbor_new_backup(zcbor_state_t *state, size_t new_elem_count)
20 {
21 ZCBOR_CHECK_ERROR();
22
23 if ((state->constant_state->current_backup)
24 >= state->constant_state->num_backups) {
25 ZCBOR_ERR(ZCBOR_ERR_NO_BACKUP_MEM);
26 }
27
28 state->payload_moved = false;
29
30 (state->constant_state->current_backup)++;
31
32 /* use the backup at current_backup - 1, since otherwise, the 0th
33 * backup would be unused. */
34 size_t i = (state->constant_state->current_backup) - 1;
35
36 memcpy(&state->constant_state->backup_list[i], state,
37 sizeof(zcbor_state_t));
38
39 state->elem_count = new_elem_count;
40
41 return true;
42 }
43
44
zcbor_process_backup(zcbor_state_t * state,uint32_t flags,size_t max_elem_count)45 bool zcbor_process_backup(zcbor_state_t *state, uint32_t flags,
46 size_t max_elem_count)
47 {
48 const uint8_t *payload = state->payload;
49 const size_t elem_count = state->elem_count;
50
51 ZCBOR_CHECK_ERROR();
52
53 if (state->constant_state->current_backup == 0) {
54 zcbor_print("No backups available.\r\n");
55 ZCBOR_ERR(ZCBOR_ERR_NO_BACKUP_ACTIVE);
56 }
57
58 if (flags & ZCBOR_FLAG_RESTORE) {
59 /* use the backup at current_backup - 1, since otherwise, the
60 * 0th backup would be unused. */
61 size_t i = state->constant_state->current_backup - 1;
62
63 if (!(flags & ZCBOR_FLAG_TRANSFER_PAYLOAD)) {
64 if (state->constant_state->backup_list[i].payload_moved) {
65 zcbor_print("Payload pointer out of date.\r\n");
66 ZCBOR_FAIL();
67 }
68 }
69 memcpy(state, &state->constant_state->backup_list[i],
70 sizeof(zcbor_state_t));
71 }
72
73 if (flags & ZCBOR_FLAG_CONSUME) {
74 state->constant_state->current_backup--;
75 }
76
77 if (elem_count > max_elem_count) {
78 zcbor_print("elem_count: %" PRIuFAST32 " (expected max %" PRIuFAST32 ")\r\n",
79 elem_count, max_elem_count);
80 ZCBOR_ERR(ZCBOR_ERR_HIGH_ELEM_COUNT);
81 }
82
83 if (flags & ZCBOR_FLAG_TRANSFER_PAYLOAD) {
84 state->payload = payload;
85 }
86
87 return true;
88 }
89
update_backups(zcbor_state_t * state,uint8_t const * new_payload_end)90 static void update_backups(zcbor_state_t *state, uint8_t const *new_payload_end)
91 {
92 if (state->constant_state) {
93 for (unsigned int i = 0; i < state->constant_state->current_backup; i++) {
94 state->constant_state->backup_list[i].payload_end = new_payload_end;
95 state->constant_state->backup_list[i].payload_moved = true;
96 }
97 }
98 }
99
100
zcbor_union_start_code(zcbor_state_t * state)101 bool zcbor_union_start_code(zcbor_state_t *state)
102 {
103 if (!zcbor_new_backup(state, state->elem_count)) {
104 ZCBOR_FAIL();
105 }
106 return true;
107 }
108
109
zcbor_union_elem_code(zcbor_state_t * state)110 bool zcbor_union_elem_code(zcbor_state_t *state)
111 {
112 if (!zcbor_process_backup(state, ZCBOR_FLAG_RESTORE, state->elem_count)) {
113 ZCBOR_FAIL();
114 }
115 return true;
116 }
117
zcbor_union_end_code(zcbor_state_t * state)118 bool zcbor_union_end_code(zcbor_state_t *state)
119 {
120 if (!zcbor_process_backup(state, ZCBOR_FLAG_CONSUME, state->elem_count)) {
121 ZCBOR_FAIL();
122 }
123 return true;
124 }
125
zcbor_new_state(zcbor_state_t * state_array,size_t n_states,const uint8_t * payload,size_t payload_len,size_t elem_count)126 void zcbor_new_state(zcbor_state_t *state_array, size_t n_states,
127 const uint8_t *payload, size_t payload_len, size_t elem_count)
128 {
129 state_array[0].payload = payload;
130 state_array[0].payload_end = payload + payload_len;
131 state_array[0].elem_count = elem_count;
132 state_array[0].indefinite_length_array = false;
133 state_array[0].payload_moved = false;
134 state_array[0].constant_state = NULL;
135
136 if(n_states < 2) {
137 return;
138 }
139
140 /* Use the last state as a struct zcbor_state_constant object. */
141 state_array[0].constant_state = (struct zcbor_state_constant *)&state_array[n_states - 1];
142 state_array[0].constant_state->backup_list = NULL;
143 state_array[0].constant_state->num_backups = n_states - 2;
144 state_array[0].constant_state->current_backup = 0;
145 state_array[0].constant_state->error = ZCBOR_SUCCESS;
146 #ifdef ZCBOR_STOP_ON_ERROR
147 state_array[0].constant_state->stop_on_error = false;
148 #endif
149 if (n_states > 2) {
150 state_array[0].constant_state->backup_list = &state_array[1];
151 }
152 }
153
zcbor_update_state(zcbor_state_t * state,const uint8_t * payload,size_t payload_len)154 void zcbor_update_state(zcbor_state_t *state,
155 const uint8_t *payload, size_t payload_len)
156 {
157 state->payload = payload;
158 state->payload_end = payload + payload_len;
159
160 update_backups(state, state->payload_end);
161 }
162
163
zcbor_validate_string_fragments(struct zcbor_string_fragment * fragments,size_t num_fragments)164 bool zcbor_validate_string_fragments(struct zcbor_string_fragment *fragments,
165 size_t num_fragments)
166 {
167 size_t total_len = 0;
168
169 if (fragments == NULL) {
170 return false;
171 }
172
173 for (size_t i = 0; i < num_fragments; i++) {
174 if (fragments[i].offset != total_len) {
175 return false;
176 }
177 if (fragments[i].fragment.value == NULL) {
178 return false;
179 }
180 if (fragments[i].total_len != fragments[0].total_len) {
181 return false;
182 }
183 total_len += fragments[i].fragment.len;
184 if (total_len > fragments[0].total_len) {
185 return false;
186 }
187 }
188
189 if (num_fragments && total_len != fragments[0].total_len) {
190 return false;
191 }
192
193 if (num_fragments && (fragments[0].total_len == ZCBOR_STRING_FRAGMENT_UNKNOWN_LENGTH)) {
194 for (size_t i = 0; i < num_fragments; i++) {
195 fragments[i].total_len = total_len;
196 }
197 }
198
199 return true;
200 }
201
zcbor_splice_string_fragments(struct zcbor_string_fragment * fragments,size_t num_fragments,uint8_t * result,size_t * result_len)202 bool zcbor_splice_string_fragments(struct zcbor_string_fragment *fragments,
203 size_t num_fragments, uint8_t *result, size_t *result_len)
204 {
205 size_t total_len = 0;
206
207 if (!fragments) {
208 return false;
209 }
210
211 for (size_t i = 0; i < num_fragments; i++) {
212 if ((total_len > *result_len)
213 || (fragments[i].fragment.len > (*result_len - total_len))) {
214 return false;
215 }
216 memcpy(&result[total_len],
217 fragments[i].fragment.value, fragments[i].fragment.len);
218 total_len += fragments[i].fragment.len;
219 }
220
221 *result_len = total_len;
222 return true;
223 }
224
225
zcbor_compare_strings(const struct zcbor_string * str1,const struct zcbor_string * str2)226 bool zcbor_compare_strings(const struct zcbor_string *str1,
227 const struct zcbor_string *str2)
228 {
229 return (str1 != NULL) && (str2 != NULL)
230 && (str1->value != NULL) && (str2->value != NULL) && (str1->len == str2->len)
231 && (memcmp(str1->value, str2->value, str1->len) == 0);
232 }
233
234
zcbor_header_len(size_t num_elems)235 size_t zcbor_header_len(size_t num_elems)
236 {
237 if (num_elems <= ZCBOR_VALUE_IN_HEADER) {
238 return 1;
239 } else if (num_elems <= 0xFF) {
240 return 2;
241 } else if (num_elems <= 0xFFFF) {
242 return 3;
243 } else if (num_elems <= 0xFFFFFFFF) {
244 return 5;
245 } else {
246 return 9;
247 }
248 }
249
250
zcbor_array_at_end(zcbor_state_t * state)251 bool zcbor_array_at_end(zcbor_state_t *state)
252 {
253 return ((!state->indefinite_length_array && (state->elem_count == 0))
254 || (state->indefinite_length_array
255 && (state->payload < state->payload_end)
256 && (*state->payload == 0xFF)));
257 }
258