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