rxml_document_t *rxml_load_document(const char *path) { #ifndef RXML_TEST RARCH_WARN("Using RXML as drop in for libxml2. Behavior might be very buggy.\n"); #endif char *memory_buffer = NULL; char *new_memory_buffer = NULL; const char *mem_ptr = NULL; long len = 0; FILE *file = fopen(path, "r"); if (!file) return NULL; rxml_document_t *doc = (rxml_document_t*)calloc(1, sizeof(*doc)); if (!doc) goto error; fseek(file, 0, SEEK_END); len = ftell(file); rewind(file); memory_buffer = (char*)malloc(len + 1); if (!memory_buffer) goto error; memory_buffer[len] = '\0'; if (fread(memory_buffer, 1, len, file) != (size_t)len) goto error; fclose(file); file = NULL; mem_ptr = memory_buffer; if (!validate_header(&mem_ptr)) goto error; new_memory_buffer = purge_xml_comments(mem_ptr); if (!new_memory_buffer) goto error; free(memory_buffer); mem_ptr = memory_buffer = new_memory_buffer; doc->root_node = rxml_parse_node(&mem_ptr); if (!doc->root_node) goto error; free(memory_buffer); return doc; error: free(memory_buffer); if (file) fclose(file); rxml_free_document(doc); return NULL; }
rxml_document_t *rxml_load_document(const char *path) { rxml_document_t *doc; char *memory_buffer = NULL; char *new_memory_buffer = NULL; const char *mem_ptr = NULL; long len = 0; RFILE *file = filestream_open(path, RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE); if (!file) return NULL; doc = (rxml_document_t*)calloc(1, sizeof(*doc)); if (!doc) goto error; len = filestream_get_size(file); memory_buffer = (char*)malloc(len + 1); if (!memory_buffer) goto error; memory_buffer[len] = '\0'; if (filestream_read(file, memory_buffer, len) != (size_t)len) goto error; filestream_close(file); file = NULL; mem_ptr = memory_buffer; if (!validate_header(&mem_ptr)) goto error; new_memory_buffer = purge_xml_comments(mem_ptr); if (!new_memory_buffer) goto error; free(memory_buffer); mem_ptr = memory_buffer = new_memory_buffer; doc->root_node = rxml_parse_node(&mem_ptr); if (!doc->root_node) goto error; free(memory_buffer); return doc; error: free(memory_buffer); filestream_close(file); rxml_free_document(doc); return NULL; }
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; }