static void rxml_free_node(struct rxml_node *node) { struct rxml_node *head; for (head = node->children; head; ) { struct rxml_node *next_node = head->next; rxml_free_node(head); head = next_node; } struct rxml_attrib_node *attrib_node_head; for (attrib_node_head = node->attrib; attrib_node_head; ) { struct rxml_attrib_node *next_attrib = attrib_node_head->next; free(attrib_node_head->attrib); free(attrib_node_head->value); free(attrib_node_head); attrib_node_head = next_attrib; } free(node->name); free(node->data); free(node); }
void rxml_free_document(rxml_document_t *doc) { if (!doc) return; if (doc->root_node) rxml_free_node(doc->root_node); free(doc); }
static void rxml_free_node(struct rxml_node *node) { struct rxml_node *head = NULL; struct rxml_attrib_node *attrib_node_head = NULL; if (!node) return; for (head = node->children; head; ) { struct rxml_node *next_node = (struct rxml_node*)head->next; rxml_free_node(head); head = next_node; } for (attrib_node_head = node->attrib; attrib_node_head; ) { struct rxml_attrib_node *next_attrib = NULL; if (!attrib_node_head) continue; next_attrib = (struct rxml_attrib_node*)attrib_node_head->next; if (!next_attrib) continue; if (attrib_node_head->attrib) free(attrib_node_head->attrib); if (attrib_node_head->value) free(attrib_node_head->value); if (attrib_node_head) free(attrib_node_head); attrib_node_head = next_attrib; } if (node->name) free(node->name); if (node->data) free(node->data); if (node) free(node); }
static struct rxml_node *rxml_parse_node(const char **ptr_) { const char *ptr = NULL; const char *closing = NULL; char *str = NULL; bool is_closing = false; struct rxml_node *node = (struct rxml_node*)calloc(1, sizeof(*node)); if (!node) return NULL; skip_spaces(ptr_); ptr = *ptr_; if (*ptr != '<') goto error; closing = strchr(ptr, '>'); if (!closing) goto error; str = strdup_range(ptr + 1, closing); if (!str) goto error; if (!rxml_parse_tag(node, str)) goto error; is_closing = strstr(ptr, "/>") + 1 == closing; // Are spaces between / and > allowed? // Look for more data. Either child nodes or data. if (!is_closing) { size_t closing_tag_size = strlen(node->name) + 4; char *closing_tag = (char*)malloc(closing_tag_size); const char *cdata_start = NULL; const char *child_start = NULL; const char *closing_start = NULL; if (!closing_tag) { free(closing_tag); goto error; } snprintf(closing_tag, closing_tag_size, "</%s>", node->name); cdata_start = strstr(closing + 1, "<![CDATA["); child_start = strchr(closing + 1, '<'); closing_start = strstr(closing + 1, closing_tag); if (!closing_start) { free(closing_tag); goto error; } if (cdata_start && range_is_space(closing + 1, cdata_start)) // CDATA section { const char *cdata_end = strstr(cdata_start, "]]>"); if (!cdata_end) { free(closing_tag); goto error; } node->data = strdup_range(cdata_start + strlen("<![CDATA["), cdata_end); } else if (closing_start && closing_start == child_start) // Simple Data node->data = strdup_range(closing + 1, closing_start); else // Parse all child nodes. { struct rxml_node *list = NULL; struct rxml_node *tail = NULL; const char *ptr = child_start; const char *first_start = strchr(ptr, '<'); const char *first_closing = strstr(ptr, "</"); while (first_start && first_closing && first_start < first_closing) { struct rxml_node *new_node = rxml_parse_node(&ptr); if (!new_node) { free(closing_tag); goto error; } if (tail) { tail->next = new_node; tail = new_node; } else list = tail = new_node; first_start = strchr(ptr, '<'); first_closing = strstr(ptr, "</"); } node->children = list; closing_start = strstr(ptr, closing_tag); if (!closing_start) { free(closing_tag); goto error; } } *ptr_ = closing_start + strlen(closing_tag); free(closing_tag); } else *ptr_ = closing + 1; free(str); return node; error: free(str); rxml_free_node(node); return NULL; }