WIP: New XML schemas used in gem-graph

This commit is contained in:
Adrien Bourmault 2021-09-21 22:39:24 +02:00
parent 33da3fee8d
commit b2a3508f08
No known key found for this signature in database
GPG Key ID: 6EB408FE0ACEC664
6 changed files with 193 additions and 47 deletions

View File

@ -37,6 +37,8 @@
#define LOGMSG "[%s]" #define LOGMSG "[%s]"
#define printLog(FORMAT, ...) printf("\e[0m" LOGMSG " " FORMAT "\e[0m", \ #define printLog(FORMAT, ...) printf("\e[0m" LOGMSG " " FORMAT "\e[0m", \
__func__, ##__VA_ARGS__) __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])) #define LEN(x) (sizeof(x) / sizeof((x)[0]))
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */

View File

@ -27,6 +27,7 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <libxml/parser.h> #include <libxml/parser.h>
#include <libxml/xmlschemas.h>
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
@ -66,4 +67,6 @@ int parseTextField(xmlDocPtr,
int ParseModelXML(Model_t*); int ParseModelXML(Model_t*);
int ParseModelIdentityXML(Model_t*, Parameters_t*);
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */

View File

@ -44,72 +44,66 @@ int main(int argc, char **argv)
int options; int options;
time_t t; time_t t;
int returnValue = 0; int returnValue = 0;
Parameters_t *parameters; Parameters_t parameters;
// Get parameters TODO from args
parameters = (Parameters_t*) calloc(sizeof(Parameters_t), 1);
while ((options = getopt(argc, argv, ":C:M:U:")) != -1) { while ((options = getopt(argc, argv, ":C:M:U:")) != -1) {
switch (options) { switch (options) {
case 'C': case 'C':
printLog("Config : %s\n", optarg); printLog("Config : %s\n", optarg);
parameters->configDir = (char*) malloc(strlen(optarg) + 1); parameters.configDir = (char*) calloc(1, strlen(optarg) + 1);
strcpy(parameters->configDir, optarg); strcpy(parameters.configDir, optarg);
break; break;
case 'M': case 'M':
printLog("Models : %s\n", optarg); printLog("Models : %s\n", optarg);
parameters->modelDir = (char*) malloc(strlen(optarg) + 1); parameters.modelDir = (char*) calloc(1, strlen(optarg) + 1);
strcpy(parameters->modelDir, optarg); strcpy(parameters.modelDir, optarg);
break; break;
case 'U': case 'U':
printLog("User : %s\n", optarg); printLog("User : %s\n", optarg);
parameters->userDir = (char*) malloc(strlen(optarg) + 1); parameters.userDir = (char*) calloc(1, strlen(optarg) + 1);
strcpy(parameters->userDir, optarg); strcpy(parameters.userDir, optarg);
break; break;
case ':': case ':':
printLog("Option missing argument : %c\n", optopt); printLog("Option missing argument : %c\n", optopt);
if (parameters->configDir) if (parameters.configDir)
free(parameters->configDir); free(parameters.configDir);
if (parameters->modelDir) if (parameters.modelDir)
free(parameters->modelDir); free(parameters.modelDir);
if (parameters->userDir) if (parameters.userDir)
free(parameters->userDir); free(parameters.userDir);
free(parameters);
return ENOSYS; return ENOSYS;
break; break;
case '?': case '?':
printLog("Unknown option : %c\n", optopt); printLog("Unknown option : %c\n", optopt);
if (parameters->configDir) if (parameters.configDir)
free(parameters->configDir); free(parameters.configDir);
if (parameters->modelDir) if (parameters.modelDir)
free(parameters->modelDir); free(parameters.modelDir);
if (parameters->userDir) if (parameters.userDir)
free(parameters->userDir); free(parameters.userDir);
free(parameters);
return ENOSYS; return ENOSYS;
break; break;
} }
} }
if (!parameters->configDir | !parameters->modelDir | !parameters->userDir) { if (!parameters.configDir | !parameters.modelDir | !parameters.userDir) {
printLog("Missing arguments\n"); printLog("Missing arguments\n");
if (parameters->configDir) if (parameters.configDir)
free(parameters->configDir); free(parameters.configDir);
if (parameters->modelDir) if (parameters.modelDir)
free(parameters->modelDir); free(parameters.modelDir);
if (parameters->userDir) if (parameters.userDir)
free(parameters->userDir); free(parameters.userDir);
free(parameters);
return ENOSYS; return ENOSYS;
} }
@ -127,7 +121,7 @@ int main(int argc, char **argv)
server = (Server_t*) calloc(1, sizeof(Server_t)); server = (Server_t*) calloc(1, sizeof(Server_t));
// Initializing model system // Initializing model system
ModelSystemInit(parameters); ModelSystemInit(&parameters);
// Launching server // Launching server
ServerInit(server); ServerInit(server);
@ -141,11 +135,9 @@ int main(int argc, char **argv)
free(server); free(server);
server = NULL; server = NULL;
free(parameters->userDir); free(parameters.userDir);
free(parameters->modelDir); free(parameters.modelDir);
free(parameters->configDir); free(parameters.configDir);
free(parameters);
parameters = NULL;
return returnValue; return returnValue;
} }

View File

@ -272,13 +272,17 @@ void ModelSystemInit(Parameters_t *parameters)
extensionPosition - modelDirEntry->d_name); extensionPosition - modelDirEntry->d_name);
// Ask to parse the new model // 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); ModelDelete(newModel->id);
continue; continue;
}; };
// Check model is valid and/or parsed // Check model is valid and/or parsed
if (newModel->validated == false) { if (newModel->validated == false) {
printLog("Deleting invalid model %s from known list\n",
newModel->name);
ModelDelete(newModel->id); ModelDelete(newModel->id);
continue; continue;
} }

View File

@ -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[] = ParserTableXML_t table[] =
{ {
// IDENTITY // IDENTITY
{(const xmlChar *)"identity", parseParentFieldXML, model}, {(const xmlChar *)"identity", parseParentFieldXML, NULL},
{(const xmlChar *)"name", parseTextFieldXML, model->name}, {(const xmlChar *)"name", parseTextFieldXML, model->name},
{(const xmlChar *)"owner", parseTextFieldXML, model->owner}, {(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 *)"owner_id", parseStubFieldXML, model->owner_id},
{(const xmlChar *)"date", parseIntFieldXML, &model->date}, {(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 <gem-graph-model> !\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 // PARAMETERS
{(const xmlChar *)"parameters", parseParentFieldPropsXML, model}, {(const xmlChar *)"parameters", parseParentFieldPropsXML, model},
// MODELIZATION // MODELIZATION
@ -361,8 +510,6 @@ int ParseModelXML(Model_t *model)
}; };
printLog("Parsing model %s\n", model->name); printLog("Parsing model %s\n", model->name);
xmlDocPtr xmlDocument;
xmlNodePtr currentNode;
xmlDocument = xmlParseFile(model->filename); xmlDocument = xmlParseFile(model->filename);
@ -405,7 +552,5 @@ int ParseModelXML(Model_t *model)
xmlFreeDoc(xmlDocument); xmlFreeDoc(xmlDocument);
// validate when we're finished
model->validated = true;
return 0; return 0;
} }