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