1 /*
2 *
3 ***** BEGIN LICENSE BLOCK *****
4
5 Copyright (C) 2009-2019 Olof Hagsand
6 Copyright (C) 2020 Olof Hagsand and Rubicon Communications, LLC(Netgate)
7
8 This file is part of CLIXON.
9
10 Licensed under the Apache License, Version 2.0 (the "License");
11 you may not use this file except in compliance with the License.
12 You may obtain a copy of the License at
13
14 http://www.apache.org/licenses/LICENSE-2.0
15
16 Unless required by applicable law or agreed to in writing, software
17 distributed under the License is distributed on an "AS IS" BASIS,
18 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 See the License for the specific language governing permissions and
20 limitations under the License.
21
22 Alternatively, the contents of this file may be used under the terms of
23 the GNU General Public License Version 3 or later (the "GPL"),
24 in which case the provisions of the GPL are applicable instead
25 of those above. If you wish to allow use of your version of this file only
26 under the terms of the GPL, and not to allow others to
27 use your version of this file under the terms of Apache License version 2,
28 indicate your decision by deleting the provisions above and replace them with
29 the notice and other provisions required by the GPL. If you do not delete
30 the provisions above, a recipient may use your version of this file under
31 the terms of any one of the Apache License version 2 or the GPL.
32
33 ***** END LICENSE BLOCK *****
34
35 * JSON support functions.
36 * JSON syntax is according to:
37 * http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf
38 * RFC 7951 JSON Encoding of Data Modeled with YANG
39 */
40
41 #ifdef HAVE_CONFIG_H
42 #include "clixon_config.h" /* generated by config & autoconf */
43 #endif
44
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <unistd.h>
48 #include <errno.h>
49 #include <string.h>
50 #include <ctype.h>
51 #include <limits.h>
52 #include <stdint.h>
53 #include <syslog.h>
54
55 /* cligen */
56 #include <cligen/cligen.h>
57
58 /* clixon */
59 #include "clixon_err.h"
60 #include "clixon_log.h"
61 #include "clixon_queue.h"
62 #include "clixon_string.h"
63 #include "clixon_hash.h"
64 #include "clixon_handle.h"
65 #include "clixon_options.h"
66 #include "clixon_yang.h"
67 #include "clixon_xml.h"
68 #include "clixon_yang_type.h"
69 #include "clixon_yang_module.h"
70 #include "clixon_xml_sort.h"
71 #include "clixon_xml_bind.h"
72 #include "clixon_xml_map.h"
73 #include "clixon_xml_nsctx.h" /* namespace context */
74 #include "clixon_netconf_lib.h"
75 #include "clixon_json.h"
76 #include "clixon_json_parse.h"
77
78 #define JSON_INDENT 2 /* maybe we should set this programmatically? */
79
80 /* Let xml2json_cbuf_vec() return json array: [a,b].
81 ALternative is to create a pseudo-object and return that: {top:{a,b}}
82 */
83 #define VEC_ARRAY 1
84
85 /* Size of json read buffer when reading from file*/
86 #define BUFLEN 1024
87
88 /* Name of xml top object created by xml parse functions */
89 #define JSON_TOP_SYMBOL "top"
90
91 enum array_element_type{
92 NO_ARRAY=0,
93 FIRST_ARRAY, /* [a, */
94 MIDDLE_ARRAY, /* a, */
95 LAST_ARRAY, /* a] */
96 SINGLE_ARRAY, /* [a] */
97 BODY_ARRAY
98 };
99
100 enum childtype{
101 NULL_CHILD=0, /* eg <a/> no children. Translated to null if in
102 * array or leaf terminal, and to {} if proper object, ie container.
103 * anyxml/anydata?
104 */
105 BODY_CHILD, /* eg one child which is a body, eg <a>1</a> */
106 ANY_CHILD, /* eg <a><b/></a> or <a><b/><c/></a> */
107 };
108
109 /*! x is element and has exactly one child which in turn has none
110 * remove attributes from x
111 * @see tleaf in clixon_xml_map.c
112 */
113 static enum childtype
child_type(cxobj * x)114 child_type(cxobj *x)
115 {
116 cxobj *xc; /* the only child of x */
117 int clen; /* nr of children */
118
119 clen = xml_child_nr_notype(x, CX_ATTR);
120 if (xml_type(x) != CX_ELMNT)
121 return -1; /* n/a */
122 if (clen == 0)
123 return NULL_CHILD;
124 if (clen > 1)
125 return ANY_CHILD;
126 /* From here exactly one noattr child, get it */
127 xc = NULL;
128 while ((xc = xml_child_each(x, xc, -1)) != NULL)
129 if (xml_type(xc) != CX_ATTR)
130 break;
131 if (xc == NULL)
132 return -2; /* n/a */
133 if (xml_child_nr_notype(xc, CX_ATTR) == 0 && xml_type(xc)==CX_BODY)
134 return BODY_CHILD;
135 else
136 return ANY_CHILD;
137 }
138
139 static char*
childtype2str(enum childtype lt)140 childtype2str(enum childtype lt)
141 {
142 switch(lt){
143 case NULL_CHILD:
144 return "null";
145 break;
146 case BODY_CHILD:
147 return "body";
148 break;
149 case ANY_CHILD:
150 return "any";
151 break;
152 }
153 return "";
154 }
155
156 static char*
arraytype2str(enum array_element_type lt)157 arraytype2str(enum array_element_type lt)
158 {
159 switch(lt){
160 case NO_ARRAY:
161 return "no";
162 break;
163 case FIRST_ARRAY:
164 return "first";
165 break;
166 case MIDDLE_ARRAY:
167 return "middle";
168 break;
169 case LAST_ARRAY:
170 return "last";
171 break;
172 case SINGLE_ARRAY:
173 return "single";
174 break;
175 case BODY_ARRAY:
176 return "body";
177 break;
178 }
179 return "";
180 }
181
182 /*! Check typeof x in array
183 * Some complexity when x is in different namespaces
184 */
185 static enum array_element_type
array_eval(cxobj * xprev,cxobj * x,cxobj * xnext)186 array_eval(cxobj *xprev,
187 cxobj *x,
188 cxobj *xnext)
189 {
190 enum array_element_type array = NO_ARRAY;
191 int eqprev=0;
192 int eqnext=0;
193 yang_stmt *ys;
194 char *nsx; /* namespace of x */
195 char *ns2;
196
197 nsx = xml_find_type_value(x, NULL, "xmlns", CX_ATTR);
198 if (xml_type(x) != CX_ELMNT){
199 array=BODY_ARRAY;
200 goto done;
201 }
202 ys = xml_spec(x);
203 if (xnext &&
204 xml_type(xnext)==CX_ELMNT &&
205 strcmp(xml_name(x), xml_name(xnext))==0){
206 ns2 = xml_find_type_value(xnext, NULL, "xmlns", CX_ATTR);
207 if ((!nsx && !ns2)
208 || (nsx && ns2 && strcmp(nsx,ns2)==0))
209 eqnext++;
210 }
211 if (xprev &&
212 xml_type(xprev)==CX_ELMNT &&
213 strcmp(xml_name(x),xml_name(xprev))==0){
214 ns2 = xml_find_type_value(xprev, NULL, "xmlns", CX_ATTR);
215 if ((!nsx && !ns2)
216 || (nsx && ns2 && strcmp(nsx,ns2)==0))
217 eqprev++;
218 }
219 if (eqprev && eqnext)
220 array = MIDDLE_ARRAY;
221 else if (eqprev)
222 array = LAST_ARRAY;
223 else if (eqnext)
224 array = FIRST_ARRAY;
225 else if (ys && yang_keyword_get(ys) == Y_LIST)
226 array = SINGLE_ARRAY;
227 else
228 array = NO_ARRAY;
229 done:
230 return array;
231 }
232
233 /*! Escape a json string as well as decode xml cdata
234 * @param[out] cb cbuf (encoded)
235 * @param[in] str string (unencoded)
236 */
237 static int
json_str_escape_cdata(cbuf * cb,char * str)238 json_str_escape_cdata(cbuf *cb,
239 char *str)
240 {
241 int retval = -1;
242 int i;
243 int esc = 0; /* cdata escape */
244
245 for (i=0;i<strlen(str);i++)
246 switch (str[i]){
247 case '\n':
248 cprintf(cb, "\\n");
249 break;
250 case '\"':
251 cprintf(cb, "\\\"");
252 break;
253 case '\\':
254 cprintf(cb, "\\\\");
255 break;
256 case '<':
257 if (!esc &&
258 strncmp(&str[i], "<![CDATA[", strlen("<![CDATA[")) == 0){
259 esc=1;
260 i += strlen("<![CDATA[")-1;
261 }
262 else
263 cprintf(cb, "%c", str[i]);
264 break;
265 case ']':
266 if (esc &&
267 strncmp(&str[i], "]]>", strlen("]]>")) == 0){
268 esc=0;
269 i += strlen("]]>")-1;
270 }
271 else
272 cprintf(cb, "%c", str[i]);
273 break;
274 default: /* fall thru */
275 cprintf(cb, "%c", str[i]);
276 break;
277 }
278 retval = 0;
279 // done:
280 return retval;
281 }
282
283 /*! Decode types from JSON to XML identityrefs
284 * Assume an xml tree where prefix:name have been split into "module":"name"
285 * In other words, from JSON RFC7951 to XML namespace trees
286 * @param[in] x XML tree. Must be yang populated.
287 * @param[in] yspec Yang spec
288 * @param[out] xerr Reason for invalid tree returned as netconf err msg or NULL
289 * @retval 1 OK
290 * @retval 0 Invalid, wrt namespace. xerr set
291 * @retval -1 Error
292 * @see RFC7951 Sec 4 and 6.8
293 */
294 static int
json2xml_decode_identityref(cxobj * x,yang_stmt * y,cxobj ** xerr)295 json2xml_decode_identityref(cxobj *x,
296 yang_stmt *y,
297 cxobj **xerr)
298 {
299 int retval = -1;
300 char *ns;
301 char *body;
302 cxobj *xb;
303 cxobj *xa;
304 char *prefix = NULL;
305 char *id = NULL;
306 yang_stmt *ymod;
307 yang_stmt *yspec;
308 cvec *nsc = NULL;
309 char *prefix2 = NULL;
310 cbuf *cbv = NULL;
311
312 clicon_debug(1, "%s", __FUNCTION__);
313 yspec = ys_spec(y);
314 if ((xb = xml_body_get(x)) == NULL)
315 goto ok;
316 body = xml_value(xb);
317 if (nodeid_split(body, &prefix, &id) < 0)
318 goto done;
319 /* prefix is a module name -> find module */
320 if (prefix){
321 if ((ymod = yang_find_module_by_name(yspec, prefix)) != NULL){
322 ns = yang_find_mynamespace(ymod);
323 /* Is this namespace in the xml context?
324 * (yes) use its prefix (unless it is NULL)
325 * (no) insert a xmlns:<prefix> statement
326 * Get the whole namespace context from x
327 */
328 if (xml_nsctx_node(x, &nsc) < 0)
329 goto done;
330 clicon_debug(1, "%s prefix:%s body:%s namespace:%s",
331 __FUNCTION__, prefix, body, ns);
332 if (!xml_nsctx_get_prefix(nsc, ns, &prefix2)){
333 /* (no) insert a xmlns:<prefix> statement
334 * Get yang prefix from import statement of my mod */
335 if (yang_find_prefix_by_namespace(y, ns, &prefix2) == 0){
336 #ifndef IDENTITYREF_KLUDGE
337 /* Just get the prefix from the module's own namespace */
338 if (xerr && netconf_unknown_namespace_xml(xerr, "application",
339 ns,
340 "No local prefix corresponding to namespace") < 0)
341 goto done;
342 goto fail;
343 #endif
344 }
345 /* if prefix2 is NULL here, we get the canonical prefix */
346 if (prefix2 == NULL)
347 prefix2 = yang_find_myprefix(ymod);
348 /* Add "xmlns:prefix2=namespace" */
349 if ((xa = xml_new(prefix2, x, CX_ATTR)) == NULL)
350 goto done;
351 if (xml_prefix_set(xa, "xmlns") < 0)
352 goto done;
353 if (xml_value_set(xa, ns) < 0)
354 goto done;
355 }
356 /* Here prefix2 is valid and can be NULL
357 Change body prefix to prefix2:id */
358 if ((cbv = cbuf_new()) == NULL){
359 clicon_err(OE_XML, errno, "cbuf_new");
360 goto done;
361 }
362 if (prefix2)
363 cprintf(cbv, "%s:%s", prefix2, id);
364 else
365 cprintf(cbv, "%s", id);
366
367 if (xml_value_set(xb, cbuf_get(cbv)) < 0)
368 goto done;
369 }
370 else{
371 if (xerr && netconf_unknown_namespace_xml(xerr, "application",
372 prefix,
373 "No module corresponding to prefix") < 0)
374 goto done;
375 goto fail;
376 }
377 } /* prefix */
378 ok:
379 retval = 1;
380 done:
381 if (prefix)
382 free(prefix);
383 if (id)
384 free(id);
385 if (nsc)
386 xml_nsctx_free(nsc);
387 if (cbv)
388 cbuf_free(cbv);
389 return retval;
390 fail:
391 retval = 0;
392 goto done;
393 }
394
395 /*! Decode leaf/leaf_list types from JSON to XML after parsing and yang
396 *
397 * Assume an xml tree where prefix:name have been split into "module":"name"
398 * In other words, from JSON RFC7951 to XML namespace trees
399 *
400 * @param[in] x XML tree. Must be yang populated. After json parsing
401 * @param[in] yspec Yang spec
402 * @param[out] xerr Reason for invalid tree returned as netconf err msg or NULL
403 * @retval 1 OK
404 * @retval 0 Invalid, wrt namespace. xerr set
405 * @retval -1 Error
406 * @see RFC7951 Sec 4 and 6.8
407 */
408 int
json2xml_decode(cxobj * x,cxobj ** xerr)409 json2xml_decode(cxobj *x,
410 cxobj **xerr)
411 {
412 int retval = -1;
413 yang_stmt *y;
414 enum rfc_6020 keyword;
415 cxobj *xc;
416 int ret;
417 yang_stmt *ytype;
418
419 if ((y = xml_spec(x)) != NULL){
420 keyword = yang_keyword_get(y);
421 if (keyword == Y_LEAF || keyword == Y_LEAF_LIST){
422 if (yang_type_get(y, NULL, &ytype, NULL, NULL, NULL, NULL, NULL) < 0)
423 goto done;
424
425 if (ytype){
426 if (strcmp(yang_argument_get(ytype), "identityref")==0){
427 if ((ret = json2xml_decode_identityref(x, y, xerr)) < 0)
428 goto done;
429 if (ret == 0)
430 goto fail;
431 }
432 else if (strcmp(yang_argument_get(ytype), "empty")==0)
433 ; /* dont need to do anything */
434 }
435 }
436 }
437 xc = NULL;
438 while ((xc = xml_child_each(x, xc, CX_ELMNT)) != NULL){
439 if ((ret = json2xml_decode(xc, xerr)) < 0)
440 goto done;
441 if (ret == 0)
442 goto fail;
443 }
444 retval = 1;
445 done:
446 return retval;
447 fail:
448 retval = 0;
449 goto done;
450 }
451
452 /*! Encode leaf/leaf_list identityref type from XML to JSON
453 * @param[in] x XML body node
454 * @param[in] body body string
455 * @param[in] ys Yang spec of parent
456 * @param[out] cb Encoded string
457 */
458 static int
xml2json_encode_identityref(cxobj * xb,char * body,yang_stmt * yp,cbuf * cb)459 xml2json_encode_identityref(cxobj *xb,
460 char *body,
461 yang_stmt *yp,
462 cbuf *cb)
463 {
464 int retval = -1;
465 char *prefix = NULL;
466 char *id = NULL;
467 char *namespace = NULL;
468 yang_stmt *ymod;
469 yang_stmt *yspec;
470 yang_stmt *my_ymod;
471
472 clicon_debug(1, "%s %s", __FUNCTION__, body);
473 my_ymod = ys_module(yp);
474 yspec = ys_spec(yp);
475 if (nodeid_split(body, &prefix, &id) < 0)
476 goto done;
477 /* prefix is xml local -> get namespace */
478 if (xml2ns(xb, prefix, &namespace) < 0)
479 goto done;
480 /* We got the namespace, now get the module */
481 // clicon_debug(1, "%s body:%s prefix:%s namespace:%s", __FUNCTION__, body, prefix, namespace);
482 #ifdef IDENTITYREF_KLUDGE
483 if (namespace == NULL){
484 /* If we dont find namespace here, we assume it is because of a missing
485 * xmlns that should be there, as a kludge we search for its (own)
486 * prefix in mymodule.
487 */
488 if ((ymod = yang_find_module_by_prefix_yspec(yspec, prefix)) != NULL)
489 cprintf(cb, "%s:%s", yang_argument_get(ymod), id);
490 else
491 cprintf(cb, "%s", id);
492 }
493 else
494 #endif
495 {
496 if ((ymod = yang_find_module_by_namespace(yspec, namespace)) != NULL){
497
498 if (ymod == my_ymod)
499 cprintf(cb, "%s", id);
500 else{
501 cprintf(cb, "%s:%s", yang_argument_get(ymod), id);
502 }
503 }
504 else
505 cprintf(cb, "%s", id);
506 }
507 retval = 0;
508 done:
509 if (prefix)
510 free(prefix);
511 if (id)
512 free(id);
513 return retval;
514 }
515
516 /*! Encode leaf/leaf_list types from XML to JSON
517 * @param[in] x XML body
518 * @param[in] ys Yang spec of parent
519 * @param[out] cb0 Encoded string
520 */
521 static int
xml2json_encode_leafs(cxobj * xb,cxobj * xp,yang_stmt * yp,cbuf * cb0)522 xml2json_encode_leafs(cxobj *xb,
523 cxobj *xp,
524 yang_stmt *yp,
525 cbuf *cb0)
526 {
527 int retval = -1;
528 enum rfc_6020 keyword;
529 yang_stmt *ytype;
530 char *restype; /* resolved type */
531 char *origtype=NULL; /* original type */
532 char *body;
533 enum cv_type cvtype;
534 int quote = 1; /* Quote value w string: "val" */
535 cbuf *cb = NULL; /* the variable itself */
536
537 if ((cb = cbuf_new()) ==NULL){
538 clicon_err(OE_XML, errno, "cbuf_new");
539 goto done;
540 }
541 body = xb?xml_value(xb):NULL;
542 if (yp == NULL){
543 cprintf(cb, "%s", body?body:"null");
544 goto ok; /* unknown */
545 }
546 keyword = yang_keyword_get(yp);
547 switch (keyword){
548 case Y_LEAF:
549 case Y_LEAF_LIST:
550 if (yang_type_get(yp, &origtype, &ytype, NULL, NULL, NULL, NULL, NULL) < 0)
551 goto done;
552 restype = ytype?yang_argument_get(ytype):NULL;
553 cvtype = yang_type2cv(yp);
554 switch (cvtype){
555 case CGV_STRING:
556 case CGV_REST:
557 if (body==NULL)
558 ; /* empty: "" */
559 else if (ytype){
560 if (strcmp(restype, "identityref")==0){
561 if (xml2json_encode_identityref(xb, body, yp, cb) < 0)
562 goto done;
563 }
564 else
565 cprintf(cb, "%s", body);
566 }
567 else
568 cprintf(cb, "%s", body);
569 break;
570 case CGV_INT8:
571 case CGV_INT16:
572 case CGV_INT32:
573 case CGV_INT64:
574 case CGV_UINT8:
575 case CGV_UINT16:
576 case CGV_UINT32:
577 case CGV_UINT64:
578 case CGV_DEC64:
579 case CGV_BOOL:
580 cprintf(cb, "%s", body);
581 quote = 0;
582 break;
583 case CGV_VOID:
584 /* special case YANG empty type */
585 if (body == NULL && strcmp(restype, "empty")==0){
586 quote = 0;
587 cprintf(cb, "[null]");
588 }
589 break;
590 default:
591 if (body)
592 cprintf(cb, "%s", body);
593 else
594 cprintf(cb, "{}"); /* dont know */
595 }
596 break;
597 default:
598 cprintf(cb, "%s", body);
599 break;
600 }
601 ok:
602 /* write into original cb0
603 * includign quoting and encoding
604 */
605 if (quote){
606 cprintf(cb0, "\"");
607 json_str_escape_cdata(cb0, cbuf_get(cb));
608 }
609 else
610 cprintf(cb0, "%s", cbuf_get(cb));
611 if (quote)
612 cprintf(cb0, "\"");
613 retval = 0;
614 done:
615 if (cb)
616 cbuf_free(cb);
617 if (origtype)
618 free(origtype);
619 return retval;
620 }
621
622 /* X has no XML child - no body.
623 * If x is a container, use {} instead of null
624 * if leaf or leaf-list then assume EMPTY type, then [null]
625 * else null
626 */
627 static int
nullchild(cbuf * cb,cxobj * x,yang_stmt * y)628 nullchild(cbuf *cb,
629 cxobj *x,
630 yang_stmt *y)
631 {
632 int retval = -1;
633
634 if (y == NULL){
635 /* This is very problematic.
636 * RFC 7951 explicitly forbids "null" to be used unless for empty types in [null]
637 */
638 cprintf(cb, "{}");
639 }
640 else{
641 switch (yang_keyword_get(y)){
642 case Y_ANYXML:
643 case Y_ANYDATA:
644 case Y_CONTAINER:
645 cprintf(cb, "{}");
646 break;
647 case Y_LEAF:
648 case Y_LEAF_LIST:
649 if (xml2json_encode_leafs(NULL, x, y, cb) < 0)
650 goto done;
651 break;
652 default:
653 /* This is very problematic.
654 * RFC 7951 explicitly forbids "null" to be used unless for empty types in [null]
655 */
656 cprintf(cb, "{}");
657 break;
658 }
659 }
660 retval = 0;
661 done:
662 return retval;
663 }
664
665 /*! Do the actual work of translating XML to JSON
666 * @param[out] cb Cligen text buffer containing json on exit
667 * @param[in] x XML tree structure containing XML to translate
668 * @param[in] yp Parent yang spec needed for body
669 * @param[in] arraytype Does x occur in a array (of its parent) and how?
670 * @param[in] level Indentation level
671 * @param[in] pretty Pretty-print output (2 means debug)
672 * @param[in] flat Dont print NO_ARRAY object name (for _vec call)
673 * @param[in] bodystr Set if value is string, 0 otherwise. Only if body
674 *
675 * @note Does not work with XML attributes
676 * The following matrix explains how the mapping is done.
677 * You need to understand what arraytype means (no/first/middle/last)
678 * and what childtype is (null,body,any)
679 +----------+--------------+--------------+--------------+
680 |array,leaf| null | body | any |
681 +----------+--------------+--------------+--------------+
682 |no | <a/> |<a>1</a> |<a><b/></a> |
683 | | | | |
684 | json: |\ta:null |\ta: |\ta:{\n |
685 | | | |\n} |
686 +----------+--------------+--------------+--------------+
687 |first |<a/><a.. |<a>1</a><a.. |<a><b/></a><a.|
688 | | | | |
689 | json: |\ta:[\n\tnull |\ta:[\n\t |\ta:[\n\t{\n |
690 | | | |\n\t} |
691 +----------+--------------+--------------+--------------+
692 |middle |..a><a/><a.. |.a><a>1</a><a.| |
693 | | | | |
694 | json: |\tnull |\t |\t{a |
695 | | | |\n\t} |
696 +----------+--------------+--------------+--------------+
697 |last |..a></a> |..a><a>1</a> | |
698 | | | | |
699 | json: |\tnull |\t |\t{a |
700 | |\n\t] |\n\t] |\n\t}\t] |
701 +----------+--------------+--------------+--------------+
702 */
703 static int
xml2json1_cbuf(cbuf * cb,cxobj * x,enum array_element_type arraytype,int level,int pretty,int flat,char * modname0)704 xml2json1_cbuf(cbuf *cb,
705 cxobj *x,
706 enum array_element_type arraytype,
707 int level,
708 int pretty,
709 int flat,
710 char *modname0)
711 {
712 int retval = -1;
713 int i;
714 cxobj *xc;
715 cxobj *xp;
716 enum childtype childt;
717 enum array_element_type xc_arraytype;
718 yang_stmt *ys;
719 yang_stmt *ymod = NULL; /* yang module */
720 int commas;
721 char *modname = NULL;
722
723 if ((ys = xml_spec(x)) != NULL){
724 if (ys_real_module(ys, &ymod) < 0)
725 goto done;
726 modname = yang_argument_get(ymod);
727 if (modname0 && strcmp(modname, modname0) == 0)
728 modname=NULL;
729 else
730 modname0 = modname; /* modname0 is ancestor ns passed to child */
731 }
732 childt = child_type(x);
733 if (pretty==2)
734 cprintf(cb, "#%s_array, %s_child ",
735 arraytype2str(arraytype),
736 childtype2str(childt));
737 switch(arraytype){
738 case BODY_ARRAY: /* Only place in fn where body is printed (except nullchild) */
739 xp = xml_parent(x);
740 if (xml2json_encode_leafs(x, xp, xml_spec(xp), cb) < 0)
741 goto done;
742 break;
743 case NO_ARRAY:
744 if (!flat){
745 cprintf(cb, "%*s\"", pretty?(level*JSON_INDENT):0, "");
746 if (modname)
747 cprintf(cb, "%s:", modname);
748 cprintf(cb, "%s\":%s", xml_name(x), pretty?" ":"");
749 }
750 switch (childt){
751 case NULL_CHILD:
752 if (nullchild(cb, x, ys) < 0)
753 goto done;
754 break;
755 case BODY_CHILD:
756 break;
757 case ANY_CHILD:
758 cprintf(cb, "{%s", pretty?"\n":"");
759 break;
760 default:
761 break;
762 }
763 break;
764 case FIRST_ARRAY:
765 case SINGLE_ARRAY:
766 cprintf(cb, "%*s\"", pretty?(level*JSON_INDENT):0, "");
767 if (modname)
768 cprintf(cb, "%s:", modname);
769 cprintf(cb, "%s\":%s", xml_name(x), pretty?" ":"");
770 level++;
771 cprintf(cb, "[%s%*s",
772 pretty?"\n":"",
773 pretty?(level*JSON_INDENT):0, "");
774 switch (childt){
775 case NULL_CHILD:
776 if (nullchild(cb, x, ys) < 0)
777 goto done;
778 break;
779 case BODY_CHILD:
780 break;
781 case ANY_CHILD:
782 cprintf(cb, "{%s", pretty?"\n":"");
783 break;
784 default:
785 break;
786 }
787 break;
788 case MIDDLE_ARRAY:
789 case LAST_ARRAY:
790 level++;
791 cprintf(cb, "%*s",
792 pretty?(level*JSON_INDENT):0, "");
793 switch (childt){
794 case NULL_CHILD:
795 if (nullchild(cb, x, ys) < 0)
796 goto done;
797 break;
798 case BODY_CHILD:
799 break;
800 case ANY_CHILD:
801 cprintf(cb, "{%s", pretty?"\n":"");
802 break;
803 default:
804 break;
805 }
806 break;
807 default:
808 break;
809 }
810 /* Check for typed sub-body if:
811 * arraytype=* but child-type is BODY_CHILD
812 * This is code for writing <a>42</a> as "a":42 and not "a":"42"
813 */
814 commas = xml_child_nr_notype(x, CX_ATTR) - 1;
815 for (i=0; i<xml_child_nr(x); i++){
816 xc = xml_child_i(x, i);
817 if (xml_type(xc) == CX_ATTR)
818 continue; /* XXX Only xmlns attributes mapped */
819
820 xc_arraytype = array_eval(i?xml_child_i(x,i-1):NULL,
821 xc,
822 xml_child_i(x, i+1));
823 if (xml2json1_cbuf(cb,
824 xc,
825 xc_arraytype,
826 level+1, pretty, 0, modname0) < 0)
827 goto done;
828 if (commas > 0) {
829 cprintf(cb, ",%s", pretty?"\n":"");
830 --commas;
831 }
832 }
833 switch (arraytype){
834 case BODY_ARRAY:
835 break;
836 case NO_ARRAY:
837 switch (childt){
838 case NULL_CHILD:
839 case BODY_CHILD:
840 break;
841 case ANY_CHILD:
842 cprintf(cb, "%s%*s}",
843 pretty?"\n":"",
844 pretty?(level*JSON_INDENT):0, "");
845 break;
846 default:
847 break;
848 }
849 level--;
850 break;
851 case FIRST_ARRAY:
852 case MIDDLE_ARRAY:
853 switch (childt){
854 case NULL_CHILD:
855 case BODY_CHILD:
856 break;
857 case ANY_CHILD:
858 cprintf(cb, "%s%*s}",
859 pretty?"\n":"",
860 pretty?(level*JSON_INDENT):0, "");
861 level--;
862 break;
863 default:
864 break;
865 }
866 break;
867 case SINGLE_ARRAY:
868 case LAST_ARRAY:
869 switch (childt){
870 case NULL_CHILD:
871 case BODY_CHILD:
872 cprintf(cb, "%s",pretty?"\n":"");
873 break;
874 case ANY_CHILD:
875 cprintf(cb, "%s%*s}",
876 pretty?"\n":"",
877 pretty?(level*JSON_INDENT):0, "");
878 cprintf(cb, "%s",pretty?"\n":"");
879 level--;
880 break;
881 default:
882 break;
883 }
884 cprintf(cb, "%*s]",
885 pretty?(level*JSON_INDENT):0,"");
886 break;
887 default:
888 break;
889 }
890 retval = 0;
891 done:
892 return retval;
893 }
894
895 /*! Translate an XML tree to JSON in a CLIgen buffer
896 *
897 * XML-style namespace notation in tree, but RFC7951 in output assume yang
898 * populated
899 *
900 * @param[in,out] cb Cligen buffer to write to
901 * @param[in] x XML tree to translate from
902 * @param[in] pretty Set if output is pretty-printed
903 * @param[in] top By default only children are printed, set if include top
904 * @retval 0 OK
905 * @retval -1 Error
906 *
907 * @code
908 * cbuf *cb;
909 * cb = cbuf_new();
910 * if (xml2json_cbuf(cb, xn, 0, 1) < 0)
911 * goto err;
912 * cbuf_free(cb);
913 * @endcode
914 * @see clicon_xml2cbuf
915 */
916 int
xml2json_cbuf(cbuf * cb,cxobj * x,int pretty)917 xml2json_cbuf(cbuf *cb,
918 cxobj *x,
919 int pretty)
920 {
921 int retval = 1;
922 int level = 0;
923
924 cprintf(cb, "%*s{%s",
925 pretty?level*JSON_INDENT:0,"",
926 pretty?"\n":"");
927 if (xml2json1_cbuf(cb,
928 x,
929 NO_ARRAY,
930 level+1,
931 pretty,
932 0,
933 NULL /* ancestor modname / namespace */
934 ) < 0)
935 goto done;
936 cprintf(cb, "%s%*s}%s",
937 pretty?"\n":"",
938 pretty?level*JSON_INDENT:0,"",
939 pretty?"\n":"");
940
941 retval = 0;
942 done:
943 return retval;
944 }
945
946 /*! Translate a vector of xml objects to JSON Cligen buffer.
947 * This is done by adding a top pseudo-object, and add the vector as subs,
948 * and then not printing the top pseudo-object using the 'flat' option.
949 * @param[out] cb Cligen buffer to write to
950 * @param[in] vec Vector of xml objecst
951 * @param[in] veclen Length of vector
952 * @param[in] pretty Set if output is pretty-printed (2 for debug)
953 * @retval 0 OK
954 * @retval -1 Error
955 * @note This only works if the vector is uniform, ie same object name.
956 * Example: <b/><c/> --> <a><b/><c/></a> --> {"b" : null,"c" : null}
957 * @see xml2json1_cbuf
958 */
959 int
xml2json_cbuf_vec(cbuf * cb,cxobj ** vec,size_t veclen,int pretty)960 xml2json_cbuf_vec(cbuf *cb,
961 cxobj **vec,
962 size_t veclen,
963 int pretty)
964 {
965 int retval = -1;
966 int level = 0;
967 cxobj *xp = NULL;
968 int i;
969 cxobj *xc;
970 cvec *nsc = NULL;
971
972 if ((xp = xml_new("xml2json", NULL, CX_ELMNT)) == NULL)
973 goto done;
974 /* Make a copy of old and graft it into new top-object
975 * Also copy namespace context */
976 for (i=0; i<veclen; i++){
977 if (xml_nsctx_node(vec[i], &nsc) < 0)
978 goto done;
979 if ((xc = xml_dup(vec[i])) == NULL)
980 goto done;
981 xml_addsub(xp, xc);
982 nscache_replace(xc, nsc);
983 nsc = NULL; /* nsc consumed */
984 }
985 if (0){
986 cprintf(cb, "[%s", pretty?"\n":" ");
987 level++;
988 }
989 if (xml2json1_cbuf(cb,
990 xp,
991 NO_ARRAY,
992 level+1, pretty,
993 1, NULL) < 0)
994 goto done;
995
996 if (0){
997 level--;
998 cprintf(cb, "%s]%s",
999 pretty?"\n":"",
1000 pretty?"\n":""); /* top object */
1001 }
1002 retval = 0;
1003 done:
1004 if (nsc)
1005 xml_nsctx_free(nsc);
1006 if (xp)
1007 xml_free(xp);
1008 return retval;
1009 }
1010
1011 /*! Translate from xml tree to JSON and print to file using a callback
1012 * @param[in] f File to print to
1013 * @param[in] x XML tree to translate from
1014 * @param[in] pretty Set if output is pretty-printed
1015 * @retval 0 OK
1016 * @retval -1 Error
1017 *
1018 * @note yang is necessary to translate to one-member lists,
1019 * eg if a is a yang LIST <a>0</a> -> {"a":["0"]} and not {"a":"0"}
1020 * @code
1021 * if (xml2json(stderr, xn, 0) < 0)
1022 * goto err;
1023 * @endcode
1024 */
1025 int
xml2json_cb(FILE * f,cxobj * x,int pretty,clicon_output_cb * fn)1026 xml2json_cb(FILE *f,
1027 cxobj *x,
1028 int pretty,
1029 clicon_output_cb *fn)
1030 {
1031 int retval = 1;
1032 cbuf *cb = NULL;
1033
1034 if ((cb = cbuf_new()) ==NULL){
1035 clicon_err(OE_XML, errno, "cbuf_new");
1036 goto done;
1037 }
1038 if (xml2json_cbuf(cb, x, pretty) < 0)
1039 goto done;
1040 (*fn)(f, "%s", cbuf_get(cb));
1041 retval = 0;
1042 done:
1043 if (cb)
1044 cbuf_free(cb);
1045 return retval;
1046 }
1047
1048 /*! Translate from xml tree to JSON and print to file
1049 * @param[in] f File to print to
1050 * @param[in] x XML tree to translate from
1051 * @param[in] pretty Set if output is pretty-printed
1052 * @retval 0 OK
1053 * @retval -1 Error
1054 *
1055 * @note yang is necessary to translate to one-member lists,
1056 * eg if a is a yang LIST <a>0</a> -> {"a":["0"]} and not {"a":"0"}
1057 * @code
1058 * if (xml2json(stderr, xn, 0) < 0)
1059 * goto err;
1060 * @endcode
1061 */
1062 int
xml2json(FILE * f,cxobj * x,int pretty)1063 xml2json(FILE *f,
1064 cxobj *x,
1065 int pretty)
1066 {
1067 return xml2json_cb(f, x, pretty, fprintf);
1068 }
1069
1070
1071 /*! Print an XML tree structure to an output stream as JSON
1072 *
1073 * @param[in] f UNIX output stream
1074 * @param[in] xn clicon xml tree
1075 */
1076 int
json_print(FILE * f,cxobj * x)1077 json_print(FILE *f,
1078 cxobj *x)
1079 {
1080 return xml2json_cb(f, x, 1, fprintf);
1081 }
1082
1083 /*! Translate a vector of xml objects to JSON File.
1084 * This is done by adding a top pseudo-object, and add the vector as subs,
1085 * and then not pritning the top pseudo-.object using the 'flat' option.
1086 * @param[out] cb Cligen buffer to write to
1087 * @param[in] vec Vector of xml objecst
1088 * @param[in] veclen Length of vector
1089 * @param[in] pretty Set if output is pretty-printed (2 for debug)
1090 * @retval 0 OK
1091 * @retval -1 Error
1092 * @note This only works if the vector is uniform, ie same object name.
1093 * Example: <b/><c/> --> <a><b/><c/></a> --> {"b" : null,"c" : null}
1094 * @see xml2json1_cbuf
1095 */
1096 int
xml2json_vec(FILE * f,cxobj ** vec,size_t veclen,int pretty)1097 xml2json_vec(FILE *f,
1098 cxobj **vec,
1099 size_t veclen,
1100 int pretty)
1101 {
1102 int retval = 1;
1103 cbuf *cb = NULL;
1104
1105 if ((cb = cbuf_new()) == NULL){
1106 clicon_err(OE_XML, errno, "cbuf_new");
1107 goto done;
1108 }
1109 if (xml2json_cbuf_vec(cb, vec, veclen, pretty) < 0)
1110 goto done;
1111 fprintf(f, "%s", cbuf_get(cb));
1112 retval = 0;
1113 done:
1114 if (cb)
1115 cbuf_free(cb);
1116 return retval;
1117 }
1118
1119 /*! Translate from JSON module:name to XML default ns: xmlns="uri" recursively
1120 * Assume an xml tree where prefix:name have been split into "module":"name"
1121 * In other words, from JSON to XML namespace trees
1122 *
1123 * @param[in] yspec Yang spec
1124 * @param[in,out] x XML tree. Translate it in-line
1125 * @param[out] xerr Reason for invalid tree returned as netconf err msg or NULL
1126 * @retval 1 OK
1127 * @retval 0 Invalid, wrt namespace. xerr set
1128 * @retval -1 Error
1129 * @note the opposite - xml2ns is made inline in xml2json1_cbuf
1130 * Example: <top><module:input> --> <top><input xmlns="">
1131 * @see RFC7951 Sec 4
1132 */
1133 static int
json_xmlns_translate(yang_stmt * yspec,cxobj * x,cxobj ** xerr)1134 json_xmlns_translate(yang_stmt *yspec,
1135 cxobj *x,
1136 cxobj **xerr)
1137 {
1138 int retval = -1;
1139 yang_stmt *ymod;
1140 char *namespace;
1141 char *modname = NULL;
1142 cxobj *xc;
1143 int ret;
1144
1145 if ((modname = xml_prefix(x)) != NULL){ /* prefix is here module name */
1146 if ((ymod = yang_find_module_by_name(yspec, modname)) == NULL){
1147 if (xerr &&
1148 netconf_unknown_namespace_xml(xerr, "application",
1149 modname,
1150 "No yang module found corresponding to prefix") < 0)
1151 goto done;
1152 goto fail;
1153 }
1154 namespace = yang_find_mynamespace(ymod);
1155 /* It would be possible to use canonical prefixes here, but probably not
1156 * necessary or even right. Therefore, the namespace given by the JSON prefix / module
1157 * is always the default namespace with prefix NULL.
1158 * If not, this would be the prefix to pass instead of NULL
1159 * prefix = yang_find_myprefix(ymod);
1160 */
1161 if (xml_namespace_change(x, namespace, NULL) < 0)
1162 goto done;
1163 }
1164 xc = NULL;
1165 while ((xc = xml_child_each(x, xc, CX_ELMNT)) != NULL){
1166 if ((ret = json_xmlns_translate(yspec, xc, xerr)) < 0)
1167 goto done;
1168 if (ret == 0)
1169 goto fail;
1170 }
1171 retval = 1;
1172 done:
1173 return retval;
1174 fail:
1175 retval = 0;
1176 goto done;
1177 }
1178
1179 /*! Parse a string containing JSON and return an XML tree
1180 *
1181 * Parsing using yacc according to JSON syntax. Names with <prefix>:<id>
1182 * are split and interpreted as in RFC7951
1183 *
1184 * @param[in] str Input string containing JSON
1185 * @param[in] yb How to bind yang to XML top-level when parsing
1186 * @param[in] yspec If set, also do yang validation
1187 * @param[out] xt XML top of tree typically w/o children on entry (but created)
1188 * @param[out] xerr Reason for invalid returned as netconf err msg
1189 *
1190 * @see _xml_parse for XML variant
1191 * @retval 1 OK and valid
1192 * @retval 0 Invalid (only if yang spec)
1193 * @retval -1 Error with clicon_err called
1194 * @see http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf
1195 * @see RFC 7951
1196 */
1197 static int
_json_parse(char * str,yang_bind yb,yang_stmt * yspec,cxobj * xt,cxobj ** xerr)1198 _json_parse(char *str,
1199 yang_bind yb,
1200 yang_stmt *yspec,
1201 cxobj *xt,
1202 cxobj **xerr)
1203 {
1204 int retval = -1;
1205 clixon_json_yacc jy = {0,};
1206 int ret;
1207 cxobj *x;
1208 cbuf *cberr = NULL;
1209 int i;
1210 int failed = 0; /* yang assignment */
1211
1212 clicon_debug(1, "%s %d %s", __FUNCTION__, yb, str);
1213 jy.jy_parse_string = str;
1214 jy.jy_linenum = 1;
1215 jy.jy_current = xt;
1216 jy.jy_xtop = xt;
1217 if (json_scan_init(&jy) < 0)
1218 goto done;
1219 if (json_parse_init(&jy) < 0)
1220 goto done;
1221 if (clixon_json_parseparse(&jy) != 0) { /* yacc returns 1 on error */
1222 clicon_log(LOG_NOTICE, "JSON error: line %d", jy.jy_linenum);
1223 if (clicon_errno == 0)
1224 clicon_err(OE_XML, 0, "JSON parser error with no error code (should not happen)");
1225 goto done;
1226 }
1227 /* Traverse new objects */
1228 for (i = 0; i < jy.jy_xlen; i++) {
1229 x = jy.jy_xvec[i];
1230 /* RFC 7951 Section 4: A namespace-qualified member name MUST be used for all
1231 * members of a top-level JSON object
1232 */
1233 if (yspec && xml_prefix(x) == NULL
1234 #ifdef XMLDB_CONFIG_HACK
1235 && strcmp(xml_name(x), "config") != 0
1236 #endif
1237 ){
1238 if ((cberr = cbuf_new()) == NULL){
1239 clicon_err(OE_UNIX, errno, "cbuf_new");
1240 goto done;
1241 }
1242 cprintf(cberr, "Top-level JSON object %s is not qualified with namespace which is a MUST according to RFC 7951", xml_name(x));
1243 if (netconf_malformed_message_xml(xerr, cbuf_get(cberr)) < 0)
1244 goto done;
1245 goto fail;
1246 }
1247 /* Names are split into name/prefix, but now add namespace info */
1248 if ((ret = json_xmlns_translate(yspec, x, xerr)) < 0)
1249 goto done;
1250 if (ret == 0)
1251 goto fail;
1252 /* Now assign yang stmts to each XML node
1253 * XXX should be xml_bind_yang0_parent() sometimes.
1254 */
1255 switch (yb){
1256 case YB_PARENT:
1257 if ((ret = xml_bind_yang0(x, yb, yspec, xerr)) < 0)
1258 goto done;
1259 if (ret == 0)
1260 failed++;
1261 break;
1262 case YB_MODULE:
1263 #ifdef XMLDB_CONFIG_HACK
1264 if (strcmp(xml_name(x),"config") == 0 ||
1265 strcmp(xml_name(x),"data") == 0){
1266 /* xt:<top> nospec
1267 * x: <config>
1268 * <a> <-- populate from modules
1269 */
1270 if ((ret = xml_bind_yang(x, yb, yspec, xerr)) < 0)
1271 goto done;
1272 }
1273 else
1274 #endif
1275 if ((ret = xml_bind_yang0(x, yb, yspec, xerr)) < 0)
1276 goto done;
1277 if (ret == 0)
1278 failed++;
1279 break;
1280 case YB_NONE:
1281 break;
1282 case YB_RPC:
1283 if ((ret = xml_bind_yang_rpc(x, yspec, xerr)) < 0)
1284 goto done;
1285 if (ret == 0)
1286 failed++;
1287 break;
1288 }
1289 /* Now find leafs with identityrefs (+transitive) and translate
1290 * prefixes in values to XML namespaces */
1291 if ((ret = json2xml_decode(x, xerr)) < 0)
1292 goto done;
1293 if (ret == 0) /* XXX necessary? */
1294 goto fail;
1295 }
1296 if (failed)
1297 goto fail;
1298 /* Sort the complete tree after parsing. Sorting is not really meaningful if Yang
1299 not bound */
1300 if (yb != YB_NONE)
1301 if (xml_sort_recurse(xt) < 0)
1302 goto done;
1303 retval = 1;
1304 done:
1305 clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
1306 if (cberr)
1307 cbuf_free(cberr);
1308 json_parse_exit(&jy);
1309 json_scan_exit(&jy);
1310 if (jy.jy_xvec)
1311 free(jy.jy_xvec);
1312 return retval;
1313 fail: /* invalid */
1314 retval = 0;
1315 goto done;
1316 }
1317
1318 /*! Parse string containing JSON and return an XML tree
1319 *
1320 * @param[in] str String containing JSON
1321 * @param[in] yb How to bind yang to XML top-level when parsing
1322 * @param[in] yspec Yang specification, mandatory to make module->xmlns translation
1323 * @param[in,out] xt Top object, if not exists, on success it is created with name 'top'
1324 * @param[out] xerr Reason for invalid returned as netconf err msg
1325 * @retval 1 OK and valid
1326 * @retval 0 Invalid (only if yang spec) w xerr set
1327 * @retval -1 Error with clicon_err called
1328 *
1329 * @code
1330 * cxobj *x = NULL;
1331 * if (clixon_json_parse_string(str, YB_MODULE, yspec, &x, &xerr) < 0)
1332 * err;
1333 * xml_free(x);
1334 * @endcode
1335 * @note you need to free the xml parse tree after use, using xml_free()
1336 * @see clixon_xml_parse_string XML instead of JSON
1337 * @see clixon_json_parse_file From a file
1338 */
1339 int
clixon_json_parse_string(char * str,yang_bind yb,yang_stmt * yspec,cxobj ** xt,cxobj ** xerr)1340 clixon_json_parse_string(char *str,
1341 yang_bind yb,
1342 yang_stmt *yspec,
1343 cxobj **xt,
1344 cxobj **xerr)
1345 {
1346 clicon_debug(1, "%s", __FUNCTION__);
1347 if (xt==NULL){
1348 clicon_err(OE_XML, EINVAL, "xt is NULL");
1349 return -1;
1350 }
1351 if (*xt == NULL){
1352 if ((*xt = xml_new("top", NULL, CX_ELMNT)) == NULL)
1353 return -1;
1354 }
1355 return _json_parse(str, yb, yspec, *xt, xerr);
1356 }
1357
1358 /*! Read a JSON definition from file and parse it into a parse-tree.
1359 *
1360 * File will be parsed as follows:
1361 * (1) parsed according to JSON; # Only this check if yspec is NULL
1362 * (2) sanity checked wrt yang
1363 * (3) namespaces check (using <ns>:<name> notation
1364 * (4) an xml parse tree will be returned
1365 * Note, only (1) and (4) will be done if yspec is NULL.
1366 * Part of (3) is to split json names if they contain colon,
1367 * eg: name="a:b" -> prefix="a", name="b"
1368 * But this is not done if yspec=NULL, and is not part of the JSON spec
1369 *
1370 * @param[in] fd File descriptor to the JSON file (ASCII string)
1371 * @param[in] yspec Yang specification, or NULL
1372 * @param[in,out] xt Pointer to (XML) parse tree. If empty, create.
1373 * @param[out] xerr Reason for invalid returned as netconf err msg
1374 *
1375 * @code
1376 * cxobj *xt = NULL;
1377 * if (clixon_json_parse_file(0, YB_MODULE, yspec, &xt) < 0)
1378 * err;
1379 * xml_free(xt);
1380 * @endcode
1381 * @note you need to free the xml parse tree after use, using xml_free()
1382 * @note, If xt empty, a top-level symbol will be added so that <tree../> will be: <top><tree.../></tree></top>
1383 * @note May block on file I/O
1384 *
1385 * @retval 1 OK and valid
1386 * @retval 0 Invalid (only if yang spec) w xerr set
1387 * @retval -1 Error with clicon_err called
1388 *
1389 * @see clixon_json_parse_string
1390 * @see RFC7951
1391 */
1392 int
clixon_json_parse_file(int fd,yang_bind yb,yang_stmt * yspec,cxobj ** xt,cxobj ** xerr)1393 clixon_json_parse_file(int fd,
1394 yang_bind yb,
1395 yang_stmt *yspec,
1396 cxobj **xt,
1397 cxobj **xerr)
1398 {
1399 int retval = -1;
1400 int ret;
1401 char *jsonbuf = NULL;
1402 int jsonbuflen = BUFLEN; /* start size */
1403 int oldjsonbuflen;
1404 char *ptr;
1405 char ch;
1406 int len = 0;
1407
1408 if (xt==NULL){
1409 clicon_err(OE_XML, EINVAL, "xt is NULL");
1410 return -1;
1411 }
1412 if ((jsonbuf = malloc(jsonbuflen)) == NULL){
1413 clicon_err(OE_XML, errno, "malloc");
1414 goto done;
1415 }
1416 memset(jsonbuf, 0, jsonbuflen);
1417 ptr = jsonbuf;
1418 while (1){
1419 if ((ret = read(fd, &ch, 1)) < 0){
1420 clicon_err(OE_XML, errno, "read");
1421 break;
1422 }
1423 if (ret != 0)
1424 jsonbuf[len++] = ch;
1425 if (ret == 0){
1426 if (*xt == NULL)
1427 if ((*xt = xml_new(JSON_TOP_SYMBOL, NULL, CX_ELMNT)) == NULL)
1428 goto done;
1429 if (len){
1430 if ((ret = _json_parse(ptr, yb, yspec, *xt, xerr)) < 0)
1431 goto done;
1432 if (ret == 0)
1433 goto fail;
1434 }
1435 break;
1436 }
1437 if (len >= jsonbuflen-1){ /* Space: one for the null character */
1438 oldjsonbuflen = jsonbuflen;
1439 jsonbuflen *= 2;
1440 if ((jsonbuf = realloc(jsonbuf, jsonbuflen)) == NULL){
1441 clicon_err(OE_XML, errno, "realloc");
1442 goto done;
1443 }
1444 memset(jsonbuf+oldjsonbuflen, 0, jsonbuflen-oldjsonbuflen);
1445 ptr = jsonbuf;
1446 }
1447 }
1448 retval = 1;
1449 done:
1450 if (retval < 0 && *xt){
1451 free(*xt);
1452 *xt = NULL;
1453 }
1454 if (jsonbuf)
1455 free(jsonbuf);
1456 return retval;
1457 fail:
1458 retval = 0;
1459 goto done;
1460 }
1461
1462
1463