diff --git a/debian/var/models/schemas/example.xmls b/debian/var/models/schemas/model_0.1.xmls similarity index 100% rename from debian/var/models/schemas/example.xmls rename to debian/var/models/schemas/model_0.1.xmls diff --git a/include/base.h b/include/base.h index ee2155a..0b82901 100644 --- a/include/base.h +++ b/include/base.h @@ -37,6 +37,8 @@ #define LOGMSG "[%s]" #define printLog(FORMAT, ...) printf("\e[0m" LOGMSG " " FORMAT "\e[0m", \ __func__, ##__VA_ARGS__) +#define printErr(FORMAT,...) sprintf(stderr, "\e[0m" LOGMSG " " FORMAT "\e[0m",\ + __func__, ##__VA_ARGS__) #define LEN(x) (sizeof(x) / sizeof((x)[0])) /* -------------------------------------------------------------------------- */ diff --git a/include/parsing.h b/include/parsing.h index 6fe8bf6..9952b9a 100644 --- a/include/parsing.h +++ b/include/parsing.h @@ -27,6 +27,7 @@ #include #include #include +#include /* -------------------------------------------------------------------------- */ @@ -66,4 +67,6 @@ int parseTextField(xmlDocPtr, int ParseModelXML(Model_t*); +int ParseModelIdentityXML(Model_t*, Parameters_t*); + /* -------------------------------------------------------------------------- */ diff --git a/src/main.c b/src/main.c index 8a32941..6dd30b4 100644 --- a/src/main.c +++ b/src/main.c @@ -44,72 +44,66 @@ int main(int argc, char **argv) int options; time_t t; int returnValue = 0; - Parameters_t *parameters; - - // Get parameters TODO from args - parameters = (Parameters_t*) calloc(sizeof(Parameters_t), 1); + Parameters_t parameters; while ((options = getopt(argc, argv, ":C:M:U:")) != -1) { switch (options) { case 'C': printLog("Config : %s\n", optarg); - parameters->configDir = (char*) malloc(strlen(optarg) + 1); - strcpy(parameters->configDir, optarg); + parameters.configDir = (char*) calloc(1, strlen(optarg) + 1); + strcpy(parameters.configDir, optarg); break; case 'M': printLog("Models : %s\n", optarg); - parameters->modelDir = (char*) malloc(strlen(optarg) + 1); - strcpy(parameters->modelDir, optarg); + parameters.modelDir = (char*) calloc(1, strlen(optarg) + 1); + strcpy(parameters.modelDir, optarg); break; case 'U': printLog("User : %s\n", optarg); - parameters->userDir = (char*) malloc(strlen(optarg) + 1); - strcpy(parameters->userDir, optarg); + parameters.userDir = (char*) calloc(1, strlen(optarg) + 1); + strcpy(parameters.userDir, optarg); break; case ':': printLog("Option missing argument : %c\n", optopt); - if (parameters->configDir) - free(parameters->configDir); + if (parameters.configDir) + free(parameters.configDir); - if (parameters->modelDir) - free(parameters->modelDir); + if (parameters.modelDir) + free(parameters.modelDir); - if (parameters->userDir) - free(parameters->userDir); + if (parameters.userDir) + free(parameters.userDir); - free(parameters); return ENOSYS; break; case '?': printLog("Unknown option : %c\n", optopt); - if (parameters->configDir) - free(parameters->configDir); + if (parameters.configDir) + free(parameters.configDir); - if (parameters->modelDir) - free(parameters->modelDir); + if (parameters.modelDir) + free(parameters.modelDir); - if (parameters->userDir) - free(parameters->userDir); + if (parameters.userDir) + free(parameters.userDir); - free(parameters); return ENOSYS; break; } } - if (!parameters->configDir | !parameters->modelDir | !parameters->userDir) { + if (!parameters.configDir | !parameters.modelDir | !parameters.userDir) { printLog("Missing arguments\n"); - if (parameters->configDir) - free(parameters->configDir); + if (parameters.configDir) + free(parameters.configDir); - if (parameters->modelDir) - free(parameters->modelDir); + if (parameters.modelDir) + free(parameters.modelDir); - if (parameters->userDir) - free(parameters->userDir); + if (parameters.userDir) + free(parameters.userDir); - free(parameters); return ENOSYS; } @@ -127,7 +121,7 @@ int main(int argc, char **argv) server = (Server_t*) calloc(1, sizeof(Server_t)); // Initializing model system - ModelSystemInit(parameters); + ModelSystemInit(¶meters); // Launching server ServerInit(server); @@ -141,11 +135,9 @@ int main(int argc, char **argv) free(server); server = NULL; - free(parameters->userDir); - free(parameters->modelDir); - free(parameters->configDir); - free(parameters); - parameters = NULL; + free(parameters.userDir); + free(parameters.modelDir); + free(parameters.configDir); return returnValue; } diff --git a/src/model.c b/src/model.c index e5b4ae0..c9b816c 100644 --- a/src/model.c +++ b/src/model.c @@ -272,13 +272,17 @@ void ModelSystemInit(Parameters_t *parameters) extensionPosition - modelDirEntry->d_name); // Ask to parse the new model - if (ParseModelXML(newModel) != 0) { + if (ParseModelIdentityXML(newModel, parameters) != 0) { + printLog("Deleting invalid model %s from known list\n", + newModel->name); ModelDelete(newModel->id); continue; }; // Check model is valid and/or parsed if (newModel->validated == false) { + printLog("Deleting invalid model %s from known list\n", + newModel->name); ModelDelete(newModel->id); continue; } diff --git a/src/parsing.c b/src/parsing.c index 353b82a..480cdee 100644 --- a/src/parsing.c +++ b/src/parsing.c @@ -294,14 +294,22 @@ int parseParentFieldPropsXML (xmlDocPtr doc, } // -------------------------------------------------------------------------- // -// Parsing a model file // +// Preparsing a model file // // -------------------------------------------------------------------------- // -int ParseModelXML(Model_t *model) +int ParseModelIdentityXML(Model_t *model, Parameters_t *params) { + xmlDocPtr xmlDocument; + xmlNodePtr currentNode; + xmlChar *version = NULL; + xmlSchemaPtr schemPtr; + xmlSchemaValidCtxtPtr schemValidator; + xmlSchemaParserCtxtPtr schemFile; + char *schemPath; + ParserTableXML_t table[] = { // IDENTITY - {(const xmlChar *)"identity", parseParentFieldXML, model}, + {(const xmlChar *)"identity", parseParentFieldXML, NULL}, {(const xmlChar *)"name", parseTextFieldXML, model->name}, {(const xmlChar *)"owner", parseTextFieldXML, model->owner}, @@ -309,8 +317,149 @@ int ParseModelXML(Model_t *model) {(const xmlChar *)"owner_id", parseStubFieldXML, model->owner_id}, {(const xmlChar *)"date", parseIntFieldXML, &model->date}, - {(const xmlChar *)"version", parseTextFieldXML, model->version}, + {(const xmlChar *)"version", parseTextFieldXML, model->version} + }; + ModelParserTableXML_t identityParserTable = + { + LEN(table), + &table[0] + }; + + // Allocating space for schema file path + schemPath = (char*)calloc(1, strlen(params->modelDir) + + strlen("/schemas/model_x.x.xmls")); + + printLog("Preparsing model %s\n", model->name); + + // Opening document + xmlDocument = xmlParseFile(model->filename); + + if (xmlDocument == NULL) { + printLog("Can't parse model file at '%s'.\n", model->filename); + return -1; + } + + // Getting root from XML model file + currentNode = xmlDocGetRootElement(xmlDocument); + + if (currentNode == NULL) { + printLog("Invalid model file at '%s', document empty !\n", + model->filename); + xmlFreeDoc(xmlDocument); + free(schemPath); + return -2; + } + + // Checking that XML file is actually a model + if (xmlStrcmp(currentNode->name, (const xmlChar *) "gem-graph-model")) { + printLog("Invalid model file at '%s', " + "root node is not !\n", + model->filename); + xmlFreeDoc(xmlDocument); + free(schemPath); + return -3; + } + + // Get gem-graph model version to parse + version = xmlGetProp(currentNode, (xmlChar*)"version"); + // Check version is present + if (!version) { + printLog("Missing version for model %s \n", model->name); + xmlFreeDoc(xmlDocument); + free(schemPath); + return -4; + } else if (strlen((char*)version) > MODEL_STRING_SIZE) { + printLog("Invalid version number for model %s \n", model->name); + free(version); + xmlFreeDoc(xmlDocument); + free(schemPath); + } + printLog("Gem-graph model version %s detected\n", version); + + // Retrieving schema file + sprintf(schemPath, "%s/schemas/model_%s.xmls", params->modelDir, version); + printLog("Loading schema %s\n", schemPath); + + // Loading schema file + schemFile = xmlSchemaNewParserCtxt(schemPath); + if (schemFile == NULL) { + printLog("Invalid gem-graph version %s in model %s: no schema present", + version, model->name); + free(version); + xmlFreeDoc(xmlDocument); + free(schemPath); + return -5; + } + + // Loading schema file content + schemPtr = xmlSchemaParse(schemFile); + xmlSchemaFreeParserCtxt(schemFile); + if (schemPtr == NULL) { + printLog("Invalid schema file, version %s\n", version); + free(version); + xmlFreeDoc(xmlDocument); + free(schemPath); + return -6; + } + + // Creating validating context + schemValidator = xmlSchemaNewValidCtxt(schemPtr); + if (schemValidator == NULL) { + xmlSchemaFree(schemPtr); + free(version); + xmlFreeDoc(xmlDocument); + free(schemPath); + printLog("An error occured preparing schema file, version %s\n", version); + return -7; + } + + // Validate (and print errors) ! + xmlSchemaSetValidErrors(schemValidator, + (xmlSchemaValidityErrorFunc) fprintf, + (xmlSchemaValidityWarningFunc) fprintf, stderr); + + // Get the validation status + model->validated = + xmlSchemaValidateDoc(schemValidator, xmlDocument) == 0 ? true : false; + + // Reset node + currentNode = xmlDocGetRootElement(xmlDocument); + + // Parsing identity + currentNode = currentNode->xmlChildrenNode; + while (currentNode != NULL) { + for (int i = 0; i < identityParserTable.len; i++) { + if ((!xmlStrcmp(currentNode->name, + identityParserTable.table[i].tag))) { + identityParserTable.table[i].parse(xmlDocument, + &identityParserTable, + i, + currentNode); + } + } + currentNode = currentNode->next; + } + + xmlSchemaFreeValidCtxt(schemValidator); + xmlSchemaFree(schemPtr); + free(version); + xmlFreeDoc(xmlDocument); + free(schemPath); + + return 0; +} + +// -------------------------------------------------------------------------- // +// Parsing a model file // +// -------------------------------------------------------------------------- // +int ParseModelXML(Model_t *model) +{ + xmlDocPtr xmlDocument; + xmlNodePtr currentNode; + + ParserTableXML_t table[] = + { // PARAMETERS {(const xmlChar *)"parameters", parseParentFieldPropsXML, model}, // MODELIZATION @@ -361,8 +510,6 @@ int ParseModelXML(Model_t *model) }; printLog("Parsing model %s\n", model->name); - xmlDocPtr xmlDocument; - xmlNodePtr currentNode; xmlDocument = xmlParseFile(model->filename); @@ -405,7 +552,5 @@ int ParseModelXML(Model_t *model) xmlFreeDoc(xmlDocument); - // validate when we're finished - model->validated = true; return 0; }