Line data Source code
1 : /*
2 : Copyright © 2018 by Danny Goossen, Gioxa Ltd. All rights reserved.
3 :
4 : This file is part of the oc-runner
5 :
6 : MIT License
7 :
8 : Permission is hereby granted, free of charge, to any person obtaining a copy
9 : of this software and associated documentation files (the "Software"), to deal
10 : in the Software without restriction, including without limitation the rights
11 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 : copies of the Software, and to permit persons to whom the Software is
13 : furnished to do so, subject to the following conditions:
14 :
15 : The above copyright notice and this permission notice shall be included in all
16 : copies or substantial portions of the Software.
17 :
18 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 : SOFTWARE.
25 :
26 : */
27 :
28 : /*! \file yalm2cjson.c
29 : * \brief Parse yaml and json to a cJSON object
30 : * \author Created by Danny Goossen on 10/5/2017.
31 : * \copyright 2018, Danny Goossen. MIT License
32 : *
33 : */
34 :
35 :
36 : #include "deployd.h"
37 : #include "yaml2cjson.h"
38 :
39 : /**
40 : \brief set object type and content of unquoted, unfolded and non Litural value item
41 : \param in_buffer value to process
42 : \return a cJSON object
43 : */
44 : cJSON * process_YAML_PLAIN_SCALAR_STYLE(char * in_buffer);
45 :
46 7 : cJSON * process_YAML_PLAIN_SCALAR_STYLE(char * in_buffer)
47 : {
48 7 : cJSON * result=NULL;
49 : // check bool / NULL
50 7 : if (!in_buffer) return NULL;
51 7 : if (strlen(in_buffer)==0) return (cJSON_CreateString(""));
52 :
53 7 : char * buffer=NULL;
54 7 : buffer=strdup(in_buffer);
55 7 : if (buffer)
56 : {
57 7 : if( strchr(buffer,'.')==NULL)
58 : {
59 : char * errCheck;
60 7 : int i = (int)strtol(buffer, &errCheck,(10));
61 7 : if(errCheck == buffer+strlen(buffer))
62 0 : result=cJSON_CreateNumber(i);
63 : }
64 7 : free(buffer);
65 7 : buffer=NULL;
66 : }
67 7 : if (result) return result;
68 7 : buffer=strdup(in_buffer);
69 7 : if (buffer)
70 : {
71 : char * errCheck;
72 7 : double f = strtod(buffer, &errCheck);
73 7 : if(errCheck == buffer+strlen(buffer))
74 0 : result=cJSON_CreateNumber(f);
75 7 : free(buffer);
76 7 : buffer=NULL;
77 : }
78 7 : if (result) return result;
79 7 : buffer=strdup(in_buffer);
80 7 : if (buffer)
81 : {
82 7 : upper_string(buffer);
83 7 : size_t len=strlen(buffer);
84 7 : if (len==4 && strncmp((const char *)buffer, "TRUE", 4)==0)
85 0 : result=cJSON_CreateTrue();
86 7 : else if (len==5 && strncmp((const char *)buffer, "FALSE", 5)==0)
87 0 : result=cJSON_CreateFalse();
88 7 : else if (len==3 && strncmp((const char *)buffer, "YES", 3)==0)
89 0 : result=cJSON_CreateTrue();
90 7 : else if (len==2 && strncmp((const char *)buffer, "NO", 2)==0)
91 0 : result=cJSON_CreateFalse();
92 7 : else if (len==2 && strncmp((const char *)buffer, "ON", 2)==0)
93 0 : result=cJSON_CreateTrue();
94 7 : else if (len==3 && strncmp((const char *)buffer, "OFF", 3)==0)
95 0 : result=cJSON_CreateFalse();
96 7 : else if (len==1 && strncmp((const char *)buffer, "Y", 1)==0)
97 0 : result=cJSON_CreateTrue();
98 7 : else if (len==1 && strncmp((const char *)buffer, "N", 1)==0)
99 0 : result=cJSON_CreateFalse();
100 7 : else if (len==4 && strncmp((const char *)buffer, "NULL", 4)==0)
101 0 : result=cJSON_CreateNull();
102 7 : free(buffer);
103 7 : buffer=NULL;
104 : }
105 :
106 7 : if (result) return result;
107 : else
108 7 : result=cJSON_CreateString(in_buffer);
109 7 : return result;
110 : }
111 :
112 : // doesn't print styles.
113 11 : static cJSON * yaml_node_json(yaml_document_t *document_p, yaml_node_t *node,cJSON* env_vars)
114 : {
115 : static int x = 0;
116 11 : x++;
117 11 : int node_n = x;
118 11 : cJSON * result=NULL;
119 : yaml_node_t *next_node_p;
120 :
121 11 : switch (node->type) {
122 : case YAML_NO_NODE:
123 0 : printf("Empty node(%d):\n", node_n);
124 0 : break;
125 : case YAML_SCALAR_NODE:
126 : {
127 7 : if (strcmp((const char*)node->tag,YAML_NULL_TAG)==0)
128 0 : result=cJSON_CreateNull();
129 7 : else if (strcmp((const char*)node->tag,YAML_STR_TAG)==0)
130 : {
131 7 : if (node->data.scalar.style==YAML_PLAIN_SCALAR_STYLE)
132 : {
133 7 : char * buf=cJSON_strdup_n((const unsigned char*)node->data.scalar.value, node->data.scalar.length);
134 7 : if (buf)
135 : {
136 7 : result=process_YAML_PLAIN_SCALAR_STYLE(buf);
137 7 : free(buf);
138 : }
139 : }
140 0 : else if (node->data.scalar.style==YAML_DOUBLE_QUOTED_SCALAR_STYLE && env_vars)
141 : {
142 0 : char * buf=cJSON_strdup_n((const unsigned char*)node->data.scalar.value, node->data.scalar.length);
143 0 : if (buf)
144 : {
145 : // todo, rework to not 3 times copy buffer!!!!
146 0 : if (strchr(buf,'$'))
147 : {
148 0 : char *tmp=resolve_const_vars(buf,env_vars);
149 0 : if (tmp)
150 : {
151 0 : result=cJSON_CreateString(tmp);
152 0 : free(tmp);
153 : }
154 : else
155 0 : result=cJSON_CreateString_n((const char* )node->data.scalar.value, node->data.scalar.length);
156 : }
157 : else
158 0 : result=cJSON_CreateString_n((const char* )node->data.scalar.value, node->data.scalar.length);
159 0 : free(buf);
160 : }
161 : }
162 : else
163 0 : result=cJSON_CreateString_n((const char* )node->data.scalar.value, node->data.scalar.length);
164 : }
165 0 : else if (strcmp((const char*)node->tag,YAML_BOOL_TAG)==0)
166 : {
167 0 : upper_string_n((char*)node->data.scalar.value, node->data.scalar.length);
168 0 : if (node->data.scalar.length==4 && strncmp((const char *)node->data.scalar.value, "TRUE", 4)==0)
169 0 : result=cJSON_CreateTrue();
170 0 : else if (node->data.scalar.length==5 && strncmp((const char *)node->data.scalar.value, "FALSE", 5)==0)
171 0 : result=cJSON_CreateFalse();
172 0 : else if (node->data.scalar.length==3 && strncmp((const char *)node->data.scalar.value, "YES", 3)==0)
173 0 : result=cJSON_CreateTrue();
174 0 : else if (node->data.scalar.length==2 && strncmp((const char *)node->data.scalar.value, "NO", 2)==0)
175 0 : result=cJSON_CreateFalse();
176 0 : else if (node->data.scalar.length==2 && strncmp((const char *)node->data.scalar.value, "ON", 2)==0)
177 0 : result=cJSON_CreateTrue();
178 0 : else if (node->data.scalar.length==3 && strncmp((const char *)node->data.scalar.value, "OFF", 3)==0)
179 0 : result=cJSON_CreateFalse();
180 0 : else if (node->data.scalar.length==1 && strncmp((const char *)node->data.scalar.value, "Y", 1)==0)
181 0 : result=cJSON_CreateTrue();
182 0 : else if (node->data.scalar.length==1 && strncmp((const char *)node->data.scalar.value, "N", 1)==0)
183 0 : result=cJSON_CreateFalse();
184 0 : else if (node->data.scalar.length==1 && strncmp((const char *)node->data.scalar.value, "1", 1)==0)
185 0 : result=cJSON_CreateTrue();
186 0 : else if (node->data.scalar.length==1 && strncmp((const char *)node->data.scalar.value, "0", 1)==0)
187 0 : result=cJSON_CreateFalse();
188 : else
189 : {
190 : char * errCheck;
191 0 : char * buf=cJSON_strdup_n((const unsigned char*)node->data.scalar.value, node->data.scalar.length);
192 0 : int i = (int)strtol(buf, &errCheck,(10));
193 0 : free(buf);
194 0 : if(errCheck == buf)
195 0 : result=cJSON_CreateString_n((const char*)node->data.scalar.value, node->data.scalar.length);
196 : else
197 0 : result=cJSON_CreateNumber(i);
198 : }
199 : //TODO why was this here?
200 : //result=cJSON_CreateString_n((const char*)node->data.scalar.value, node->data.scalar.length);
201 : }
202 0 : else if (strcmp((const char*)node->tag,YAML_INT_TAG)==0)
203 : {
204 : char * errCheck;
205 0 : char * buf=cJSON_strdup_n((const unsigned char*)node->data.scalar.value, node->data.scalar.length);
206 0 : int i = (int)strtol(buf, &errCheck,(10));
207 0 : free(buf);
208 0 : if(errCheck == buf)
209 0 : result=cJSON_CreateString_n((const char*)node->data.scalar.value, node->data.scalar.length);
210 : else
211 0 : result=cJSON_CreateNumber(i);
212 : }
213 0 : else if (strcmp((const char*)node->tag,YAML_FLOAT_TAG)==0)
214 : {
215 : char * errCheck;
216 0 : char * buf=cJSON_strdup_n((const unsigned char*)node->data.scalar.value, node->data.scalar.length);
217 0 : float f = (float)strtod(buf, &errCheck);
218 0 : free(buf);
219 0 : if(errCheck == buf)
220 0 : result=cJSON_CreateString_n((const char*)node->data.scalar.value, node->data.scalar.length);
221 : else
222 0 : result=cJSON_CreateNumber(f);
223 : }
224 0 : else if (strcmp((const char*)node->tag,YAML_TIMESTAMP_TAG)==0)
225 0 : result=cJSON_CreateString_n((const char*)node->data.scalar.value, node->data.scalar.length);
226 : break;
227 : }
228 : case YAML_SEQUENCE_NODE:
229 : {
230 : yaml_node_item_t *i_node;
231 4 : cJSON * temp=NULL;
232 11 : for (i_node = node->data.sequence.items.start; i_node < node->data.sequence.items.top; i_node++) {
233 7 : next_node_p = yaml_document_get_node(document_p, *i_node);
234 7 : if (next_node_p)
235 : {
236 7 : temp=yaml_node_json(document_p, next_node_p,env_vars);
237 7 : if (temp)
238 : {
239 7 : if (result==NULL ) result=cJSON_CreateArray();
240 7 : cJSON_AddItemToArray(result, temp);
241 : }
242 : }
243 : }
244 : break;
245 : }
246 : case YAML_MAPPING_NODE:
247 : {
248 : yaml_node_pair_t *i_node_p;
249 0 : cJSON * temp=NULL;
250 0 : for (i_node_p = node->data.mapping.pairs.start; i_node_p < node->data.mapping.pairs.top; i_node_p++) {
251 :
252 0 : next_node_p = yaml_document_get_node(document_p, i_node_p->value);
253 0 : if (next_node_p) {
254 0 : temp=yaml_node_json(document_p, next_node_p,env_vars);
255 : }
256 0 : next_node_p = yaml_document_get_node(document_p, i_node_p->key);
257 0 : if (next_node_p && next_node_p->type==YAML_SCALAR_NODE)
258 : {
259 0 : if (result==NULL) result=cJSON_CreateObject();
260 0 : if (strncmp("<<", (const char*)next_node_p->data.scalar.value, next_node_p->data.scalar.length)==0)
261 : { // merge, deconstruct temp
262 0 : if (temp && temp->type==cJSON_Object)
263 : {
264 0 : cJSON * temp_item= temp->child;
265 0 : temp->child=NULL;
266 : cJSON * traverse;
267 : temp->child=NULL;
268 0 : if (result->child)
269 : {
270 : traverse=result->child;
271 0 : while ( traverse->next !=NULL) traverse=traverse->next;
272 0 : traverse->next=temp_item;
273 0 : temp_item->prev=traverse;
274 : }
275 : else
276 : {
277 0 : result->child=temp_item;
278 : }
279 0 : } else if (temp && temp->type==cJSON_Array)
280 : {
281 : // loop the array and add children to result
282 0 : cJSON * pos=NULL;
283 0 : int item=0;
284 : cJSON * traverse;
285 0 : cJSON_ArrayForEach(pos,temp)
286 : {
287 0 : if (result->child)
288 : {
289 : traverse=result->child;
290 0 : while ( traverse->next !=NULL) traverse=traverse->next;
291 0 : traverse->next=pos->child;
292 0 : pos->child=NULL;
293 : }
294 : else
295 : {
296 0 : result->child=pos->child;
297 0 : pos->child=NULL;
298 : }
299 0 : item ++;
300 : }
301 : }
302 : else
303 : {
304 0 : cJSON_AddItemToObject(result, "", temp);
305 : }
306 0 : cJSON_Delete(temp);
307 : }
308 : else
309 : {
310 0 : if (temp)
311 0 : cJSON_AddItemToObject_n(result, (const char*)next_node_p->data.scalar.value, next_node_p->data.scalar.length, temp);
312 : else
313 0 : cJSON_AddItemToObject_n(result, (const char*)next_node_p->data.scalar.value, next_node_p->data.scalar.length, cJSON_CreateObject());
314 : }
315 0 : }else if (next_node_p)
316 : {
317 0 : cJSON * temp_key=yaml_node_json(document_p, next_node_p,env_vars);
318 0 : if (temp_key){
319 0 : char * special_key=cJSON_PrintUnformatted(temp_key);
320 0 : char * print_key=calloc(1, strlen(special_key)+ 25);
321 : // TODO can maybe do something with raw
322 0 : sprintf(print_key,".error_unsupported_key: %s",special_key);
323 0 : cJSON_AddItemToObject(result,print_key,temp);
324 0 : if (special_key) free(special_key);
325 0 : if (print_key) free(print_key);
326 : }
327 : }
328 : }
329 : break;
330 : }
331 : default:
332 : break;
333 : }
334 11 : return result;
335 : }
336 :
337 4 : static void yaml_document_2_cJSON(yaml_document_t *document_p, cJSON ** json_doc,cJSON*env_vars)
338 : {
339 4 : cJSON * result=NULL;
340 4 : result=yaml_node_json(document_p, yaml_document_get_root_node(document_p),env_vars);
341 4 : if (result && *json_doc==NULL) *json_doc=cJSON_CreateArray();
342 4 : if (result) cJSON_AddItemToArray(*json_doc,result);
343 4 : }
344 :
345 0 : cJSON * yaml_sting_2_cJSON_env ( __attribute__((unused))void * opaque , cJSON * env_vars,const char * yaml)
346 : {
347 0 : cJSON * result=NULL;
348 : yaml_parser_t parser;
349 : yaml_document_t document;
350 0 : yaml_parser_initialize(&parser);
351 0 : yaml_parser_set_input_string(&parser, (const unsigned char *) yaml, strlen(yaml));
352 :
353 0 : int done = 0;
354 0 : while (!done)
355 : {
356 0 : if (!yaml_parser_load(&parser, &document)) {
357 0 : debug( "Failed to load document \n");
358 : // todo feedback
359 0 : break;
360 : }
361 :
362 0 : done = (!yaml_document_get_root_node(&document));
363 :
364 0 : if (!done)
365 0 : yaml_document_2_cJSON(&document,&result,env_vars);
366 :
367 0 : yaml_document_delete(&document);
368 : }
369 0 : yaml_parser_delete(&parser);
370 0 : return result;
371 : }
372 :
373 4 : cJSON * yaml_sting_2_cJSON ( __attribute__((unused))void * opaque , const char * yaml)
374 : {
375 4 : cJSON * result=NULL;
376 : yaml_parser_t parser;
377 : yaml_document_t document;
378 4 : yaml_parser_initialize(&parser);
379 4 : yaml_parser_set_input_string(&parser, (const unsigned char *) yaml, strlen(yaml));
380 :
381 4 : int done = 0;
382 16 : while (!done)
383 : {
384 8 : if (!yaml_parser_load(&parser, &document)) {
385 0 : debug( "Failed to load document \n");
386 : // todo feedback
387 0 : break;
388 : }
389 :
390 8 : done = (!yaml_document_get_root_node(&document));
391 :
392 8 : if (!done)
393 4 : yaml_document_2_cJSON(&document,&result,NULL);
394 :
395 8 : yaml_document_delete(&document);
396 : }
397 4 : yaml_parser_delete(&parser);
398 4 : return result;
399 : }
400 :
401 0 : cJSON * yaml_file_2_cJSON ( __attribute__((unused))void * opaque ,const char * fileName, ...)
402 : {
403 0 : char *filePath=CSPRINTF(fileName);
404 0 : if (!filePath)
405 : {
406 0 : debug("error getting filePath from vargs\n");
407 0 : return NULL;
408 : }
409 0 : FILE * file=fopen(filePath, "r");
410 0 : free(filePath); filePath=NULL;
411 0 : if (!file)
412 : {
413 0 : debug("error opening %s",filePath);
414 0 : return NULL;
415 : }
416 0 : cJSON * result=NULL;
417 : yaml_parser_t parser;
418 : yaml_document_t document;
419 0 : yaml_parser_initialize(&parser);
420 :
421 0 : yaml_parser_set_input_file(&parser,file);
422 0 : int done = 0;
423 0 : while (!done)
424 : {
425 0 : if (!yaml_parser_load(&parser, &document)) {
426 0 : debug( "Failed to load document \n");
427 : // todo feedback
428 0 : break;
429 : }
430 :
431 0 : done = (!yaml_document_get_root_node(&document));
432 :
433 0 : if (!done)
434 0 : yaml_document_2_cJSON(&document,&result, NULL);
435 :
436 0 : yaml_document_delete(&document);
437 : }
438 0 : yaml_parser_delete(&parser);
439 0 : if (file) fclose(file);
440 0 : return result;
441 : }
442 :
443 0 : cJSON * yaml_file_doc0_2_cJSON ( char ** errormsg ,const char * fileName, ...)
444 : {
445 0 : char *filePath=CSPRINTF(fileName);
446 0 : if (!filePath)
447 : {
448 0 : if (errormsg) asprintf(errormsg, "error getting filePath from vargs\n");
449 : return NULL;
450 : }
451 0 : FILE * file=fopen(filePath, "r");
452 0 : free(filePath); filePath=NULL;
453 0 : if (!file)
454 : {
455 0 : if (errormsg) asprintf(errormsg, "error opening %s",filePath);
456 : return NULL;
457 : }
458 0 : cJSON * result=NULL;
459 : yaml_parser_t parser;
460 : yaml_document_t document;
461 0 : yaml_parser_initialize(&parser);
462 :
463 0 : yaml_parser_set_input_file(&parser,file);
464 0 : int done = 0;
465 0 : while (!done)
466 : {
467 0 : if (!yaml_parser_load(&parser, &document)) {
468 0 : if (errormsg) asprintf(errormsg, "Failed to load document \n");
469 : // todo feedback
470 : break;
471 : }
472 :
473 0 : done = (!yaml_document_get_root_node(&document));
474 :
475 0 : if (!done)
476 0 : yaml_document_2_cJSON(&document,&result, NULL);
477 :
478 0 : yaml_document_delete(&document);
479 : }
480 0 : yaml_parser_delete(&parser);
481 0 : if (file) fclose(file);
482 0 : if (result && cJSON_IsArray(result) && cJSON_GetArraySize(result)>0)
483 : {
484 0 : cJSON * tmp=cJSON_DetachItemFromArray(result, 0);
485 0 : cJSON_Delete(result);
486 0 : result=tmp;
487 : }
488 0 : return result;
489 : }
490 :
491 :
492 0 : cJSON * yaml_file_2_cJSON_env ( __attribute__((unused))void * opaque ,cJSON * env_vars,const char * fileName, ...)
493 : {
494 0 : char *filePath=CSPRINTF(fileName);
495 0 : if (!filePath)
496 : {
497 0 : debug("error getting filePath from vargs\n");
498 0 : return NULL;
499 : }
500 0 : FILE * file=fopen(filePath, "r");
501 0 : free(filePath); filePath=NULL;
502 0 : if (!file)
503 : {
504 0 : debug("error opening %s",filePath);
505 0 : return NULL;
506 : }
507 0 : cJSON * result=NULL;
508 : yaml_parser_t parser;
509 : yaml_document_t document;
510 0 : yaml_parser_initialize(&parser);
511 :
512 0 : yaml_parser_set_input_file(&parser,file);
513 0 : int done = 0;
514 0 : while (!done)
515 : {
516 0 : if (!yaml_parser_load(&parser, &document)) {
517 0 : debug( "Failed to load document \n");
518 : // todo feedback
519 0 : break;
520 : }
521 :
522 0 : done = (!yaml_document_get_root_node(&document));
523 :
524 0 : if (!done)
525 0 : yaml_document_2_cJSON(&document,&result, env_vars);
526 :
527 0 : yaml_document_delete(&document);
528 : }
529 0 : yaml_parser_delete(&parser);
530 0 : if (file) fclose(file);
531 0 : return result;
532 : }
|