Line data Source code
1 : /* SPDX-License-Identifier: Apache-2.0 */
2 : /**
3 : * Copyright (C) 2022 Samsung Electronics Co., Ltd. All Rights Reserved.
4 : *
5 : * @file nnstreamer-edge-metadata.c
6 : * @date 6 April 2022
7 : * @brief Util functions for metadata.
8 : * @see https://github.com/nnstreamer/nnstreamer
9 : * @author Gichan Jang <gichan2.jang@samsung.com>
10 : * @bug No known bugs except for NYI items
11 : */
12 :
13 : #include "nnstreamer-edge-metadata.h"
14 : #include "nnstreamer-edge-util.h"
15 :
16 : /**
17 : * @brief Internal data structure for metadata.
18 : */
19 : typedef struct _nns_edge_metadata_node_s nns_edge_metadata_node_s;
20 :
21 : /**
22 : * @brief Internal data structure for metadata.
23 : */
24 : struct _nns_edge_metadata_node_s
25 : {
26 : char *key;
27 : char *value;
28 : nns_edge_metadata_node_s *next;
29 : };
30 :
31 : /**
32 : * @brief Internal data structure to handle metadata. This struct should be managed in the handle.
33 : */
34 : typedef struct
35 : {
36 : uint32_t list_len;
37 : nns_edge_metadata_node_s *list;
38 : } nns_edge_metadata_s;
39 :
40 : /**
41 : * @brief Internal function to find node in the list.
42 : */
43 : static nns_edge_metadata_node_s *
44 434 : nns_edge_metadata_find (nns_edge_metadata_s * meta, const char *key)
45 : {
46 : nns_edge_metadata_node_s *node;
47 :
48 434 : if (!meta)
49 1 : return NULL;
50 :
51 433 : if (!STR_IS_VALID (key))
52 2 : return NULL;
53 :
54 431 : node = meta->list;
55 763 : while (node) {
56 470 : if (strcasecmp (key, node->key) == 0)
57 138 : return node;
58 :
59 332 : node = node->next;
60 : }
61 :
62 293 : return NULL;
63 : }
64 :
65 : /**
66 : * @brief Internal function to initialize metadata structure.
67 : */
68 : static int
69 303 : nns_edge_metadata_init (nns_edge_metadata_s * meta)
70 : {
71 303 : if (!meta)
72 0 : return NNS_EDGE_ERROR_INVALID_PARAMETER;
73 :
74 303 : memset (meta, 0, sizeof (nns_edge_metadata_s));
75 303 : return NNS_EDGE_ERROR_NONE;
76 : }
77 :
78 : /**
79 : * @brief Internal function to free the list and items in metadata structure.
80 : */
81 : static int
82 335 : nns_edge_metadata_free (nns_edge_metadata_s * meta)
83 : {
84 : nns_edge_metadata_node_s *node, *tmp;
85 :
86 335 : if (!meta)
87 0 : return NNS_EDGE_ERROR_INVALID_PARAMETER;
88 :
89 335 : node = meta->list;
90 335 : meta->list_len = 0;
91 335 : meta->list = NULL;
92 :
93 627 : while (node) {
94 292 : tmp = node->next;
95 :
96 292 : SAFE_FREE (node->key);
97 292 : SAFE_FREE (node->value);
98 292 : SAFE_FREE (node);
99 :
100 292 : node = tmp;
101 : }
102 :
103 335 : return NNS_EDGE_ERROR_NONE;
104 : }
105 :
106 : /**
107 : * @brief Internal function to create metadata.
108 : */
109 : int
110 225 : nns_edge_metadata_create (nns_edge_metadata_h * metadata_h)
111 : {
112 : nns_edge_metadata_s *meta;
113 :
114 225 : if (!metadata_h)
115 1 : return NNS_EDGE_ERROR_INVALID_PARAMETER;
116 :
117 224 : meta = calloc (1, sizeof (nns_edge_metadata_s));
118 224 : if (!meta)
119 0 : return NNS_EDGE_ERROR_OUT_OF_MEMORY;
120 :
121 224 : nns_edge_metadata_init (meta);
122 :
123 224 : *metadata_h = meta;
124 224 : return NNS_EDGE_ERROR_NONE;
125 : }
126 :
127 : /**
128 : * @brief Internal function to destroy metadata.
129 : */
130 : int
131 225 : nns_edge_metadata_destroy (nns_edge_metadata_h metadata_h)
132 : {
133 : nns_edge_metadata_s *meta;
134 :
135 225 : meta = (nns_edge_metadata_s *) metadata_h;
136 :
137 225 : if (!meta)
138 1 : return NNS_EDGE_ERROR_INVALID_PARAMETER;
139 :
140 224 : nns_edge_metadata_free (meta);
141 224 : SAFE_FREE (meta);
142 :
143 224 : return NNS_EDGE_ERROR_NONE;
144 : }
145 :
146 : /**
147 : * @brief Internal function to set the metadata.
148 : */
149 : int
150 339 : nns_edge_metadata_set (nns_edge_metadata_h metadata_h,
151 : const char *key, const char *value)
152 : {
153 : nns_edge_metadata_s *meta;
154 : nns_edge_metadata_node_s *node;
155 :
156 339 : meta = (nns_edge_metadata_s *) metadata_h;
157 :
158 339 : if (!meta)
159 1 : return NNS_EDGE_ERROR_INVALID_PARAMETER;
160 :
161 338 : if (!STR_IS_VALID (key))
162 2 : return NNS_EDGE_ERROR_INVALID_PARAMETER;
163 :
164 336 : if (!STR_IS_VALID (value))
165 3 : return NNS_EDGE_ERROR_INVALID_PARAMETER;
166 :
167 : /* Replace old value if key exists in the list. */
168 333 : node = nns_edge_metadata_find (meta, key);
169 333 : if (node) {
170 41 : char *val = nns_edge_strdup (value);
171 :
172 41 : if (!val)
173 0 : return NNS_EDGE_ERROR_OUT_OF_MEMORY;
174 :
175 41 : SAFE_FREE (node->value);
176 41 : node->value = val;
177 41 : return NNS_EDGE_ERROR_NONE;
178 : }
179 :
180 292 : node = calloc (1, sizeof (nns_edge_metadata_node_s));
181 292 : if (!node)
182 0 : return NNS_EDGE_ERROR_OUT_OF_MEMORY;
183 :
184 292 : node->key = nns_edge_strdup (key);
185 292 : node->value = nns_edge_strdup (value);
186 :
187 292 : if (!node->key || !node->value) {
188 0 : SAFE_FREE (node->key);
189 0 : SAFE_FREE (node->value);
190 0 : SAFE_FREE (node);
191 0 : return NNS_EDGE_ERROR_OUT_OF_MEMORY;
192 : }
193 :
194 : /* Prepend new node to the start of the list. */
195 292 : meta->list_len++;
196 292 : node->next = meta->list;
197 292 : meta->list = node;
198 :
199 292 : return NNS_EDGE_ERROR_NONE;
200 : }
201 :
202 : /**
203 : * @brief Internal function to get the metadata in the list. Caller should release the returned value using free().
204 : */
205 : int
206 102 : nns_edge_metadata_get (nns_edge_metadata_h metadata_h,
207 : const char *key, char **value)
208 : {
209 : nns_edge_metadata_s *meta;
210 : nns_edge_metadata_node_s *node;
211 :
212 102 : meta = (nns_edge_metadata_s *) metadata_h;
213 :
214 102 : if (!value)
215 1 : return NNS_EDGE_ERROR_INVALID_PARAMETER;
216 :
217 101 : node = nns_edge_metadata_find (meta, key);
218 101 : if (node) {
219 97 : *value = nns_edge_strdup (node->value);
220 97 : return (*value) ? NNS_EDGE_ERROR_NONE : NNS_EDGE_ERROR_OUT_OF_MEMORY;
221 : }
222 :
223 4 : return NNS_EDGE_ERROR_INVALID_PARAMETER;
224 : }
225 :
226 : /**
227 : * @brief Internal function to copy the metadata.
228 : */
229 : int
230 81 : nns_edge_metadata_copy (nns_edge_metadata_h dest_h, nns_edge_metadata_h src_h)
231 : {
232 : nns_edge_metadata_s *dest, *src;
233 : nns_edge_metadata_s tmp;
234 : nns_edge_metadata_node_s *node;
235 : int ret;
236 :
237 81 : dest = (nns_edge_metadata_s *) dest_h;
238 81 : src = (nns_edge_metadata_s *) src_h;
239 :
240 81 : if (!dest || !src)
241 81 : return NNS_EDGE_ERROR_INVALID_PARAMETER;
242 :
243 79 : nns_edge_metadata_init (&tmp);
244 :
245 79 : node = src->list;
246 245 : while (node) {
247 166 : ret = nns_edge_metadata_set (&tmp, node->key, node->value);
248 166 : if (ret != NNS_EDGE_ERROR_NONE) {
249 0 : nns_edge_metadata_free (&tmp);
250 0 : return ret;
251 : }
252 :
253 166 : node = node->next;
254 : }
255 :
256 : /* Replace dest when new metadata is successfully copied. */
257 79 : nns_edge_metadata_free (dest);
258 79 : *dest = tmp;
259 :
260 79 : return NNS_EDGE_ERROR_NONE;
261 : }
262 :
263 : /**
264 : * @brief Internal function to serialize the metadata. Caller should release the returned value using free().
265 : */
266 : int
267 51 : nns_edge_metadata_serialize (nns_edge_metadata_h metadata_h,
268 : void **data, nns_size_t * data_len)
269 : {
270 : nns_edge_metadata_s *meta;
271 : nns_edge_metadata_node_s *node;
272 : char *serialized, *ptr;
273 : nns_size_t total, len;
274 :
275 51 : meta = (nns_edge_metadata_s *) metadata_h;
276 :
277 51 : if (!meta)
278 1 : return NNS_EDGE_ERROR_INVALID_PARAMETER;
279 :
280 50 : if (!data || !data_len)
281 5 : return NNS_EDGE_ERROR_INVALID_PARAMETER;
282 :
283 45 : *data = NULL;
284 45 : *data_len = 0U;
285 :
286 45 : if (meta->list_len == 0)
287 5 : return NNS_EDGE_ERROR_NONE;
288 :
289 : /* length, # of metadata */
290 40 : total = len = sizeof (uint32_t);
291 :
292 40 : node = meta->list;
293 133 : while (node) {
294 93 : total += (strlen (node->key) + strlen (node->value) + 2);
295 93 : node = node->next;
296 : }
297 :
298 40 : serialized = ptr = (char *) nns_edge_malloc (total);
299 40 : if (!serialized)
300 0 : return NNS_EDGE_ERROR_OUT_OF_MEMORY;
301 :
302 : /* length + list of key-value pair */
303 40 : ((uint32_t *) serialized)[0] = meta->list_len;
304 40 : ptr += len;
305 :
306 40 : node = meta->list;
307 133 : while (node) {
308 93 : len = strlen (node->key);
309 93 : memcpy (ptr, node->key, len);
310 93 : ptr[len] = '\0';
311 93 : ptr += (len + 1);
312 :
313 93 : len = strlen (node->value);
314 93 : memcpy (ptr, node->value, len);
315 93 : ptr[len] = '\0';
316 93 : ptr += (len + 1);
317 :
318 93 : node = node->next;
319 : }
320 :
321 40 : *data = serialized;
322 40 : *data_len = total;
323 :
324 40 : return NNS_EDGE_ERROR_NONE;
325 : }
326 :
327 : /**
328 : * @brief Internal function to deserialize memory into metadata.
329 : */
330 : int
331 47 : nns_edge_metadata_deserialize (nns_edge_metadata_h metadata_h,
332 : const void *data, const nns_size_t data_len)
333 : {
334 : nns_edge_metadata_s *meta;
335 : char *key, *value;
336 : nns_size_t cur, total;
337 : int ret;
338 :
339 47 : meta = (nns_edge_metadata_s *) metadata_h;
340 :
341 47 : if (!meta)
342 1 : return NNS_EDGE_ERROR_INVALID_PARAMETER;
343 :
344 46 : if (!data || data_len <= 0)
345 14 : return NNS_EDGE_ERROR_INVALID_PARAMETER;
346 :
347 32 : nns_edge_metadata_free (meta);
348 :
349 : /* length + list of key-value pair */
350 32 : total = ((uint32_t *) data)[0];
351 :
352 32 : cur = sizeof (uint32_t);
353 117 : while (cur < data_len || meta->list_len < total) {
354 85 : key = (char *) data + cur;
355 85 : cur += (strlen (key) + 1);
356 :
357 85 : value = (char *) data + cur;
358 85 : cur += (strlen (value) + 1);
359 :
360 85 : ret = nns_edge_metadata_set (meta, key, value);
361 85 : if (ret != NNS_EDGE_ERROR_NONE) {
362 0 : nns_edge_metadata_free (meta);
363 0 : return ret;
364 : }
365 : }
366 :
367 32 : return NNS_EDGE_ERROR_NONE;
368 : }
|