gpu_neon: fix some missing ebuf updates
[pcsx_rearmed.git] / deps / libretro-common / formats / xml / rxml.c
CommitLineData
3719602c
PC
1/* Copyright (C) 2010-2020 The RetroArch team
2 *
3 * ---------------------------------------------------------------------------------------
4 * The following license statement only applies to this file (rxml.c).
5 * ---------------------------------------------------------------------------------------
6 *
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:
12 *
13 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
14 *
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.
21 */
22
23#include <boolean.h>
24#include <streams/file_stream.h>
25#include <compat/posix_string.h>
26#include <string/stdstring.h>
27
28#include <formats/rxml.h>
29
30#include "../../deps/yxml/yxml.h"
31
32#define BUFSIZE 4096
33
34struct rxml_parse_buffer
35{
36 rxml_node_t *stack[32];
37 char xml[BUFSIZE];
38 char val[BUFSIZE];
39};
40
41struct rxml_document
42{
43 struct rxml_node *root_node;
44};
45
46struct rxml_node *rxml_root_node(rxml_document_t *doc)
47{
48 if (doc)
49 return doc->root_node;
50 return NULL;
51}
52
53static void rxml_free_node(struct rxml_node *node)
54{
55 struct rxml_node *head = NULL;
56 struct rxml_attrib_node *attrib_node_head = NULL;
57
58 if (!node)
59 return;
60
61 for (head = node->children; head; )
62 {
63 struct rxml_node *next_node = (struct rxml_node*)head->next;
64 rxml_free_node(head);
65 head = next_node;
66 }
67
68 for (attrib_node_head = node->attrib; attrib_node_head; )
69 {
70 struct rxml_attrib_node *next_attrib =
71 (struct rxml_attrib_node*)attrib_node_head->next;
72
73 if (attrib_node_head->attrib)
74 free(attrib_node_head->attrib);
75 if (attrib_node_head->value)
76 free(attrib_node_head->value);
77 if (attrib_node_head)
78 free(attrib_node_head);
79
80 attrib_node_head = next_attrib;
81 }
82
83 if (node->name)
84 free(node->name);
85 if (node->data)
86 free(node->data);
87 if (node)
88 free(node);
89}
90
91rxml_document_t *rxml_load_document(const char *path)
92{
93 rxml_document_t *doc = NULL;
94 char *memory_buffer = NULL;
95 int64_t len = 0;
96 RFILE *file = filestream_open(path,
97 RETRO_VFS_FILE_ACCESS_READ,
98 RETRO_VFS_FILE_ACCESS_HINT_NONE);
99 if (!file)
100 return NULL;
101
102 len = filestream_get_size(file);
103 memory_buffer = (char*)malloc((size_t)(len + 1));
104 if (!memory_buffer)
105 goto error;
106
107 memory_buffer[len] = '\0';
108 if (filestream_read(file, memory_buffer, len) != len)
109 goto error;
110
111 filestream_close(file);
112 file = NULL;
113
114 doc = rxml_load_document_string(memory_buffer);
115
116 free(memory_buffer);
117 return doc;
118
119error:
120 free(memory_buffer);
121 if (file)
122 filestream_close(file);
123 return NULL;
124}
125
126rxml_document_t *rxml_load_document_string(const char *str)
127{
128 yxml_t x;
129 rxml_document_t *doc = NULL;
130 size_t stack_i = 0;
131 size_t level = 0;
132 int i = 0;
133 char *valptr = 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));
138 if (!buf)
139 return NULL;
140
141 valptr = buf->val;
142 doc = (rxml_document_t*)malloc(sizeof(*doc));
143 if (!doc)
144 goto error;
145
146 yxml_init(&x, buf->xml, BUFSIZE);
147
148 for (; *str; ++str)
149 {
150 yxml_ret_t r = yxml_parse(&x, *str);
151
152 if (r < 0)
153 goto error;
154
155 switch (r)
156 {
157
158 case YXML_ELEMSTART:
159 if (node)
160 {
161 if (level > stack_i)
162 {
163 buf->stack[stack_i] = node;
164 ++stack_i;
165
166 node->children = (rxml_node_t*)
167 malloc(sizeof(*node));
168
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;
174
175 node = node->children;
176 }
177 else
178 {
179 node->next = (rxml_node_t*)
180 malloc(sizeof(*node));
181
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;
187
188 node = node->next;
189 }
190 }
191 else
192 node = doc->root_node = (rxml_node_t*)
193 calloc(1, sizeof(*node));
194
195 if (node->name)
196 free(node->name);
197 node->name = strdup(x.elem);
198
199 attr = NULL;
200 valptr = buf->val;
201
202 ++level;
203 break;
204
205 case YXML_ELEMEND:
206 --level;
207
208 if (valptr > buf->val)
209 {
210 *valptr = '\0';
211
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
216 * get overwritten
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)
224 {
225 if (node->data)
226 free(node->data);
227 node->data = strdup(buf->val);
228 }
229
230 valptr = buf->val;
231 }
232
233 if (level < stack_i)
234 {
235 --stack_i;
236 node = buf->stack[stack_i];
237 }
238 break;
239
240 case YXML_CONTENT:
241 for (i = 0; i < (int)sizeof(x.data) && x.data[i]; i++)
242 {
243 *valptr = x.data[i];
244 ++valptr;
245 }
246 break;
247
248 case YXML_ATTRSTART:
249 if (attr)
250 attr = attr->next = (struct rxml_attrib_node*)
251 calloc(1, sizeof(*attr));
252 else
253 attr = node->attrib = (struct rxml_attrib_node*)calloc(1, sizeof(*attr));
254
255 if (attr->attrib)
256 free(attr->attrib);
257 attr->attrib = strdup(x.attr);
258
259 valptr = buf->val;
260 break;
261
262 case YXML_ATTRVAL:
263 for (i = 0; i < (int)sizeof(x.data) && x.data[i]; i++)
264 {
265 *valptr = x.data[i];
266 ++valptr;
267 }
268 break;
269
270 case YXML_ATTREND:
271 if (valptr > buf->val)
272 {
273 *valptr = '\0';
274
275 if (attr)
276 {
277 if (attr->value)
278 free(attr->value);
279 attr->value = strdup(buf->val);
280 }
281
282 valptr = buf->val;
283 }
284 break;
285
286 default:
287 break;
288 }
289 }
290
291 free(buf);
292 return doc;
293
294error:
295 rxml_free_document(doc);
296 free(buf);
297 return NULL;
298}
299
300void rxml_free_document(rxml_document_t *doc)
301{
302 if (!doc)
303 return;
304
305 if (doc->root_node)
306 rxml_free_node(doc->root_node);
307
308 free(doc);
309}
310
311const char *rxml_node_attrib(struct rxml_node *node, const char *attrib)
312{
313 struct rxml_attrib_node *attribs = NULL;
314 for (attribs = node->attrib; attribs; attribs = attribs->next)
315 {
316 if (string_is_equal(attrib, attribs->attrib))
317 return attribs->value;
318 }
319
320 return NULL;
321}