halcc: Introduce halcc library
[platform/hal/api/common.git] / halcc / src / halcc-parser.c
1 /*
2  * Copyright (c) 2024 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 #include <stdio.h>
18 #include <assert.h>
19 #include <errno.h>
20 #include <libxml/parser.h>
21 #include <libxml/tree.h>
22
23
24 #include "halcc-object.h"
25 #include "halcc-parser.h"
26 #include "halcc-util.h"
27
28 #define HALCC_DESERIALIZER_VERSION_MAJOR                1
29 #define HALCC_DESERIALIZER_VERSION_MINOR                0
30
31 #define __xmlchar__ __attribute__((__cleanup__(free_xmlstr)))
32
33 static void free_xmlstr(unsigned char **str)
34 {
35         xmlFree(*str);
36 }
37
38 static int parse_interface(xmlNode *node, halcc_interface *interface)
39 {
40         assert(node);
41         assert(interface);
42
43         if (!xmlStrEqual(node->name, "interface")) {
44                 printf("Invalid interface node, %s\n", node->name);
45                 return -EINVAL;
46         }
47
48         for (xmlNode *child = node->children; child; child = child->next) {
49                 if (xmlStrEqual(child->name, "name")) {
50                         __xmlchar__ xmlChar *name = xmlNodeGetContent(child);
51                         halcc_interface_set_name(interface, name);
52                 } else if (xmlStrEqual(child->name, "instance")) {
53                         __xmlchar__ xmlChar *instance = xmlNodeGetContent(child);
54                         halcc_interface_set_instance_id(interface, (char *) instance);
55                 }
56         }
57
58         return 0;
59 }
60
61 static int parse_hal(xmlNode *node, halcc_hal *hal)
62 {
63         int ret = 0;
64
65         assert(node);
66         assert(hal);
67
68         if (!xmlStrEqual(node->name, "hal")) {
69                 printf("Invalid hal node, %s\n", node->name);
70                 return -EINVAL;
71         }
72
73         for (xmlNode *child = node->children; child; child = child->next) {
74                 if (xmlStrEqual(child->name, "name")) {
75                         __xmlchar__ xmlChar *name = xmlNodeGetContent(child);
76
77                         ret = halcc_hal_set_name(hal, name);
78                         if (ret != 0)
79                                 printf("Failed to halcc_hal_set_name(), name=%s, ret=%d\n", name, ret);
80                 } else if (xmlStrEqual(child->name, "version")) {
81                         int major, min_minor, max_minor;
82                         int scanned;
83                         __xmlchar__ xmlChar *version = xmlNodeGetContent(child);
84
85                         scanned = sscanf(version, "%d.%d-%d", &major, &min_minor, &max_minor);
86                         switch (scanned) {
87                                 case 2: // 3.5 is equal to 3.5-5
88                                         max_minor = min_minor;
89                                         ret = halcc_hal_set_version(hal, major, min_minor, max_minor);
90                                         break;
91                                 case 3: // 3.5-8
92                                         ret = halcc_hal_set_version(hal, major, min_minor, max_minor);
93                                         break;
94                                 default:
95                                         ret = -EINVAL;
96                                         break;
97                         }
98
99                         if (ret != 0)
100                                 printf("Failed to halcc_hal_set_version(), ret=%d\n", ret);
101                 } else if (xmlStrEqual(child->name, "transport")) {
102                         __xmlchar__ xmlChar *transport = xmlNodeGetContent(child);
103
104                         if (xmlStrEqual(transport, "passthrough"))
105                                 ret = halcc_hal_set_transport(hal, HALCC_TRANSPORT_PASSTHROUGH);
106                         else if (xmlStrEqual(transport, "IPC"))
107                                 ret = halcc_hal_set_transport(hal, HALCC_TRANSPORT_IPC);
108                         else
109                                 ret = -EINVAL;
110
111                         if (ret != 0)
112                                 printf("Failed to halcc_hal_set_transport(), %s, ret=%d\n", transport, ret);
113                 } else if (xmlStrEqual(child->name, "interface")) {
114                         halcc_interface *iface;
115
116                         ret = halcc_interface_new(&iface);
117                         if (ret != 0) {
118                                 printf("Failed to halcc_interface_new(), ret=%d\n", ret);
119                                 continue;
120                         }
121
122                         ret = parse_interface(child, iface);
123                         if (ret != 0) {
124                                 printf("Failed to parse_interface(), ret=%d\n", ret);
125                                 halcc_interface_free(iface);
126                                 continue;
127                         }
128
129                         halcc_hal_add_interface(hal, iface);
130                         iface = NULL;
131                 } else if (xmlStrEqual(child->name, "dependency")) {
132                         for (xmlNode *grand_child = child->children; grand_child; grand_child = grand_child->next) {
133                                 halcc_hal *h;
134
135                                 if (!xmlStrEqual(grand_child->name, "hal"))
136                                         continue;
137
138                                 ret = halcc_hal_new(&h);
139                                 if (ret != 0)
140                                         continue;
141
142                                 ret = parse_hal(grand_child, h);
143                                 if (ret != 0) {
144                                         halcc_hal_free(h);
145                                         h = NULL;
146                                         continue;
147                                 }
148
149                                 halcc_hal_add_dependency(hal, h);
150                                 h = NULL;
151                         }
152                 }
153         }
154
155         return 0;
156 }
157
158 static int parse_manifest(xmlNode *node, halcc_manifest *manifest)
159 {
160         int ret;
161         xmlChar *prop;
162         int major;
163         int minor;
164         int level;
165
166         assert(node);
167         assert(manifest);
168
169         if (!xmlStrEqual(node->name, "manifest")) {
170                 printf("Invalid manifest node, %s\n", node->name);
171                 return -EINVAL;
172         }
173
174         // version
175         prop = xmlGetProp(node, "version");
176         if (!prop) {
177                 printf("Failed to xmlGetProp() \"version\"\n");
178                 return -EINVAL;
179         }
180
181         ret = sscanf(prop, "%d.%d", &major, &minor);
182         xmlFree(prop);
183
184         if (ret != 2) {
185                 printf("Failed to scan version, ret=%d\n", ret);
186                 return -EINVAL;
187         }
188
189         if (major != HALCC_DESERIALIZER_VERSION_MAJOR || minor != HALCC_DESERIALIZER_VERSION_MINOR) {
190                 printf("Manifest scheme doesn't match. Requires manifest version %d.%d\n",
191                         HALCC_DESERIALIZER_VERSION_MAJOR, HALCC_DESERIALIZER_VERSION_MINOR);
192                 return -ENOTSUP;
193         }
194
195         ret = halcc_manifest_set_version(manifest, major, minor);
196         if (ret != 0) {
197                 printf("Failed to halcc_manifest_set_version(), ret=%d\n", ret);
198                 return -EINVAL;
199         }
200
201         // type
202         prop = xmlGetProp(node, "type");
203         if (!prop) {
204                 printf("Failed to xmlGetProp() \"type\"\n");
205                 return -EINVAL;
206         }
207
208         if (xmlStrEqual(prop, "platform")) {
209                 ret = halcc_manifest_set_type(manifest, HALCC_MANIFEST_TYPE_HAL_API);
210                 if (ret != 0)
211                         printf("Failed to halcc_manifest_set_type() HALCC_MANIFEST_TYPE_HAL_API, ret=%d\n", ret);
212         } else if (xmlStrEqual(prop, "device")) {
213                 ret = halcc_manifest_set_type(manifest, HALCC_MANIFEST_TYPE_HAL_BACKEND);
214                 if (ret != 0)
215                         printf("Failed to halcc_manifest_set_type() HALCC_MANIFEST_TYPE_HAL_BACKEND, ret=%d\n", ret);
216         } else {
217                 printf("Invalid type property=%s\n", prop);
218                 ret = -EINVAL;
219         }
220
221         xmlFree(prop);
222
223         if (ret != 0)
224                 return ret;
225
226         // level
227         prop = xmlGetProp(node, "level");
228         if (!prop) {
229                 printf("Failed to xmlGetProp() \"level\"\n");
230                 return -EINVAL;
231         }
232
233         ret = sscanf(prop, "%d", &level);
234         xmlFree(prop);
235
236         if (ret != 1) {
237                 printf("Failed to scan manifest level\n");
238                 return -EINVAL;
239         }
240
241         ret = halcc_manifest_set_level(manifest, level);
242         if (ret != 0) {
243                 printf("Failed to halcc_manifest_set_level(), ret=%d\n", ret);
244                 return ret;
245         }
246
247         for (xmlNode *child = node->children; child; child = child->next) {
248                 halcc_hal *h;
249
250                 if (!xmlStrEqual(child->name, "hal"))
251                         continue;
252
253                 ret = halcc_hal_new(&h);
254                 if (ret != 0) {
255                         printf("Failed to halcc_hal_new(), ret=%d\n", ret);
256                         continue;
257                 }
258
259                 ret = parse_hal(child, h);
260                 if (ret != 0) {
261                         printf("Failed to parse_hal(), ret=%d\n", ret);
262                         halcc_hal_free(h);
263                         h = NULL;
264                         continue;
265                 }
266
267                 halcc_manifest_add_hal(manifest, h);
268                 h = NULL;
269         }
270
271         return 0;
272 }
273
274
275 static int parse_xml_doc(xmlDoc *doc, halcc_manifest *manifest)
276 {
277         xmlNode *root = NULL;
278         int ret;
279
280         if (!doc || !manifest)
281                 return -EINVAL;
282
283         root = xmlDocGetRootElement(doc);
284         if (!root) {
285                 printf("Failed to get root element\n");
286                 return -EINVAL;
287         }
288
289         ret = parse_manifest(root, manifest);
290         if (ret != 0) {
291                 printf("Failed to parse_manifest(), ret=%d\n", ret);
292                 return ret;
293         }
294
295         return 0;
296 }
297
298 int halcc_parse_fd(int fd, halcc_manifest *manifest)
299 {
300         xmlDoc *doc = NULL;
301         int ret = 0;
302
303         if (!manifest) {
304                 printf("Invalid manifest\n");
305                 return -EINVAL;
306         }
307
308         doc = xmlReadFd(fd, NULL, NULL, 0);
309         if (!doc) {
310                 printf("Failed to read doc %d\n", fd);
311                 return -ENOENT;
312         }
313
314         ret = parse_xml_doc(doc, manifest);
315
316         xmlFreeDoc(doc);
317
318         return ret;
319 }
320
321 int halcc_parse_path(const char *filepath, halcc_manifest *manifest)
322 {
323         xmlDoc *doc = NULL;
324         int ret = 0;
325
326         if (!filepath || !manifest) {
327                 printf("Invalid filepath or manifest\n");
328                 return -EINVAL;
329         }
330
331         doc = xmlReadFile(filepath, NULL, 0);
332         if (!doc) {
333                 printf("Failed to read doc %s\n", filepath);
334                 return -ENOENT;
335         }
336
337         ret = parse_xml_doc(doc, manifest);
338
339         xmlFreeDoc(doc);
340
341         return ret;
342 }
343
344 int halcc_parse_string(const char *string, int len, halcc_manifest *manifest)
345 {
346         xmlDoc *doc = NULL;
347         int ret = 0;
348
349         if (!string || !manifest) {
350                 printf("Invalid string or manifest\n");
351                 return -EINVAL;
352         }
353
354         doc = xmlReadMemory(string, len, NULL, NULL, 0);
355         if (!doc) {
356                 printf("Failed to read xml string\n");
357                 return -ENOENT;
358         }
359
360         ret = parse_xml_doc(doc, manifest);
361
362         xmlFreeDoc(doc);
363
364         return ret;
365 }