1 // Copyright 2013 Intel Corporation
2 //
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
7 //
8 // - Redistributions of source code must retain the above copyright notice, this
9 // list of conditions and the following disclaimer.
10 //
11 // - Redistributions in binary form must reproduce the above copyright notice,
12 // this list of conditions and the following disclaimer in the documentation
13 // and/or other materials provided with the distribution.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
26 #include "wcore_attrib_list.h"
27
28 #include <stdbool.h>
29 #include <stdint.h>
30 #include <stddef.h>
31 #include <string.h>
32
33 #include "wcore_error.h"
34 #include "wcore_util.h"
35
36 #define WCORE_ATTRIB_LIST_COMMON_FUNCS(T, \
37 length_func, \
38 get_func, \
39 get_with_default_func, \
40 update_func) \
41 \
42 size_t \
43 length_func(const T attrib_list[]) \
44 { \
45 const T *i = attrib_list; \
46 \
47 if (!attrib_list) { \
48 return 0; \
49 } \
50 \
51 while (*i) { \
52 i += 2; \
53 } \
54 \
55 return (i - attrib_list) / 2; \
56 } \
57 \
58 bool \
59 get_func(const T *attrib_list, \
60 T key, \
61 T *value) \
62 { \
63 if (!attrib_list) { \
64 return false; \
65 } \
66 \
67 for (size_t i = 0; attrib_list[i] != 0; i += 2) { \
68 if (attrib_list[i] == key) { \
69 *value = attrib_list[i + 1]; \
70 return true; \
71 } \
72 } \
73 \
74 return false; \
75 } \
76 \
77 bool \
78 get_with_default_func( \
79 const T attrib_list[], \
80 T key, \
81 T *value, \
82 T default_value) \
83 { \
84 if (get_func(attrib_list, key, value)) { \
85 return true; \
86 } else { \
87 *value = default_value; \
88 return false; \
89 } \
90 } \
91 \
92 bool \
93 update_func(T *attrib_list, \
94 T key, \
95 T value) \
96 { \
97 T *i = attrib_list; \
98 \
99 if (attrib_list == NULL) { \
100 return false; \
101 } \
102 \
103 while (*i != 0 && *i != key) { \
104 i += 2; \
105 } \
106 \
107 if (*i == key) { \
108 i[1] = value; \
109 return true; \
110 } else { \
111 return false; \
112 } \
113 }
114
WCORE_ATTRIB_LIST_COMMON_FUNCS(int32_t,wcore_attrib_list32_length,wcore_attrib_list32_get,wcore_attrib_list32_get_with_default,wcore_attrib_list32_update)115 WCORE_ATTRIB_LIST_COMMON_FUNCS(int32_t,
116 wcore_attrib_list32_length,
117 wcore_attrib_list32_get,
118 wcore_attrib_list32_get_with_default,
119 wcore_attrib_list32_update)
120
121 WCORE_ATTRIB_LIST_COMMON_FUNCS(intptr_t,
122 wcore_attrib_list_length,
123 wcore_attrib_list_get,
124 wcore_attrib_list_get_with_default,
125 wcore_attrib_list_update)
126
127 /// Given length of attribute list, calculate its size in bytes. Return false
128 /// on arithemtic overflow.
129 static bool
130 wcore_attrib_list_get_size(size_t *size, size_t len) {
131 bool ok;
132
133 ok = wcore_mul_size(size, 2, len);
134 ok &= wcore_iadd_size(size, 1);
135 ok &= wcore_imul_size(size, sizeof(intptr_t));
136
137 return ok;
138 }
139
140 intptr_t*
wcore_attrib_list_from_int32(const int32_t attrib_list32[])141 wcore_attrib_list_from_int32(const int32_t attrib_list32[])
142 {
143 size_t len = 0;
144 size_t size = 0;
145 intptr_t *attrib_list = NULL;
146
147 len = wcore_attrib_list32_length(attrib_list32);
148
149 if (!wcore_attrib_list_get_size(&size, len)) {
150 // Arithmetic overflow occurred, therefore we can't allocate the
151 // memory.
152 wcore_error(WAFFLE_ERROR_BAD_ALLOC);
153 return NULL;
154 }
155
156 attrib_list = wcore_malloc(size);
157 if (!attrib_list) {
158 return NULL;
159 }
160
161 // Copy all key/value pairs.
162 for (size_t i = 0; i < 2 * len; ++i) {
163 attrib_list[i] = attrib_list32[i];
164 }
165
166 // Add terminal null.
167 attrib_list[2 * len] = 0;
168
169 return attrib_list;
170 }
171
172 intptr_t*
wcore_attrib_list_copy(const intptr_t attrib_list[])173 wcore_attrib_list_copy(const intptr_t attrib_list[])
174 {
175 intptr_t *copy = NULL;
176
177 if (attrib_list) {
178 size_t len;
179 size_t size = 0;
180
181 len = wcore_attrib_list_length(attrib_list);
182
183 if (!wcore_attrib_list_get_size(&size, len)) {
184 // Arithmetic overflow occurred, therefore we can't allocate the
185 // memory.
186 wcore_error(WAFFLE_ERROR_BAD_ALLOC);
187 return NULL;
188 }
189
190 copy = wcore_malloc(size);
191 if (!copy) {
192 return NULL;
193 }
194
195 memcpy(copy, attrib_list, size);
196 } else {
197 copy = wcore_malloc(sizeof(intptr_t));
198 if (!copy) {
199 return NULL;
200 }
201
202 copy[0] = 0;
203 }
204
205 return copy;
206 }
207
208 bool
wcore_attrib_list_pop(intptr_t attrib_list[],intptr_t key,intptr_t * value)209 wcore_attrib_list_pop(
210 intptr_t attrib_list[],
211 intptr_t key,
212 intptr_t *value)
213 {
214 // Address of key in attrib_list.
215 intptr_t *key_addr = NULL;
216
217 // Address of the terminal zero in attrib_list.
218 intptr_t *end_addr = NULL;
219
220 if (attrib_list == NULL) {
221 return false;
222 }
223
224 for (intptr_t *i = attrib_list; *i != 0; i += 2) {
225 if (i[0] == key) {
226 key_addr = i;
227 *value = i[1];
228 break;
229 }
230 }
231
232 if (!key_addr) {
233 return false;
234 }
235
236 end_addr = key_addr + 2; // Step to next pair.
237 while (*end_addr != 0) {
238 end_addr += 2; // Step to next pair.
239 }
240
241 // Move all key/value pairs located at or above (key_addr + 2), and
242 // move the terminal null too.
243 memmove(key_addr, key_addr + 2,
244 sizeof(intptr_t) * (end_addr - key_addr - 1));
245 return true;
246 }
247