Line data Source code
1 : /**
2 : * NNStreamer Configurations / Environmental Variable Manager.
3 : * Copyright (C) 2018 MyungJoo Ham <myungjoo.ham@samsung.com>
4 : *
5 : * This library is free software; you can redistribute it and/or
6 : * modify it under the terms of the GNU Library General Public
7 : * License as published by the Free Software Foundation;
8 : * version 2.1 of the License.
9 : *
10 : * This library is distributed in the hope that it will be useful,
11 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 : * Library General Public License for more details.
14 : *
15 : */
16 : /**
17 : * @file nnstreamer_conf.c
18 : * @date 26 Nov 2018
19 : * @brief NNStreamer Configuration (conf file, env-var) Management.
20 : * @see https://github.com/nnstreamer/nnstreamer
21 : * @author MyungJoo Ham <myungjoo.ham@samsung.com>
22 : * @bug No known bugs except for NYI items
23 : *
24 : */
25 :
26 : #include <string.h>
27 : #include <glib.h>
28 :
29 : #include "nnstreamer_log.h"
30 : #include "nnstreamer_conf.h"
31 : #include "nnstreamer_subplugin.h"
32 :
33 : /**
34 : * Note that users still can place their custom filters anywhere if they
35 : * designate them with the full path.
36 : */
37 :
38 : /* Subplugin Naming Rules */
39 : #define NNSTREAMER_PREFIX_DECODER "libnnstreamer_decoder_"
40 : #define NNSTREAMER_PREFIX_FILTER "libnnstreamer_filter_"
41 : #define NNSTREAMER_PREFIX_CUSTOMFILTERS ""
42 : #define NNSTREAMER_PREFIX_CONVERTER "libnnstreamer_converter_"
43 : #define NNSTREAMER_PREFIX_TRAINER "libnnstreamer_trainer_"
44 : /* Custom filter does not have prefix */
45 :
46 : /* Env-var names */
47 : static const gchar *NNSTREAMER_ENVVAR[NNSCONF_PATH_END] = {
48 : [NNSCONF_PATH_FILTERS] = "NNSTREAMER_FILTERS",
49 : [NNSCONF_PATH_DECODERS] = "NNSTREAMER_DECODERS",
50 : [NNSCONF_PATH_CUSTOM_FILTERS] = "NNSTREAMER_CUSTOMFILTERS",
51 : [NNSCONF_PATH_CONVERTERS] = "NNSTREAMER_CONVERTERS",
52 : [NNSCONF_PATH_TRAINERS] = "NNSTREAMER_TRAINERS"
53 : };
54 :
55 : static const gchar *NNSTREAMER_PATH[NNSCONF_PATH_END] = {
56 : [NNSCONF_PATH_FILTERS] = "/usr/lib/nnstreamer/filters/",
57 : [NNSCONF_PATH_DECODERS] = "/usr/lib/nnstreamer/decoders/",
58 : [NNSCONF_PATH_CUSTOM_FILTERS] = "/usr/lib/nnstreamer/customfilters/",
59 : [NNSCONF_PATH_CONVERTERS] = "/usr/lib/nnstreamer/converters/",
60 : [NNSCONF_PATH_TRAINERS] = "/usr/lib/nnstreamer/trainers/"
61 : };
62 :
63 : static const gchar *subplugin_prefixes[] = {
64 : [NNSCONF_PATH_FILTERS] = NNSTREAMER_PREFIX_FILTER,
65 : [NNSCONF_PATH_DECODERS] = NNSTREAMER_PREFIX_DECODER,
66 : [NNSCONF_PATH_CUSTOM_FILTERS] = NNSTREAMER_PREFIX_CUSTOMFILTERS,
67 : [NNSCONF_PATH_EASY_CUSTOM_FILTERS] = NNSTREAMER_PREFIX_CUSTOMFILTERS, /**< Same as Custom Filters */
68 : [NNSCONF_PATH_CONVERTERS] = NNSTREAMER_PREFIX_CONVERTER,
69 : [NNSCONF_PATH_TRAINERS] = NNSTREAMER_PREFIX_TRAINER,
70 : [NNSCONF_PATH_END] = NULL
71 : };
72 :
73 : typedef enum
74 : {
75 : CONF_SOURCE_ENVVAR = 0,
76 : CONF_SOURCE_INI = 1,
77 : CONF_SOURCE_HARDCODE = 2,
78 : CONF_SOURCE_EXTRA_CONF = 3, /**< path from extra config file */
79 : CONF_SOURCE_END
80 : } conf_sources;
81 :
82 : typedef struct
83 : {
84 : /*************************************************
85 : * Cached Raw Values *
86 : * 0: ENVVAR. 1: CONFFILE, 2: Hardcoded *
87 : *************************************************/
88 : gchar *path[CONF_SOURCE_END]; /**< directory paths */
89 :
90 : /*************************************************
91 : * Processed Values *
92 : *************************************************/
93 : gchar **files; /**< Null terminated list of full filepaths */
94 : gchar **names; /**< Null terminated list of subplugin names */
95 : } subplugin_conf;
96 :
97 : typedef struct
98 : {
99 : gboolean loaded; /**< TRUE if loaded at least once */
100 : gboolean enable_envvar; /**< TRUE to parse env variables */
101 : gboolean enable_symlink; /**< TRUE to allow symbolic link file */
102 :
103 : gchar *conffile; /**< Location of conf file. */
104 : gchar *extra_conffile; /**< Location of extra configuration file. */
105 :
106 : subplugin_conf conf[NNSCONF_PATH_END];
107 : } confdata;
108 :
109 : static confdata conf = { 0 };
110 :
111 : /**
112 : * @brief Parse string to get boolean value.
113 : */
114 : static gboolean
115 910 : _parse_bool_string (const gchar * strval, gboolean def)
116 : {
117 910 : gboolean res = def;
118 :
119 910 : if (strval) {
120 : /* 1/0, true/false, t/f, yes/no, on/off. case incensitive. */
121 905 : if (strval[0] == '1' || strval[0] == 't' || strval[0] == 'T' ||
122 457 : strval[0] == 'y' || strval[0] == 'Y' ||
123 455 : g_ascii_strncasecmp ("on", strval, 2) == 0) {
124 452 : res = TRUE;
125 453 : } else if (strval[0] == '0' || strval[0] == 'f' || strval[0] == 'F' ||
126 10 : strval[0] == 'n' || strval[0] == 'N' ||
127 8 : g_ascii_strncasecmp ("of", strval, 2) == 0) {
128 447 : res = FALSE;
129 : }
130 : }
131 :
132 910 : return res;
133 : }
134 :
135 : /**
136 : * @brief Private function to get strdup-ed env-var if it's valid.
137 : * Otherwise, NULL
138 : *
139 : * @retval strdup-ed env-var value
140 : * @param[in] name Environmental variable name
141 : */
142 : static gchar *
143 2744 : _strdup_getenv (const gchar * name)
144 : {
145 : /**
146 : * @todo Evaluate if we need to use secure_getenv() here
147 : * (and compatible with other OS
148 : */
149 2744 : const gchar *tmp = g_getenv (name);
150 :
151 2744 : return g_strdup (tmp);
152 : }
153 :
154 : /**
155 : * @brief Private function to validate .so file can be added to the list.
156 : */
157 : static gboolean
158 13285 : _validate_file (nnsconf_type_path type, const gchar * fullpath)
159 : {
160 : /* ignore directory */
161 13285 : if (!fullpath || !g_file_test (fullpath, G_FILE_TEST_IS_REGULAR))
162 143 : return FALSE;
163 : /* ignore symbol link file */
164 13142 : if (!conf.enable_symlink && g_file_test (fullpath, G_FILE_TEST_IS_SYMLINK))
165 0 : return FALSE;
166 13142 : if (type < 0 || type >= NNSCONF_PATH_END)
167 0 : return FALSE;
168 : /** @todo how to validate with nnsconf type. */
169 13142 : return TRUE;
170 : }
171 :
172 : /**
173 : * @brief Private function to fill in ".so/.dylib list" with fullpath-filenames in a directory.
174 : * @param[in] type conf type to scan.
175 : * @param[in] dir Directory to be searched.
176 : * @param[in/out] listF The fullpath list to be updated.
177 : * @param[in/out] listN The name list to be updated.
178 : * @param[in/out] counter increased by the number of appended elements.
179 : * @return True if successfully updated.
180 : * @todo This assumes .so/.dylib for all sub plugins. Support Windows!
181 : */
182 : static gboolean
183 3986 : _get_filenames (nnsconf_type_path type, const gchar * dir, GSList ** listF,
184 : GSList ** listN, guint * counter)
185 : {
186 : GDir *gdir;
187 : const gchar *entry;
188 : gchar *fullpath;
189 : gchar *basename;
190 : gchar *name;
191 : gsize prefix, extension, len;
192 :
193 3986 : if ((gdir = g_dir_open (dir, 0U, NULL)) == NULL)
194 2657 : return FALSE;
195 :
196 1329 : prefix = strlen (subplugin_prefixes[type]);
197 1329 : extension = strlen (NNSTREAMER_SO_FILE_EXTENSION);
198 :
199 51648 : while (NULL != (entry = g_dir_read_name (gdir))) {
200 : /* check file prefix for given type, currently handle .so and .dylib. */
201 48990 : if (g_str_has_prefix (entry, subplugin_prefixes[type]) &&
202 44206 : g_str_has_suffix (entry, NNSTREAMER_SO_FILE_EXTENSION)) {
203 12824 : fullpath = g_build_filename (dir, entry, NULL);
204 :
205 12824 : if (_validate_file (type, fullpath)) {
206 12824 : basename = g_path_get_basename (entry);
207 12824 : len = strlen (basename) - prefix - extension;
208 12824 : name = g_strndup (basename + prefix, len);
209 :
210 12824 : *listF = g_slist_prepend (*listF, fullpath);
211 12824 : *listN = g_slist_prepend (*listN, name);
212 12824 : *counter = *counter + 1;
213 :
214 12824 : g_free (basename);
215 : } else {
216 0 : g_free (fullpath);
217 : }
218 : }
219 : }
220 :
221 1329 : g_dir_close (gdir);
222 1329 : return TRUE;
223 : }
224 :
225 : /**
226 : * @brief Private function to get sub-plugins list with type.
227 : */
228 : static gboolean
229 1587 : _get_subplugin_with_type (nnsconf_type_path type, gchar *** name,
230 : gchar *** filepath)
231 : {
232 1587 : if (type >= NNSCONF_PATH_END) {
233 : /* unknown type */
234 0 : ml_loge ("Failed to get sub-plugins, unknown sub-plugin type.");
235 0 : return FALSE;
236 : }
237 :
238 1587 : if (!conf.loaded) {
239 0 : ml_loge ("Configuration file is not loaded.");
240 0 : return FALSE;
241 : }
242 :
243 : /* Easy custom uses the configuration of custom */
244 1587 : if (type == NNSCONF_PATH_EASY_CUSTOM_FILTERS)
245 25 : type = NNSCONF_PATH_CUSTOM_FILTERS;
246 :
247 1587 : *name = conf.conf[type].names;
248 1587 : *filepath = conf.conf[type].files;
249 1587 : return TRUE;
250 : }
251 :
252 : /**
253 : * @brief Data structure for _g_list_foreach_vstr_helper
254 : */
255 : typedef struct
256 : {
257 : gchar **vstr; /**< The vstr data (string array) */
258 : guint cursor; /**< The first "empty" element in vstr */
259 : guint size; /**< The number of "g_char *" in vstr, excluding the terminator */
260 : } vstr_helper;
261 :
262 : /**
263 : * @brief Private function to help convert linked-list to vstr with foreach
264 : * @data The element data of linked-list
265 : * @user_data The struct to fill in vstr
266 : */
267 : static void
268 25648 : _g_list_foreach_vstr_helper (gpointer data, gpointer user_data)
269 : {
270 25648 : vstr_helper *helper = (vstr_helper *) user_data;
271 25648 : g_assert (helper->cursor < helper->size); /** library error? internal logic error? */
272 25648 : helper->vstr[helper->cursor] = data;
273 25648 : helper->cursor++;
274 25648 : }
275 :
276 : /**
277 : * @brief Private function to fill in vstr
278 : */
279 : static void
280 2215 : _fill_in_vstr (gchar *** fullpath_vstr, gchar *** name_vstr,
281 : gchar * searchpath[CONF_SOURCE_END], nnsconf_type_path type)
282 : {
283 2215 : GSList *lstF = NULL, *lstN = NULL;
284 : vstr_helper vstrF, vstrN;
285 : guint i, j, counter;
286 :
287 2215 : counter = 0;
288 11075 : for (i = 0; i < CONF_SOURCE_END; i++) {
289 8860 : if (searchpath[i]) {
290 : /* skip duplicated paths */
291 13275 : for (j = i + 1; j < CONF_SOURCE_END; j++) {
292 9289 : if (searchpath[j] && !g_strcmp0 (searchpath[i], searchpath[j])) {
293 1764 : break;
294 : }
295 : }
296 5750 : if (j == CONF_SOURCE_END)
297 3986 : _get_filenames (type, searchpath[i], &lstF, &lstN, &counter);
298 : }
299 : }
300 :
301 : /* Because _get_* does "prepend", reverse them to have the correct order. */
302 2215 : lstF = g_slist_reverse (lstF);
303 2215 : lstN = g_slist_reverse (lstN);
304 :
305 2215 : *fullpath_vstr = g_malloc0_n (counter + 1, sizeof (gchar *));
306 2215 : g_assert (*fullpath_vstr != NULL); /* This won't happen, but doesn't hurt either */
307 2215 : *name_vstr = g_malloc0_n (counter + 1, sizeof (gchar *));
308 2215 : g_assert (*name_vstr != NULL); /* This won't happen, but doesn't hurt either */
309 :
310 2215 : vstrF.vstr = *fullpath_vstr;
311 2215 : vstrN.vstr = *name_vstr;
312 2215 : vstrF.size = counter;
313 2215 : vstrN.size = counter;
314 2215 : vstrF.cursor = 0;
315 2215 : vstrN.cursor = 0;
316 2215 : g_slist_foreach (lstF, _g_list_foreach_vstr_helper, (gpointer) & vstrF);
317 2215 : g_slist_foreach (lstN, _g_list_foreach_vstr_helper, (gpointer) & vstrN);
318 :
319 : /* Do not free elements. They are now at vstr */
320 2215 : g_slist_free (lstF);
321 2215 : g_slist_free (lstN);
322 2215 : }
323 :
324 : /** @brief Private function to fill subplugin path */
325 : static void
326 443 : _fill_subplugin_path (confdata * cdata, GKeyFile * key_file, conf_sources src)
327 : {
328 443 : cdata->conf[NNSCONF_PATH_FILTERS].path[src] =
329 443 : g_key_file_get_string (key_file, "filter", "filters", NULL);
330 443 : cdata->conf[NNSCONF_PATH_DECODERS].path[src] =
331 443 : g_key_file_get_string (key_file, "decoder", "decoders", NULL);
332 443 : cdata->conf[NNSCONF_PATH_CUSTOM_FILTERS].path[src] =
333 443 : g_key_file_get_string (key_file, "filter", "customfilters", NULL);
334 443 : cdata->conf[NNSCONF_PATH_CONVERTERS].path[src] =
335 443 : g_key_file_get_string (key_file, "converter", "converters", NULL);
336 443 : cdata->conf[NNSCONF_PATH_TRAINERS].path[src] =
337 443 : g_key_file_get_string (key_file, "trainer", "trainer", NULL);
338 443 : }
339 :
340 : /** @brief Public function defined in the header */
341 : gboolean
342 2625 : nnsconf_loadconf (gboolean force_reload)
343 : {
344 2625 : const gchar root_path_prefix[] = NNSTREAMER_SYS_ROOT_PATH_PREFIX;
345 2625 : GKeyFile *key_file = NULL;
346 : guint i, t;
347 :
348 2625 : if (!force_reload && conf.loaded)
349 2625 : return TRUE;
350 :
351 443 : if (force_reload && conf.loaded) {
352 : /* Do Clean Up */
353 1 : g_free (conf.conffile);
354 1 : conf.conffile = NULL;
355 1 : g_free (conf.extra_conffile);
356 1 : conf.extra_conffile = NULL;
357 :
358 7 : for (t = 0; t < NNSCONF_PATH_END; t++) {
359 :
360 30 : for (i = 0; i < CONF_SOURCE_END; i++) {
361 24 : g_free (conf.conf[t].path[i]);
362 : }
363 :
364 6 : g_strfreev (conf.conf[t].files);
365 6 : g_strfreev (conf.conf[t].names);
366 : }
367 :
368 : /* init with 0 */
369 1 : memset (&conf, 0, sizeof (confdata));
370 : }
371 : #ifndef __TIZEN__
372 : /** if it's not Tizen, configuration from env-var has a higher priority */
373 : conf.conffile = _strdup_getenv (NNSTREAMER_ENVVAR_CONF_FILE);
374 : if (conf.conffile && !g_file_test (conf.conffile, G_FILE_TEST_IS_REGULAR)) {
375 : g_free (conf.conffile);
376 : conf.conffile = NULL;
377 : }
378 : #endif
379 443 : if (conf.conffile == NULL) {
380 : /**
381 : * Priority of reading a conf file
382 : * 1) read from NNSTREAMER_CONF_FILE
383 : * 2) read from NNSTREAMER_DEFAULT_CONF_FILE
384 : * 3) read from env-var
385 : */
386 443 : if (g_path_is_absolute (NNSTREAMER_CONF_FILE)) {
387 443 : conf.conffile = g_strdup (NNSTREAMER_CONF_FILE);
388 : } else {
389 : /** default value of 'sysconfdir' in meson is 'etc' */
390 0 : conf.conffile = g_build_path (G_DIR_SEPARATOR_S, root_path_prefix,
391 : NNSTREAMER_CONF_FILE, NULL);
392 : }
393 :
394 443 : if (!g_file_test (conf.conffile, G_FILE_TEST_IS_REGULAR)) {
395 : /* File not found or not configured */
396 443 : g_free (conf.conffile);
397 443 : conf.conffile = NULL;
398 :
399 443 : if (g_file_test (NNSTREAMER_DEFAULT_CONF_FILE, G_FILE_TEST_IS_REGULAR)) {
400 0 : conf.conffile = g_strdup (NNSTREAMER_DEFAULT_CONF_FILE);
401 : } else {
402 : /* Try to read from Environmental Variables */
403 443 : conf.conffile = _strdup_getenv (NNSTREAMER_ENVVAR_CONF_FILE);
404 : }
405 : }
406 : }
407 :
408 443 : if (conf.conffile) {
409 443 : key_file = g_key_file_new ();
410 443 : g_assert (key_file != NULL); /** Internal lib error? out-of-memory? */
411 :
412 : /* Read the conf file. It's ok even if we cannot load it. */
413 443 : if (g_key_file_load_from_file (key_file, conf.conffile, G_KEY_FILE_NONE,
414 : NULL)) {
415 : gchar *value;
416 :
417 443 : value = g_key_file_get_string (key_file, "common", "enable_envvar", NULL);
418 443 : conf.enable_envvar = _parse_bool_string (value, FALSE);
419 443 : g_free (value);
420 :
421 : value =
422 443 : g_key_file_get_string (key_file, "common", "enable_symlink", NULL);
423 443 : conf.enable_symlink = _parse_bool_string (value, FALSE);
424 443 : g_free (value);
425 :
426 443 : conf.extra_conffile =
427 443 : g_key_file_get_string (key_file, "common", "extra_config_path", NULL);
428 :
429 443 : _fill_subplugin_path (&conf, key_file, CONF_SOURCE_INI);
430 : }
431 :
432 443 : g_key_file_free (key_file);
433 :
434 : /* load from extra config file */
435 443 : if (conf.extra_conffile) {
436 1 : if (g_file_test (conf.extra_conffile, G_FILE_TEST_IS_REGULAR)) {
437 0 : key_file = g_key_file_new ();
438 0 : g_assert (key_file != NULL); /** Internal lib error? out-of-memory? */
439 :
440 0 : if (g_key_file_load_from_file (key_file, conf.extra_conffile,
441 : G_KEY_FILE_NONE, NULL)) {
442 0 : _fill_subplugin_path (&conf, key_file, CONF_SOURCE_EXTRA_CONF);
443 : }
444 :
445 0 : g_key_file_free (key_file);
446 : } else {
447 1 : ml_logw
448 : ("Cannot find config file '%s'. You should set a valid path to load extra configuration.",
449 : conf.extra_conffile);
450 : }
451 : }
452 : } else {
453 : /**
454 : * Failed to get the configuration.
455 : * Note that Android API does not use the configuration.
456 : */
457 0 : ml_logw ("Failed to load the configuration, no config file found.");
458 : }
459 :
460 3101 : for (t = 0; t < NNSCONF_PATH_END; t++) {
461 2658 : if (t == NNSCONF_PATH_EASY_CUSTOM_FILTERS)
462 443 : continue; /* It does not have its own configuration */
463 :
464 : /* Read from env variables. */
465 2215 : if (conf.enable_envvar)
466 2210 : conf.conf[t].path[CONF_SOURCE_ENVVAR] =
467 2210 : _strdup_getenv (NNSTREAMER_ENVVAR[t]);
468 :
469 : /* Strdup the hardcoded */
470 2215 : conf.conf[t].path[CONF_SOURCE_HARDCODE] = g_strdup (NNSTREAMER_PATH[t]);
471 :
472 : /* Fill in conf.files* */
473 2215 : _fill_in_vstr (&conf.conf[t].files, &conf.conf[t].names,
474 2215 : conf.conf[t].path, t);
475 : }
476 :
477 443 : conf.loaded = TRUE;
478 443 : return TRUE;
479 : }
480 :
481 : /** @brief Public function defined in the header */
482 : const gchar *
483 383 : nnsconf_get_fullpath (const gchar * subpluginname, nnsconf_type_path type)
484 : {
485 : subplugin_info_s info;
486 : guint i, total;
487 :
488 383 : nnsconf_loadconf (FALSE);
489 :
490 383 : total = nnsconf_get_subplugin_info (type, &info);
491 3608 : for (i = 0; i < total; i++) {
492 3462 : if (g_strcmp0 (info.names[i], subpluginname) == 0)
493 383 : return info.paths[i];
494 : }
495 :
496 146 : return NULL;
497 : }
498 :
499 : /**
500 : * @brief Public function to validate sub-plugin library is available.
501 : */
502 : gboolean
503 461 : nnsconf_validate_file (nnsconf_type_path type, const gchar * fullpath)
504 : {
505 461 : nnsconf_loadconf (FALSE);
506 :
507 461 : return _validate_file (type, fullpath);
508 : }
509 :
510 : /**
511 : * @brief Get sub-plugin's name prefix.
512 : * @param[in] type The type (FILTERS/DECODERS/CUSTOM_FILTERS)
513 : * @return Predefined prefix string for given type.
514 : */
515 : const gchar *
516 2 : nnsconf_get_subplugin_name_prefix (nnsconf_type_path type)
517 : {
518 2 : g_return_val_if_fail (type >= 0 && type <= NNSCONF_PATH_END, NULL);
519 1 : return subplugin_prefixes[type];
520 : }
521 :
522 : /**
523 : * @brief Public function to get the list of sub-plugins name and path
524 : * @return total number of sub-plugins for given type
525 : * @note DO NOT free sub-plugins info
526 : */
527 : guint
528 1587 : nnsconf_get_subplugin_info (nnsconf_type_path type, subplugin_info_s * info)
529 : {
530 : gchar **vstr, **vstrFull;
531 :
532 3174 : g_return_val_if_fail (info != NULL, 0);
533 1587 : info->names = info->paths = NULL;
534 :
535 1587 : nnsconf_loadconf (FALSE);
536 :
537 1587 : if (!_get_subplugin_with_type (type, &vstr, &vstrFull))
538 0 : return 0;
539 :
540 1587 : info->names = vstr;
541 1587 : info->paths = vstrFull;
542 :
543 1587 : return g_strv_length (vstr);
544 : }
545 :
546 : /**
547 : * @brief Internal cache for the custom key-values
548 : */
549 : static GHashTable *custom_table = NULL;
550 :
551 : /**
552 : * @brief Public function defined in the header.
553 : * @note This function is included in nnstreamer internal header for native APIs.
554 : * When changing the declaration, you should update the internal header (nnstreamer_internal.h).
555 : */
556 : gchar *
557 192 : nnsconf_get_custom_value_string (const gchar * group, const gchar * key)
558 : {
559 192 : gchar *hashkey = g_strdup_printf ("[%s]%s", group, key);
560 192 : gchar *value = NULL;
561 :
562 192 : nnsconf_loadconf (FALSE); /* Load .ini file path */
563 :
564 192 : if (NULL == custom_table)
565 43 : custom_table =
566 43 : g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
567 :
568 192 : value = g_hash_table_lookup (custom_table, hashkey);
569 :
570 192 : if (NULL == value) {
571 : /* 1. Read envvar */
572 92 : if (conf.enable_envvar) {
573 91 : gchar *envkey = g_strdup_printf ("NNSTREAMER_%s_%s", group, key);
574 :
575 91 : value = _strdup_getenv (envkey);
576 91 : g_free (envkey);
577 : }
578 :
579 : /* 2. Read ini */
580 92 : if (NULL == value && conf.conffile) {
581 92 : g_autoptr (GKeyFile) key_file = g_key_file_new ();
582 :
583 92 : g_assert (key_file != NULL); /** Internal lib error? out-of-memory? */
584 :
585 92 : if (g_key_file_load_from_file (key_file, conf.conffile, G_KEY_FILE_NONE,
586 : NULL)) {
587 92 : value = g_key_file_get_string (key_file, group, key, NULL);
588 : }
589 : }
590 :
591 92 : if (value) {
592 48 : g_hash_table_insert (custom_table, hashkey, value);
593 : } else {
594 44 : g_free (hashkey);
595 : }
596 : } else {
597 100 : g_free (hashkey);
598 : }
599 :
600 192 : return g_strdup (value);
601 : }
602 :
603 : /**
604 : * @brief Public function defined in the header.
605 : * @note This function is included in nnstreamer internal header for native APIs.
606 : * When changing the declaration, you should update the internal header (nnstreamer_internal.h).
607 : */
608 : gboolean
609 24 : nnsconf_get_custom_value_bool (const gchar * group, const gchar * key,
610 : gboolean def)
611 : {
612 : gchar *strval;
613 : gboolean ret;
614 :
615 24 : strval = nnsconf_get_custom_value_string (group, key);
616 24 : ret = _parse_bool_string (strval, def);
617 :
618 24 : g_free (strval);
619 24 : return ret;
620 : }
621 :
622 : #define STR_BOOL(x) ((x) ? "TRUE" : "FALSE")
623 : /**
624 : * @brief Print out configurations
625 : * @todo Add more configuration values to dump.
626 : */
627 : void
628 0 : nnsconf_dump (gchar * str, gulong size)
629 : {
630 0 : gchar *cur = str;
631 0 : gulong _size = size;
632 : gint len;
633 :
634 0 : if (!conf.loaded)
635 0 : nnsconf_loadconf (FALSE);
636 :
637 0 : len = g_snprintf (cur, _size,
638 : "Configuration Loaded: %s\n"
639 : "Configuration file path: %s\n"
640 : " Candidates: envvar(NNSTREAMER_CONF): %s\n"
641 : " build-config: %s\n"
642 : " hard-coded: %s\n"
643 : "[Common]\n"
644 : " Enable envvar: %s\n"
645 : " Enable sym-linked subplugins: %s\n"
646 : "[Filter]\n"
647 : " Filter paths from .ini: %s\n"
648 : " from envvar: %s\n"
649 0 : " from hard-coded: %s\n", STR_BOOL (conf.loaded),
650 : /* 1. Configuration file path */
651 0 : (conf.conffile ? conf.conffile : "<error> config file not loaded"),
652 : #ifdef __TIZEN__
653 : "Not available (Tizen)",
654 : #else
655 : g_getenv (NNSTREAMER_ENVVAR_CONF_FILE),
656 : #endif
657 : NNSTREAMER_CONF_FILE, NNSTREAMER_DEFAULT_CONF_FILE,
658 : /* 2. [Common] */
659 0 : STR_BOOL (conf.enable_envvar), STR_BOOL (conf.enable_symlink),
660 : /* 3. [Filter] */
661 : conf.conf[NNSCONF_PATH_FILTERS].path[CONF_SOURCE_INI],
662 0 : (conf.enable_envvar) ?
663 : conf.conf[NNSCONF_PATH_FILTERS].path[CONF_SOURCE_ENVVAR] : "<disabled>",
664 : conf.conf[NNSCONF_PATH_FILTERS].path[CONF_SOURCE_HARDCODE]);
665 :
666 0 : if (len <= 0)
667 0 : g_printerr ("Config dump is too large. The results show partially.\n");
668 0 : }
669 :
670 : typedef struct
671 : {
672 : gchar *base;
673 : gulong size;
674 : gulong pos;
675 : } dump_buf;
676 :
677 : /**
678 : * @brief foreach callback for custom property
679 : */
680 : static void
681 0 : _foreach_custom_property (GQuark key_id, gpointer data, gpointer user_data)
682 : {
683 0 : dump_buf *buf = (dump_buf *) user_data;
684 :
685 0 : if (buf->size > buf->pos) {
686 0 : buf->pos += g_snprintf (buf->base + buf->pos, buf->size - buf->pos,
687 : " - %s: %s\n", g_quark_to_string (key_id), (gchar *) data);
688 : }
689 0 : }
690 :
691 : /**
692 : * @brief Print out the information of registered sub-plugins
693 : */
694 : void
695 0 : nnsconf_subplugin_dump (gchar * str, gulong size)
696 : {
697 : static const nnsconf_type_path dump_list_type[] = {
698 : NNSCONF_PATH_FILTERS, NNSCONF_PATH_DECODERS, NNSCONF_PATH_CONVERTERS,
699 : NNSCONF_PATH_TRAINERS
700 : };
701 : static const char *dump_list_str[] = {
702 : "Filter", "Decoder", "Conterver", "Trainer"
703 : };
704 :
705 : dump_buf buf;
706 : subplugin_info_s info;
707 : guint i, j, ret;
708 :
709 0 : if (!conf.loaded)
710 0 : nnsconf_loadconf (FALSE);
711 :
712 0 : buf.base = str;
713 0 : buf.size = size;
714 0 : buf.pos = 0;
715 :
716 0 : for (i = 0; i < sizeof (dump_list_type) / sizeof (nnsconf_type_path); i++) {
717 0 : buf.pos += g_snprintf (buf.base + buf.pos, buf.size - buf.pos,
718 : "\n[%s]\n", dump_list_str[i]);
719 0 : if (buf.size <= buf.pos)
720 0 : goto truncated;
721 :
722 0 : ret = nnsconf_get_subplugin_info (dump_list_type[i], &info);
723 0 : for (j = 0; j < ret; j++) {
724 : GData *data;
725 0 : subpluginType stype = (subpluginType) dump_list_type[i];
726 0 : gchar *sname = info.names[j];
727 :
728 0 : if (!get_subplugin (stype, sname))
729 0 : break;
730 :
731 0 : buf.pos += g_snprintf (buf.base + buf.pos, buf.size - buf.pos,
732 : " %s\n", sname);
733 0 : if (buf.size <= buf.pos)
734 0 : goto truncated;
735 :
736 0 : data = subplugin_get_custom_property_desc (stype, sname);
737 0 : if (data) {
738 0 : g_datalist_foreach (&data, _foreach_custom_property, &buf);
739 : } else {
740 0 : buf.pos += g_snprintf (buf.base + buf.pos, buf.size - buf.pos,
741 : " - No custom property found\n");
742 : }
743 :
744 0 : if (buf.size <= buf.pos)
745 0 : goto truncated;
746 : }
747 : }
748 0 : return;
749 :
750 0 : truncated:
751 0 : g_printerr ("Config dump is too large. The results show partially.\n");
752 : }
|