Provide unit in config.xml and documentation
[src/app-framework-main.git] / src / wgt-json.c
1 /*
2  Copyright 2015, 2016, 2017 IoT.bzh
3
4  author: José Bollo <jose.bollo@iot.bzh>
5
6  Licensed under the Apache License, Version 2.0 (the "License");
7  you may not use this file except in compliance with the License.
8  You may obtain a copy of the License at
9
10      http://www.apache.org/licenses/LICENSE-2.0
11
12  Unless required by applicable law or agreed to in writing, software
13  distributed under the License is distributed on an "AS IS" BASIS,
14  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  See the License for the specific language governing permissions and
16  limitations under the License.
17 */
18
19 #define _GNU_SOURCE
20
21 #include <stdlib.h>
22 #include <assert.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <unistd.h>
27 #include <stdarg.h>
28 #include <sys/types.h>
29
30 #include <json-c/json.h>
31
32 #include "utils-json.h"
33 #include "wgt-info.h"
34 #include "wgt-json.h"
35 #include "wgt-strings.h"
36 #include "verbose.h"
37
38 struct paramaction
39 {
40         const char *name;
41         int (*action)(struct json_object *obj, const struct wgt_desc_param *param, void *closure);
42         void *closure;
43 };
44
45
46 /* apply params */
47 static int apply_params(struct json_object *obj, const struct wgt_desc_param *param, const struct paramaction *actions)
48 {
49         int rc;
50         const struct paramaction *a;
51
52         if (!obj)
53                 rc = -1;
54         else {
55                 rc = 0;
56                 while(param) {
57                         for (a = actions ; a->name && strcmp(a->name, param->name) ; a++);
58                         if (a->action && a->action(obj, param, a->closure) < 0)
59                                 rc = -1;
60                         param = param->next;
61                 }
62         }
63         return rc;
64 }
65
66 static int get_array(struct json_object **result, struct json_object *obj, const char *key, int create)
67 {
68         int rc = j_enter_m(&obj, &key, 1);
69         if (rc < 0)
70                 *result = NULL;
71         else if (!json_object_object_get_ex(obj, key, result)) {
72                 if (!create) {
73                         *result = NULL;
74                         rc = -ENOENT;
75                 } else {
76                         if (!(*result = j_add_new_array(obj, key)))
77                                 rc = -ENOMEM;
78                 }
79         }
80         return rc;
81 }
82
83 /* get the param of 'name' for the feature 'feat' */
84 static const char *get_target_name(const struct wgt_desc_feature *feat, const char *defval)
85 {
86         const struct wgt_desc_param *param = feat->params;
87         while (param && strcmp(param->name, string_sharp_target))
88                 param = param->next;
89         if (param) {
90                 defval = param->value;
91                 param = param->next;
92                 while (param) {
93                         if (!strcmp(param->name, string_sharp_target)) {
94                                 defval = NULL;
95                                 break;
96                         }
97                         param = param->next;
98                 }
99         }
100         return defval;
101 }
102
103 /* get the target */
104 static struct json_object *get_array_item_by_key(struct json_object *array, const char *key, const char *val)
105 {
106         struct json_object *result, *k;
107         int i, n;
108
109         n = json_object_array_length(array);
110         for (i = 0 ; i < n ; i++) {
111                 result = json_object_array_get_idx(array, i);
112                 if (result && json_object_object_get_ex(result, key, &k)
113                         && json_object_get_type(k) == json_type_string
114                         && !strcmp(json_object_get_string(k), val))
115                         return result;
116         }
117         return NULL;
118 }
119
120 static int get_target(struct json_object **result, struct json_object *targets, const char *name, int create)
121 {
122         int rc;
123         struct json_object *t;
124
125         t = get_array_item_by_key(targets, string_sharp_target, name);
126         if (t) {
127                 if (!create)
128                         rc = 0;
129                 else {
130                         ERROR("duplicated target name: %s", name);
131                         t = NULL;
132                         rc = -EEXIST;
133                 }
134         } else {
135                 if (!create) {
136                         ERROR("target name not found: %s", name);
137                         rc = -ENOENT;
138                 } else {
139                         t = j_add_new_object(targets, NULL);
140                         if (t && j_add_string(t, string_sharp_target, name))
141                                 rc = 0;
142                         else {
143                                 json_object_put(t);
144                                 t = NULL;
145                                 rc = -ENOMEM;
146                         }
147                 }
148         }
149         *result = t;
150         return rc;
151 }
152
153 static int make_target(struct json_object *targets, const struct wgt_desc_feature *feat)
154 {
155         const char *id;
156         struct json_object *target;
157
158         id = get_target_name(feat, NULL);
159         if (id == NULL) {
160                 ERROR("target of feature %s is missing or repeated", feat->name);
161                 return -EINVAL;
162         }
163
164         return get_target(&target, targets, id, 1);
165 }
166
167 static int add_icon(struct json_object *target, const char *src, int width, int height)
168 {
169         int rc;
170         struct json_object *icon, *array;
171
172         rc = get_array(&array, target, string_icon, 1);
173         if (rc >= 0) {
174                 icon = json_object_new_object();
175                 if(!icon
176                 || !j_add_string(icon, string_src, src)
177                 || (width > 0 && !j_add_integer(icon, string_width, width))
178                 || (height > 0 && !j_add_integer(icon, string_height, height))
179                 || !j_add(array, NULL, icon)) {
180                         json_object_put(icon);
181                         rc = -ENOMEM;
182                 }
183         }
184         return rc;
185 }
186
187 static int make_main_target(struct json_object *targets, const struct wgt_desc *desc)
188 {
189         int rc;
190         struct wgt_desc_icon *icon;
191         struct json_object *target;
192
193         /* create the target 'main' */
194         rc = get_target(&target, targets, string_main, 1);
195
196         /* adds icons if any */
197         icon = desc->icons;
198         while (rc >= 0 && icon) {
199                 rc = add_icon(target, icon->src, icon->width, icon->height);
200                 icon = icon->next;
201         }
202
203         if (rc >= 0)
204                 rc = j_add_many_strings_m(target,
205                         "content.src", desc->content_src,
206                         "content.type", desc->content_type,
207                         "content.encoding", desc->content_encoding,
208                         NULL) ? 0 : -errno;
209
210         if (rc >= 0)
211                 if((desc->width && !j_add_integer(target, string_width, desc->width))
212                 || (desc->height && !j_add_integer(target, string_height, desc->height)))
213                         rc = -ENOMEM;
214
215         return rc;
216 }
217
218 /***********************************************************************************************************/
219
220 static struct json_object *object_of_param(const struct wgt_desc_param *param)
221 {
222         struct json_object *value;
223
224         value = json_object_new_object();
225         if (value
226          && j_add_string(value, string_name, param->name)
227          && j_add_string(value, string_value, param->value))
228                 return value;
229
230         json_object_put(value);
231         return NULL;
232 }
233
234 static int add_param_simple(struct json_object *obj, const struct wgt_desc_param *param, void *closure)
235 {
236         return j_add_string_m(obj, param->name, param->value);
237 }
238
239 static int add_param_array(struct json_object *obj, const struct wgt_desc_param *param, void *closure)
240 {
241         const char *array_name = closure;
242         struct json_object *array, *value;
243
244         if (!array_name)
245                 array = obj;
246         else if (!json_object_object_get_ex(obj, array_name, &array)) {
247                 array = j_add_new_array(obj, array_name);
248                 if (!array)
249                         return -ENOMEM;
250         }
251         value = object_of_param(param);
252         if (value && j_add(array, NULL, value))
253                 return 0;
254
255         json_object_put(value);
256         return -ENOMEM;
257 }
258
259 static int add_param_object(struct json_object *obj, const struct wgt_desc_param *param, void *closure)
260 {
261         struct json_object *object, *value;
262
263         if (!closure)
264                 object = obj;
265         else if (!json_object_object_get_ex(obj, closure, &object)) {
266                 object = j_add_new_object(obj, closure);
267                 if (!object)
268                         return -ENOMEM;
269         }
270         value = object_of_param(param);
271         if (value && j_add(object, param->name, value))
272                 return 0;
273
274         json_object_put(value);
275         return -ENOMEM;
276 }
277
278 static int add_targeted_params(struct json_object *targets, const struct wgt_desc_feature *feat, struct paramaction actions[])
279 {
280         int rc;
281         const char *id;
282         struct json_object *obj;
283
284         id = get_target_name(feat, string_main);
285         rc = get_target(&obj, targets, id, 0);
286         return rc < 0 ? rc : apply_params(obj, feat->params, actions);
287 }
288
289 static int add_provided_unit(struct json_object *targets, const struct wgt_desc_feature *feat)
290 {
291         static struct paramaction actions[] = {
292                 { .name = string_sharp_target, .action = NULL, .closure = NULL },
293                 { .name = NULL, .action = add_param_simple, .closure = NULL }
294         };
295         return add_targeted_params(targets, feat, actions);
296 }
297
298 static int add_provided_api(struct json_object *targets, const struct wgt_desc_feature *feat)
299 {
300         static struct paramaction actions[] = {
301                 { .name = string_sharp_target, .action = NULL, .closure = NULL },
302                 { .name = NULL, .action = add_param_array, .closure = (void*)string_provided_api }
303         };
304         return add_targeted_params(targets, feat, actions);
305 }
306
307 static int add_required_api(struct json_object *targets, const struct wgt_desc_feature *feat)
308 {
309         static struct paramaction actions[] = {
310                 { .name = string_sharp_target, .action = NULL, .closure = NULL },
311                 { .name = NULL, .action = add_param_array, .closure = (void*)string_required_api }
312         };
313         return add_targeted_params(targets, feat, actions);
314 }
315
316 static int add_required_permission(struct json_object *targets, const struct wgt_desc_feature *feat)
317 {
318         static struct paramaction actions[] = {
319                 { .name = string_sharp_target, .action = NULL, .closure = NULL },
320                 { .name = NULL, .action = add_param_object, .closure = (void*)string_required_permission }
321         };
322         return add_targeted_params(targets, feat, actions);
323 }
324
325 static int add_defined_permission(struct json_object *defperm, const struct wgt_desc_feature *feat)
326 {
327         static struct paramaction actions[] = {
328                 { .name = NULL, .action = add_param_array, .closure = NULL }
329         };
330         return apply_params(defperm, feat->params, actions);
331 }
332
333 /***********************************************************************************************************/
334
335 static struct json_object *to_json(const struct wgt_desc *desc)
336 {
337         size_t prefixlen;
338         const struct wgt_desc_feature *feat;
339         const char *featname;
340         struct json_object *result, *targets, *permissions;
341         int rc, rc2;
342
343         /* create the application structure */
344         if(!(result = json_object_new_object())
345         || !(targets = j_add_new_array(result, string_targets))
346         || !(permissions = j_add_new_array(result, string_defined_permission))
347         )
348                 goto error;
349
350         /* first pass: declarations */
351         rc = make_main_target(targets, desc);
352         prefixlen = strlen(string_AGL_widget_prefix);
353         for (feat = desc->features ; feat ; feat = feat->next) {
354                 featname = feat->name;
355                 if (!memcmp(featname, string_AGL_widget_prefix, prefixlen)) {
356                         if (!feat->required) {
357                                 ERROR("feature %s can't be optional", featname);
358                                 if (!rc)
359                                         rc = -EINVAL;
360                         }
361                         featname += prefixlen;
362                         if (!strcmp(featname, string_provided_unit)) {
363                                 rc2 = make_target(targets, feat);
364                                 if (rc2 < 0 && !rc)
365                                         rc = rc2;
366                         }
367                 }
368         }
369
370         /* second pass: definitions */
371         for (feat = desc->features ; feat ; feat = feat->next) {
372                 featname = feat->name;
373                 if (!memcmp(featname, string_AGL_widget_prefix, prefixlen)) {
374                         featname += prefixlen;
375                         if (!strcmp(featname, string_defined_permission)) {
376                                 rc2 = add_defined_permission(permissions, feat);
377                         }
378                         else if (!strcmp(featname, string_provided_unit)) {
379                                 rc2 = add_provided_unit(targets, feat);
380                         }
381                         else if (!strcmp(featname, string_provided_api)) {
382                                 rc2 = add_provided_api(targets, feat);
383                         }
384                         else if (!strcmp(featname, string_required_api)) {
385                                 rc2 = add_required_api(targets, feat);
386                         }
387                         else if (!strcmp(featname, string_required_permission)) {
388                                 rc2 = add_required_permission(targets, feat);
389                         } else {
390                                 /* gently ignore other features */
391                                 rc2 = 0;
392                         }
393                         if (rc2 < 0 && !rc)
394                                 rc = rc2;
395                 }
396         }
397
398         /* fills the main */
399         rc2 = j_add_many_strings_m(result,
400                 string_id, desc->id,
401                 string_idaver, desc->idaver,
402                 string_version, desc->version,
403                 "ver", desc->ver,
404                 "author.content", desc->author,
405                 "author.href", desc->author_href,
406                 "author.email", desc->author_email,
407                 "license.content", desc->license,
408                 "license.href", desc->license_href,
409                 "defaultlocale", desc->defaultlocale,
410                 "name.content", desc->name,
411                 "name.short", desc->name_short,
412                 "description", desc->description,
413                 NULL) ? 0 : -errno;
414         if (rc2 < 0 && !rc)
415                 rc = rc2;
416
417         /* */
418
419         /* */
420         if (!rc) {
421                 return result;
422         }
423
424 error:
425         json_object_put(result);
426         return NULL;
427 }
428
429 struct json_object *wgt_info_to_json(struct wgt_info *info)
430 {
431         return to_json(wgt_info_desc(info));
432 }
433
434 struct json_object *wgt_to_json(struct wgt *wgt)
435 {
436         struct json_object *result;
437         struct wgt_info *info;
438
439         info = wgt_info_create(wgt, 1, 1, 1);
440         if (info == NULL)
441                 result = NULL;
442         else {
443                 result = wgt_info_to_json(info);
444                 wgt_info_unref(info);
445         }
446         return result;
447 }
448
449 struct json_object *wgt_path_at_to_json(int dfd, const char *path)
450 {
451         struct json_object *result;
452         struct wgt_info *info;
453
454         info = wgt_info_createat(dfd, path, 1, 1, 1);
455         if (info == NULL)
456                 result = NULL;
457         else {
458                 result = wgt_info_to_json(info);
459                 wgt_info_unref(info);
460         }
461         return result;
462 }
463
464 struct json_object *wgt_path_to_json(const char *path)
465 {
466         return wgt_path_at_to_json(AT_FDCWD, path);
467 }
468
469