1 /*
2  * This file has been copied from the zcbor library.
3  * Commit zcbor 0.7.0
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 "zcbor_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 
21 _Static_assert((sizeof(zcbor_state_t) >= sizeof(struct zcbor_state_constant)),
22 	"This code needs zcbor_state_t to be at least as large as zcbor_backups_t.");
23 
zcbor_new_backup(zcbor_state_t * state,uint_fast32_t new_elem_count)24 bool zcbor_new_backup(zcbor_state_t *state, uint_fast32_t new_elem_count)
25 {
26 	ZCBOR_CHECK_ERROR();
27 
28 	if ((state->constant_state->current_backup)
29 		>= state->constant_state->num_backups) {
30 		ZCBOR_ERR(ZCBOR_ERR_NO_BACKUP_MEM);
31 	}
32 
33 	state->payload_moved = false;
34 
35 	(state->constant_state->current_backup)++;
36 
37 	/* use the backup at current_backup - 1, since otherwise, the 0th
38 	 * backup would be unused. */
39 	uint_fast32_t i = (state->constant_state->current_backup) - 1;
40 
41 	memcpy(&state->constant_state->backup_list[i], state,
42 		sizeof(zcbor_state_t));
43 
44 	state->elem_count = new_elem_count;
45 
46 	return true;
47 }
48 
49 
zcbor_process_backup(zcbor_state_t * state,uint32_t flags,uint_fast32_t max_elem_count)50 bool zcbor_process_backup(zcbor_state_t *state, uint32_t flags,
51 		uint_fast32_t max_elem_count)
52 {
53 	const uint8_t *payload = state->payload;
54 	const uint_fast32_t elem_count = state->elem_count;
55 
56 	ZCBOR_CHECK_ERROR();
57 
58 	if (state->constant_state->current_backup == 0) {
59 		zcbor_print("No backups available.\r\n");
60 		ZCBOR_ERR(ZCBOR_ERR_NO_BACKUP_ACTIVE);
61 	}
62 
63 	if (flags & ZCBOR_FLAG_RESTORE) {
64 		/* use the backup at current_backup - 1, since otherwise, the
65 		 * 0th backup would be unused. */
66 		uint_fast32_t i = state->constant_state->current_backup - 1;
67 
68 		if (!(flags & ZCBOR_FLAG_TRANSFER_PAYLOAD)) {
69 			if (state->constant_state->backup_list[i].payload_moved) {
70 				zcbor_print("Payload pointer out of date.\r\n");
71 				ZCBOR_FAIL();
72 			}
73 		}
74 		memcpy(state, &state->constant_state->backup_list[i],
75 			sizeof(zcbor_state_t));
76 	}
77 
78 	if (flags & ZCBOR_FLAG_CONSUME) {
79 		state->constant_state->current_backup--;
80 	}
81 
82 	if (elem_count > max_elem_count) {
83 		zcbor_print("elem_count: %" PRIuFAST32 " (expected max %" PRIuFAST32 ")\r\n",
84 			elem_count, max_elem_count);
85 		ZCBOR_ERR(ZCBOR_ERR_HIGH_ELEM_COUNT);
86 	}
87 
88 	if (flags & ZCBOR_FLAG_TRANSFER_PAYLOAD) {
89 		state->payload = payload;
90 	}
91 
92 	return true;
93 }
94 
update_backups(zcbor_state_t * state,uint8_t const * new_payload_end)95 static void update_backups(zcbor_state_t *state, uint8_t const *new_payload_end)
96 {
97 	if (state->constant_state) {
98 		for (int i = 0; i < state->constant_state->current_backup; i++) {
99 			state->constant_state->backup_list[i].payload_end = new_payload_end;
100 			state->constant_state->backup_list[i].payload_moved = true;
101 		}
102 	}
103 }
104 
105 
zcbor_union_start_code(zcbor_state_t * state)106 bool zcbor_union_start_code(zcbor_state_t *state)
107 {
108 	if (!zcbor_new_backup(state, state->elem_count)) {
109 		ZCBOR_FAIL();
110 	}
111 	return true;
112 }
113 
114 
zcbor_union_elem_code(zcbor_state_t * state)115 bool zcbor_union_elem_code(zcbor_state_t *state)
116 {
117 	if (!zcbor_process_backup(state, ZCBOR_FLAG_RESTORE, state->elem_count)) {
118 		ZCBOR_FAIL();
119 	}
120 	return true;
121 }
122 
zcbor_union_end_code(zcbor_state_t * state)123 bool zcbor_union_end_code(zcbor_state_t *state)
124 {
125 	if (!zcbor_process_backup(state, ZCBOR_FLAG_CONSUME, state->elem_count)) {
126 		ZCBOR_FAIL();
127 	}
128 	return true;
129 }
130 
zcbor_new_state(zcbor_state_t * state_array,uint_fast32_t n_states,const uint8_t * payload,size_t payload_len,uint_fast32_t elem_count)131 void zcbor_new_state(zcbor_state_t *state_array, uint_fast32_t n_states,
132 		const uint8_t *payload, size_t payload_len, uint_fast32_t elem_count)
133 {
134 	state_array[0].payload = payload;
135 	state_array[0].payload_end = payload + payload_len;
136 	state_array[0].elem_count = elem_count;
137 	state_array[0].indefinite_length_array = false;
138 	state_array[0].payload_moved = false;
139 	state_array[0].constant_state = NULL;
140 
141 	if(n_states < 2) {
142 		return;
143 	}
144 
145 	/* Use the last state as a struct zcbor_state_constant object. */
146 	state_array[0].constant_state = (struct zcbor_state_constant *)&state_array[n_states - 1];
147 	state_array[0].constant_state->backup_list = NULL;
148 	state_array[0].constant_state->num_backups = n_states - 2;
149 	state_array[0].constant_state->current_backup = 0;
150 	state_array[0].constant_state->error = ZCBOR_SUCCESS;
151 #ifdef ZCBOR_STOP_ON_ERROR
152 	state_array[0].constant_state->stop_on_error = false;
153 #endif
154 	if (n_states > 2) {
155 		state_array[0].constant_state->backup_list = &state_array[1];
156 	}
157 }
158 
zcbor_update_state(zcbor_state_t * state,const uint8_t * payload,size_t payload_len)159 void zcbor_update_state(zcbor_state_t *state,
160 		const uint8_t *payload, size_t payload_len)
161 {
162 	state->payload = payload;
163 	state->payload_end = payload + payload_len;
164 
165 	update_backups(state, state->payload_end);
166 }
167 
168 
zcbor_validate_string_fragments(struct zcbor_string_fragment * fragments,uint_fast32_t num_fragments)169 bool zcbor_validate_string_fragments(struct zcbor_string_fragment *fragments,
170 		uint_fast32_t num_fragments)
171 {
172 	size_t total_len = 0;
173 
174 	if (fragments == NULL) {
175 		return false;
176 	}
177 
178 	for (uint_fast32_t i = 0; i < num_fragments; i++) {
179 		if (fragments[i].offset != total_len) {
180 			return false;
181 		}
182 		if (fragments[i].fragment.value == NULL) {
183 			return false;
184 		}
185 		if (fragments[i].total_len != fragments[0].total_len) {
186 			return false;
187 		}
188 		total_len += fragments[i].fragment.len;
189 		if (total_len > fragments[0].total_len) {
190 			return false;
191 		}
192 	}
193 
194 	if (num_fragments && total_len != fragments[0].total_len) {
195 		return false;
196 	}
197 
198 	if (num_fragments && (fragments[0].total_len == ZCBOR_STRING_FRAGMENT_UNKNOWN_LENGTH)) {
199 		for (uint_fast32_t i = 0; i < num_fragments; i++) {
200 			fragments[i].total_len = total_len;
201 		}
202 	}
203 
204 	return true;
205 }
206 
zcbor_splice_string_fragments(struct zcbor_string_fragment * fragments,uint_fast32_t num_fragments,uint8_t * result,size_t * result_len)207 bool zcbor_splice_string_fragments(struct zcbor_string_fragment *fragments,
208 		uint_fast32_t num_fragments, uint8_t *result, size_t *result_len)
209 {
210 	size_t total_len = 0;
211 
212 	if (!fragments) {
213 		return false;
214 	}
215 
216 	for (uint_fast32_t i = 0; i < num_fragments; i++) {
217 		if ((total_len > *result_len)
218 			|| (fragments[i].fragment.len > (*result_len - total_len))) {
219 			return false;
220 		}
221 		memcpy(&result[total_len],
222 			fragments[i].fragment.value, fragments[i].fragment.len);
223 		total_len += fragments[i].fragment.len;
224 	}
225 
226 	*result_len = total_len;
227 	return true;
228 }
229