Implement xml export / import #3
@ -395,6 +395,7 @@ int main(int argc, char **argv)
|
|||||||
elfpatch_handle_t *ep;
|
elfpatch_handle_t *ep;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
uint32_t *crcs = NULL;
|
uint32_t *crcs = NULL;
|
||||||
|
struct xml_crc_import *import_data = NULL;
|
||||||
|
|
||||||
xml_init();
|
xml_init();
|
||||||
|
|
||||||
@ -477,7 +478,7 @@ int main(int argc, char **argv)
|
|||||||
ret = -3;
|
ret = -3;
|
||||||
}
|
}
|
||||||
/* Fix this: */
|
/* Fix this: */
|
||||||
(void)xml_import_from_file(cmd_opts.export_xml);
|
import_data = xml_import_from_file(cmd_opts.export_xml);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -490,6 +491,8 @@ free_cmds:
|
|||||||
/* Free CRCs if necessary */
|
/* Free CRCs if necessary */
|
||||||
if (crcs)
|
if (crcs)
|
||||||
free(crcs);
|
free(crcs);
|
||||||
|
if (import_data)
|
||||||
|
xml_crc_import_free(import_data);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
198
src/xml.c
198
src/xml.c
@ -1,4 +1,5 @@
|
|||||||
#include <libxml/parser.h>
|
#include <libxml/parser.h>
|
||||||
|
#include <libxml/xpath.h>
|
||||||
#include <libxml/xmlIO.h>
|
#include <libxml/xmlIO.h>
|
||||||
#include <libxml/xinclude.h>
|
#include <libxml/xinclude.h>
|
||||||
#include <libxml/tree.h>
|
#include <libxml/tree.h>
|
||||||
@ -7,6 +8,8 @@
|
|||||||
#include <libxml/xmlreader.h>
|
#include <libxml/xmlreader.h>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <patchelfcrc/reporting.h>
|
#include <patchelfcrc/reporting.h>
|
||||||
#include <patchelfcrc/xml.h>
|
#include <patchelfcrc/xml.h>
|
||||||
@ -106,33 +109,6 @@ static struct xml_crc_import *xml_crc_import_alloc(void)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void recusive_node_iter(xmlNodePtr node, int level)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
xmlNodePtr iter;
|
|
||||||
xmlAttrPtr attr;
|
|
||||||
xmlChar *t;
|
|
||||||
|
|
||||||
for (i = level; i > 0; i--)
|
|
||||||
printf(" ");
|
|
||||||
|
|
||||||
if (node->content)
|
|
||||||
printf("Node <%s> (%d) >%s<", node->name, node->type, node->content);
|
|
||||||
else
|
|
||||||
printf("Node <%s> (%d)", node->name, node->type);
|
|
||||||
if (node->properties) {
|
|
||||||
for (attr = node->properties; attr; attr = attr->next) {
|
|
||||||
t = xmlNodeListGetString(node->doc, attr->children, 1);
|
|
||||||
printf(" %s=\"%s\"", attr->name, t);
|
|
||||||
xmlFree(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
for (iter = node->children; iter; iter = iter->next) {
|
|
||||||
recusive_node_iter(iter, level + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool validate_xml_doc(xmlDocPtr doc)
|
static bool validate_xml_doc(xmlDocPtr doc)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
@ -173,11 +149,143 @@ ret_none:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the content of a node specified by the xpath \p path
|
||||||
|
* @param path Xpath to search for
|
||||||
|
* @param xpath_ctx Context
|
||||||
|
* @param required Print error if not found
|
||||||
|
* @return NULL in case of error
|
||||||
|
* @return pointer to newly alloceted string data.
|
||||||
|
* @note Pointers retured from this function must be freed using xmlFree()
|
||||||
|
*/
|
||||||
|
static const char *get_node_content_from_xpath(const char *path, xmlXPathContextPtr xpath_ctx, bool required)
|
||||||
|
{
|
||||||
|
xmlXPathObjectPtr xpath_obj;
|
||||||
|
const char *ret = NULL;
|
||||||
|
|
||||||
|
xpath_obj = xmlXPathEvalExpression(BAD_CAST path, xpath_ctx);
|
||||||
|
if (xpath_obj) {
|
||||||
|
if (xmlXPathNodeSetIsEmpty(xpath_obj->nodesetval)) {
|
||||||
|
if (required)
|
||||||
|
print_err("Required XML path %s not found.\n", path);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
ret = (const char *)xmlNodeGetContent(xpath_obj->nodesetval->nodeTab[0]);
|
||||||
|
}
|
||||||
|
xmlXPathFreeObject(xpath_obj);
|
||||||
|
} else {
|
||||||
|
/* Error */
|
||||||
|
print_err("Error searching for path %s in XML. This is an error. Report this.\n", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convert a number string (either prefixed 0x hex or decimal) to a uint64
|
||||||
|
*
|
||||||
|
* In case of an error, the \p output remains untouched
|
||||||
|
*
|
||||||
|
* @param[in] data input data. 0 terminated
|
||||||
|
* @param[in] output Converted number.
|
||||||
|
* @return 0 if okay
|
||||||
|
* @return negative in case of error
|
||||||
|
*/
|
||||||
|
static int convert_number_string_to_uint(const char *data, uint64_t *output)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
uint64_t num;
|
||||||
|
char *endptr;
|
||||||
|
|
||||||
|
if (!data || !output)
|
||||||
|
return -1000;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
num = strtoull(data, &endptr, 0);
|
||||||
|
if (endptr == data) {
|
||||||
|
/* Error finding number */
|
||||||
|
print_err("Data %s in XML is not a valid number\n", data);
|
||||||
|
} else if (errno == ERANGE) {
|
||||||
|
print_err("Data %s in XML overflowed\n", data);
|
||||||
|
} else if (errno == EINVAL) {
|
||||||
|
print_err("Unspecified error converting '%s' to a number\n", data);
|
||||||
|
} else if (errno == 0 && data && *endptr != '\0') {
|
||||||
|
print_err("Data '%s' could not be fully parsed to a number. Part '%s' is irritating\n", data, endptr);
|
||||||
|
} else if (errno == 0 && data && *endptr == '\0') {
|
||||||
|
ret = 0;
|
||||||
|
*output = num;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the content of an xpath and convert it to a uint64_t
|
||||||
|
* @param[in] xpath Path to get content from
|
||||||
|
* @param[in] xpath_ctx Xpath context
|
||||||
|
* @param[out] output Number output. Remains untouched in case of an error
|
||||||
|
* @param required This xpath is required. Will turn on error reporting if it is not found.
|
||||||
|
* @return 0 if successful
|
||||||
|
* @return negative in case of an error
|
||||||
|
*/
|
||||||
|
static int get_uint64_from_xpath_content(const char *xpath, xmlXPathContextPtr xpath_ctx, uint64_t *output, bool required)
|
||||||
|
{
|
||||||
|
const char *data;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
data = get_node_content_from_xpath(xpath, xpath_ctx, required);
|
||||||
|
if (data) {
|
||||||
|
ret = convert_number_string_to_uint(data, output);
|
||||||
|
xmlFree((void *)data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the content of an xpath and convert it to a uint64_t
|
||||||
|
* @param[in] xpath Path to get content from
|
||||||
|
* @param[in] xpath_ctx Xpath context
|
||||||
|
* @param[out] output Number output. Remains untouched in case of an error
|
||||||
|
* @param required This xpath is required. Will turn on error reporting if it is not found.
|
||||||
|
* @return 0 if successful
|
||||||
|
* @return negative in case of an error
|
||||||
|
*/
|
||||||
|
static int get_uint32_from_xpath_content(const char *xpath, xmlXPathContextPtr xpath_ctx, uint32_t *output, bool required)
|
||||||
|
{
|
||||||
|
const char *data;
|
||||||
|
uint64_t tmp;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
data = get_node_content_from_xpath(xpath, xpath_ctx, required);
|
||||||
|
if (data) {
|
||||||
|
ret = convert_number_string_to_uint(data, &tmp);
|
||||||
|
xmlFree((void *)data);
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
if (tmp > UINT32_MAX) {
|
||||||
|
ret = -2;
|
||||||
|
print_err("Value in XML file at path '%s' is too large for uint32_t\n", xpath);
|
||||||
|
} else {
|
||||||
|
*output = (uint32_t)tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
struct xml_crc_import *xml_import_from_file(const char *path)
|
struct xml_crc_import *xml_import_from_file(const char *path)
|
||||||
{
|
{
|
||||||
struct xml_crc_import *ret = NULL;
|
struct xml_crc_import *ret = NULL;
|
||||||
xmlDocPtr doc;
|
xmlDocPtr doc;
|
||||||
xmlNodePtr root_node, settings_node, crc_node, iter;
|
xmlNodePtr root_node, settings_node, crc_node, iter;
|
||||||
|
xmlXPathContextPtr xpath_ctx = NULL;
|
||||||
|
uint64_t tmp_num64 = 0;
|
||||||
|
uint32_t tmp_num32 = 0;
|
||||||
|
const char *cptr;
|
||||||
|
|
||||||
if (!path)
|
if (!path)
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -198,15 +306,47 @@ struct xml_crc_import *xml_import_from_file(const char *path)
|
|||||||
goto ret_close_doc;
|
goto ret_close_doc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get xpath context */
|
||||||
|
xpath_ctx = xmlXPathNewContext(doc);
|
||||||
|
if (!xpath_ctx) {
|
||||||
|
goto ret_close_doc;
|
||||||
|
}
|
||||||
|
|
||||||
/* Allocate xml import structure */
|
/* Allocate xml import structure */
|
||||||
ret = xml_crc_import_alloc();
|
ret = xml_crc_import_alloc();
|
||||||
if (!ret)
|
if (!ret)
|
||||||
goto ret_close_doc;
|
goto ret_close_doc;
|
||||||
|
|
||||||
recusive_node_iter(root_node, 0);
|
|
||||||
|
|
||||||
|
/* Do not do extensive error handling. It is assured by the schema that the numbers are parsable */
|
||||||
|
(void)get_uint64_from_xpath_content("/patchelfcrc/settings/poly", xpath_ctx, &tmp_num64, true);
|
||||||
|
ret->crc_config.polynomial = tmp_num64;
|
||||||
|
|
||||||
|
(void)get_uint32_from_xpath_content("/patchelfcrc/settings/start", xpath_ctx, &tmp_num32, true);
|
||||||
|
ret->crc_config.start_value = tmp_num32;
|
||||||
|
|
||||||
|
(void)get_uint32_from_xpath_content("/patchelfcrc/settings/xor", xpath_ctx, &tmp_num32, true);
|
||||||
|
ret->crc_config.xor = tmp_num32;
|
||||||
|
|
||||||
|
cptr = get_node_content_from_xpath("/patchelfcrc/settings/rev", xpath_ctx, false);
|
||||||
|
if (cptr) {
|
||||||
|
xmlFree((void *)cptr);
|
||||||
|
ret->crc_config.rev = true;
|
||||||
|
} else {
|
||||||
|
ret->crc_config.rev = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
goto ret_close_doc;
|
||||||
|
|
||||||
|
ret_dealloc:
|
||||||
|
xml_crc_import_free(ret);
|
||||||
|
ret = NULL;
|
||||||
|
|
||||||
ret_close_doc:
|
ret_close_doc:
|
||||||
|
if (xpath_ctx)
|
||||||
|
xmlXPathFreeContext(xpath_ctx);
|
||||||
|
|
||||||
/* Free document and all of its children */
|
/* Free document and all of its children */
|
||||||
xmlFreeDoc(doc);
|
xmlFreeDoc(doc);
|
||||||
|
|
||||||
@ -214,6 +354,8 @@ ret_close_doc:
|
|||||||
xmlCleanupParser();
|
xmlCleanupParser();
|
||||||
ret_none:
|
ret_none:
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void free_xml_crc_entry(void *entry) {
|
static void free_xml_crc_entry(void *entry) {
|
||||||
|
Loading…
Reference in New Issue
Block a user