//=-------------------------------------------------------------------------=// // XML parsing module // // // // Copyright © 2021 The Gem-graph Project // // // // This file is part of gem-graph. // // // // This program is free software: you can redistribute it and/or modify // // it under the terms of the GNU Affero General Public License as // // published by the Free Software Foundation, either version 3 of the // // License, or (at your option) any later version. // // // // This program is distributed in the hope that it will be useful, // // but WITHOUT ANY WARRANTY; without even the implied warranty of // // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // // GNU Affero General Public License for more details. // // // // You should have received a copy of the GNU Affero General Public License // // along with this program. If not, see . // //=-------------------------------------------------------------------------=// #include "../include/base.h" #include "../include/model.h" #include #include #include /* -------------------------------------------------------------------------- */ #define NO_DESTINATION NULL /* -------------------------------------------------------------------------- */ struct ModelParserTableXML_t; struct ParserTableXML_t { const xmlChar *tag; int (*parse) (xmlDoc*, struct ModelParserTableXML_t*, int currentParser, xmlNode*); void *destination; } typedef ParserTableXML_t; struct ModelParserTableXML_t { size_t len; ParserTableXML_t *table; } typedef ModelParserTableXML_t; /* -------------------------------------------------------------------------- */ int parseParentFieldXML(xmlDocPtr, ModelParserTableXML_t*, int, xmlNodePtr); int parseTextField(xmlDocPtr, ModelParserTableXML_t*, int, xmlNodePtr); /* -------------------------------------------------------------------------- */ // -------------------------------------------------------------------------- // // Parsing NOTHING (but yeah that prints) // // -------------------------------------------------------------------------- // int parseStubFieldXML (xmlDocPtr doc, ModelParserTableXML_t *ModelTable, int currentParser, xmlNodePtr currentNode) { xmlChar *content, *contentText, *contentValueAttribute; contentText = xmlNodeListGetString(doc, currentNode->xmlChildrenNode, 1); contentValueAttribute = xmlGetProp(currentNode, (xmlChar*)"value"); if (contentText) { content = contentText; } else if (contentValueAttribute) { content = contentValueAttribute; // Detect children if (currentNode->xmlChildrenNode) { printLog("%s has children\n", ModelTable->table[currentParser].tag); } } printLog("%s: %s\n", ModelTable->table[currentParser].tag, content); if (!content) { xmlFree(contentText); xmlFree(contentValueAttribute); return -1; } xmlFree(contentText); xmlFree(contentValueAttribute); return 0; } // -------------------------------------------------------------------------- // // Parsing a text field // // -------------------------------------------------------------------------- // int parseTextFieldXML (xmlDocPtr doc, ModelParserTableXML_t *ModelTable, int currentParser, xmlNodePtr currentNode) { xmlChar *content, *contentText, *contentValueAttribute; char *destination = (char*)ModelTable->table[currentParser].destination; contentText = xmlNodeListGetString(doc, currentNode->xmlChildrenNode, 1); contentValueAttribute = xmlGetProp(currentNode, (xmlChar*)"value"); if (contentText) { content = contentText; } else if (contentValueAttribute) { content = contentValueAttribute; // Detect children if (currentNode->xmlChildrenNode) { printLog("%s has children\n", ModelTable->table[currentParser].tag); } } printLog("%s: %s\n", ModelTable->table[currentParser].tag, content); if (!content) { xmlFree(contentText); xmlFree(contentValueAttribute); return -1; } strcat(destination, " "); strncpy(destination + strlen(destination), (char *)content, MODEL_STRING_SIZE - strlen(destination)); xmlFree(contentText); xmlFree(contentValueAttribute); return 0; } // -------------------------------------------------------------------------- // // Parsing an integer field // // -------------------------------------------------------------------------- // int parseIntFieldXML (xmlDocPtr doc, ModelParserTableXML_t *ModelTable, int currentParser, xmlNodePtr currentNode) { xmlChar *content, *contentText, *contentValueAttribute; int *destination = (int*)ModelTable->table[currentParser].destination; contentText = xmlNodeListGetString(doc, currentNode->xmlChildrenNode, 1); contentValueAttribute = xmlGetProp(currentNode, (xmlChar*)"value"); if (contentText) { content = contentText; } else if (contentValueAttribute) { content = contentValueAttribute; // Detect children if (currentNode->xmlChildrenNode) { printLog("%s has children\n", ModelTable->table[currentParser].tag); } } printLog("%s: %s\n", ModelTable->table[currentParser].tag, content); if (!content) { xmlFree(contentText); xmlFree(contentValueAttribute); return -1; } *destination = (int)atoi((char*)content); xmlFree(content); return 0; } // -------------------------------------------------------------------------- // // Parsing a field that contains children fields // // -------------------------------------------------------------------------- // int parseParentFieldXML (xmlDocPtr doc, ModelParserTableXML_t *ModelTable, int currentParser, xmlNodePtr currentNode) { currentNode = currentNode->xmlChildrenNode; printLog("%s parsed\n", ModelTable->table[currentParser].tag); while (currentNode != NULL) { for (int i = 0; i < ModelTable->len; i++) { if ((!xmlStrcmp(currentNode->name, ModelTable->table[i].tag))) { ModelTable->table[i].parse(doc, ModelTable, i, currentNode); break; } } currentNode = currentNode->next; } return 0; } // -------------------------------------------------------------------------- // // Parsing a model file // // -------------------------------------------------------------------------- // int ParseModelXML(Model_t *model) { ParserTableXML_t table[] = { // IDENTITY {(const xmlChar *)"identity", parseParentFieldXML,model}, {(const xmlChar *)"name", parseTextFieldXML, model->name}, {(const xmlChar *)"owner", parseTextFieldXML, model->owner}, // TODO lacking implementation (model side) {(const xmlChar *)"owner_id", parseStubFieldXML, model->owner_id}, {(const xmlChar *)"date", parseIntFieldXML, &model->date}, {(const xmlChar *)"version", parseTextFieldXML, model->version}, // PARAMETERS {(const xmlChar *)"parameters", parseParentFieldXML, model}, // MODELIZATION {(const xmlChar *)"modelization", parseParentFieldXML, model}, {(const xmlChar *)"max_thread", parseStubFieldXML, model}, {(const xmlChar *)"max_cycles", parseStubFieldXML, model}, // SPACE {(const xmlChar *)"space", parseParentFieldXML, model}, {(const xmlChar *)"dimension", parseStubFieldXML, model}, {(const xmlChar *)"size", parseStubFieldXML, model}, {(const xmlChar *)"site_multiplicity", parseStubFieldXML, model}, // TODO lacking implementation (model side) {(const xmlChar *)"boundaries", parseStubFieldXML, model}, // OBJECTS {(const xmlChar *)"objects", parseParentFieldXML, model}, {(const xmlChar *)"object", parseParentFieldXML, model}, // SPACE {(const xmlChar *)"space", parseParentFieldXML, model}, // SAVESTATES {(const xmlChar *)"savestates", parseParentFieldXML, model}, // TRANSITIONS {(const xmlChar *)"transitions", parseParentFieldXML, model}, // TRANSITION // TODO probability {(const xmlChar *)"transition", parseParentFieldXML, model}, {(const xmlChar *)"if", parseParentFieldXML, model}, {(const xmlChar *)"then", parseParentFieldXML, model}, // ARROW {(const xmlChar *)"arrow", parseStubFieldXML, model}, // REF {(const xmlChar *)"ref", parseStubFieldXML, model}, // QUOTE {(const xmlChar *)"quote", parseStubFieldXML, model}, }; ModelParserTableXML_t modelParserTable = { LEN(table), &table[0] }; printLog("Parsing model %s\n", model->name); xmlDocPtr xmlDocument; xmlNodePtr currentNode; xmlDocument = xmlParseFile(model->filename); if (xmlDocument == NULL) { printLog("Can't parse model file at '%s'.\n", model->filename); return -1; } currentNode = xmlDocGetRootElement(xmlDocument); if (currentNode == NULL) { printLog("Invalid model file at '%s', document empty !\n", model->filename); xmlFreeDoc(xmlDocument); return -2; } if (xmlStrcmp(currentNode->name, (const xmlChar *) "gem-graph-model")) { printLog("Invalid model file at '%s', " "root node is not !\n", model->filename); xmlFreeDoc(xmlDocument); return -3; } currentNode = currentNode->xmlChildrenNode; while (currentNode != NULL) { for (int i = 0; i < modelParserTable.len; i++) { if ((!xmlStrcmp(currentNode->name, modelParserTable.table[i].tag))) { modelParserTable.table[i].parse(xmlDocument, &modelParserTable, i, currentNode); } } currentNode = currentNode->next; } xmlFreeDoc(xmlDocument); // validate when we're finished model->validated = true; return 0; }