From 99c6f616373a9ca22ca429dd91a2661dbb0b4ba7 Mon Sep 17 00:00:00 2001 From: Olof Hagsand Date: Mon, 2 Jan 2023 21:25:49 +0100 Subject: [PATCH] Enhanced for client-side functionality: - parse of yang from string, not only file - Decode of xml encoding, not only decoding --- lib/clixon/clixon_string.h | 1 + lib/clixon/clixon_yang_parse_lib.h | 1 + lib/src/clixon_proto_client.c | 2 +- lib/src/clixon_string.c | 144 ++++++++++++++++++++++++++++- lib/src/clixon_xml_parse.l | 4 +- lib/src/clixon_xml_parse.y | 11 ++- lib/src/clixon_yang_parse_lib.c | 2 +- 7 files changed, 158 insertions(+), 7 deletions(-) diff --git a/lib/clixon/clixon_string.h b/lib/clixon/clixon_string.h index c28ed8fe..456972ab 100644 --- a/lib/clixon/clixon_string.h +++ b/lib/clixon/clixon_string.h @@ -95,6 +95,7 @@ int uri_str2cvec(char *string, char delim1, char delim2, int decode, cvec **c int uri_percent_encode(char **encp, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); int xml_chardata_encode(char **escp, const char *fmt, ... ) __attribute__ ((format (printf, 2, 3))); int xml_chardata_cbuf_append(cbuf *cb, char *str); +int xml_chardata_decode(char **escp, const char *fmt,...); int uri_percent_decode(char *enc, char **str); const char *clicon_int2str(const map_str2int *mstab, int i); diff --git a/lib/clixon/clixon_yang_parse_lib.h b/lib/clixon/clixon_yang_parse_lib.h index 32dc2784..927f1f40 100644 --- a/lib/clixon/clixon_yang_parse_lib.h +++ b/lib/clixon/clixon_yang_parse_lib.h @@ -55,6 +55,7 @@ yang_stmt *yang_parse_file(FILE *fp, const char *name, yang_stmt *ysp); yang_stmt *yang_parse_filename(const char *filename, yang_stmt *ysp); int yang_spec_parse_module(clicon_handle h, const char *module, const char *revision, yang_stmt *yspec); +yang_stmt *yang_parse_str(char *str, const char *name, yang_stmt *yspec); int yang_spec_parse_file(clicon_handle h, char *filename, yang_stmt *yspec); int yang_spec_load_dir(clicon_handle h, char *dir, yang_stmt *yspec); int ys_parse_date_arg(char *datearg, uint32_t *dateint); diff --git a/lib/src/clixon_proto_client.c b/lib/src/clixon_proto_client.c index 623ccb0f..b14b5462 100644 --- a/lib/src/clixon_proto_client.c +++ b/lib/src/clixon_proto_client.c @@ -1270,7 +1270,7 @@ clicon_rpc_validate(clicon_handle h, /*! Commit changes send a commit request to backend daemon * @param[in] h CLICON handle * @param[in] confirmed If set, send commit/confirmed - * @param[in] cancel If set, send cancle-commit + * @param[in] cancel If set, send cancel-commit * @param[in] timeout For confirmed, a timeout in seconds (default 600s) * @param[in] persist A persist identifier to use * @param[in] persist_id If cancel or confirmed, the persist id diff --git a/lib/src/clixon_string.c b/lib/src/clixon_string.c index b1d387cb..2482476a 100644 --- a/lib/src/clixon_string.c +++ b/lib/src/clixon_string.c @@ -387,7 +387,7 @@ uri_percent_decode(char *enc, return retval; } -/*! Escape characters according to XML definition +/*! Encode escape characters according to XML definition * @param[out] encp Encoded malloced output string * @param[in] fmt Not-encoded input string (stdarg format string) * @param[in] ... stdarg variable parameters @@ -410,6 +410,7 @@ uri_percent_decode(char *enc, * @see uri_percent_encode * @see AMPERSAND mode in clixon_xml_parse.l, implicit decoding * @see xml_chardata_cbuf_append for a specialized version + * @see xml_chardata_decode for decoding */ int xml_chardata_encode(char **escp, @@ -587,6 +588,147 @@ xml_chardata_cbuf_append(cbuf *cb, return retval; } +/*! xml decode &...; + * + * @param[in] str Input string on the form &..; with & stripped + * @param[out] ch Decoded character + * @param[in,out] ip + * @retval 1 OK and identified a decoding + * @retval 0 OK No identified decoding + * @retval -1 Error + */ +static int +xml_chardata_decode_ampersand(char *str, + char *ch, + int *ip) +{ + int retval = -1; + char *semi; + char *p; + size_t len; + uint32_t code; + cbuf *cb = NULL; + int ret; + + if ((semi = index(str, ';')) == NULL) + goto fail; + *semi = '\0'; + len = strlen(str); + p = str; + if (strcmp(p, "amp") == 0) + *ch = '&'; + else if (strcmp(p, "lt") == 0) + *ch = '<'; + else if (strcmp(p, "gt") == 0) + *ch = '>'; + else if (strcmp(p, "apos") == 0) + *ch = '\''; + else if (strcmp(p, "quot") == 0) + *ch = '"'; + else if (len > 0 && *p == '#'){ + p++; + if ((cb = cbuf_new()) == NULL){ + clicon_err(OE_UNIX, errno, "parse_uint32"); + goto done; + } + if (len > 1 && *p == 'x'){ + cprintf(cb, "0x"); + p++; + } + cprintf(cb, "%s", p); + if ((ret = parse_uint32(cbuf_get(cb), &code, NULL)) < 0){ + clicon_err(OE_UNIX, errno, "parse_uint32"); + goto done; + } + if (ret == 0){ + goto fail; + } + *ch = code; + } + else + goto fail; + *ip += len+1; + retval = 1; + done: + if (cb) + cbuf_free(cb); + return retval; + fail: + retval = 0; + if (semi) + *semi = ';'; + goto done; +} + +/*! Decode escape characters according to XML definition + * @param[out] decp Decoded malloced output string + * @param[in] fmt Encoded input string (stdarg format string) + * @see xml_chardata_encode for encoding + */ +int +xml_chardata_decode(char **decp, + const char *fmt,...) +{ + int retval = -1; + char *str = NULL; /* Expanded encoded format string w stdarg */ + char *dec = NULL; + int fmtlen; + va_list args; + size_t slen; + int i; + int j; + char ch; + int ret; + + /* Two steps: (1) read in the complete format string */ + va_start(args, fmt); /* dryrun */ + fmtlen = vsnprintf(NULL, 0, fmt, args) + 1; + va_end(args); + if ((str = malloc(fmtlen)) == NULL){ + clicon_err(OE_UNIX, errno, "malloc"); + goto done; + } + memset(str, 0, fmtlen); + va_start(args, fmt); /* real */ + fmtlen = vsnprintf(str, fmtlen, fmt, args) + 1; + va_end(args); + /* Now str is the combined fmt + ... */ + + /* Step (2) decode str --> dec + * First allocate decoded string, encoded is always >= larger */ + slen = strlen(str); + if ((dec = malloc(slen+1)) == NULL){ + clicon_err(OE_UNIX, errno, "malloc"); + goto done; + } + j = 0; + memset(dec, 0, slen+1); + for (i=0; i"gt;" { BEGIN(_XY->xy_lex_state); clixon_xml_parselval.string = ">"; return CHARDATA;} "apos;" { BEGIN(_XY->xy_lex_state); clixon_xml_parselval.string = "'"; return CHARDATA;} "quot;" { BEGIN(_XY->xy_lex_state); clixon_xml_parselval.string = "\""; return CHARDATA;} -"#"[0-9]+";" { BEGIN(_XY->xy_lex_state); clixon_xml_parselval.string = "\""; return CHARDATA; /* ISO/IEC 10646 */ } -"#x"[0-9a-fA-F]+";" { BEGIN(_XY->xy_lex_state); clixon_xml_parselval.string = "\""; return CHARDATA;} +"#"[0-9]+";" { BEGIN(_XY->xy_lex_state); clixon_xml_parselval.string = yytext; return ENCODED; /* ISO/IEC 10646 */ } +"#x"[0-9a-fA-F]+";" { BEGIN(_XY->xy_lex_state); clixon_xml_parselval.string = yytext; return ENCODED;} \n { clixon_xml_parselval.string = yytext;_XY->xy_linenum++; return (CHARDATA);} "]]>" { BEGIN(_XY->xy_lex_state); clixon_xml_parselval.string = yytext; return CHARDATA;} diff --git a/lib/src/clixon_xml_parse.y b/lib/src/clixon_xml_parse.y index 8041a45f..fde7dfb8 100644 --- a/lib/src/clixon_xml_parse.y +++ b/lib/src/clixon_xml_parse.y @@ -45,7 +45,7 @@ %start document -%token NAME CHARDATA WHITESPACE STRING +%token NAME CHARDATA ENCODED WHITESPACE STRING %token MY_EOF %token VER ENC SD %token BSLASH ESLASH @@ -104,12 +104,14 @@ clixon_xml_parseerror(void *_xy, /*! Parse XML content, eg chars between >...< * @param[in] xy + * @param[in] encoded set if ampersand encoded * @param[in] str Body string, direct pointer (copy before use, dont free) * Note that we dont handle escaped characters correctly * there may also be some leakage here on NULL return */ static int xml_parse_content(clixon_xml_yacc *xy, + int encoded, char *str) { cxobj *xn = xy->xy_xelement; @@ -121,6 +123,9 @@ xml_parse_content(clixon_xml_yacc *xy, if ((xn = xml_new("body", xp, CX_BODY)) == NULL) goto done; } + if (encoded) + if (xml_value_append(xn, "&") < 0) + goto done; if (xml_value_append(xn, str) < 0) goto done; xy->xy_xelement = xn; @@ -446,8 +451,10 @@ elist : elist content { _PARSE_DEBUG("elist -> elist content"); } content : element { _PARSE_DEBUG("content -> element"); } | comment { _PARSE_DEBUG("content -> comment"); } | pi { _PARSE_DEBUG("content -> pi"); } - | CHARDATA { if (xml_parse_content(_XY, $1) < 0) YYABORT; + | CHARDATA { if (xml_parse_content(_XY, 0, $1) < 0) YYABORT; _PARSE_DEBUG("content -> CHARDATA"); } + | ENCODED { if (xml_parse_content(_XY, 1, $1) < 0) YYABORT; + _PARSE_DEBUG("content -> ENCODED"); } | WHITESPACE { if (xml_parse_whitespace(_XY, $1) < 0) YYABORT; _PARSE_DEBUG("content -> WHITESPACE"); } | { _PARSE_DEBUG("content -> "); } diff --git a/lib/src/clixon_yang_parse_lib.c b/lib/src/clixon_yang_parse_lib.c index 83f18466..992e3e77 100644 --- a/lib/src/clixon_yang_parse_lib.c +++ b/lib/src/clixon_yang_parse_lib.c @@ -759,7 +759,7 @@ yang_expand_grouping(yang_stmt *yn) * @retval NULL Error encountered * See top of file for diagram of calling order */ -static yang_stmt * +yang_stmt * yang_parse_str(char *str, const char *name, /* just for errs */ yang_stmt *yspec)