Пример #1
0
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;
    }
Пример #2
0
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;
}
Пример #3
0
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);
}