Add missing attribute in manifest.xsd.in
[platform/core/appfw/pkgmgr-info.git] / parser / pkgmgr_parser_resource.c
1 /*
2  * pkgmgr-info
3  *
4  * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Jayoun Lee <airjany@samsung.com>, Sewook Park <sewook7.park@samsung.com>,
7  * Jaeho Lee <jaeho81.lee@samsung.com>, Shobhit Srivastava <shobhit.s@samsung.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <unistd.h>
29 #include <db-util.h>
30 #include <glib.h>
31 #include <dlfcn.h>
32 #include <libxml/parser.h>
33 #include <libxml/xmlreader.h>
34 #include <libxml/xmlschemas.h>
35 #include <bundle.h>
36 #include "pkgmgr-info.h"
37 #include "pkgmgrinfo_debug.h"
38 #include "pkgmgr_parser.h"
39 #include "pkgmgr_parser_resource.h"
40 #ifdef LOG_TAG
41 #undef LOG_TAG
42 #endif
43
44 #define LOG_TAG "PKGMGR_PARSER"
45
46 #define XMLCHAR(s) (const xmlChar *)s
47 #define ASCII(s) (char *)s
48
49 #define FREE_AND_NULL(ptr) do { \
50                 if (ptr) { \
51                         free((void *)ptr); \
52                         ptr = NULL; \
53                 } \
54         } while (0)
55
56
57 #define RSC_XML_QUALIFIER "res"
58 #define RSC_GROUP_NAME_SEPERATOR '-'
59 #define RSC_GROUP "group"
60 #define RSC_GROUP_ATTR_FOLDER "folder"
61 #define RSC_GROUP_ATTR_TYPE "type"
62 #define RSC_NODE "node"
63 #define RSC_MANIFEST_SCHEMA_FILE "/etc/package-manager/preload/res.xsd"
64
65 static int __next_child_element(xmlTextReaderPtr reader, int depth)
66 {
67         int ret = xmlTextReaderRead(reader);
68         int cur = xmlTextReaderDepth(reader);
69         while (ret == 1) {
70                 switch (xmlTextReaderNodeType(reader)) {
71                 case XML_READER_TYPE_ELEMENT:
72                         if (cur == depth + 1)
73                                 return 1;
74                         break;
75                 case XML_READER_TYPE_TEXT:
76                         /*text is handled by each function separately*/
77                         if (cur == depth + 1)
78                                 return 0;
79                         break;
80                 case XML_READER_TYPE_END_ELEMENT:
81                         if (cur == depth)
82                                 return 0;
83                         break;
84                 default:
85                         if (cur <= depth)
86                                 return 0;
87                         break;
88                 }
89                 ret = xmlTextReaderRead(reader);
90                 cur = xmlTextReaderDepth(reader);
91         }
92         return ret;
93 }
94
95 static void _free_node_list(gpointer data)
96 {
97         resource_node_t *tmp_node = (resource_node_t *)data;
98
99         if (tmp_node == NULL) {
100                 _LOGE("node list's element is NULL");
101                 return;
102         }
103
104         FREE_AND_NULL(tmp_node->folder);
105         if (tmp_node->attr != NULL) {
106                 bundle_free(tmp_node->attr);
107                 tmp_node->attr = NULL;
108         }
109 }
110
111 static void _free_group_list(gpointer data)
112 {
113         resource_group_t *tmp_group = (resource_group_t *)data;
114
115         if (tmp_group == NULL) {
116                 _LOGE("group list's element is NULL");
117                 return;
118         }
119
120         FREE_AND_NULL(tmp_group->folder);
121         FREE_AND_NULL(tmp_group->type);
122
123         g_list_free_full(tmp_group->node_list, (GDestroyNotify)_free_node_list);
124 }
125
126 static void __save_resource_attribute_into_bundle(xmlTextReaderPtr reader, char *attribute, bundle **b)
127 {
128         xmlChar *attr_val = xmlTextReaderGetAttribute(reader, XMLCHAR(attribute));
129
130         if (attr_val)
131                 bundle_add_str(*b, attribute, (char *)attr_val);
132 }
133
134 static void __save_resource_attribute(xmlTextReaderPtr reader, char *attribute, char **xml_attribute, char *default_value)
135 {
136         xmlChar *attrib_val = xmlTextReaderGetAttribute(reader, XMLCHAR(attribute));
137
138         if (attrib_val)
139                 *xml_attribute = strdup(ASCII(attrib_val));
140         else {
141                 if (default_value != NULL)
142                         *xml_attribute = strdup(default_value);
143         }
144 }
145
146
147 static void __psp_process_node(xmlTextReaderPtr reader, resource_node_t **res_node)
148 {
149         char *node_folder = NULL;
150
151         __save_resource_attribute(reader, "folder", &node_folder, NULL);
152         bundle *b = NULL;
153         (*res_node)->folder = node_folder;
154
155         /*retrieve node's attribute and put it into bundle*/
156         b = bundle_create();
157
158         __save_resource_attribute_into_bundle(reader, RSC_NODE_ATTR_SCREEN_DPI, &b);
159         __save_resource_attribute_into_bundle(reader, RSC_NODE_ATTR_SCREEN_DPI_RANGE, &b);
160         __save_resource_attribute_into_bundle(reader, RSC_NODE_ATTR_SCREEN_WIDTH_RANGE, &b);
161         __save_resource_attribute_into_bundle(reader, RSC_NODE_ATTR_SCREEN_LARGE, &b);
162         __save_resource_attribute_into_bundle(reader, RSC_NODE_ATTR_SCREEN_BPP, &b);
163         __save_resource_attribute_into_bundle(reader, RSC_NODE_ATTR_PLATFORM_VER, &b);
164         __save_resource_attribute_into_bundle(reader, RSC_NODE_ATTR_LANGUAGE, &b);
165
166         (*res_node)->attr = b;
167 }
168
169 static int __psp_process_group(xmlTextReaderPtr reader, resource_group_t **res_group, char *group_type)
170 {
171         int depth = -1;
172         int ret = -1;
173         resource_group_t *tmp_group = NULL;
174         resource_node_t *res_node = NULL;
175         const xmlChar *node;
176         char *folder = NULL;
177
178         if (reader == NULL || *res_group == NULL || group_type == NULL) {
179                 _LOGE("invalid parameter");
180                 return PMINFO_R_EINVAL;
181         }
182
183         tmp_group = *res_group;
184         /*handle group's own attribute*/
185         __save_resource_attribute(reader, RSC_GROUP_ATTR_FOLDER, &folder, NULL);
186         tmp_group->folder = folder;
187         tmp_group->type = group_type;
188
189         depth = xmlTextReaderDepth(reader);
190         while ((ret = __next_child_element(reader, depth))) {
191                 node = xmlTextReaderConstName(reader);
192                 if (!node) {
193                         _LOGE("xmlTextReaderConstName value is NULL");
194                         return PMINFO_R_ERROR;
195                 }
196
197                 res_node = NULL;
198                 if (!strcmp(ASCII(node), RSC_NODE)) {
199                         res_node = malloc(sizeof(resource_node_t));
200                         if (res_node == NULL) {
201                                 _LOGE("malloc failed");
202                                 return -1;
203                         }
204                         tmp_group->node_list = g_list_append(tmp_group->node_list, res_node);
205                         __psp_process_node(reader, &res_node);
206                 } else {
207                         _LOGE("unidentified node has found[%s]", ASCII(node));
208                         return PMINFO_R_ERROR;
209                 }
210         }
211         return ret;
212 }
213
214 static int __is_group(char *node, char **type)
215 {
216         char *tmp = NULL;
217
218         if (node == NULL) {
219                 _LOGE("node is null");
220                 return PMINFO_R_EINVAL;
221         }
222
223         tmp = strchr(node, RSC_GROUP_NAME_SEPERATOR);
224         tmp = tmp + 1; /*remove dash seperator*/
225         if (!strcmp(tmp, PKGMGR_RSC_GROUP_TYPE_IMAGE))
226                 *type = strdup(tmp);
227         else if (!strcmp(tmp, PKGMGR_RSC_GROUP_TYPE_LAYOUT))
228                 *type = strdup(tmp);
229         else if (!strcmp(tmp, PKGMGR_RSC_GROUP_TYPE_SOUND))
230                 *type = strdup(tmp);
231         else if (!strcmp(tmp, PKGMGR_RSC_GROUP_TYPE_BIN))
232                 *type = strdup(tmp);
233         else
234                 return PMINFO_R_ERROR;
235
236         if (*type == NULL) {
237                 _LOGE("strdup failed with node[%s]", node);
238                 return PMINFO_R_ERROR;
239         }
240
241         return PMINFO_R_OK;
242 }
243
244 static int __start_resource_process(xmlTextReaderPtr reader, GList **list)
245 {
246         GList *tmp_list = NULL;
247         const xmlChar *node;
248         char *group_type = NULL;
249         int ret = -1;
250         int depth = -1;
251         resource_group_t *res_group = NULL;
252
253         if (reader == NULL) {
254                 _LOGE("reader is null");
255                 return PMINFO_R_EINVAL;
256         }
257
258         depth = xmlTextReaderDepth(reader);
259         while ((ret = __next_child_element(reader, depth))) {
260                 node = xmlTextReaderConstName(reader);
261                 if (!node) {
262                         _LOGE("xmlTextReaderConstName value is null");
263                         return -1;
264                 }
265
266                 group_type = NULL;
267                 ret = __is_group(ASCII(node), &group_type);
268                 if (ret) {
269                         _LOGE("unidentified node[%s] has found with error[%d]", ASCII(node), ret);
270                         goto err;
271                 }
272                 res_group = NULL;
273                 res_group = malloc(sizeof(resource_group_t));
274                 if (res_group == NULL) {
275                         _LOGE("malloc failed");
276                         ret = PMINFO_R_ERROR;
277                         goto err;
278                 }
279                 memset(res_group, '\0', sizeof(resource_group_t));
280                 tmp_list = g_list_append(tmp_list, res_group);
281                 ret = __psp_process_group(reader, &res_group, group_type);
282                 if (ret != 0) {
283                         _LOGE("resource group processing failed");
284                         ret = PMINFO_R_ERROR;
285                         goto err;
286                 }
287         }
288
289         *list = g_list_first(tmp_list);
290         return ret;
291
292 err:
293         FREE_AND_NULL(group_type);
294         FREE_AND_NULL(res_group);
295         g_list_free_full(tmp_list, _free_group_list);
296
297         return ret;
298 }
299
300 static int __process_resource_manifest(xmlTextReaderPtr reader, resource_data_t *data)
301 {
302         const xmlChar *node;
303         int ret = PMINFO_R_ERROR;
304
305         if (reader == NULL)
306                 return PMINFO_R_ERROR;
307
308         ret = __next_child_element(reader, -1);
309         if (ret) {
310                 node = xmlTextReaderConstName(reader);
311                 retvm_if(!node, PMINFO_R_ERROR, "xmlTextReaderConstName value is NULL\n");
312
313                 if (!strcmp(ASCII(node), RSC_XML_QUALIFIER)) {
314                         ret = __start_resource_process(reader, &data->group_list);
315                         if (data->group_list == NULL)
316                                 _LOGE("__process_resource_manifest about to end but group list is null[%d]", ret);
317                 } else {
318                         _LOGE("no manifest element[res] has found");
319                         return PMINFO_R_ERROR;
320                 }
321         }
322         return ret;
323 }
324
325 static resource_data_t *_pkgmgr_resource_parser_process_manifest_xml(const char *manifest)
326 {
327         xmlTextReaderPtr reader;
328         resource_data_t *rsc_data = NULL;
329
330         reader = xmlReaderForFile(manifest, NULL, 0);
331         if (reader) {
332                 rsc_data = malloc(sizeof(resource_data_t));
333                 if (rsc_data == NULL) {
334                         _LOGE("memory allocation failed");
335                         return NULL;
336                 }
337
338                 memset(rsc_data, '\0', sizeof(resource_data_t));
339                 if (__process_resource_manifest(reader, rsc_data) < 0) {
340                         _LOGE("parsing failed with given manifest[%s]", manifest);
341                         if (pkgmgr_resource_parser_close(rsc_data) != 0)
342                                 _LOGE("closing failed");
343                         FREE_AND_NULL(rsc_data);
344                 } else
345                         _LOGE("parsing succeed");
346
347                 xmlFreeTextReader(reader);
348         } else {
349                 _LOGE("creating xmlreader failed");
350                 FREE_AND_NULL(rsc_data);
351         }
352         return rsc_data;
353 }
354
355 API int pkgmgr_resource_parser_open(const char *fname, resource_data_t **data)
356 {
357         resource_data_t *rsc_data = NULL;
358         int ret = PMINFO_R_ERROR;
359
360         if (fname == NULL || access(fname, R_OK) != 0) {
361                 _LOGE("filename is null or cannot access file");
362                 return PMINFO_R_EINVAL;
363         }
364         xmlInitParser();
365         rsc_data = _pkgmgr_resource_parser_process_manifest_xml(fname);
366         if (rsc_data == NULL) {
367                 _LOGE("parsing failed");
368                 goto catch;
369         }
370
371         rsc_data->package = NULL;
372
373         *data = rsc_data;
374         ret = PMINFO_R_OK;
375 catch:
376         xmlCleanupParser();
377         return ret;
378 }
379
380 API int pkgmgr_resource_parser_close(resource_data_t *data)
381 {
382         if (data == NULL) {
383                 _LOGE("parameter is NULL");
384                 return PMINFO_R_EINVAL;
385         }
386
387         FREE_AND_NULL(data->package);
388         g_list_free_full(data->group_list, (GDestroyNotify)_free_group_list);
389
390         return PMINFO_R_OK;
391 }
392
393 API int pkgmgr_resource_parser_check_xml_validation(const char *xmlfile)
394 {
395         if (xmlfile == NULL) {
396                 _LOGE("manifest file is NULL\n");
397                 return PM_PARSER_R_EINVAL;
398         }
399         int ret = PM_PARSER_R_OK;
400         xmlSchemaParserCtxtPtr ctx = NULL;
401         xmlSchemaValidCtxtPtr vctx = NULL;
402         xmlSchemaPtr xschema = NULL;
403         ctx = xmlSchemaNewParserCtxt(RSC_MANIFEST_SCHEMA_FILE);
404         if (ctx == NULL) {
405                 _LOGE("xmlSchemaNewParserCtxt() Failed\n");
406                 return PM_PARSER_R_ERROR;
407         }
408         xschema = xmlSchemaParse(ctx);
409         if (xschema == NULL) {
410                 _LOGE("xmlSchemaParse() Failed\n");
411                 ret = PM_PARSER_R_ERROR;
412                 goto cleanup;
413         }
414         vctx = xmlSchemaNewValidCtxt(xschema);
415         if (vctx == NULL) {
416                 _LOGE("xmlSchemaNewValidCtxt() Failed\n");
417                 return PM_PARSER_R_ERROR;
418         }
419         xmlSchemaSetValidErrors(vctx, (xmlSchemaValidityErrorFunc) fprintf, (xmlSchemaValidityWarningFunc) fprintf, stderr);
420         ret = xmlSchemaValidateFile(vctx, xmlfile, 0);
421         if (ret == -1) {
422                 _LOGE("xmlSchemaValidateFile() failed\n");
423                 ret = PM_PARSER_R_ERROR;
424                 goto cleanup;
425         } else if (ret == 0) {
426                 _LOGE("Manifest is Valid\n");
427                 ret = PM_PARSER_R_OK;
428                 goto cleanup;
429         } else {
430                 _LOGE("Manifest Validation Failed with error code %d\n", ret);
431                 ret = PM_PARSER_R_ERROR;
432                 goto cleanup;
433         }
434
435 cleanup:
436         if(vctx != NULL)
437                 xmlSchemaFreeValidCtxt(vctx);
438
439         if(ctx != NULL)
440                 xmlSchemaFreeParserCtxt(ctx);
441
442         if(xschema != NULL)
443                 xmlSchemaFree(xschema);
444
445         return ret;
446 }