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