gpu_neon: fix some missing ebuf updates
[pcsx_rearmed.git] / deps / libretro-common / formats / xml / rxml.c
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
34 struct rxml_parse_buffer
35 {
36    rxml_node_t *stack[32];
37    char xml[BUFSIZE];
38    char val[BUFSIZE];
39 };
40
41 struct rxml_document
42 {
43    struct rxml_node *root_node;
44 };
45
46 struct rxml_node *rxml_root_node(rxml_document_t *doc)
47 {
48    if (doc)
49       return doc->root_node;
50    return NULL;
51 }
52
53 static 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
91 rxml_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
119 error:
120    free(memory_buffer);
121    if (file)
122       filestream_close(file);
123    return NULL;
124 }
125
126 rxml_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
294 error:
295    rxml_free_document(doc);
296    free(buf);
297    return NULL;
298 }
299
300 void 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
311 const 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 }