static void test_df1(void **state) { struct state *st = (*state); struct lyd_node *node; const char *xml = "<df xmlns=\"urn:libyang:tests:defaults\">" "<bar><ho>1</ho><hi>42</hi></bar>" "<foo>42</foo><b1_1>42</b1_1>" "</df><hidden xmlns=\"urn:libyang:tests:defaults\">" "<foo>42</foo><baz>42</baz></hidden>"; st->dt = lyd_new(NULL, st->mod, "df"); assert_ptr_not_equal(st->dt, NULL); /* presence container */ assert_ptr_not_equal((node = lyd_new(st->dt, NULL, "bar")), NULL); assert_int_not_equal(lyd_validate(&(st->dt), LYD_OPT_CONFIG), 0); assert_string_equal(ly_errmsg(), "Missing required element \"ho\" in \"bar\"."); /* manadatory node in bar */ assert_ptr_not_equal(lyd_new_leaf(node, NULL, "ho", "1"), NULL); assert_int_equal(lyd_validate(&(st->dt), LYD_OPT_CONFIG), 0); assert_int_equal(lyd_wd_add(NULL, &(st->dt), LYD_OPT_CONFIG | LYD_WD_ALL), 0); assert_int_equal(lyd_print_mem(&(st->xml), st->dt, LYD_XML, LYP_WITHSIBLINGS), 0); assert_ptr_not_equal(st->xml, NULL); assert_string_equal(st->xml, xml); }
static void test_parse_print_oookeys_xml(void **state) { struct state *st = (*state); const char *xmlin = "<cont1 xmlns=\"urn:all\">" "<leaf3>-1</leaf3>" "<list1><leaf18>aaa</leaf18></list1>" "<list1><leaf19>123</leaf19><leaf18>bbb</leaf18></list1>" "</cont1>"; const char *xmlout = "<cont1 xmlns=\"urn:all\">" "<leaf3>-1</leaf3>" "<list1><leaf18>aaa</leaf18></list1>" "<list1><leaf18>bbb</leaf18><leaf19>123</leaf19></list1>" "</cont1>"; st->dt = NULL; /* with strict parsing, it is error since the key is not encoded as the first child */ st->dt = lyd_parse_mem(st->ctx, xmlin, LYD_XML, LYD_OPT_CONFIG | LYD_OPT_STRICT); assert_ptr_equal(st->dt, NULL); assert_int_equal(ly_vecode, LYVE_INORDER); assert_string_equal(ly_errmsg(), "Invalid position of the key \"leaf18\" in a list \"list1\"."); /* without strict, it produces only warning, but the data are correctly loaded */ st->dt = lyd_parse_mem(st->ctx, xmlin, LYD_XML, LYD_OPT_CONFIG); assert_ptr_not_equal(st->dt, NULL); assert_int_equal(lyd_print_mem(&st->str1, st->dt, LYD_XML, 0), 0); assert_string_equal(st->str1, xmlout); }
static void test_dup_to_ctx(void **state) { struct state *st = (*state); const struct lys_module *mod; const char *sch = "module x {" " namespace urn:x;" " prefix x;" " leaf x { type string; }}"; const char *data = "<x xmlns=\"urn:x\">hello</x>"; /* case 1 - schema is only in the first context, duplicating data into the second context is supposed to * fail because of missing schema */ mod = lys_parse_mem(st->ctx1, sch, LYS_IN_YANG); assert_ptr_not_equal(mod, NULL); st->dt1 = lyd_parse_mem(st->ctx1, data, LYD_XML, LYD_OPT_CONFIG); assert_ptr_not_equal(st->dt1, NULL); st->dt2 = lyd_dup_to_ctx(st->dt1, 1, st->ctx2); assert_ptr_equal(st->dt2, NULL); assert_int_equal(ly_errno, LY_EINVAL); assert_string_equal(ly_errmsg(st->ctx2), "Target context does not contain schema node for the data node being duplicated (x:x)."); /* case 2 - with the schema present in both contexts, duplication should succeed */ mod = lys_parse_mem(st->ctx2, sch, LYS_IN_YANG); assert_ptr_not_equal(mod, NULL); st->dt2 = lyd_dup_to_ctx(st->dt1, 1, st->ctx2); assert_ptr_not_equal(st->dt2, NULL); /* the values are the same, but they are stored in different contexts */ assert_string_equal(((struct lyd_node_leaf_list *)st->dt1)->value_str, ((struct lyd_node_leaf_list *)st->dt2)->value_str); assert_ptr_not_equal(((struct lyd_node_leaf_list *)st->dt1)->value_str, ((struct lyd_node_leaf_list *)st->dt2)->value_str); /* and the schema nodes are the same, but comes from a different contexts */ assert_int_equal(st->dt1->schema->nodetype, st->dt2->schema->nodetype); assert_string_equal(st->dt1->schema->name, st->dt2->schema->name); assert_string_equal(st->dt1->schema->module->name, st->dt2->schema->module->name); assert_ptr_equal(st->dt1->schema->module->ctx, st->ctx1); assert_ptr_equal(st->dt2->schema->module->ctx, st->ctx2); }
/** * @brief Export content of the specified datastore for the given module into a file * referenced by the descriptor 'fd_out' */ static int srcfg_export_datastore(struct ly_ctx *ly_ctx, int fd_out, const char *module_name, LYD_FORMAT format) { int rc = SR_ERR_INTERNAL; struct lyd_node *data_tree = NULL; int ret = 0; CHECK_NULL_ARG2(ly_ctx, module_name); /* get data tree of currently stored configuration */ rc = srcfg_get_module_data(ly_ctx, module_name, &data_tree); if (SR_ERR_OK != rc) { goto cleanup; } /* dump data */ ret = lyd_print_fd(fd_out, data_tree, format, LYP_WITHSIBLINGS | LYP_FORMAT); CHECK_ZERO_LOG_GOTO(ret, rc, SR_ERR_INTERNAL, cleanup, "Unable to print the data: %s", ly_errmsg()); rc = SR_ERR_OK; cleanup: if (NULL != data_tree) { lyd_free_withsiblings(data_tree); } return rc; }
/** * @brief Import content of the specified datastore for the given module from a file * referenced by the descriptor 'fd_in' */ static int srcfg_import_datastore(struct ly_ctx *ly_ctx, int fd_in, const char *module_name, srcfg_datastore_t datastore, LYD_FORMAT format, bool permanent) { int rc = SR_ERR_INTERNAL; unsigned i = 0; struct lyd_node *new_data_tree = NULL; struct lyd_node *current_data_tree = NULL; struct lyd_difflist *diff = NULL; char *first_xpath = NULL, *second_xpath = NULL; char *input_data = NULL; int ret = 0; struct stat info; CHECK_NULL_ARG2(ly_ctx, module_name); /* parse input data */ ret = fstat(fd_in, &info); CHECK_NOT_MINUS1_LOG_GOTO(ret, rc, SR_ERR_INTERNAL, cleanup, "Unable to obtain input file info: %s.", sr_strerror_safe(errno)); ly_errno = LY_SUCCESS; if (S_ISREG(info.st_mode)) { /* load (using mmap) and parse the input data in one step */ new_data_tree = lyd_parse_fd(ly_ctx, fd_in, format, LYD_OPT_STRICT | LYD_OPT_CONFIG); } else { /* most likely STDIN */ /* load input data into the memory first */ ret = srcfg_read_file_content(fd_in, &input_data); CHECK_RC_MSG_GOTO(ret, cleanup, "Unable to read the input data."); /* parse the input data stored inside memory buffer */ new_data_tree = lyd_parse_mem(ly_ctx, input_data, format, LYD_OPT_STRICT | LYD_OPT_CONFIG); } if (NULL == new_data_tree && LY_SUCCESS != ly_errno) { SR_LOG_ERR("Unable to parse the input data: %s", ly_errmsg()); goto cleanup; } /* validate input data */ if (NULL != new_data_tree) { ret = lyd_validate(&new_data_tree, LYD_OPT_STRICT | LYD_OPT_CONFIG | LYD_WD_IMPL_TAG); CHECK_ZERO_LOG_GOTO(ret, rc, SR_ERR_INTERNAL, cleanup, "Input data are not valid: %s", ly_errmsg()); } /* remove default nodes */ lyd_wd_cleanup(&new_data_tree, 0); /* get data tree of currently stored configuration */ rc = srcfg_get_module_data(ly_ctx, module_name, ¤t_data_tree); if (SR_ERR_OK != rc) { goto cleanup; } /* get the list of changes made by the user */ diff = lyd_diff(current_data_tree, new_data_tree, 0); if (NULL == diff) { SR_LOG_ERR("Unable to get the list of changes: %s", ly_errmsg()); goto cleanup; } /* iterate over the list of differences and for each issue corresponding Sysrepo command(s) */ while (diff->type && LYD_DIFF_END != diff->type[i]) { if (NULL != diff->first[i]) { first_xpath = lyd_path(diff->first[i]); if (NULL == first_xpath) { SR_LOG_ERR("Error returned from lyd_path: %s.", ly_errmsg()); goto cleanup; } } if (NULL != diff->second[i]) { second_xpath = lyd_path(diff->second[i]); if (NULL == second_xpath) { free(first_xpath); first_xpath = NULL; SR_LOG_ERR("Error returned from lyd_path: %s.", ly_errmsg()); goto cleanup; } } switch (diff->type[i]) { case LYD_DIFF_DELETED: SR_LOG_DBG("<LYD_DIFF_DELETED> node: %s", first_xpath); rc = srcfg_convert_lydiff_deleted(first_xpath); break; case LYD_DIFF_CHANGED: SR_LOG_DBG("<LYD_DIFF_CHANGED> orig: %s, new: %s", first_xpath, second_xpath); rc = srcfg_convert_lydiff_changed(first_xpath, diff->second[i]); break; case LYD_DIFF_MOVEDAFTER1: SR_LOG_DBG("<LYD_DIFF_MOVEDAFTER1> moved: %s, after: %s", first_xpath, second_xpath); rc = srcfg_convert_lydiff_movedafter(first_xpath, second_xpath); break; case LYD_DIFF_CREATED: SR_LOG_DBG("<LYD_DIFF_CREATED> parent: %s, new node: %s", first_xpath, second_xpath); rc = srcfg_convert_lydiff_created(diff->second[i]); break; case LYD_DIFF_MOVEDAFTER2: SR_LOG_DBG("<LYD_DIFF_MOVEDAFTER2> after: %s, this new node was inserted: %s", first_xpath, second_xpath); rc = srcfg_convert_lydiff_movedafter(second_xpath, first_xpath); break; default: assert(0 && "not reachable"); } free(first_xpath); free(second_xpath); first_xpath = second_xpath = NULL; if (SR_ERR_OK != rc) { goto cleanup; } ++i; } if (0 == i) { SR_LOG_DBG_MSG("No changes were made."); } else { /* commit the changes */ rc = sr_commit(srcfg_session); if (SR_ERR_OK != rc) { SR_LOG_ERR("Error returned from sr_commit: %s.", sr_strerror(rc)); goto cleanup; } if (SRCFG_STORE_RUNNING == datastore && permanent) { /* copy running datastore data into the startup datastore */ rc = sr_copy_config(srcfg_session, module_name, SR_DS_RUNNING, SR_DS_STARTUP); if (SR_ERR_OK != rc) { SR_LOG_ERR("Error returned from sr_copy_config: %s.", sr_strerror(rc)); goto cleanup; } } } rc = SR_ERR_OK; cleanup: if (NULL != diff) { lyd_free_diff(diff); } if (NULL != current_data_tree) { lyd_free_withsiblings(current_data_tree); } if (NULL != new_data_tree) { lyd_free_withsiblings(new_data_tree); } if (input_data) { free(input_data); } return rc; }
/** * @brief Convert data tree difference of type LYD_DIFF_CREATED to corresponding set of Sysrepo public API calls. */ static int srcfg_convert_lydiff_created(struct lyd_node *node) { int rc = SR_ERR_INTERNAL; struct lyd_node *elem = node; bool process_children = true; sr_val_t value = { 0, SR_UNKNOWN_T }; struct lyd_node_leaf_list *data_leaf = NULL; struct lys_node_list *slist = NULL; char *xpath = NULL, *delim = NULL; CHECK_NULL_ARG(node); /* non-recursive DFS post-order */ do { /* go as deep as possible */ if (process_children) { while (!(elem->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) && elem->child) { elem = elem->child; } } /* get appropriate xpath and value */ free(xpath); xpath = value.xpath = NULL; value.type = SR_UNKNOWN_T; switch (elem->schema->nodetype) { case LYS_LEAF: /* e.g.: /test-module:user[name='nameE']/name */ /* get value */ data_leaf = (struct lyd_node_leaf_list *)elem; value.type = sr_libyang_leaf_get_type(data_leaf); rc = sr_libyang_leaf_copy_value(data_leaf, &value); if (SR_ERR_OK != rc) { SR_LOG_ERR("Error returned from sr_libyang_leaf_copy_value: %s.", sr_strerror(rc)); goto cleanup; } /* get xpath */ xpath = lyd_path(elem); if (NULL == xpath) { SR_LOG_ERR("Error returned from lyd_path: %s.", ly_errmsg()); goto cleanup; } /* key value of a list cannot be set directly */ if (elem->parent && (elem->parent->schema->nodetype == LYS_LIST)) { slist = (struct lys_node_list *)elem->parent->schema; for (unsigned i = 0; i < slist->keys_size; ++i) { if (slist->keys[i]->name == elem->schema->name) { /* key */ if (i == 0) { delim = strrchr(xpath, '/'); if (delim) { *delim = '\0'; } goto set_value; } else { /* create list instance (directly) only once - with the first key */ goto next_node; } } } } break; case LYS_LEAFLIST: /* e.g.: /test-module:main/numbers[.='10'] */ /* get value */ data_leaf = (struct lyd_node_leaf_list *)elem; value.type = sr_libyang_leaf_get_type(data_leaf); rc = sr_libyang_leaf_copy_value(data_leaf, &value); if (SR_ERR_OK != rc) { SR_LOG_ERR("Error returned from sr_libyang_leaf_copy_value: %s.", sr_strerror(rc)); goto cleanup; } /* get xpath */ xpath = lyd_path(elem); if (NULL == xpath) { SR_LOG_ERR("Error returned from lyd_path: %s.", ly_errmsg()); goto cleanup; } /* strip away the predicate */ delim = strrchr(xpath, '['); if (delim) { *delim = '\0'; } break; case LYS_ANYXML: SR_LOG_ERR_MSG("The anyxml statement is not yet supported by Sysrepo."); goto cleanup; case LYS_CONTAINER: /* explicitly create only presence containers */ if (((struct lys_node_container *)elem->schema)->presence) { xpath = lyd_path(elem); } else { goto next_node; } break; default: /* no data to set */ goto next_node; } set_value: /* set value */ rc = sr_set_item(srcfg_session, xpath, SR_UNKNOWN_T != value.type ? &value : NULL, SR_EDIT_DEFAULT); if (SR_ERR_OK != rc) { SR_LOG_ERR("Error returned from sr_set_item: %s.", sr_strerror(rc)); goto cleanup; } next_node: /* backtracking + automatically moving to the next sibling if there is any */ if (elem != node) { if (elem->next) { elem = elem->next; process_children = true; } else { assert(elem->parent); elem = elem->parent; process_children = false; } } else { break; } } while (true); rc = SR_ERR_OK; cleanup: if (NULL != xpath) { free(xpath); } sr_free_val_content(&value); return rc; }
/** * @brief Get complete libyang data tree of a specified module from sysrepo. */ static int srcfg_get_module_data(struct ly_ctx *ly_ctx, const char *module_name, struct lyd_node **data_tree) { int rc = SR_ERR_OK, ret = 0; sr_val_t *value = NULL; sr_val_iter_t *iter = NULL; struct lyd_node *node = NULL; const struct lys_node *schema = NULL; char query[PATH_MAX] = { 0, }; char *string_val = NULL; snprintf(query, PATH_MAX, "/%s:*//.", module_name); rc = sr_get_items_iter(srcfg_session, query, &iter); if (SR_ERR_OK != rc) { SR_LOG_ERR("Error by sr_get_items_iter: %s", sr_strerror(rc)); goto cleanup; } *data_tree = NULL; ly_errno = LY_SUCCESS; ly_diminish_errors = true; while (SR_ERR_OK == (rc = sr_get_item_next(srcfg_session, iter, &value))) { ly_diminish_errors = false; if (NULL == value) { goto next; } /* get node schema */ schema = ly_ctx_get_node2(ly_ctx, NULL, value->xpath, 0); if (!schema) { SR_LOG_ERR("Error by ly_ctx_get_node2: %s", ly_errmsg()); goto fail; } /* skip default values */ if (schema->nodetype == LYS_LEAF && value->dflt) { goto next; } /* skip non-presence containers */ if (value->type == SR_CONTAINER_T) { goto next; } /* convert value to string */ rc = sr_val_to_str(value, schema, &string_val); if (SR_ERR_OK != rc) { SR_LOG_ERR("Error by sr_val_to_str: %s", sr_strerror(rc)); goto fail; } /* add node to data tree */ ly_errno = LY_SUCCESS; node = lyd_new_path(*data_tree, ly_ctx, value->xpath, string_val, LYD_PATH_OPT_UPDATE); if (!node && LY_SUCCESS != ly_errno) { SR_LOG_ERR("Error by lyd_new_path: %s", ly_errmsg()); goto fail; } if (NULL == *data_tree) { *data_tree = node; } next: /* cleanup before next iteration */ if (NULL != string_val) { free(string_val); string_val = NULL; } if (NULL != value) { sr_free_val(value); value = NULL; } ly_diminish_errors = true; } ly_diminish_errors = false; if (SR_ERR_NOT_FOUND == rc) { rc = SR_ERR_OK; } if (SR_ERR_OK == rc) { if (NULL != *data_tree) { /* validate returned data, but most importantly resolve leafrefs */ ret = lyd_validate(data_tree, LYD_OPT_STRICT | LYD_OPT_CONFIG | LYD_WD_IMPL_TAG); CHECK_ZERO_LOG_GOTO(ret, rc, SR_ERR_INTERNAL, fail, "Received data tree from sysrepo is not valid: %s", ly_errmsg()); /* remove default nodes added by validation */ lyd_wd_cleanup(data_tree, 0); } goto cleanup; } fail: rc = SR_ERR_INTERNAL; if (NULL != *data_tree) { lyd_free_withsiblings(*data_tree); *data_tree = NULL; } cleanup: if (NULL != string_val) { free(string_val); } if (NULL != value) { sr_free_val(value); } if (NULL != iter) { sr_free_val_iter(iter); } return rc; }
/** * @brief Initializes libyang ctx with all schemas installed for specified module in sysrepo. */ static int srcfg_ly_init(struct ly_ctx **ly_ctx, const char *module_name) { DIR *dp = NULL; struct dirent *ep = NULL; char *delim = NULL; char schema_filename[PATH_MAX] = { 0, }; const struct lys_module *module = NULL; CHECK_NULL_ARG2(ly_ctx, module_name); *ly_ctx = ly_ctx_new(srcfg_schema_search_dir); if (NULL == *ly_ctx) { SR_LOG_ERR("Unable to initialize libyang context: %s", ly_errmsg()); return SR_ERR_INTERNAL; } ly_set_log_clb(srcfg_ly_log_cb, 1); /* iterate over all files in the directory with schemas */ dp = opendir(srcfg_schema_search_dir); if (NULL == dp) { SR_LOG_ERR("Failed to open the schema directory: %s.", sr_strerror_safe(errno)); return SR_ERR_INTERNAL; } while (NULL != (ep = readdir(dp))) { /* test file extension */ LYS_INFORMAT fmt = LYS_IN_UNKNOWN; if (sr_str_ends_with(ep->d_name, SR_SCHEMA_YIN_FILE_EXT)) { fmt = LYS_IN_YIN; } else if (sr_str_ends_with(ep->d_name, SR_SCHEMA_YANG_FILE_EXT)) { fmt = LYS_IN_YANG; } if (fmt != LYS_IN_UNKNOWN) { /* strip extension and revision */ strcpy(schema_filename, ep->d_name); delim = strrchr(schema_filename, '.'); assert(delim); *delim = '\0'; delim = strrchr(schema_filename, '@'); if (delim) { *delim = '\0'; } /* TODO install all revisions and dependencies of the specified module, but not more */ #if 0 /* XXX install all schemas until we can resolve all dependencies */ if (strcmp(schema_filename, module_name) == 0) { #endif /* construct full file path */ snprintf(schema_filename, PATH_MAX, "%s%s", srcfg_schema_search_dir, ep->d_name); /* load the schema into the context */ SR_LOG_DBG("Loading module schema: '%s'.", schema_filename); module = lys_parse_path(*ly_ctx, schema_filename, fmt); if (NULL == module) { continue; } for (uint8_t i = 0; i < module->features_size; i++) { lys_features_enable(module, module->features[i].name); } #if 0 } #endif } } closedir(dp); return SR_ERR_OK; }
static void test_parse_noncharacters_xml(void **state) { struct state *st; const char* mod = "module x {namespace urn:x; prefix x; leaf x { type string;}}"; const char* data = "<x xmlns=\"urn:x\">----------</x>"; assert_ptr_not_equal(((*state) = st = calloc(1, sizeof *st)), NULL); assert_ptr_not_equal((st->ctx = ly_ctx_new(NULL)), NULL); /* test detection of invalid characters according to RFC 7950, sec 9.4 */ assert_ptr_not_equal(lys_parse_mem(st->ctx, mod, LYS_IN_YANG), 0); assert_ptr_not_equal((st->str1 = strdup(data)), NULL); /* exclude surrogate blocks 0xD800-DFFF - trying 0xd800 */ st->str1[17] = 0xed; st->str1[18] = 0xa0; st->str1[19] = 0x80; assert_ptr_equal(lyd_parse_mem(st->ctx, st->str1, LYD_XML, LYD_OPT_CONFIG), NULL); assert_int_equal(ly_errno, LY_EVALID); assert_int_equal(ly_vecode, LYVE_XML_INCHAR); assert_string_equal(ly_errmsg(), "Invalid UTF-8 value 0x0000d800"); /* exclude noncharacters %xFDD0-FDEF - trying 0xfdd0 */ st->str1[17] = 0xef; st->str1[18] = 0xb7; st->str1[19] = 0x90; assert_ptr_equal(lyd_parse_mem(st->ctx, st->str1, LYD_XML, LYD_OPT_CONFIG), NULL); assert_int_equal(ly_errno, LY_EVALID); assert_int_equal(ly_vecode, LYVE_XML_INCHAR); assert_string_equal(ly_errmsg(), "Invalid UTF-8 value 0x0000fdd0"); /* exclude noncharacters %xFFFE-FFFF - trying 0xfffe */ st->str1[17] = 0xef; st->str1[18] = 0xbf; st->str1[19] = 0xbe; assert_ptr_equal(lyd_parse_mem(st->ctx, st->str1, LYD_XML, LYD_OPT_CONFIG), NULL); assert_int_equal(ly_errno, LY_EVALID); assert_int_equal(ly_vecode, LYVE_XML_INCHAR); assert_string_equal(ly_errmsg(), "Invalid UTF-8 value 0x0000fffe"); /* exclude c0 control characters except tab, carriage return and line feed */ st->str1[17] = 0x9; /* valid - horizontal tab */ st->str1[18] = 0xa; /* valid - new line */ st->str1[19] = 0xd; /* valid - carriage return */ st->str1[20] = 0x6; /* invalid - ack */ assert_ptr_equal(lyd_parse_mem(st->ctx, st->str1, LYD_XML, LYD_OPT_CONFIG), NULL); assert_int_equal(ly_errno, LY_EVALID); assert_int_equal(ly_vecode, LYVE_XML_INCHAR); assert_string_equal(ly_errmsg(), "Invalid UTF-8 value 0x06"); /* exclude noncharacters %x?FFFE-?FFFF - trying 0x10ffff */ st->str1[17] = 0xf4; st->str1[18] = 0x8f; st->str1[19] = 0xbf; st->str1[20] = 0xbf; assert_ptr_equal(lyd_parse_mem(st->ctx, st->str1, LYD_XML, LYD_OPT_CONFIG), NULL); assert_int_equal(ly_errno, LY_EVALID); assert_int_equal(ly_vecode, LYVE_XML_INCHAR); assert_string_equal(ly_errmsg(), "Invalid UTF-8 value 0x0010ffff"); /* 0x6 */ st->str1[17] = '&'; st->str1[18] = '#'; st->str1[19] = 'x'; st->str1[20] = '6'; st->str1[21] = ';'; assert_ptr_equal(lyd_parse_mem(st->ctx, st->str1, LYD_XML, LYD_OPT_CONFIG), NULL); assert_int_equal(ly_errno, LY_EVALID); assert_int_equal(ly_vecode, LYVE_XML_INVAL); assert_string_equal(ly_errmsg(), "Invalid character reference value."); /* 0xdfff */ st->str1[17] = '&'; st->str1[18] = '#'; st->str1[19] = 'x'; st->str1[20] = 'd'; st->str1[21] = 'f'; st->str1[22] = 'f'; st->str1[23] = 'f'; st->str1[24] = ';'; assert_ptr_equal(lyd_parse_mem(st->ctx, st->str1, LYD_XML, LYD_OPT_CONFIG), NULL); assert_int_equal(ly_errno, LY_EVALID); assert_int_equal(ly_vecode, LYVE_XML_INVAL); assert_string_equal(ly_errmsg(), "Invalid character reference value."); /* 0xfdef */ st->str1[17] = '&'; st->str1[18] = '#'; st->str1[19] = 'x'; st->str1[20] = 'f'; st->str1[21] = 'd'; st->str1[22] = 'e'; st->str1[23] = 'f'; st->str1[24] = ';'; assert_ptr_equal(lyd_parse_mem(st->ctx, st->str1, LYD_XML, LYD_OPT_CONFIG), NULL); assert_int_equal(ly_errno, LY_EVALID); assert_int_equal(ly_vecode, LYVE_XML_INVAL); assert_string_equal(ly_errmsg(), "Invalid character reference value."); /* 0xffff */ st->str1[17] = '&'; st->str1[18] = '#'; st->str1[19] = 'x'; st->str1[20] = 'f'; st->str1[21] = 'f'; st->str1[22] = 'f'; st->str1[23] = 'f'; st->str1[24] = ';'; assert_ptr_equal(lyd_parse_mem(st->ctx, st->str1, LYD_XML, LYD_OPT_CONFIG), NULL); assert_int_equal(ly_errno, LY_EVALID); assert_int_equal(ly_vecode, LYVE_XML_INVAL); assert_string_equal(ly_errmsg(), "Invalid character reference value."); /* the same using character reference */ /* 0x10ffff */ st->str1[17] = '&'; st->str1[18] = '#'; st->str1[19] = 'x'; st->str1[20] = '1'; st->str1[21] = '0'; st->str1[22] = 'f'; st->str1[23] = 'f'; st->str1[24] = 'f'; st->str1[25] = 'f'; st->str1[26] = ';'; assert_ptr_equal(lyd_parse_mem(st->ctx, st->str1, LYD_XML, LYD_OPT_CONFIG), NULL); assert_int_equal(ly_errno, LY_EVALID); assert_int_equal(ly_vecode, LYVE_XML_INVAL); assert_string_equal(ly_errmsg(), "Invalid character reference value."); }