src/model.c: making node research efficient and safe

This commit is contained in:
Adrien Bourmault 2024-03-24 22:04:07 +02:00
parent 19acd2672c
commit b2cd2c2fca
Signed by: neox
GPG Key ID: 95F65F55F682A17A
1 changed files with 35 additions and 71 deletions

View File

@ -2,7 +2,7 @@
// Model management module //
// //
// Copyright © 2021 Libre en Communs (contact@a-lec.org) //
// Copyright © 2021 Adrien Bourmault (neox@a-lec.org) //
// Copyright © 2021-2024 Adrien Bourmault (neox@a-lec.org) //
// //
// This file is part of gem-graph. //
// //
@ -40,85 +40,49 @@ struct model_t *knownModels = NULL;
/* -------------------------------------------------------------------------- */
static inline xmlNodePtr getNextChild (xmlNodePtr node, xmlChar *last)
{
while (node != NULL && xmlStrcmp(node->name, last)) {
// //printf(" <>--- line n°%lu <%s>\n", xmlGetLineNo(node), node->name);
node = node->next;
}
return node;
}
/*
* Finds a node by a path of tags.
*
* @param node The starting node for the search.
* @param path The path to the tag, with '/' as the delimiter.
* @return The content of the tag at the end of the path, or NULL if not found.
*/
char* model_find_node_by_path(xmlNode *node, const char *path) {
char *pathCopy = strdup(path); // Duplicate path to modify it
char *tag = strtok(pathCopy, "/"); // Get the first tag in the path
xmlNode *currentNode = node;
static inline xmlChar* splitStrAtSlash (xmlChar *toSplit)
{
toSplit = (xmlChar *)xmlStrchr(toSplit, '/');
toSplit = xmlStrsub (toSplit, 1, xmlStrlen(toSplit));
return toSplit;
}
while (tag != NULL && currentNode != NULL) {
xmlNode *foundNode = NULL;
static inline xmlChar* getFirstTag (xmlChar *path)
{
xmlChar *preop = path;
path = (xmlChar *)xmlStrchr(path, '/');
path = xmlStrsub (path, 1, xmlStrlen(path));
return xmlStrsub (preop, 0, xmlStrlen(preop) - xmlStrlen(path) - 1);
}
static inline xmlChar* getLastTag (xmlChar *path)
{
while ((ulong)xmlStrchr (path, '/'))
path = splitStrAtSlash ((xmlChar *)path);
// //printf("last tag in the path = <%s>\n", path);
return path; // which is no more the given path but only its last tag !
}
/* -------------------------------------------------------------------------- */
static xmlNodePtr model_get_node (struct model_t *self, xmlChar *path)
{
xmlNodePtr node;
xmlChar *extrait;
xmlChar *reste, *last, *affich;
// Lookup for node from path in hash table
node = xmlHashLookup(self->hashtable, path);
// Found a node in hash table
if (node) {
return node;
// no node found in hash table
} else {
reste = path;
affich = reste;
last = getLastTag(reste);
node = xmlDocGetRootElement(self->doc);
while (xmlStrchr (reste, '/')) {
extrait = getFirstTag(reste);
reste = splitStrAtSlash((xmlChar *)reste);
node = node->xmlChildrenNode;
node = getNextChild(node, extrait);
}
if(node && xmlStrcmp(node->name, last)) {
node = node->xmlChildrenNode;
while (node && xmlStrcmp(node->name, last)) {
node = node->next;
// Search for the tag at the current level
for (xmlNode *child = currentNode->children; child; child = child->next) {
if (child->type == XML_ELEMENT_NODE && strcmp((const char *)child->name, tag) == 0) {
foundNode = child; // Tag found at the current level
break;
}
xmlHashAddEntry (self->hashtable, path, node);
}
return node;
tag = strtok(NULL, "/"); // Move to the next tag in the path
// If there are more tags to find, continue with the found node's children
if (tag != NULL && foundNode != NULL) {
currentNode = foundNode;
} else {
// If this was the last tag, try to get its content
if (foundNode != NULL && tag == NULL) {
char *content = (char *)xmlNodeGetContent(foundNode);
free(pathCopy);
return content;
}
currentNode = NULL; // End loop if tag not found
}
}
return NULL;
free(pathCopy);
return NULL; // Path not fully matched
}
/* -------------------------------------------------------------------------- */
static inline long model_get_node_long_attrib (xmlNodePtr node, char *id)