1 /* Copyright (C) 2010-2020 The RetroArch team
3 * ---------------------------------------------------------------------------------------
4 * The following license statement only applies to this file (rxml.c).
5 * ---------------------------------------------------------------------------------------
7 * Permission is hereby granted, free of charge,
8 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation the rights to
10 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
11 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
16 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 #include <streams/file_stream.h>
25 #include <compat/posix_string.h>
26 #include <string/stdstring.h>
28 #include <formats/rxml.h>
30 #include "../../deps/yxml/yxml.h"
34 struct rxml_parse_buffer
36 rxml_node_t *stack[32];
43 struct rxml_node *root_node;
46 struct rxml_node *rxml_root_node(rxml_document_t *doc)
49 return doc->root_node;
53 static void rxml_free_node(struct rxml_node *node)
55 struct rxml_node *head = NULL;
56 struct rxml_attrib_node *attrib_node_head = NULL;
61 for (head = node->children; head; )
63 struct rxml_node *next_node = (struct rxml_node*)head->next;
68 for (attrib_node_head = node->attrib; attrib_node_head; )
70 struct rxml_attrib_node *next_attrib =
71 (struct rxml_attrib_node*)attrib_node_head->next;
73 if (attrib_node_head->attrib)
74 free(attrib_node_head->attrib);
75 if (attrib_node_head->value)
76 free(attrib_node_head->value);
78 free(attrib_node_head);
80 attrib_node_head = next_attrib;
91 rxml_document_t *rxml_load_document(const char *path)
93 rxml_document_t *doc = NULL;
94 char *memory_buffer = NULL;
96 RFILE *file = filestream_open(path,
97 RETRO_VFS_FILE_ACCESS_READ,
98 RETRO_VFS_FILE_ACCESS_HINT_NONE);
102 len = filestream_get_size(file);
103 memory_buffer = (char*)malloc((size_t)(len + 1));
107 memory_buffer[len] = '\0';
108 if (filestream_read(file, memory_buffer, len) != len)
111 filestream_close(file);
114 doc = rxml_load_document_string(memory_buffer);
122 filestream_close(file);
126 rxml_document_t *rxml_load_document_string(const char *str)
129 rxml_document_t *doc = NULL;
134 rxml_node_t *node = NULL;
135 struct rxml_attrib_node *attr = NULL;
136 struct rxml_parse_buffer *buf = (struct rxml_parse_buffer*)
137 malloc(sizeof(*buf));
142 doc = (rxml_document_t*)malloc(sizeof(*doc));
146 yxml_init(&x, buf->xml, BUFSIZE);
150 yxml_ret_t r = yxml_parse(&x, *str);
163 buf->stack[stack_i] = node;
166 node->children = (rxml_node_t*)
167 malloc(sizeof(*node));
169 node->children->name = NULL;
170 node->children->data = NULL;
171 node->children->attrib = NULL;
172 node->children->children = NULL;
173 node->children->next = NULL;
175 node = node->children;
179 node->next = (rxml_node_t*)
180 malloc(sizeof(*node));
182 node->next->name = NULL;
183 node->next->data = NULL;
184 node->next->attrib = NULL;
185 node->next->children = NULL;
186 node->next->next = NULL;
192 node = doc->root_node = (rxml_node_t*)
193 calloc(1, sizeof(*node));
197 node->name = strdup(x.elem);
208 if (valptr > buf->val)
212 /* Original code was broken here:
213 * > If an element ended on two successive
214 * iterations, on the second iteration
215 * the 'data' for the *previous* node would
217 * > This effectively erased the data for the
218 * previous node, *and* caused a memory leak
219 * (due to the double strdup())
220 * It seems the correct thing to do here is
221 * only copy the data if the current 'level'
222 * and 'stack index' are the same... */
223 if (level == stack_i)
227 node->data = strdup(buf->val);
236 node = buf->stack[stack_i];
241 for (i = 0; i < (int)sizeof(x.data) && x.data[i]; i++)
250 attr = attr->next = (struct rxml_attrib_node*)
251 calloc(1, sizeof(*attr));
253 attr = node->attrib = (struct rxml_attrib_node*)calloc(1, sizeof(*attr));
257 attr->attrib = strdup(x.attr);
263 for (i = 0; i < (int)sizeof(x.data) && x.data[i]; i++)
271 if (valptr > buf->val)
279 attr->value = strdup(buf->val);
295 rxml_free_document(doc);
300 void rxml_free_document(rxml_document_t *doc)
306 rxml_free_node(doc->root_node);
311 const char *rxml_node_attrib(struct rxml_node *node, const char *attrib)
313 struct rxml_attrib_node *attribs = NULL;
314 for (attribs = node->attrib; attribs; attribs = attribs->next)
316 if (string_is_equal(attrib, attribs->attrib))
317 return attribs->value;