static int _xml_get_value(struct lyd_node *node, struct lys_type *node_type, struct lyxml_elem *xml, int options, struct unres_data **unres, int log) { #define DECSIZE 21 struct lyd_node_leaf *leaf = (struct lyd_node_leaf *)node; struct lys_type *type; struct lyxml_ns *ns; char dec[DECSIZE]; char *strptr; const char *name; int64_t num; uint64_t unum; int len; int c, i, j, d; int found; struct unres_data *new_unres; leaf->value_str = xml->content; xml->content = NULL; /* will be change in case of union */ leaf->value_type = node_type->base; if ((options & LYD_OPT_FILTER) && !leaf->value_str) { /* no value in filter (selection) node -> nothing more is needed */ return EXIT_SUCCESS; } switch (node_type->base) { case LY_TYPE_BINARY: leaf->value.binary = leaf->value_str; if (node_type->info.binary.length && validate_length_range(0, strlen(leaf->value.binary), 0, 0, node_type, xml, leaf->value_str, log)) { return EXIT_FAILURE; } break; case LY_TYPE_BITS: /* locate bits structure with the bits definitions */ for (type = node_type; type->der->type.der; type = &type->der->type); /* allocate the array of pointers to bits definition */ leaf->value.bit = calloc(type->info.bits.count, sizeof *leaf->value.bit); if (!leaf->value_str) { /* no bits set */ break; } c = 0; i = 0; while (leaf->value_str[c]) { /* skip leading whitespaces */ while(isspace(leaf->value_str[c])) { c++; } /* get the length of the bit identifier */ for (len = 0; leaf->value_str[c] && !isspace(leaf->value_str[c]); c++, len++); /* go back to the beginning of the identifier */ c = c - len; /* find bit definition, identifiers appear ordered by their posititon */ for (found = 0; i < type->info.bits.count; i++) { if (!strncmp(type->info.bits.bit[i].name, &leaf->value_str[c], len) && !type->info.bits.bit[i].name[len]) { /* we have match, store the pointer */ leaf->value.bit[i] = &type->info.bits.bit[i]; /* stop searching */ i++; found = 1; break; } } if (!found) { /* referenced bit value does not exists */ if (log) { LOGVAL(LYE_INVAL, LOGLINE(xml), leaf->value_str, xml->name); } return EXIT_FAILURE; } c = c + len; } break; case LY_TYPE_BOOL: if (!strcmp(leaf->value_str, "true")) { leaf->value.bool = 1; } /* else false, so keep it zero */ break; case LY_TYPE_DEC64: /* locate dec64 structure with the fraction-digits value */ for (type = node_type; type->der->type.der; type = &type->der->type); for (c = 0; isspace(leaf->value_str[c]); c++); for (len = 0; leaf->value_str[c] && !isspace(leaf->value_str[c]); c++, len++); c = c - len; if (len > DECSIZE) { /* too long */ if (log) { LOGVAL(LYE_INVAL, LOGLINE(xml), leaf->value_str, xml->name); } return EXIT_FAILURE; } /* normalize the number */ dec[0] = '\0'; for (i = j = d = found = 0; i < DECSIZE; i++) { if (leaf->value_str[c + i] == '.') { found = 1; j = type->info.dec64.dig; i--; c++; continue; } if (leaf->value_str[c + i] == '\0') { c--; if (!found) { j = type->info.dec64.dig; found = 1; } if (!j) { dec[i] = '\0'; break; } d++; if (d > DECSIZE - 2) { if (log) { LOGVAL(LYE_OORVAL, LOGLINE(xml), leaf->value_str, xml->name); } return EXIT_FAILURE; } dec[i] = '0'; } else { if (!isdigit(leaf->value_str[c + i])) { if (i || leaf->value_str[c] != '-') { if (log) { LOGVAL(LYE_INVAL, LOGLINE(xml), leaf->value_str, xml->name); } return EXIT_FAILURE; } } else { d++; } if (d > DECSIZE - 2 || (found && !j)) { if (log) { LOGVAL(LYE_OORVAL, LOGLINE(xml), leaf->value_str, xml->name); } return EXIT_FAILURE; } dec[i] = leaf->value_str[c + i]; } if (j) { j--; } } if (parse_int(dec, xml, -9223372036854775807L - 1L, 9223372036854775807L, 10, &num, log) || validate_length_range(2, 0, 0, ((long double)num)/(1 << type->info.dec64.dig), node_type, xml, leaf->value_str, log)) { return EXIT_FAILURE; } leaf->value.dec64 = num; break; case LY_TYPE_EMPTY: /* just check that it is empty */ if (leaf->value_str && leaf->value_str[0]) { if (log) { LOGVAL(LYE_INVAL, LOGLINE(xml), leaf->value_str, xml->name); } return EXIT_FAILURE; } break; case LY_TYPE_ENUM: if (!leaf->value_str) { if (log) { LOGVAL(LYE_INVAL, LOGLINE(xml), "", xml->name); } return EXIT_FAILURE; } /* locate enums structure with the enumeration definitions */ for (type = node_type; type->der->type.der; type = &type->der->type); /* find matching enumeration value */ for (i = 0; i < type->info.enums.count; i++) { if (!strcmp(leaf->value_str, type->info.enums.enm[i].name)) { /* we have match, store pointer to the definition */ leaf->value.enm = &type->info.enums.enm[i]; break; } } if (!leaf->value.enm) { if (log) { LOGVAL(LYE_INVAL, LOGLINE(xml), leaf->value_str, xml->name); } return EXIT_FAILURE; } break; case LY_TYPE_IDENT: if ((strptr = strchr(leaf->value_str, ':'))) { len = strptr - leaf->value_str; if (!len) { if (log) { LOGVAL(LYE_INVAL, LOGLINE(xml), leaf->value_str, xml->name); } return EXIT_FAILURE; } strptr = strndup(leaf->value_str, len); } ns = lyxml_get_ns(xml, strptr); if (!ns) { if (log) { LOGVAL(LYE_INVAL, LOGLINE(xml), leaf->value_str, xml->name); } return EXIT_FAILURE; } if (strptr) { free(strptr); name = leaf->value_str + len + 1; } else { name = leaf->value_str; } leaf->value.ident = resolve_identityref(node_type->info.ident.ref, name, ns->value); if (!leaf->value.ident) { if (log) { LOGVAL(LYE_INVAL, LOGLINE(xml), leaf->value_str, xml->name); } return EXIT_FAILURE; } break; case LY_TYPE_INST: if (!leaf->value_str) { if (log) { LOGVAL(LYE_INVAL, LOGLINE(xml), "", xml->name); } return EXIT_FAILURE; } /* convert the path from the XML form using XML namespaces into the JSON format * using module names as namespaces */ xml->content = leaf->value_str; leaf->value_str = instid_xml2json(node->schema->module->ctx, xml); lydict_remove(node->schema->module->ctx, xml->content); xml->content = NULL; if (!leaf->value_str) { return EXIT_FAILURE; } if (options & (LYD_OPT_EDIT | LYD_OPT_FILTER)) { leaf->value_type |= LY_TYPE_INST_UNRES; } else { /* validity checking is performed later, right now the data tree * is not complete, so many instanceids cannot be resolved */ /* remember the leaf for later checking */ new_unres = malloc(sizeof *new_unres); new_unres->is_leafref = 0; new_unres->dnode = node; new_unres->next = *unres; #ifndef NDEBUG new_unres->line = LOGLINE(xml); #endif *unres = new_unres; } break; case LY_TYPE_LEAFREF: if (!leaf->value_str) { if (log) { LOGVAL(LYE_INVAL, LOGLINE(xml), "", xml->name); } return EXIT_FAILURE; } if (options & (LYD_OPT_EDIT | LYD_OPT_FILTER)) { do { type = &((struct lys_node_leaf *)leaf->schema)->type.info.lref.target->type; } while (type->base == LY_TYPE_LEAFREF); leaf->value_type = type->base | LY_TYPE_LEAFREF_UNRES; } else { /* validity checking is performed later, right now the data tree * is not complete, so many leafrefs cannot be resolved */ /* remember the leaf for later checking */ new_unres = malloc(sizeof *new_unres); new_unres->is_leafref = 1; new_unres->dnode = node; new_unres->next = *unres; #ifndef NDEBUG new_unres->line = LOGLINE(xml); #endif *unres = new_unres; } break; case LY_TYPE_STRING: leaf->value.string = leaf->value_str; if (node_type->info.str.length && validate_length_range(0, strlen(leaf->value.string), 0, 0, node_type, xml, leaf->value_str, log)) { return EXIT_FAILURE; } if (node_type->info.str.patterns && validate_pattern(leaf->value.string, node_type, xml, leaf->value_str, log)) { return EXIT_FAILURE; } break; case LY_TYPE_UNION: found = 0; type = get_next_union_type(node_type, NULL, &found); for (; type; found = 0, type = get_next_union_type(node_type, type, &found)) { xml->content = leaf->value_str; if (!_xml_get_value(node, type, xml, options, unres, 0)) { leaf->value_type = type->base; break; } } if (!type) { if (log) { LOGVAL(LYE_INVAL, LOGLINE(xml), leaf->value_str, xml->name); } return EXIT_FAILURE; } break; case LY_TYPE_INT8: if (parse_int(leaf->value_str, xml, -128, 127, 0, &num, log) || validate_length_range(1, 0, num, 0, node_type, xml, leaf->value_str, log)) { return EXIT_FAILURE; } leaf->value.int8 = num; break; case LY_TYPE_INT16: if (parse_int(leaf->value_str, xml, -32768, 32767, 0, &num, log) || validate_length_range(1, 0, num, 0, node_type, xml, leaf->value_str, log)) { return EXIT_FAILURE; } leaf->value.int16 = num; break; case LY_TYPE_INT32: if (parse_int(leaf->value_str, xml, -2147483648, 2147483647, 0, &num, log) || validate_length_range(1, 0, num, 0, node_type, xml, leaf->value_str, log)) { return EXIT_FAILURE; } leaf->value.int32 = num; break; case LY_TYPE_INT64: if (parse_int(leaf->value_str, xml, -9223372036854775807L - 1L, 9223372036854775807L, 0, &num, log) || validate_length_range(1, 0, num, 0, node_type, xml, leaf->value_str, log)) { return EXIT_FAILURE; } leaf->value.int64 = num; break; case LY_TYPE_UINT8: if (parse_uint(leaf->value_str, xml, 255, 0, &unum, log) || validate_length_range(0, unum, 0, 0, node_type, xml, leaf->value_str, log)) { return EXIT_FAILURE; } leaf->value.uint8 = unum; break; case LY_TYPE_UINT16: if (parse_uint(leaf->value_str, xml, 65535, 0, &unum, log) || validate_length_range(0, unum, 0, 0, node_type, xml, leaf->value_str, log)) { return EXIT_FAILURE; } leaf->value.uint16 = unum; break; case LY_TYPE_UINT32: if (parse_uint(leaf->value_str, xml, 4294967295, 0, &unum, log) || validate_length_range(0, unum, 0, 0, node_type, xml, leaf->value_str, log)) { return EXIT_FAILURE; } leaf->value.uint32 = unum; break; case LY_TYPE_UINT64: if (parse_uint(leaf->value_str, xml, 18446744073709551615UL, 0, &unum, log) || validate_length_range(0, unum, 0, 0, node_type, xml, leaf->value_str, log)) { return EXIT_FAILURE; } leaf->value.uint64 = unum; break; default: return EXIT_FAILURE; }
const char * transform_xml2json(struct ly_ctx *ctx, const char *expr, struct lyxml_elem *xml, int log) { const char *in, *id; char *out, *col, *prefix; size_t out_size, out_used, id_len, rc; const struct lys_module *mod; const struct lyxml_ns *ns; in = expr; out_size = strlen(in)+1; out = malloc(out_size); if (!out) { if (log) { LOGMEM; } return NULL; } out_used = 0; while (1) { col = strchr(in, ':'); /* we're finished, copy the remaining part */ if (!col) { strcpy(&out[out_used], in); out_used += strlen(in)+1; assert(out_size == out_used); return lydict_insert_zc(ctx, out); } id = strpbrk_backwards(col-1, "/ [\'\"", (col-in)-1); if ((id[0] == '/') || (id[0] == ' ') || (id[0] == '[') || (id[0] == '\'') || (id[0] == '\"')) { ++id; } id_len = col-id; rc = parse_identifier(id); if (rc < id_len) { if (log) { LOGVAL(LYE_XML_INCHAR, LY_VLOG_XML, xml, id[rc], &id[rc]); } free(out); return NULL; } /* get the module */ prefix = strndup(id, id_len); if (!prefix) { if (log) { LOGMEM; } free(out); return NULL; } ns = lyxml_get_ns(xml, prefix); free(prefix); if (!ns) { if (log) { LOGVAL(LYE_XML_INVAL, LY_VLOG_XML, xml, "namespace prexif"); LOGVAL(LYE_SPEC, LY_VLOG_XML, xml, "XML namespace with prefix \"%.*s\" not defined.", id_len, id); } free(out); return NULL; } mod = ly_ctx_get_module_by_ns(ctx, ns->value, NULL); if (!mod) { if (log) { LOGVAL(LYE_XML_INVAL, LY_VLOG_XML, xml, "module namespace"); LOGVAL(LYE_SPEC, LY_VLOG_XML, xml, "Module with the namespace \"%s\" could not be found.", ns->value); } free(out); return NULL; } /* adjust out size (it can even decrease in some strange cases) */ out_size += strlen(mod->name)-id_len; out = ly_realloc(out, out_size); if (!out) { if (log) { LOGMEM; } return NULL; } /* copy the data before prefix */ strncpy(&out[out_used], in, id-in); out_used += id-in; /* copy the model name */ strcpy(&out[out_used], mod->name); out_used += strlen(mod->name); /* copy ':' */ out[out_used] = ':'; ++out_used; /* finally adjust in pointer for next round */ in = col+1; } /* unreachable */ LOGINT; return NULL; }
static const char * instid_xml2json(struct ly_ctx *ctx, struct lyxml_elem *xml) { const char *in = xml->content; char *out, *aux, *prefix; size_t out_size, len, size, i = 0, o = 0; int start = 1, interior = 1; struct lys_module *mod, *mod_prev = NULL; struct lyxml_ns *ns; out_size = strlen(in); out = malloc((out_size + 1) * sizeof *out); while (in[i]) { /* skip whitespaces */ while (isspace(in[i])) { i++; } if (start) { /* leading '/' character */ if (start == 1 && in[i] != '/') { LOGVAL(LYE_INCHAR, LOGLINE(xml), in[i], &in[i]); free(out); return NULL; } /* check the output buffer size */ if (out_size == o) { out_size += 16; /* just add some size */ aux = realloc(out, out_size + 1); if (!aux) { free(out); LOGMEM; return NULL; } out = aux; } out[o++] = in[i++]; start = 0; continue; } else { /* translate the node identifier */ /* prefix */ aux = strchr(&in[i], ':'); if (aux) { /* interior segment */ len = aux - &in[i]; prefix = strndup(&in[i], len); i += len + 1; /* move after ':' */ } else { /* missing prefix -> invalid instance-identifier */ LOGVAL(LYE_INVAL, LOGLINE(xml), xml->content, xml->name); free(out); return NULL; } ns = lyxml_get_ns(xml, prefix); free(prefix); mod = ly_ctx_get_module_by_ns(ctx, ns->value, NULL); /* node name */ aux = strpbrk(&in[i], "/[="); if (aux) { /* interior segment */ len = aux - &in[i]; } else { /* end segment */ interior = 0; len = strlen(&in[i]); } /* check the output buffer size */ if (!mod_prev || (mod != mod_prev)) { /* prefix + ':' + name to print + '/' */ size = o + len + 1 + strlen(mod->name) + interior; } else { /* name to print + '/' */ size = o + len + interior; } if (out_size <= size) { /* extend to fit the needed size */ out_size = size; aux = realloc(out, out_size + 1); if (!aux) { free(out); LOGMEM; return NULL; } out = aux; } if (!mod_prev || (mod != mod_prev)) { mod_prev = mod; size = strlen(mod->name); memcpy(&out[o], mod->name, size); o += size; out[o++] = ':'; } memcpy(&out[o], &in[i], len); o += len; i += len; if (in[i] == '=') { /* we are in the predicate on the value, so just copy data */ aux = strchr(&in[i], ']'); if (aux) { len = aux - &in[i] + 1; /* include ] */ /* check the output buffer size */ size = o + len + 1; if (out_size <= size) { out_size = size; /* just add some size */ aux = realloc(out, out_size + 1); if (!aux) { free(out); LOGMEM; return NULL; } out = aux; } memcpy(&out[o], &in[i], len); o += len; i += len; } else { /* missing closing ] of predicate -> invalid instance-identifier */ LOGVAL(LYE_INVAL, LOGLINE(xml), xml->content, xml->name); free(out); return NULL; } } start = 2; } } /* terminating NULL byte */ /* check the output buffer size */ if (out_size < o) { out_size += 1; /* just add some size */ aux = realloc(out, out_size + 1); if (!aux) { free(out); LOGMEM; return NULL; } out = aux; } out[o] = '\0'; return lydict_insert_zc(ctx, out); }