summaryrefslogtreecommitdiffstats
path: root/pcilib/xml.c
diff options
context:
space:
mode:
Diffstat (limited to 'pcilib/xml.c')
-rw-r--r--pcilib/xml.c230
1 files changed, 151 insertions, 79 deletions
diff --git a/pcilib/xml.c b/pcilib/xml.c
index 1238ba8..bc48a34 100644
--- a/pcilib/xml.c
+++ b/pcilib/xml.c
@@ -78,6 +78,17 @@ static xmlNodePtr pcilib_xml_get_parent_register_node(xmlDocPtr doc, xmlNodePtr
}
*/
+int pcilib_get_xml_attr(pcilib_t *ctx, pcilib_xml_node_t *node, const char *attr, pcilib_value_t *val) {
+ xmlAttr *prop;
+ xmlChar *str;
+
+ prop = xmlHasProp(node, BAD_CAST attr);
+ if ((!prop)||(!prop->children)) return PCILIB_ERROR_NOTFOUND;
+
+ str = prop->children->content;
+ return pcilib_set_value_from_static_string(ctx, val, (const char*)str);
+}
+
static int pcilib_xml_parse_view_reference(pcilib_t *ctx, xmlDocPtr doc, xmlNodePtr node, pcilib_view_reference_t *desc) {
xmlAttr *cur;
char *value, *name;
@@ -873,11 +884,14 @@ static int pcilib_xml_process_document(pcilib_t *ctx, xmlDocPtr doc, xmlXPathCon
return 0;
}
-static int pcilib_xml_load_xsd(pcilib_t *ctx, char *xsd_filename) {
+static int pcilib_xml_load_xsd_file(pcilib_t *ctx, char *xsd_filename, xmlSchemaPtr *schema, xmlSchemaValidCtxtPtr *validator) {
int err;
xmlSchemaParserCtxtPtr ctxt;
+ *schema = NULL;
+ *validator = NULL;
+
/** we first parse the xsd file for AST with validation*/
ctxt = xmlSchemaNewParserCtxt(xsd_filename);
if (!ctxt) {
@@ -887,8 +901,8 @@ static int pcilib_xml_load_xsd(pcilib_t *ctx, char *xsd_filename) {
return PCILIB_ERROR_FAILED;
}
- ctx->xml.schema = xmlSchemaParse(ctxt);
- if (!ctx->xml.schema) {
+ *schema = xmlSchemaParse(ctxt);
+ if (!*schema) {
xmlErrorPtr xmlerr = xmlGetLastError();
xmlSchemaFreeParserCtxt(ctxt);
if (xmlerr) pcilib_error("Failed to parse XML schema, xmlSchemaParse reported error %d - %s", xmlerr->code, xmlerr->message);
@@ -898,15 +912,15 @@ static int pcilib_xml_load_xsd(pcilib_t *ctx, char *xsd_filename) {
xmlSchemaFreeParserCtxt(ctxt);
- ctx->xml.validator = xmlSchemaNewValidCtxt(ctx->xml.schema);
- if (!ctx->xml.validator) {
+ *validator = xmlSchemaNewValidCtxt(*schema);
+ if (!*validator) {
xmlErrorPtr xmlerr = xmlGetLastError();
if (xmlerr) pcilib_error("xmlSchemaNewValidCtxt reported error %d - %s", xmlerr->code, xmlerr->message);
else pcilib_error("Failed to create a validation context");
return PCILIB_ERROR_FAILED;
}
- err = xmlSchemaSetValidOptions(ctx->xml.validator, XML_SCHEMA_VAL_VC_I_CREATE);
+ err = xmlSchemaSetValidOptions(*validator, XML_SCHEMA_VAL_VC_I_CREATE);
if (err) {
xmlErrorPtr xmlerr = xmlGetLastError();
if (xmlerr) pcilib_error("xmlSchemaSetValidOptions reported error %d - %s", xmlerr->code, xmlerr->message);
@@ -917,16 +931,45 @@ static int pcilib_xml_load_xsd(pcilib_t *ctx, char *xsd_filename) {
return 0;
}
-static int pcilib_xml_load_file(pcilib_t *ctx, const char *path, const char *name) {
+
+static int pcilib_xml_load_xsd(pcilib_t *ctx, char *model_dir) {
+ int err;
+
+ struct stat st;
+ char *xsd_path;
+
+ xsd_path = (char*)alloca(strlen(model_dir) + 32);
+ if (!xsd_path) return PCILIB_ERROR_MEMORY;
+
+ sprintf(xsd_path, "%s/model.xsd", model_dir);
+ if (stat(xsd_path, &st)) {
+ pcilib_info("XML models are not present, missing parts schema");
+ return PCILIB_ERROR_NOTFOUND;
+ }
+
+ err = pcilib_xml_load_xsd_file(ctx, xsd_path, &ctx->xml.parts_schema, &ctx->xml.parts_validator);
+ if (err) return err;
+
+ sprintf(xsd_path, "%s/references.xsd", model_dir);
+ if (stat(xsd_path, &st)) {
+ pcilib_info("XML models are not present, missing schema");
+ return PCILIB_ERROR_NOTFOUND;
+ }
+
+ return pcilib_xml_load_xsd_file(ctx, xsd_path, &ctx->xml.schema, &ctx->xml.validator);
+}
+
+
+
+static xmlDocPtr pcilib_xml_load_file(pcilib_t *ctx, const char *path, const char *name) {
int err;
char *full_name;
xmlDocPtr doc;
- xmlXPathContextPtr xpath;
full_name = (char*)alloca(strlen(path) + strlen(name) + 2);
if (!name) {
pcilib_error("Error allocating %zu bytes of memory in stack to create a file name", strlen(path) + strlen(name) + 2);
- return PCILIB_ERROR_MEMORY;
+ return NULL;
}
sprintf(full_name, "%s/%s", path, name);
@@ -936,104 +979,139 @@ static int pcilib_xml_load_file(pcilib_t *ctx, const char *path, const char *nam
xmlErrorPtr xmlerr = xmlCtxtGetLastError(ctx->xml.parser);
if (xmlerr) pcilib_error("Error parsing %s, xmlCtxtReadFile reported error %d - %s", full_name, xmlerr->code, xmlerr->message);
else pcilib_error("Error parsing %s", full_name);
- return PCILIB_ERROR_INVALID_DATA;
+ return NULL;
}
- err = xmlSchemaValidateDoc(ctx->xml.validator, doc);
+ err = xmlSchemaValidateDoc(ctx->xml.parts_validator, doc);
if (err) {
xmlErrorPtr xmlerr = xmlCtxtGetLastError(ctx->xml.parser);
xmlFreeDoc(doc);
if (xmlerr) pcilib_error("Error validating %s, xmlSchemaValidateDoc reported error %d - %s", full_name, xmlerr->code, xmlerr->message);
else pcilib_error("Error validating %s", full_name);
- return PCILIB_ERROR_VERIFY;
- }
-
- xpath = xmlXPathNewContext(doc);
- if (!xpath) {
- xmlErrorPtr xmlerr = xmlGetLastError();
- xmlFreeDoc(doc);
- if (xmlerr) pcilib_error("Document %s: xmlXpathNewContext reported error %d - %s for document %s", full_name, xmlerr->code, xmlerr->message);
- else pcilib_error("Error creating XPath context for %s", full_name);
- return PCILIB_ERROR_FAILED;
- }
-
- // This can only partially fail... Therefore we need to keep XML and just return the error...
- err = pcilib_xml_process_document(ctx, doc, xpath);
-
- if (ctx->xml.num_files == PCILIB_MAX_MODEL_FILES) {
- xmlFreeDoc(doc);
- xmlXPathFreeContext(xpath);
- pcilib_error("Too many XML files for a model, only up to %zu are supported", PCILIB_MAX_MODEL_FILES);
- return PCILIB_ERROR_TOOBIG;
+ return NULL;
}
- ctx->xml.docs[ctx->xml.num_files] = doc;
- ctx->xml.xpath[ctx->xml.num_files] = xpath;
- ctx->xml.num_files++;
-
- return err;
+ return doc;
}
-
-int pcilib_process_xml(pcilib_t *ctx, const char *location) {
+static int pcilib_process_xml_internal(pcilib_t *ctx, const char *model, const char *location) {
int err;
DIR *rep;
struct dirent *file = NULL;
char *model_dir, *model_path;
+ xmlDocPtr doc = NULL;
+ xmlNodePtr root = NULL;
+ xmlXPathContextPtr xpath;
+
+ if (ctx->xml.num_files == PCILIB_MAX_MODEL_FILES) {
+ pcilib_error("Too many XML locations for a model, only up to %zu are supported", PCILIB_MAX_MODEL_FILES);
+ return PCILIB_ERROR_TOOBIG;
+ }
+
model_dir = getenv("PCILIB_MODEL_DIR");
if (!model_dir) model_dir = PCILIB_MODEL_DIR;
- model_path = (char*)alloca(strlen(model_dir) + strlen(location) + 2);
+ if (!model) model = ctx->model;
+ if (!location) location = "";
+
+ model_path = (char*)alloca(strlen(model_dir) + strlen(model) + strlen(location) + 3);
if (!model_path) return PCILIB_ERROR_MEMORY;
- sprintf(model_path, "%s/%s", model_dir, location);
+ sprintf(model_path, "%s/%s/%s", model_dir, model, location);
rep = opendir(model_path);
if (!rep) return PCILIB_ERROR_NOTFOUND;
while ((file = readdir(rep)) != NULL) {
+ xmlDocPtr newdoc;
+
size_t len = strlen(file->d_name);
if ((len < 4)||(strcasecmp(file->d_name + len - 4, ".xml"))) continue;
if (file->d_type != DT_REG) continue;
- err = pcilib_xml_load_file(ctx, model_path, file->d_name);
- if (err) pcilib_error("Error processing XML file %s", file->d_name);
- }
+ newdoc = pcilib_xml_load_file(ctx, model_path, file->d_name);
+ if (!newdoc) {
+ pcilib_error("Error processing XML file %s", file->d_name);
+ continue;
+ }
+
+ if (doc) {
+ xmlNodePtr node;
+ node = xmlDocGetRootElement(newdoc);
+ if (node) node = xmlFirstElementChild(node);
+ if (node) node = xmlDocCopyNodeList(doc, node);
+ xmlFreeDoc(newdoc);
+
+ if ((!node)||(!xmlAddChildList(root, node))) {
+ xmlErrorPtr xmlerr = xmlCtxtGetLastError(ctx->xml.parser);
+ if (node) xmlFreeNode(node);
+ if (xmlerr) pcilib_error("Error manipulating XML tree of %s, libXML2 reported error %d - %s", file->d_name, xmlerr->code, xmlerr->message);
+ else pcilib_error("Error manipulating XML tree of %s", file->d_name);
+ continue;
+ }
+ } else {
+ root = xmlDocGetRootElement(newdoc);
+ if (!root) {
+ xmlErrorPtr xmlerr = xmlCtxtGetLastError(ctx->xml.parser);
+ xmlFreeDoc(newdoc);
+ if (xmlerr) pcilib_error("Error manipulating XML tree of %s, libXML2 reported error %d - %s", file->d_name, xmlerr->code, xmlerr->message);
+ else pcilib_error("Error manipulating XML tree of %s", file->d_name);
+ continue;
+ }
+ doc = newdoc;
+ // This is undocumented, but should be fine...
+ if (doc->URL) xmlFree((xmlChar*)doc->URL);
+ doc->URL = xmlStrdup(BAD_CAST model_path);
+ }
+ }
closedir(rep);
- return 0;
+ if (!doc)
+ return 0;
+
+ err = xmlSchemaValidateDoc(ctx->xml.validator, doc);
+ if (err) {
+ xmlErrorPtr xmlerr = xmlCtxtGetLastError(ctx->xml.parser);
+ xmlFreeDoc(doc);
+ if (xmlerr) pcilib_error("Error validating %s, xmlSchemaValidateDoc reported error %d - %s", model_path, xmlerr->code, xmlerr->message);
+ else pcilib_error("Error validating %s", model_path);
+ return PCILIB_ERROR_VERIFY;
+ }
+
+ xpath = xmlXPathNewContext(doc);
+ if (!xpath) {
+ xmlErrorPtr xmlerr = xmlGetLastError();
+ xmlFreeDoc(doc);
+ if (xmlerr) pcilib_error("Document %s: xmlXpathNewContext reported error %d - %s for document %s", model_path, xmlerr->code, xmlerr->message);
+ else pcilib_error("Error creating XPath context for %s", model_path);
+ return PCILIB_ERROR_FAILED;
+ }
+
+ // This can only partially fail... Therefore we need to keep XML and just return the error...
+ err = pcilib_xml_process_document(ctx, doc, xpath);
+
+ ctx->xml.docs[ctx->xml.num_files] = doc;
+ ctx->xml.xpath[ctx->xml.num_files] = xpath;
+ ctx->xml.num_files++;
+
+ return err;
}
+int pcilib_process_xml(pcilib_t *ctx, const char *location) {
+ return pcilib_process_xml_internal(ctx, NULL, location);
+}
-/** pcilib_init_xml
- * this function will initialize the registers and banks from the xml files
- * @param[in,out] ctx the pciilib_t running that gets filled with structures
- * @param[in] model the current model of ctx
- * @return an error code
- */
int pcilib_init_xml(pcilib_t *ctx, const char *model) {
int err;
char *model_dir;
- char *xsd_path;
-
- struct stat st;
model_dir = getenv("PCILIB_MODEL_DIR");
if (!model_dir) model_dir = PCILIB_MODEL_DIR;
- xsd_path = (char*)alloca(strlen(model_dir) + 16);
- if (!xsd_path) return PCILIB_ERROR_MEMORY;
-
- sprintf(xsd_path, "%s/model.xsd", model_dir);
- if (stat(xsd_path, &st)) {
- pcilib_info("XML models are not present");
- return PCILIB_ERROR_NOTFOUND;
- }
-
ctx->xml.parser = xmlNewParserCtxt();
if (!ctx->xml.parser) {
xmlErrorPtr xmlerr = xmlGetLastError();
@@ -1042,16 +1120,12 @@ int pcilib_init_xml(pcilib_t *ctx, const char *model) {
return PCILIB_ERROR_FAILED;
}
- err = pcilib_xml_load_xsd(ctx, xsd_path);
+ err = pcilib_xml_load_xsd(ctx, model_dir);
if (err) return err;
- return pcilib_process_xml(ctx, model);
+ return pcilib_process_xml_internal(ctx, model, NULL);
}
-/** pcilib_free_xml
- * this function free the xml parts of the pcilib_t running, and some libxml ashes
- * @param[in] pci the pcilib_t running
-*/
void pcilib_free_xml(pcilib_t *ctx) {
int i;
@@ -1085,7 +1159,16 @@ void pcilib_free_xml(pcilib_t *ctx) {
if (ctx->xml.schema) {
xmlSchemaFree(ctx->xml.schema);
ctx->xml.schema = NULL;
+ }
+
+ if (ctx->xml.parts_validator) {
+ xmlSchemaFreeValidCtxt(ctx->xml.parts_validator);
+ ctx->xml.parts_validator = NULL;
+ }
+ if (ctx->xml.parts_schema) {
+ xmlSchemaFree(ctx->xml.parts_schema);
+ ctx->xml.parts_schema = NULL;
}
if (ctx->xml.parser) {
@@ -1099,14 +1182,3 @@ void pcilib_free_xml(pcilib_t *ctx) {
xmlMemoryDump();
*/
}
-
-int pcilib_get_xml_attr(pcilib_t *ctx, pcilib_xml_node_t *node, const char *attr, pcilib_value_t *val) {
- xmlAttr *prop;
- xmlChar *str;
-
- prop = xmlHasProp(node, BAD_CAST attr);
- if ((!prop)||(!prop->children)) return PCILIB_ERROR_NOTFOUND;
-
- str = prop->children->content;
- return pcilib_set_value_from_static_string(ctx, val, (const char*)str);
-}