1 /*
2  * Copyright (c) 2022-2023 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <string.h>
8 #include <errno.h>
9 
10 #include <zcbor_common.h>
11 #include <zcbor_decode.h>
12 
13 #include <mgmt/mcumgr/util/zcbor_bulk.h>
14 
zcbor_map_decode_bulk(zcbor_state_t * zsd,struct zcbor_map_decode_key_val * map,size_t map_size,size_t * matched)15 int zcbor_map_decode_bulk(zcbor_state_t *zsd, struct zcbor_map_decode_key_val *map,
16 	size_t map_size, size_t *matched)
17 {
18 	bool ok;
19 	struct zcbor_map_decode_key_val *dptr = map;
20 
21 	if (!zcbor_map_start_decode(zsd)) {
22 		return -EBADMSG;
23 	}
24 
25 	*matched = 0;
26 	ok = true;
27 
28 	do {
29 		struct zcbor_string key;
30 		bool found = false;
31 		size_t map_count = 0;
32 
33 		ok = zcbor_tstr_decode(zsd, &key);
34 
35 		while (ok && map_count < map_size) {
36 			if (dptr >= (map + map_size)) {
37 				dptr = map;
38 			}
39 
40 			if (key.len == dptr->key.len		&&
41 			    memcmp(key.value, dptr->key.value, key.len) == 0) {
42 
43 				if (dptr->found) {
44 					return -EADDRINUSE;
45 				}
46 				if (!dptr->decoder(zsd, dptr->value_ptr)) {
47 					/* Failure to decode value matched to key
48 					 * means that either decoder has been
49 					 * incorrectly assigned or SMP payload
50 					 * is broken anyway.
51 					 */
52 					return -ENOMSG;
53 				}
54 
55 				dptr->found = true;
56 				found = true;
57 				++dptr;
58 				++(*matched);
59 				break;
60 			}
61 
62 			++dptr;
63 			++map_count;
64 		}
65 
66 		if (!found && ok) {
67 			ok = zcbor_any_skip(zsd, NULL);
68 		}
69 	} while (ok);
70 
71 	return zcbor_map_end_decode(zsd) ? 0 : -EBADMSG;
72 }
73 
zcbor_map_decode_bulk_key_found(struct zcbor_map_decode_key_val * map,size_t map_size,const char * key)74 bool zcbor_map_decode_bulk_key_found(struct zcbor_map_decode_key_val *map, size_t map_size,
75 	const char *key)
76 {
77 	size_t key_len;
78 	struct zcbor_map_decode_key_val *dptr = map;
79 
80 	/* Lazy run, comparing pointers only assuming that compiler will be able to store
81 	 * read-only string of the same value as single instance.
82 	 */
83 	while (dptr < (map + map_size)) {
84 		if (dptr->key.value == (const uint8_t *)key) {
85 			return dptr->found;
86 		}
87 		++dptr;
88 	}
89 
90 	/* Lazy run failed so need to do real comprison */
91 	key_len = strlen(key);
92 	dptr = map;
93 
94 	while (dptr < (map + map_size)) {
95 		if (dptr->key.len == key_len &&
96 		    memcmp(key, dptr->key.value, key_len) == 0) {
97 			return dptr->found;
98 		}
99 		++dptr;
100 	}
101 
102 	return false;
103 }
104 
zcbor_map_decode_bulk_reset(struct zcbor_map_decode_key_val * map,size_t map_size)105 void zcbor_map_decode_bulk_reset(struct zcbor_map_decode_key_val *map, size_t map_size)
106 {
107 	for (size_t map_index = 0; map_index < map_size; ++map_index) {
108 		map[map_index].found = false;
109 	}
110 }
111