Move function definition to aul header
[platform/core/appfw/aul-1.git] / src / aul_rsc_mgr.c
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 #define _GNU_SOURCE
19 #include <unistd.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <stdint.h>
24 #include <glib/gstdio.h>
25 #include <bundle_internal.h>
26 #include <assert.h>
27 #include <dlog.h>
28 #include <vconf.h>
29 #include <system_info.h>
30
31 #include "aul.h"
32 #include "aul_api.h"
33 #include "aul_rsc_mgr.h"
34 #include "aul_rsc_mgr_internal.h"
35
36 #define WEIGHT_SCREEN_DPI 10000
37 #define WEIGHT_SCREEN_DPI_RANGE 10000
38 #define WEIGHT_SCREEN_BPP 1000
39 #define WEIGHT_SCREEN_WIDTH_RANGE 100
40 #define WEIGHT_SCREEN_LARGE 10
41 #define WEIGHT_PLATFORM_VERSION 1000000
42 #define WEIGHT_LANGUAGE 100000
43
44 #define THRESHOLD_TO_CLEAN 50   /* app_resource_manager_trim_cache */
45
46 #define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0]))
47 #define MAX_PATH  1024
48
49 typedef struct {
50         resource_data_t *data;
51         GHashTable *cache;
52 } resource_manager_t;
53
54 typedef struct {
55         char *output;
56         int hit_cnt;
57         bool remove;
58 } resource_cache_context_t;
59
60 typedef struct {
61         const char *bundle_attr_key;
62         unsigned int bundle_attr_value;
63 } resource_node_attr_t;
64
65 typedef struct {
66         char *folder;
67         char *type;
68 } resource_node_list_t;
69
70 enum {
71         NODE_ATTR_MIN = 0,
72         NODE_ATTR_SCREEN_DPI,
73         NODE_ATTR_SCREEN_DPI_RANGE,
74         NODE_ATTR_SCREEN_WIDTH_RANGE,
75         NODE_ATTR_SCREEN_LARGE,
76         NODE_ATTR_SCREEN_BPP,
77         NODE_ATTR_PLATFORM_VER,
78         NODE_ATTR_LANGUAGE,
79         NODE_ATTR_MAX
80 };
81
82 static resource_manager_t *resource_handle = NULL;
83
84 static resource_node_attr_t map[] = {
85                 { RSC_NODE_ATTR_SCREEN_DPI, NODE_ATTR_SCREEN_DPI },
86                 { RSC_NODE_ATTR_SCREEN_DPI_RANGE, NODE_ATTR_SCREEN_DPI_RANGE },
87                 { RSC_NODE_ATTR_SCREEN_WIDTH_RANGE, NODE_ATTR_SCREEN_WIDTH_RANGE },
88                 { RSC_NODE_ATTR_SCREEN_LARGE, NODE_ATTR_SCREEN_LARGE },
89                 { RSC_NODE_ATTR_SCREEN_BPP, NODE_ATTR_SCREEN_BPP },
90                 { RSC_NODE_ATTR_PLATFORM_VER, NODE_ATTR_PLATFORM_VER },
91                 { RSC_NODE_ATTR_LANGUAGE, NODE_ATTR_LANGUAGE },
92 };
93
94 static GHashTable *attr_key = NULL;
95 static const char *res_path = NULL;
96 static char *cur_language = NULL;
97 static bool is_slice = FALSE;
98
99 static GHashTable *valid_path_list = NULL;
100 static GHashTable *supported_lang_list = NULL;
101 static GHashTable *id_list = NULL;
102 static GList *all_node_list = NULL;
103 static bundle *given_attr_list = NULL;
104
105 static gint __resource_manager_comp(gconstpointer a, gconstpointer b)
106 {
107         resource_group_t *rsc_group = (resource_group_t *) a;
108
109         return strcmp(rsc_group->type, b);
110 }
111
112 static gint __compare_path(gconstpointer a, gconstpointer b)
113 {
114         char tmp_path[MAX_PATH] = {0, };
115         resource_node_list_t *tmp_node_info = (resource_node_list_t *)a;
116
117         snprintf(tmp_path, MAX_PATH - 1, "%s%s", res_path, tmp_node_info->folder);
118         return strncmp(tmp_path, (char *)b, strlen(tmp_path));
119 }
120
121 static int __get_dpi(void)
122 {
123         int dpi = 0;
124         char *tmp = NULL;
125
126         if (is_slice) {
127                 bundle_get_str(given_attr_list, RSC_NODE_ATTR_SCREEN_DPI, &tmp);
128                 if (tmp == NULL) {
129                         LOGE("Failed to retrieve DPI");
130                         dpi = 0;
131                 } else {
132                         dpi = atoi(tmp);
133                 }
134         } else {
135                 system_info_get_platform_int("http://tizen.org/feature/screen.dpi", &dpi);
136         }
137
138         return dpi;
139 }
140
141 static int __get_screen_width(void)
142 {
143         int screen_width = 0;
144         char *tmp = NULL;
145
146         if (is_slice) {
147                 bundle_get_str(given_attr_list, RSC_NODE_ATTR_SCREEN_WIDTH_RANGE, &tmp);
148                 if (tmp == NULL) {
149                         LOGE("Failed to retrieve screen width");
150                         screen_width = 0;
151                 } else
152                         screen_width = atoi(tmp);
153         } else
154                 system_info_get_platform_int("http://tizen.org/feature/screen.width", &screen_width);
155
156         return screen_width;
157 }
158
159 static bool __get_screen_large(void)
160 {
161         bool screen_large = true;
162         char *tmp = NULL;
163
164         if (is_slice) {
165                 bundle_get_str(given_attr_list, RSC_NODE_ATTR_SCREEN_LARGE, &tmp);
166                 if (tmp == NULL) {
167                         LOGE("Failed to retrieve screen large");
168                         screen_large = false;
169                 } else
170                         screen_large = atoi(tmp);
171         } else {
172                 if (system_info_get_platform_bool("http://tizen.org/feature/screen.size.large", &screen_large) != SYSTEM_INFO_ERROR_NONE) {
173                         LOGE("Failed to get info of screen.size.large");
174                         screen_large = false;
175                 }
176         }
177
178         return screen_large;
179 }
180
181 static int __get_screen_bpp(void)
182 {
183         int screen_bpp = 0;
184         char *tmp = NULL;
185
186         if (is_slice) {
187                 bundle_get_str(given_attr_list, RSC_NODE_ATTR_SCREEN_BPP, &tmp);
188                 if (tmp == NULL) {
189                         LOGE("Failed to retrieve screen bpp");
190                         screen_bpp = 0;
191                 } else
192                         screen_bpp = atoi(tmp);
193         } else
194                 system_info_get_platform_int("http://tizen.org/feature/screen.bpp", &screen_bpp);
195
196         return screen_bpp;
197 }
198
199 static char *__get_platform_version(void)
200 {
201         char *version = NULL;
202         if (is_slice)
203                 bundle_get_str(given_attr_list, RSC_NODE_ATTR_PLATFORM_VER, &version);
204         else
205                 system_info_get_platform_string("http://tizen.org/feature/platform.version", &version);
206
207         return version;
208 }
209
210 static void __bundle_iterator_get_valid_nodes(const char *key, const int type,
211                 const bundle_keyval_t *kv, void *data)
212 {
213         unsigned int node_attr;
214         bool *invalid = (bool *) data;
215         bool ret_bool = true;
216         int min, max;
217         char *from = NULL;
218         char *to = NULL;
219         bool t_val;
220         char *val;
221         size_t size;
222         static int screen_dpi = -1;
223         static int screen_width = -1;
224         static int screen_size_large = -1;
225         static char *version = NULL;
226         static int screen_bpp = -1;
227
228         if (*invalid)
229                 return;
230
231         bundle_keyval_get_basic_val((bundle_keyval_t *) kv, (void**) &val, &size);
232
233         node_attr = (uintptr_t)g_hash_table_lookup(attr_key, key);
234         if (node_attr <= NODE_ATTR_MIN || node_attr >= NODE_ATTR_MAX) {
235                 LOGE("INVALID_PARAMETER(0x%08x), node_attr(%d)",
236                                 AUL_RESOURCE_ERROR_INVALID_PARAMETER, node_attr);
237                 *invalid = true;
238                 return;
239         }
240
241         switch (node_attr) {
242         case NODE_ATTR_SCREEN_DPI:
243                 if (screen_dpi == -1)
244                         screen_dpi = __get_dpi();
245                 if (screen_dpi != atoi(val))
246                         *invalid = true;
247                 break;
248         case NODE_ATTR_SCREEN_DPI_RANGE:
249                 sscanf(val, "%ms %d %ms %d", &from, &min, &to, &max);
250                 if (screen_dpi == -1)
251                         screen_dpi = __get_dpi();
252                 if (!(min <= screen_dpi && screen_dpi <= max))
253                         *invalid = true;
254                 if (from)
255                         free(from);
256                 if (to)
257                         free(to);
258                 break;
259         case NODE_ATTR_SCREEN_WIDTH_RANGE:
260                 sscanf(val, "%ms %d %ms %d", &from, &min, &to, &max);
261                 if (screen_width == -1)
262                         screen_width = __get_screen_width();
263                 if (!(min <= screen_width && screen_width <= max))
264                         *invalid = true;
265                 if (from)
266                         free(from);
267                 if (to)
268                         free(to);
269                 break;
270         case NODE_ATTR_SCREEN_LARGE:
271                 if (!(strcmp(val, "true")))
272                         t_val = true;
273                 else
274                         t_val = false;
275                 if (screen_size_large == -1) {
276                         ret_bool = __get_screen_large();
277                         if (ret_bool)
278                                 screen_size_large = 1;
279                         else
280                                 screen_size_large = 0;
281                 }
282                 if (((bool)screen_size_large) != t_val)
283                         *invalid = true;
284                 break;
285         case NODE_ATTR_SCREEN_BPP:
286                 if (screen_bpp == -1)
287                         screen_bpp = __get_screen_bpp();
288                 if (screen_bpp != atoi(val))
289                         *invalid = true;
290                 break;
291         case NODE_ATTR_PLATFORM_VER:
292                 if (version == NULL)
293                         version = __get_platform_version();
294                 if (strcmp(version, val))
295                         *invalid = true;
296                 break;
297         case NODE_ATTR_LANGUAGE:
298                 if (cur_language == NULL) {
299                         cur_language = vconf_get_str(VCONFKEY_LANGSET);
300                         if (cur_language == NULL)
301                                 *invalid = true;
302                 }
303                 if (cur_language && strncmp(cur_language, val, strlen(val)))
304                         *invalid = true;
305                 break;
306         }
307 }
308
309 static void __bundle_iterator_get_best_node(const char *key, const char *val,
310                 void *data)
311 {
312         unsigned int node_attr;
313         unsigned int *weight = (unsigned int *)data;
314
315         node_attr = (uintptr_t)g_hash_table_lookup(attr_key, key);
316         if (node_attr <= NODE_ATTR_MIN || node_attr >= NODE_ATTR_MAX) {
317                 LOGE("INVALID_PARAMETER(0x%08x), node_attr(%d)",
318                                 AUL_RESOURCE_ERROR_INVALID_PARAMETER, node_attr);
319                 return;
320         }
321
322         switch (node_attr) {
323         case NODE_ATTR_SCREEN_DPI:
324                 *weight += WEIGHT_SCREEN_DPI;
325                 break;
326         case NODE_ATTR_SCREEN_DPI_RANGE:
327                 *weight += WEIGHT_SCREEN_DPI_RANGE;
328                 break;
329         case NODE_ATTR_SCREEN_WIDTH_RANGE:
330                 *weight += WEIGHT_SCREEN_WIDTH_RANGE;
331                 break;
332         case NODE_ATTR_SCREEN_LARGE:
333                 *weight += WEIGHT_SCREEN_LARGE;
334                 break;
335         case NODE_ATTR_SCREEN_BPP:
336                 *weight += WEIGHT_SCREEN_BPP;
337                 break;
338         case NODE_ATTR_PLATFORM_VER:
339                 *weight += WEIGHT_PLATFORM_VERSION;
340                 break;
341         case NODE_ATTR_LANGUAGE:
342                 *weight += WEIGHT_LANGUAGE;
343                 break;
344         }
345 }
346
347 static const char *__get_cache(aul_resource_e type,
348                 const char *id)
349 {
350         unsigned int total_len = 0;
351         char *key = NULL;
352         char *rsc_type;
353         resource_cache_context_t *resource_cache = NULL;
354
355         if (is_slice == TRUE)
356                 return NULL;
357
358         if (id == NULL) {
359                 LOGW("(0x%08x), id",
360                                 AUL_RESOURCE_ERROR_INVALID_PARAMETER);
361                 return NULL;
362         }
363
364         if (type < AUL_RESOURCE_TYPE_MIN || type > AUL_RESOURCE_TYPE_MAX) {
365                 LOGW("(0x%08x), type(%d)",
366                                 AUL_RESOURCE_ERROR_INVALID_PARAMETER, type);
367                 return NULL;
368         } else {
369                 switch (type) {
370                 case AUL_RESOURCE_TYPE_IMAGE:
371                         rsc_type = RSC_GROUP_TYPE_IMAGE;
372                         break;
373                 case AUL_RESOURCE_TYPE_LAYOUT:
374                         rsc_type = RSC_GROUP_TYPE_LAYOUT;
375                         break;
376                 case AUL_RESOURCE_TYPE_SOUND:
377                         rsc_type = RSC_GROUP_TYPE_SOUND;
378                         break;
379                 case AUL_RESOURCE_TYPE_BIN:
380                         rsc_type = RSC_GROUP_TYPE_BIN;
381                         break;
382                 }
383         }
384
385         if (resource_handle->cache == NULL) {
386                 LOGW("(0x%08x), hashtable",
387                                 AUL_RESOURCE_ERROR_INVALID_PARAMETER);
388                 return NULL;
389         } else {
390                 total_len = (unsigned int)(strlen(rsc_type) + strlen(id) + 2);
391                 key = (char *)calloc(1, total_len);
392                 if (key == NULL) {
393                         LOGE("OOM!, failed to create a resource_cache(0x%08x)",
394                                         AUL_RESOURCE_ERROR_OUT_OF_MEMORY);
395                         free(resource_cache);
396                         return NULL;
397                 }
398
399                 snprintf(key, total_len, "%s:%s", rsc_type, id);
400                 LOGD("key : %s", key);
401
402                 resource_cache = g_hash_table_lookup(resource_handle->cache, key);
403                 free(key);
404                 if (resource_cache == NULL) {
405                         LOGW("(0x%08x), find list resource_cache",
406                                         AUL_RESOURCE_ERROR_IO_ERROR);
407                         return NULL;
408                 }
409
410                 resource_cache->hit_cnt++;
411         }
412
413         return resource_cache->output;
414 }
415
416 static gint __cache_hit_compare(gconstpointer a, gconstpointer b)
417 {
418         const resource_cache_context_t *lhs = (const resource_cache_context_t *) a;
419         const resource_cache_context_t *rhs = (const resource_cache_context_t *) b;
420
421         return lhs->hit_cnt - rhs->hit_cnt;
422 }
423
424 static gboolean __cache_remove(gpointer key, gpointer value, gpointer user_data)
425 {
426         resource_cache_context_t *c = (resource_cache_context_t *) (value);
427
428         if (c->remove) {
429                 free(key);
430                 free(c->output);
431                 free(c);
432                 return TRUE;
433         }
434
435         return FALSE;
436 }
437
438 static void __trim_cache(void)
439 {
440         GList *values = g_hash_table_get_values(resource_handle->cache);
441         values = g_list_sort(values, __cache_hit_compare);
442
443         int i = 0;
444         GList *iter_list = values;
445         while (iter_list != NULL) {
446                 if (i >= (THRESHOLD_TO_CLEAN / 2))
447                         break;
448
449                 resource_cache_context_t *c =
450                                 (resource_cache_context_t *) (iter_list->data);
451                 c->remove = true;
452                 iter_list = g_list_next(iter_list);
453                 i++;
454         }
455
456         g_list_free(values);
457         g_hash_table_foreach_remove(resource_handle->cache, __cache_remove, NULL);
458
459 }
460
461 static void __put_cache(aul_resource_e type, const char *id,
462                 const char *val)
463 {
464         unsigned int total_len = 0;
465         char *key;
466         char *rsc_type;
467         resource_cache_context_t *resource_cache;
468
469         if (is_slice == TRUE)
470                 return;
471
472         /* To remove chache from the low frequency of use. */
473         if (val == NULL) {
474                 LOGE("INVALID_PARAMETER(0x%08x), fname",
475                                 AUL_RESOURCE_ERROR_INVALID_PARAMETER);
476                 return;
477         }
478
479         if (id == NULL) {
480                 LOGE("INVALID_PARAMETER(0x%08x), id",
481                                 AUL_RESOURCE_ERROR_INVALID_PARAMETER);
482                 return;
483         }
484
485         if (type < AUL_RESOURCE_TYPE_MIN || type > AUL_RESOURCE_TYPE_MAX) {
486                 LOGE("INVALID_PARAMETER(0x%08x), type(%d)",
487                                 AUL_RESOURCE_ERROR_INVALID_PARAMETER, type);
488                 return;
489         } else {
490                 switch (type) {
491                 case AUL_RESOURCE_TYPE_IMAGE:
492                         rsc_type = RSC_GROUP_TYPE_IMAGE;
493                         break;
494                 case AUL_RESOURCE_TYPE_LAYOUT:
495                         rsc_type = RSC_GROUP_TYPE_LAYOUT;
496                         break;
497                 case AUL_RESOURCE_TYPE_SOUND:
498                         rsc_type = RSC_GROUP_TYPE_SOUND;
499                         break;
500                 case AUL_RESOURCE_TYPE_BIN:
501                         rsc_type = RSC_GROUP_TYPE_BIN;
502                         break;
503                 }
504         }
505
506         if (g_hash_table_size(resource_handle->cache) > THRESHOLD_TO_CLEAN)
507                 __trim_cache();
508
509         resource_cache = (resource_cache_context_t *)calloc(1,
510                         sizeof(resource_cache_context_t));
511         if (resource_cache == NULL) {
512                 LOGE("failed to create a resource_group(0x%08x)",
513                                 AUL_RESOURCE_ERROR_OUT_OF_MEMORY);
514                 return;
515         }
516
517         total_len = (unsigned int)(strlen(rsc_type) + strlen(id) + 2);
518         key = (char *)calloc(1, total_len);
519         if (key == NULL) {
520                 LOGE("failed to create a resource_cache(0x%08x)",
521                                 AUL_RESOURCE_ERROR_OUT_OF_MEMORY);
522                 free(resource_cache);
523                 return;
524         }
525
526         snprintf(key, total_len, "%s:%s", rsc_type, id);
527         LOGD("key : %s", key);
528
529         resource_cache->output = strdup(val);
530         resource_cache->hit_cnt = 0;
531         resource_cache->remove = false;
532
533         g_hash_table_insert(resource_handle->cache, key, resource_cache);
534 }
535
536 static resource_group_t *__find_group(resource_data_t *data,
537                 int type)
538 {
539         resource_group_t *rsc_group = NULL;
540         char *rsc_type;
541
542         if (data == NULL) {
543                 LOGE("INVALID_PARAMETER(0x%08x), resource_data_t",
544                                 AUL_RESOURCE_ERROR_INVALID_PARAMETER);
545                 return NULL;
546         }
547
548         if (type < AUL_RESOURCE_TYPE_MIN || type > AUL_RESOURCE_TYPE_MAX) {
549                 LOGE("INVALID_PARAMETER(0x%08x), type(%d)",
550                                 AUL_RESOURCE_ERROR_INVALID_PARAMETER, type);
551                 return NULL;
552         } else {
553                 switch (type) {
554                 case AUL_RESOURCE_TYPE_IMAGE:
555                         rsc_type = RSC_GROUP_TYPE_IMAGE;
556                         break;
557                 case AUL_RESOURCE_TYPE_LAYOUT:
558                         rsc_type = RSC_GROUP_TYPE_LAYOUT;
559                         break;
560                 case AUL_RESOURCE_TYPE_SOUND:
561                         rsc_type = RSC_GROUP_TYPE_SOUND;
562                         break;
563                 case AUL_RESOURCE_TYPE_BIN:
564                         rsc_type = RSC_GROUP_TYPE_BIN;
565                         break;
566                 }
567         }
568
569         GList* found = g_list_find_custom(data->group_list, rsc_type,
570                         __resource_manager_comp);
571         if (found == NULL) {
572                 LOGE("IO_ERROR(0x%08x), find list resource_group %s",
573                                 AUL_RESOURCE_ERROR_IO_ERROR, rsc_type);
574                 return NULL;
575         }
576
577         rsc_group = (resource_group_t *) (found->data);
578
579         return rsc_group;
580 }
581
582 static GList *__get_valid_nodes(resource_group_t *group,
583                 const char *id)
584 {
585         GList *list = NULL;
586         GList *valid_list = NULL;
587         resource_node_t *valid_node = NULL;
588         resource_node_t *rsc_node = NULL;
589
590         if (group->node_list == NULL) {
591                 LOGE("INVALID_PARAMETER(0x%08x), resource_group",
592                                 AUL_RESOURCE_ERROR_INVALID_PARAMETER);
593                 return NULL;
594         }
595
596         list = g_list_first(group->node_list);
597
598         char path_buf[MAX_PATH] = { 0, };
599         while (list) {
600                 bool invalid = false;
601                 rsc_node = (resource_node_t *) list->data;
602
603                 snprintf(path_buf, MAX_PATH - 1, "%s%s/%s", res_path,
604                                 rsc_node->folder, id);
605                 if (access(path_buf, R_OK) == 0) {
606                         bundle_foreach(rsc_node->attr, __bundle_iterator_get_valid_nodes,
607                                         &invalid);
608
609                         if (!invalid) {
610                                 valid_node = (resource_node_t *) list->data;
611                                 valid_list = g_list_append(valid_list, valid_node);
612                         }
613                 }
614
615                 list = g_list_next(list);
616         }
617
618         return valid_list;
619 }
620
621 static resource_node_t *__get_best_node(GList *nodes)
622 {
623         unsigned int weight_tmp = 0;
624         resource_node_t *best_node = NULL;
625         GList *list = NULL;
626
627         if (nodes == NULL) {
628                 LOGE("INVALID_PARAMETER(0x%08x), resource_node lists",
629                                 AUL_RESOURCE_ERROR_INVALID_PARAMETER);
630                 return NULL;
631         }
632
633         list = g_list_first(nodes);
634
635         while (list != NULL) {
636                 unsigned int weight = 0;
637                 resource_node_t *res_node = (resource_node_t *) (list->data);
638
639                 bundle_iterate(res_node->attr, __bundle_iterator_get_best_node, &weight);
640                 if (weight > weight_tmp) {
641                         best_node = res_node;
642                         weight_tmp = weight;
643                 }
644                 list = g_list_next(list);
645         }
646
647         return best_node;
648 }
649
650 static int __open(resource_manager_t **handle)
651 {
652         int retval = AUL_RESOURCE_ERROR_NONE;
653         resource_manager_t *rsc_manager = NULL;
654         char buf[MAX_PATH] = { 0, };
655
656         rsc_manager = (resource_manager_t *) calloc(1, sizeof(resource_manager_t));
657         if (!rsc_manager) {
658                 LOGE("failed to create a resource_manager(0x%08x)",
659                                 AUL_RESOURCE_ERROR_OUT_OF_MEMORY);
660                 return AUL_RESOURCE_ERROR_OUT_OF_MEMORY;
661         }
662
663         snprintf(buf, MAX_PATH - 1, "%sres.xml", res_path);
664         retval = _resource_open(buf, &(rsc_manager->data));
665         if (retval) {
666                 LOGE("IO_ERROR(0x%08x), failed to get db for resource manager",
667                                 AUL_RESOURCE_ERROR_IO_ERROR);
668                 free(rsc_manager);
669                 return AUL_RESOURCE_ERROR_IO_ERROR;
670         }
671
672         rsc_manager->cache = g_hash_table_new(g_str_hash, g_str_equal);
673         *handle = rsc_manager;
674
675         return AUL_RESOURCE_ERROR_NONE;
676 }
677
678 static void __invalidate_cache()
679 {
680         if (resource_handle != NULL) {
681                 if (resource_handle->cache != NULL) {
682                         GHashTableIter iter;
683                         gpointer key, value;
684
685                         g_hash_table_iter_init(&iter, resource_handle->cache);
686                         while (g_hash_table_iter_next(&iter, &key, &value)) {
687                                 free(key);
688                                 resource_cache_context_t *c = (resource_cache_context_t *) value;
689                                 free(c->output);
690                                 free(value);
691                         }
692                         g_hash_table_remove_all(resource_handle->cache);
693                         if (cur_language) {
694                                 free(cur_language);
695                                 cur_language = NULL;
696                         }
697                 }
698         }
699 }
700
701 static int __close(resource_manager_t *handle)
702 {
703         if (handle == NULL) {
704                 LOGE("INVALID_PARAMETER(0x%08x), resource_manager",
705                                 AUL_RESOURCE_ERROR_INVALID_PARAMETER);
706                 return AUL_RESOURCE_ERROR_INVALID_PARAMETER;
707         }
708
709         __invalidate_cache();
710         if (handle->cache != NULL)
711                 g_hash_table_destroy(handle->cache);
712
713         if (handle->data != NULL)
714                 _resource_close(handle->data);
715
716         free(handle);
717
718         return AUL_RESOURCE_ERROR_NONE;
719 }
720
721 static void __vconf_cb(keynode_t *key, void *data)
722 {
723         char *val;
724
725         val = vconf_keynode_get_str(key);
726         if (val && cur_language && !strcmp(val, cur_language))
727                 return;
728
729         __invalidate_cache();
730 }
731
732 static const char *_get_app_resource_path(const char *rsc_folder_path)
733 {
734         if (is_slice == FALSE)
735                 return aul_get_app_resource_path();
736
737         if (rsc_folder_path == NULL)
738                 return NULL;
739
740         return rsc_folder_path;
741 }
742
743 static void path_callback(char *path)
744 {
745         char orig_path[PATH_MAX] = {0, };
746         char *path_ptr = NULL;
747         int path_len = 0;
748         GList *tmp_list = g_list_find_custom(all_node_list, path, __compare_path);
749
750         resource_node_list_t *tmp_node_info = NULL;
751         if (tmp_list == NULL)
752                 g_hash_table_add(valid_path_list, strdup(path));
753         else {
754                 tmp_node_info = (resource_node_list_t *)tmp_list->data;
755                 path_len = strlen(path);
756                 if (path_len >= PATH_MAX) {
757                         LOGE("path[%s] is too long", path);
758                         return;
759                 }
760                 strncpy(orig_path, path, sizeof(orig_path) - path_len - 1);
761                 path_ptr = &orig_path[strlen(res_path) + strlen(tmp_node_info->folder)];
762                 g_hash_table_insert(id_list, strdup(path_ptr), strdup(tmp_node_info->type));
763         }
764 }
765
766 static void __scan_dir(const char *path, void (*func)(char *))
767 {
768         struct dirent **items;
769         int nitems, i;
770         struct stat fstat;
771         char abs_path[PATH_MAX] = {0, };
772         char cwd[MAX_PATH] = {0, };
773         char *tmp = NULL;
774
775         if (chdir(path) < 0) {
776                 LOGE("failed to chdir[%s]", path);
777                 return;
778         }
779
780         tmp = getcwd(cwd, MAX_PATH - 1);
781         if (tmp == NULL) {
782                 LOGE("failed to get cwd");
783                 return;
784         }
785         nitems = scandir("./", &items, NULL, alphasort);
786
787         for (i = 0; i < nitems; i++) {
788                 if (items[i]->d_name[0] == '.')
789                         continue;
790
791                 snprintf(abs_path, sizeof(abs_path), "%s/%s", cwd, items[i]->d_name);
792
793                 if (g_lstat(abs_path, &fstat) != 0) {
794                         LOGE("failed to retrieve info[%s]", abs_path);
795                         return;
796                 }
797                 if ((fstat.st_mode & S_IFDIR) == S_IFDIR)
798                         __scan_dir(abs_path, path_callback);
799                 else
800                         func(abs_path);
801         }
802
803 }
804
805 static aul_resource_e __get_resource_type(char *type)
806 {
807         if (type == NULL)
808                 return -1;
809
810         if (strcmp(type, RSC_GROUP_TYPE_IMAGE) == 0)
811                 return AUL_RESOURCE_TYPE_IMAGE;
812         else if (strcmp(type, RSC_GROUP_TYPE_LAYOUT) == 0)
813                 return AUL_RESOURCE_TYPE_LAYOUT;
814         else if (strcmp(type, RSC_GROUP_TYPE_SOUND) == 0)
815                 return AUL_RESOURCE_TYPE_SOUND;
816         else if (strcmp(type, RSC_GROUP_TYPE_BIN) == 0)
817                 return AUL_RESOURCE_TYPE_BIN;
818         else
819                 return -1;
820 }
821
822 static int __set_valid_filelist(bundle *b)
823 {
824         if (b == NULL || supported_lang_list == NULL) {
825                 LOGE("INVALID_PARAMETER(0x%08x), bundle",
826                                 AUL_RESOURCE_ERROR_INVALID_PARAMETER);
827                 return AUL_RESOURCE_ERROR_INVALID_PARAMETER;
828         }
829
830         int retval = AUL_RESOURCE_ERROR_NONE;
831         char *path = NULL;
832         GHashTableIter id_list_iter;
833         GHashTableIter lang_list_iter;
834         gpointer id_key, lang_key, id_type;
835         aul_resource_e rsc_type = AUL_RESOURCE_TYPE_MIN;
836
837         given_attr_list = b;
838         g_hash_table_iter_init(&id_list_iter, id_list);
839
840         while (g_hash_table_iter_next(&id_list_iter, &id_key, &id_type)) {
841                 rsc_type = __get_resource_type((char *)id_type);
842                 if (rsc_type == -1) {
843                         LOGE("failed to get resource type[%s]", (char *)id_type);
844                         return AUL_RESOURCE_ERROR_IO_ERROR;
845                 }
846
847                 g_hash_table_iter_init(&lang_list_iter, supported_lang_list);
848                 while (g_hash_table_iter_next(&lang_list_iter, &lang_key, NULL)) {
849                         cur_language = strdup(lang_key);
850                         if (cur_language == NULL) {
851                                 LOGE("failed to strdup");
852                                 return AUL_RESOURCE_ERROR_OUT_OF_MEMORY;
853                         }
854
855                         retval = aul_resource_manager_get(rsc_type, id_key, &path);
856                         if (retval == AUL_RESOURCE_ERROR_NONE)
857                                 g_hash_table_add(valid_path_list, path);
858                         else
859                                 LOGE("failed to get value with given type[%d], key[%s]", rsc_type, (const char *)id_key);
860
861                         if (cur_language) {
862                                 free(cur_language);
863                                 cur_language = NULL;
864                         }
865                 }
866         }
867         return AUL_RESOURCE_ERROR_NONE;
868 }
869
870 static int __make_list(void)
871 {
872         resource_group_t *tmp_group = NULL;
873         resource_node_t  *tmp_node = NULL;
874         resource_node_list_t *tmp_node_struct = NULL;
875         char *group_type = NULL;
876         char folder[MAX_PATH] = {0 ,};
877         char *node_lang = NULL;
878         GList *group_list = NULL;
879         GList *node_list = NULL;
880         bundle *b = NULL;
881
882
883         /* make node folder list */
884         group_list = resource_handle->data->group_list;
885         if (group_list == NULL)
886                 return AUL_RESOURCE_ERROR_IO_ERROR;
887
888         while (group_list != NULL) {
889                 tmp_group = (resource_group_t *)group_list->data;
890                 if (tmp_group == NULL)
891                         return AUL_RESOURCE_ERROR_IO_ERROR;
892
893                 group_type = tmp_group->type;
894                 node_list = tmp_group->node_list;
895                 memset(folder, '\0', MAX_PATH);
896                 snprintf(folder, MAX_PATH - 1, "%s/", tmp_group->folder);
897
898                 /* make struct and put it into all node list */
899                 tmp_node_struct = (resource_node_list_t *)calloc(1, sizeof(resource_node_list_t));
900                 if (tmp_node_struct == NULL) {
901                         LOGE("calloc failed");
902                         return AUL_RESOURCE_ERROR_OUT_OF_MEMORY;
903                 }
904
905                 tmp_node_struct->folder = strdup(folder);
906                 tmp_node_struct->type = strdup(group_type);
907                 all_node_list = g_list_append(all_node_list, tmp_node_struct);
908
909                 while (node_list != NULL) {
910                         tmp_node = (resource_node_t *)node_list->data;
911                         if (tmp_node == NULL)
912                                 return AUL_RESOURCE_ERROR_IO_ERROR;
913
914                         /* retrieve language value from each node */
915                         b = tmp_node->attr;
916                         if (b == NULL)
917                                 return AUL_RESOURCE_ERROR_IO_ERROR;
918                         bundle_get_str(b, RSC_NODE_ATTR_LANGUAGE, &node_lang);
919                         if (node_lang != NULL)
920                                 g_hash_table_add(supported_lang_list, strdup(node_lang));
921
922                         memset(folder, '\0', MAX_PATH);
923                         snprintf(folder, MAX_PATH - 1, "%s/", tmp_node->folder);
924
925                         /* make struct and put it into all node list */
926                         tmp_node_struct = (resource_node_list_t *)calloc(1, sizeof(resource_node_list_t));
927                         if (tmp_node_struct == NULL) {
928                                 LOGE("calloc failed");
929                                 return AUL_RESOURCE_ERROR_OUT_OF_MEMORY;
930                         }
931
932                         tmp_node_struct->folder = strdup(folder);
933                         tmp_node_struct->type = strdup(group_type);
934                         all_node_list = g_list_prepend(all_node_list, tmp_node_struct);
935
936                         node_list = g_list_next(node_list);
937                 }
938                 group_list = g_list_next(group_list);
939         }
940
941         __scan_dir(res_path, path_callback);
942
943         /* add language which is not existed to find default resources */
944         g_hash_table_add(supported_lang_list, strdup("NoLang"));
945         return AUL_RESOURCE_ERROR_NONE;
946 }
947
948 static void __free_str(gpointer data)
949 {
950         if (data == NULL)
951                 return;
952
953         char *char_data = (char *)data;
954         free(char_data);
955         data = NULL;
956 }
957
958 static int __init(const char *rsc_folder_path, bundle *b)
959 {
960         if (rsc_folder_path != NULL && b != NULL)
961                 is_slice = TRUE;
962         else
963                 is_slice = FALSE;
964
965         if (resource_handle != NULL)
966                 return AUL_RESOURCE_ERROR_NONE;
967
968         int retval = AUL_RESOURCE_ERROR_NONE;
969
970         res_path = _get_app_resource_path(rsc_folder_path);
971         if (res_path == NULL) {
972                 LOGE("IO_ERROR(0x%08x), failed to get resource path",
973                                 AUL_RESOURCE_ERROR_IO_ERROR);
974                 return AUL_RESOURCE_ERROR_IO_ERROR;
975         }
976
977         retval = __open(&resource_handle);
978         if (retval != AUL_RESOURCE_ERROR_NONE) {
979                 LOGE("IO_ERROR(0x%08x), failed to get resource_handle(%d)",
980                                 AUL_RESOURCE_ERROR_IO_ERROR, retval);
981                 return AUL_RESOURCE_ERROR_IO_ERROR;
982         }
983
984         if (attr_key == NULL) {
985                 attr_key = g_hash_table_new(g_str_hash, g_str_equal);
986
987                 if (attr_key == NULL)
988                         return AUL_RESOURCE_ERROR_OUT_OF_MEMORY;
989
990                 unsigned int i;
991                 for (i = 0; i < ARRAY_SIZE(map); i++) {
992                         g_hash_table_insert(attr_key, (char *)map[i].bundle_attr_key,
993                                         (gpointer)((uintptr_t)(map[i].bundle_attr_value)));
994                 }
995         }
996
997         if (is_slice == FALSE) {
998                 int r = vconf_notify_key_changed(VCONFKEY_LANGSET, __vconf_cb, NULL);
999
1000                 if (r < 0) {
1001                         LOGE("IO_ERROR(0x%08x), failed to register vconf(%d)",
1002                                         AUL_RESOURCE_ERROR_IO_ERROR, r);
1003                         return AUL_RESOURCE_ERROR_IO_ERROR;
1004                 }
1005         } else {
1006                 /* make ID list */
1007                 if (id_list == NULL)
1008                         id_list = g_hash_table_new_full(g_str_hash, g_str_equal, __free_str, __free_str);
1009
1010                 if (supported_lang_list == NULL)
1011                         supported_lang_list = g_hash_table_new_full(g_str_hash, g_str_equal, __free_str, NULL);
1012
1013                 if (valid_path_list == NULL)
1014                         valid_path_list = g_hash_table_new_full(g_str_hash, g_str_equal, __free_str, NULL);
1015
1016                 retval = __make_list();
1017                 if (retval < 0) {
1018                         LOGE("Failed to initialize filelist");
1019                         return AUL_RESOURCE_ERROR_IO_ERROR;
1020                 }
1021
1022                 retval = __set_valid_filelist(b);
1023                 if (retval < 0) {
1024                         LOGE("Failed to get valid filelist");
1025                         return AUL_RESOURCE_ERROR_IO_ERROR;
1026                 }
1027
1028         }
1029
1030         return AUL_RESOURCE_ERROR_NONE;
1031 }
1032
1033 API int aul_resource_manager_init(void)
1034 {
1035         return __init(NULL, NULL);
1036 }
1037
1038 API int aul_resource_manager_init_slice(const char *rsc_folder_path, bundle *b)
1039 {
1040         if (rsc_folder_path == NULL || b == NULL)
1041                 return AUL_RESOURCE_ERROR_INVALID_PARAMETER;
1042
1043         return __init(rsc_folder_path, b);
1044 }
1045
1046
1047 API int aul_resource_manager_get_path_list(GHashTable **list)
1048 {
1049         if (is_slice == FALSE)
1050                 return AUL_RESOURCE_ERROR_IO_ERROR;
1051
1052         if (valid_path_list != NULL)
1053                 *list = valid_path_list;
1054         else
1055                 return AUL_RESOURCE_ERROR_IO_ERROR;
1056
1057         return AUL_RESOURCE_ERROR_NONE;
1058 }
1059
1060 static bool __verify_current_language(void)
1061 {
1062         char *lang;
1063
1064         lang = vconf_get_str(VCONFKEY_LANGSET);
1065         if (!lang)
1066                 return false;
1067
1068         if (cur_language && !strcmp(lang, cur_language)) {
1069                 free(lang);
1070                 return true;
1071         }
1072
1073         free(lang);
1074
1075         return false;
1076 }
1077
1078 API int aul_resource_manager_get(aul_resource_e type, const char *id, char **path)
1079 {
1080         int retval = AUL_RESOURCE_ERROR_NONE;
1081         char *put_fname = NULL;
1082         const char *cached_path = NULL;
1083         GList *list = NULL;
1084         resource_group_t *resource_group = NULL;
1085         resource_node_t *resource_node = NULL;
1086
1087         *path = NULL;
1088
1089         if (id == NULL) {
1090                 LOGE("INVALID_PARAMETER(0x%08x), resource_data_t",
1091                                 AUL_RESOURCE_ERROR_INVALID_PARAMETER);
1092                 return AUL_RESOURCE_ERROR_INVALID_PARAMETER;
1093         }
1094
1095         if (type < AUL_RESOURCE_TYPE_MIN || type > AUL_RESOURCE_TYPE_MAX) {
1096                 LOGE("INVALID_PARAMETER(0x%08x), type(%d)",
1097                                 AUL_RESOURCE_ERROR_INVALID_PARAMETER, type);
1098                 return AUL_RESOURCE_ERROR_INVALID_PARAMETER;
1099         }
1100
1101         if (is_slice == FALSE) {
1102                 if (resource_handle == NULL) {
1103                         retval = aul_resource_manager_init();
1104                         if (retval != AUL_RESOURCE_ERROR_NONE)
1105                                 return retval;
1106                 }
1107
1108                 if (__verify_current_language()) {
1109                         /* To get fname from cache */
1110                         cached_path = __get_cache(type, id);
1111                         if (cached_path != NULL) {
1112                                 *path = strdup(cached_path);
1113                                 return AUL_RESOURCE_ERROR_NONE;
1114                         }
1115                 } else {
1116                         __invalidate_cache();
1117                 }
1118         }
1119
1120         if (resource_handle == NULL)
1121                 return AUL_RESOURCE_ERROR_IO_ERROR;
1122
1123         resource_group = __find_group(resource_handle->data, type);
1124         if (resource_group == NULL) {
1125                 LOGE("IO_ERROR(0x%08x), failed to get resource_group",
1126                                 AUL_RESOURCE_ERROR_IO_ERROR);
1127                 retval = AUL_RESOURCE_ERROR_IO_ERROR;
1128                 goto Exception;
1129         }
1130
1131         list = __get_valid_nodes(resource_group, id);
1132         if (list == NULL) {
1133                 retval = AUL_RESOURCE_ERROR_IO_ERROR;
1134                 goto Exception;
1135         }
1136
1137         resource_node = __get_best_node(list);
1138         if (resource_node == NULL) {
1139                 retval = AUL_RESOURCE_ERROR_IO_ERROR;
1140                 goto Exception;
1141         } else {
1142                 unsigned int total_len = (unsigned int)(strlen(res_path)
1143                                 + strlen(resource_node->folder)
1144                                 + strlen(id) + 3);
1145                 put_fname = (char *) calloc(1, total_len);
1146                 if (!put_fname) {
1147                         if (list != NULL)
1148                                 g_list_free(list);
1149                         return AUL_RESOURCE_ERROR_OUT_OF_MEMORY;
1150                 }
1151                 snprintf(put_fname, total_len, "%s%s/%s", res_path,
1152                                 resource_node->folder, id);
1153                 *path = strdup(put_fname);
1154         }
1155
1156         __put_cache(type, id, put_fname);
1157
1158
1159 Exception:
1160         if (list != NULL)
1161                 g_list_free(list);
1162
1163         if (put_fname == NULL && resource_group != NULL) {
1164                 char path_buf[MAX_PATH] = { 0, };
1165                 char group_path_buf[MAX_PATH] = { 0, };
1166
1167                 snprintf(path_buf, MAX_PATH - 1, "%s%s/%s", res_path,
1168                                 resource_group->folder, id);
1169                 snprintf(group_path_buf, MAX_PATH - 1, "%s/%s", resource_group->folder, id);
1170
1171                 list = g_list_first(resource_group->node_list);
1172                 while (list) {
1173                         resource_node = (resource_node_t *) list->data;
1174                         if (strncmp(group_path_buf, resource_node->folder, strlen(resource_node->folder)) == 0) {
1175                                 *path = NULL;
1176                                 return AUL_RESOURCE_ERROR_IO_ERROR;
1177                         }
1178                         list = g_list_next(list);
1179                 }
1180
1181                 if (access(path_buf, R_OK) == 0) {
1182                         __put_cache(type, id, path_buf);
1183                         *path = strdup(path_buf);
1184                         retval = AUL_RESOURCE_ERROR_NONE;
1185                 }
1186         }
1187
1188         if (put_fname != NULL)
1189                 free(put_fname);
1190
1191         return retval;
1192 }
1193
1194 static void __free_node_folder_list(gpointer data)
1195 {
1196         resource_node_list_t *node_data = (resource_node_list_t *)data;
1197         if (node_data == NULL)
1198                 return;
1199
1200         if (node_data->folder != NULL) {
1201                 free(node_data->folder);
1202                 node_data->folder = NULL;
1203         }
1204
1205         if (node_data->type != NULL) {
1206                 free(node_data->type);
1207                 node_data->type = NULL;
1208         }
1209
1210         free(node_data);
1211 }
1212
1213 API int aul_resource_manager_release(void)
1214 {
1215         if (resource_handle != NULL) {
1216                 __close(resource_handle);
1217                 resource_handle = NULL;
1218         }
1219
1220         if (attr_key != NULL) {
1221                 g_hash_table_destroy(attr_key);
1222                 attr_key = NULL;
1223         }
1224
1225         if (cur_language) {
1226                 free(cur_language);
1227                 cur_language = NULL;
1228         }
1229
1230         if (is_slice == FALSE)
1231                 vconf_ignore_key_changed(VCONFKEY_LANGSET, __vconf_cb);
1232         else {
1233                 if (valid_path_list != NULL) {
1234                         g_hash_table_destroy(valid_path_list);
1235                         valid_path_list = NULL;
1236                 }
1237
1238                 if (supported_lang_list != NULL) {
1239                         g_hash_table_destroy(supported_lang_list);
1240                         supported_lang_list = NULL;
1241                 }
1242
1243                 if (id_list != NULL) {
1244                         g_hash_table_destroy(id_list);
1245                         id_list = NULL;
1246                 }
1247
1248                 if (all_node_list != NULL) {
1249                         g_list_free_full(all_node_list, __free_node_folder_list);
1250                         all_node_list = NULL;
1251                 }
1252         }
1253         return AUL_RESOURCE_ERROR_NONE;
1254 }