Fix validating resource schema
[platform/core/appfw/aul-1.git] / src / rsc-mgr / aul_rsc_mgr_internal.c
1 /*
2  * Copyright (c) 2016 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 #include <stdlib.h>
19 #include <string.h>
20
21 #include <glib.h>
22 #include <libxml/tree.h>
23 #include <libxml/xmlschemas.h>
24
25 #include <dlog.h>
26 #include <bundle.h>
27
28 #include "aul_rsc_mgr_internal.h"
29
30 static char *__get_attribute(xmlNode *xml_node, const char *name)
31 {
32         xmlChar *val;
33         char *attr = NULL;
34
35         val = xmlGetProp(xml_node, (const xmlChar *)name);
36         if (val) {
37                 attr = strdup((const char *)val);
38                 xmlFree(val);
39         }
40
41         return attr;
42 }
43
44 static void __get_attribute_into_bundle(xmlNode *xml_node, const char *name,
45                 bundle *b)
46 {
47         char *attr;
48
49         attr = __get_attribute(xml_node, name);
50         if (attr) {
51                 bundle_add_str(b, name, attr);
52                 free(attr);
53         }
54 }
55
56 static int __parse_node(xmlNode *xml_node, GList **nodes)
57 {
58         resource_node_t *node;
59
60         if (strcmp((char *)xml_node->name, "node"))
61                 return -1;
62
63         node = calloc(1, sizeof(resource_node_t));
64         if (!node) {
65                 LOGE("Out of memory");
66                 return -1;
67         }
68
69         node->folder = __get_attribute(xml_node, "folder");
70         /* why we should use bundle here? */
71         node->attr = bundle_create();
72         if (node->attr == NULL) {
73                 LOGE("Out of memory");
74                 free(node->folder);
75                 free(node);
76                 return -1;
77         }
78
79         __get_attribute_into_bundle(xml_node, RSC_NODE_ATTR_SCREEN_DPI,
80                         node->attr);
81         __get_attribute_into_bundle(xml_node, RSC_NODE_ATTR_SCREEN_DPI_RANGE,
82                         node->attr);
83         __get_attribute_into_bundle(xml_node, RSC_NODE_ATTR_SCREEN_WIDTH_RANGE,
84                         node->attr);
85         __get_attribute_into_bundle(xml_node, RSC_NODE_ATTR_SCREEN_LARGE,
86                         node->attr);
87         __get_attribute_into_bundle(xml_node, RSC_NODE_ATTR_SCREEN_BPP,
88                         node->attr);
89         __get_attribute_into_bundle(xml_node, RSC_NODE_ATTR_PLATFORM_VER,
90                         node->attr);
91         __get_attribute_into_bundle(xml_node, RSC_NODE_ATTR_LANGUAGE,
92                         node->attr);
93
94         *nodes = g_list_append(*nodes, node);
95
96         return 0;
97 }
98
99 static char *_get_group_type(xmlNode *xml_node)
100 {
101         static const char delim[] = "-";
102         char *str;
103         char *tok;
104         char *ptr;
105
106         /* copy original string */
107         str = strdup((const char *)xml_node->name);
108         if (str == NULL) {
109                 LOGE("Out of memory");
110                 return NULL;
111         }
112
113         tok = strtok_r(str, delim, &ptr);
114         /* not a group element */
115         if (tok == NULL || strcmp(tok, "group")) {
116                 free(str);
117                 return NULL;
118         }
119
120         tok = strtok_r(NULL, delim, &ptr);
121         /* invalid element */
122         if (tok == NULL) {
123                 free(str);
124                 return NULL;
125         }
126
127         ptr = strdup(tok);
128         free(str);
129
130         return ptr;
131 }
132
133 static int __parse_group(xmlNode *xml_node, GList **groups)
134 {
135         xmlNode *tmp;
136         char *type;
137         resource_group_t *group;
138
139         type = _get_group_type(xml_node);
140         if (type == NULL)
141                 return -1;
142
143         group = calloc(1, sizeof(resource_group_t));
144         if (group == NULL) {
145                 LOGE("Out of memory");
146                 free(type);
147                 return -1;
148         }
149
150         group->type = type;
151         group->folder = __get_attribute(xml_node, "folder");
152
153         for (tmp = xml_node->children; tmp; tmp = tmp->next) {
154                 if (xml_node->type != XML_ELEMENT_NODE)
155                         continue;
156                 if (__parse_node(tmp, &group->node_list))
157                         continue;
158         }
159
160         *groups = g_list_append(*groups, group);
161
162         return 0;
163 }
164
165 static int __parse_resource(xmlNode *xml_node, resource_data_t **data)
166 {
167         xmlNode *tmp;
168
169         *data = calloc(1, sizeof(resource_data_t));
170         if (*data == NULL) {
171                 LOGE("out of memory");
172                 return -1;
173         }
174
175         for (tmp = xml_node->children; tmp; tmp = tmp->next) {
176                 if (tmp->type != XML_ELEMENT_NODE)
177                         continue;
178                 __parse_group(tmp, &(*data)->group_list);
179         }
180
181         return 0;
182 }
183
184 #define SCHEMA_FILE SHARE_PREFIX"/res.xsd"
185 static int __validate_schema(const char *path)
186 {
187         xmlSchemaParserCtxt *parser_ctxt;
188         xmlSchema *schema;
189         xmlSchemaValidCtxt *valid_ctxt;
190         int ret;
191
192         parser_ctxt = xmlSchemaNewParserCtxt(SCHEMA_FILE);
193         if (parser_ctxt == NULL) {
194                 LOGE("failed to create parser context");
195                 return -1;
196         }
197
198         schema = xmlSchemaParse(parser_ctxt);
199         if (schema == NULL) {
200                 LOGE("failed to create schema");
201                 xmlSchemaFreeParserCtxt(parser_ctxt);
202                 return -1;
203         }
204
205         valid_ctxt = xmlSchemaNewValidCtxt(schema);
206         if (valid_ctxt == NULL) {
207                 LOGE("failed to create valid context");
208                 xmlSchemaFree(schema);
209                 xmlSchemaFreeParserCtxt(parser_ctxt);
210                 return -1;
211         }
212
213         ret = xmlSchemaValidateFile(valid_ctxt, path, 0);
214         if (ret)
215                 LOGE("%s: validation failed(%d)", path, ret);
216
217         xmlSchemaFreeValidCtxt(valid_ctxt);
218         xmlSchemaFree(schema);
219         xmlSchemaFreeParserCtxt(parser_ctxt);
220
221         return ret;
222 }
223
224 int _resource_open(const char *path, resource_data_t **data)
225 {
226         int ret;
227         xmlDoc *doc;
228         xmlNode *root;
229
230         if (__validate_schema(path))
231                 return -1;
232         doc = xmlReadFile(path, NULL, 0);
233         if (doc == NULL)
234                 return -1;
235         root = xmlDocGetRootElement(doc);
236         if (!root) {
237                 xmlFreeDoc(doc);
238                 return -1;
239         }
240
241         ret = __parse_resource(root, data);
242
243         xmlFreeDoc(doc);
244
245         return ret;
246 }
247
248 static void __free_resource_node(gpointer data)
249 {
250         resource_node_t *node = (resource_node_t *)data;
251
252         free(node->folder);
253         bundle_free(node->attr);
254         free(node);
255 }
256
257 static void __free_resource_group(gpointer data)
258 {
259         resource_group_t *group = (resource_group_t *)data;
260
261         free(group->folder);
262         free(group->type);
263
264         g_list_free_full(group->node_list, __free_resource_node);
265
266         free(group);
267 }
268
269 int _resource_close(resource_data_t *data)
270 {
271         /*
272         free(data->package);
273         */
274         g_list_free_full(data->group_list, __free_resource_group);
275
276         free(data);
277
278         return 0;
279 }