Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2005-2021
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / common tools sub-project
9 : *
10 : * GPAC is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU Lesser General Public License as published by
12 : * the Free Software Foundation; either version 2, or (at your option)
13 : * any later version.
14 : *
15 : * GPAC is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU Lesser General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Lesser General Public
21 : * License along with this library; see the file COPYING. If not, write to
22 : * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 : *
24 : */
25 :
26 : #include <gpac/xml.h>
27 : #include <gpac/utf.h>
28 : #include <gpac/network.h>
29 :
30 : #ifndef GPAC_DISABLE_CORE_TOOLS
31 :
32 : #ifndef GPAC_DISABLE_ZLIB
33 : /*since 0.2.2, we use zlib for xmt/x3d reading to handle gz files*/
34 : #include <zlib.h>
35 :
36 : #if (defined(WIN32) || defined(_WIN32_WCE)) && !defined(__GNUC__)
37 : #pragma comment(lib, "zlib")
38 : #endif
39 : #else
40 : #define NO_GZIP
41 : #endif
42 :
43 :
44 : #define XML_INPUT_SIZE 4096
45 :
46 :
47 : static GF_Err gf_xml_sax_parse_intern(GF_SAXParser *parser, char *current);
48 :
49 127 : static char *xml_translate_xml_string(char *str)
50 : {
51 : char *value;
52 : u32 size, i, j;
53 127 : if (!str || !strlen(str)) return NULL;
54 127 : value = (char *)gf_malloc(sizeof(char) * 500);
55 : size = 500;
56 : i = j = 0;
57 9794 : while (str[i]) {
58 9540 : if (j+20 >= size) {
59 10 : size += 500;
60 10 : value = (char *)gf_realloc(value, sizeof(char)*size);
61 : }
62 9540 : if (str[i] == '&') {
63 523 : if (str[i+1]=='#') {
64 : char szChar[20], *end;
65 : u16 wchar[2];
66 : u32 val;
67 : const unsigned short *srcp;
68 : strncpy(szChar, str+i, 10);
69 51 : szChar[10] = 0;
70 51 : end = strchr(szChar, ';');
71 51 : if (!end) break;
72 51 : end[1] = 0;
73 51 : i += (u32) strlen(szChar);
74 51 : wchar[1] = 0;
75 51 : if (szChar[2]=='x')
76 4 : sscanf(szChar, "&#x%x;", &val);
77 : else
78 47 : sscanf(szChar, "&#%u;", &val);
79 51 : wchar[0] = val;
80 51 : srcp = wchar;
81 51 : j += (u32) gf_utf8_wcstombs(&value[j], 20, &srcp);
82 : }
83 472 : else if (!strnicmp(&str[i], "&", sizeof(char)*5)) {
84 20 : value[j] = '&';
85 20 : j++;
86 20 : i+= 5;
87 : }
88 452 : else if (!strnicmp(&str[i], "<", sizeof(char)*4)) {
89 71 : value[j] = '<';
90 71 : j++;
91 71 : i+= 4;
92 : }
93 381 : else if (!strnicmp(&str[i], ">", sizeof(char)*4)) {
94 117 : value[j] = '>';
95 117 : j++;
96 117 : i+= 4;
97 : }
98 264 : else if (!strnicmp(&str[i], "'", sizeof(char)*6)) {
99 30 : value[j] = '\'';
100 30 : j++;
101 30 : i+= 6;
102 : }
103 234 : else if (!strnicmp(&str[i], """, sizeof(char)*6)) {
104 234 : value[j] = '\"';
105 234 : j++;
106 234 : i+= 6;
107 : } else {
108 0 : value[j] = str[i];
109 0 : j++;
110 : i++;
111 : }
112 : } else {
113 9017 : value[j] = str[i];
114 9017 : j++;
115 9017 : i++;
116 : }
117 : }
118 127 : value[j] = 0;
119 127 : return value;
120 : }
121 :
122 :
123 : enum
124 : {
125 : SAX_STATE_ATT_NAME,
126 : SAX_STATE_ATT_VALUE,
127 : SAX_STATE_ELEMENT,
128 : SAX_STATE_COMMENT,
129 : SAX_STATE_TEXT_CONTENT,
130 : SAX_STATE_ENTITY,
131 : SAX_STATE_SKIP_DOCTYPE,
132 : SAX_STATE_CDATA,
133 : SAX_STATE_DONE,
134 : SAX_STATE_XML_PROC,
135 : SAX_STATE_SYNTAX_ERROR,
136 : SAX_STATE_ALLOC_ERROR,
137 : };
138 :
139 : typedef struct
140 : {
141 : u32 name_start, name_end;
142 : u32 val_start, val_end;
143 : Bool has_entities;
144 : } GF_XMLSaxAttribute;
145 :
146 :
147 : /* #define NO_GZIP */
148 :
149 :
150 : struct _tag_sax_parser
151 : {
152 : /*0: UTF-8, 1: UTF-16 BE, 2: UTF-16 LE. String input is always converted back to utf8*/
153 : s32 unicode_type;
154 : char *buffer;
155 : /*alloc size, line size and current position*/
156 : u32 alloc_size, line_size, current_pos;
157 : /*current node depth*/
158 : u32 node_depth;
159 :
160 : /*gz input file*/
161 : #ifdef NO_GZIP
162 : FILE *f_in;
163 : #else
164 : gzFile gz_in;
165 : #endif
166 : /*current line , file size and pos for user notif*/
167 : u32 line, file_size, file_pos;
168 :
169 : /*SAX callbacks*/
170 : gf_xml_sax_node_start sax_node_start;
171 : gf_xml_sax_node_end sax_node_end;
172 : gf_xml_sax_text_content sax_text_content;
173 : void *sax_cbck;
174 : gf_xml_sax_progress on_progress;
175 :
176 : u32 sax_state;
177 : u32 init_state;
178 : GF_List *entities;
179 : char att_sep;
180 : Bool in_entity, suspended;
181 : u32 in_quote;
182 :
183 : u32 elt_start_pos, elt_end_pos;
184 :
185 : /*last error found*/
186 : char err_msg[1000];
187 :
188 : u32 att_name_start, elt_name_start, elt_name_end, text_start, text_end;
189 :
190 : GF_XMLAttribute *attrs;
191 : GF_XMLSaxAttribute *sax_attrs;
192 : u32 nb_attrs, nb_alloc_attrs;
193 : };
194 :
195 59949 : static GF_XMLSaxAttribute *xml_get_sax_attribute(GF_SAXParser *parser)
196 : {
197 59949 : if (parser->nb_attrs==parser->nb_alloc_attrs) {
198 6486 : parser->nb_alloc_attrs++;
199 6486 : parser->sax_attrs = (GF_XMLSaxAttribute *)gf_realloc(parser->sax_attrs, sizeof(GF_XMLSaxAttribute)*parser->nb_alloc_attrs);
200 6486 : parser->attrs = (GF_XMLAttribute *)gf_realloc(parser->attrs, sizeof(GF_XMLAttribute)*parser->nb_alloc_attrs);
201 : }
202 59949 : return &parser->sax_attrs[parser->nb_attrs++];
203 : }
204 :
205 48013 : static void xml_sax_swap(GF_SAXParser *parser)
206 : {
207 48013 : if (parser->current_pos && ((parser->sax_state==SAX_STATE_TEXT_CONTENT) || (parser->sax_state==SAX_STATE_COMMENT) ) ) {
208 23864 : if (parser->line_size >= parser->current_pos) {
209 23864 : parser->line_size -= parser->current_pos;
210 23864 : parser->file_pos += parser->current_pos;
211 23864 : if (parser->line_size) memmove(parser->buffer, parser->buffer + parser->current_pos, sizeof(char)*parser->line_size);
212 23864 : parser->buffer[parser->line_size] = 0;
213 23864 : parser->current_pos = 0;
214 : }
215 : }
216 48013 : }
217 :
218 1005 : static void format_sax_error(GF_SAXParser *parser, u32 linepos, const char* fmt, ...)
219 : {
220 : va_list args;
221 : u32 len;
222 :
223 2010 : if (!parser) return;
224 :
225 0 : va_start(args, fmt);
226 0 : vsnprintf(parser->err_msg, GF_ARRAY_LENGTH(parser->err_msg), fmt, args);
227 0 : va_end(args);
228 :
229 0 : if (strlen(parser->err_msg)+30 < GF_ARRAY_LENGTH(parser->err_msg)) {
230 : char szM[20];
231 0 : snprintf(szM, 20, " - Line %d: ", parser->line + 1);
232 : strcat(parser->err_msg, szM);
233 0 : len = (u32) strlen(parser->err_msg);
234 0 : strncpy(parser->err_msg + len, parser->buffer+ (linepos ? linepos : parser->current_pos), 10);
235 0 : parser->err_msg[len + 10] = 0;
236 : }
237 0 : parser->sax_state = SAX_STATE_SYNTAX_ERROR;
238 : }
239 :
240 22148 : static void xml_sax_node_end(GF_SAXParser *parser, Bool had_children)
241 : {
242 : char *name, c;
243 :
244 : assert(parser->elt_name_start);
245 : assert(parser->elt_name_end);
246 22148 : if (!parser->node_depth) {
247 0 : format_sax_error(parser, 0, "Markup error");
248 : return;
249 : }
250 22148 : c = parser->buffer[parser->elt_name_end - 1];
251 22148 : parser->buffer[parser->elt_name_end - 1] = 0;
252 22148 : name = parser->buffer + parser->elt_name_start - 1;
253 :
254 22148 : if (parser->sax_node_end) {
255 21996 : char *sep = strchr(name, ':');
256 21996 : if (sep) {
257 325 : sep[0] = 0;
258 325 : parser->sax_node_end(parser->sax_cbck, sep+1, name);
259 325 : sep[0] = ':';
260 : } else {
261 21671 : parser->sax_node_end(parser->sax_cbck, name, NULL);
262 : }
263 : }
264 22148 : parser->buffer[parser->elt_name_end - 1] = c;
265 22148 : parser->node_depth--;
266 22148 : if (!parser->init_state && !parser->node_depth) parser->sax_state = SAX_STATE_DONE;
267 22148 : xml_sax_swap(parser);
268 22148 : parser->text_start = parser->text_end = 0;
269 : }
270 :
271 22287 : static void xml_sax_node_start(GF_SAXParser *parser)
272 : {
273 : Bool has_entities = GF_FALSE;
274 : u32 i;
275 : char c, *name;
276 :
277 : assert(parser->elt_name_start && parser->elt_name_end);
278 22287 : c = parser->buffer[parser->elt_name_end - 1];
279 22287 : parser->buffer[parser->elt_name_end - 1] = 0;
280 22287 : name = parser->buffer + parser->elt_name_start - 1;
281 :
282 80696 : for (i=0; i<parser->nb_attrs; i++) {
283 58409 : parser->attrs[i].name = parser->buffer + parser->sax_attrs[i].name_start - 1;
284 58409 : parser->buffer[parser->sax_attrs[i].name_end-1] = 0;
285 58409 : parser->attrs[i].value = parser->buffer + parser->sax_attrs[i].val_start - 1;
286 58409 : parser->buffer[parser->sax_attrs[i].val_end-1] = 0;
287 :
288 58409 : if (strchr(parser->attrs[i].value, '&')) {
289 63 : parser->sax_attrs[i].has_entities = GF_TRUE;
290 : has_entities = GF_TRUE;
291 63 : parser->attrs[i].value = xml_translate_xml_string(parser->attrs[i].value);
292 : }
293 : /*store first char pos after current attrib for node peeking*/
294 58409 : parser->att_name_start = parser->sax_attrs[i].val_end;
295 : }
296 :
297 22287 : if (parser->sax_node_start) {
298 22287 : char *sep = strchr(name, ':');
299 22287 : if (sep) {
300 334 : sep[0] = 0;
301 334 : parser->sax_node_start(parser->sax_cbck, sep+1, name, parser->attrs, parser->nb_attrs);
302 334 : sep[0] = ':';
303 : } else {
304 21953 : parser->sax_node_start(parser->sax_cbck, name, NULL, parser->attrs, parser->nb_attrs);
305 : }
306 : }
307 22287 : parser->att_name_start = 0;
308 22287 : parser->buffer[parser->elt_name_end - 1] = c;
309 22287 : parser->node_depth++;
310 22287 : if (has_entities) {
311 182 : for (i=0; i<parser->nb_attrs; i++) {
312 182 : if (parser->sax_attrs[i].has_entities) {
313 63 : parser->sax_attrs[i].has_entities = GF_FALSE;
314 63 : gf_free(parser->attrs[i].value);
315 : }
316 : }
317 : }
318 22287 : parser->nb_attrs = 0;
319 22287 : xml_sax_swap(parser);
320 22287 : parser->text_start = parser->text_end = 0;
321 22287 : }
322 :
323 83335 : static Bool xml_sax_parse_attribute(GF_SAXParser *parser)
324 : {
325 : char *sep;
326 : GF_XMLSaxAttribute *att = NULL;
327 :
328 : /*looking for attribute name*/
329 83335 : if (parser->sax_state==SAX_STATE_ATT_NAME) {
330 : /*looking for start*/
331 82858 : if (!parser->att_name_start) {
332 166996 : while (parser->current_pos < parser->line_size) {
333 166993 : u8 c = parser->buffer[parser->current_pos];
334 166993 : switch (c) {
335 1318 : case '\n':
336 1318 : parser->line++;
337 84133 : case ' ':
338 : case '\r':
339 : case '\t':
340 84133 : parser->current_pos++;
341 84133 : continue;
342 : /*end of element*/
343 469 : case '?':
344 469 : if (parser->init_state!=1) break;
345 : case '/':
346 : /*not enough data*/
347 15104 : if (parser->current_pos+1 == parser->line_size) return GF_TRUE;
348 15100 : if (parser->buffer[parser->current_pos+1]=='>') {
349 15100 : parser->current_pos+=2;
350 15100 : parser->elt_end_pos = parser->file_pos + parser->current_pos - 1;
351 : /*done parsing attr AND elements*/
352 15100 : if (!parser->init_state) {
353 14229 : xml_sax_node_start(parser);
354 : /*move to SAX_STATE_TEXT_CONTENT to force text flush*/
355 14229 : parser->sax_state = SAX_STATE_TEXT_CONTENT;
356 14229 : xml_sax_node_end(parser, GF_FALSE);
357 : } else {
358 871 : parser->nb_attrs = 0;
359 : }
360 15100 : parser->sax_state = (parser->init_state) ? SAX_STATE_ELEMENT : SAX_STATE_TEXT_CONTENT;
361 15100 : parser->text_start = parser->text_end = 0;
362 15100 : return GF_FALSE;
363 : }
364 0 : if (!parser->in_quote && (c=='/')) {
365 0 : if (!parser->init_state) {
366 0 : format_sax_error(parser, 0, "Markup error");
367 0 : return GF_TRUE;
368 : }
369 : }
370 : break;
371 : case '"':
372 : if (parser->sax_state==SAX_STATE_ATT_VALUE) break;
373 40 : if (parser->in_quote && (parser->in_quote!=c) ) {
374 0 : format_sax_error(parser, 0, "Markup error");
375 0 : return GF_TRUE;
376 : }
377 40 : if (parser->in_quote) parser->in_quote = 0;
378 40 : else parser->in_quote = c;
379 : break;
380 7687 : case '>':
381 7687 : parser->current_pos+=1;
382 : /*end of <!DOCTYPE>*/
383 7687 : if (parser->init_state) {
384 20 : if (parser->init_state==1) {
385 0 : format_sax_error(parser, 0, "Invalid <!DOCTYPE...> or <?xml...?>");
386 0 : return GF_TRUE;
387 : }
388 20 : parser->sax_state = SAX_STATE_ELEMENT;
389 20 : return GF_FALSE;
390 : }
391 : /*done parsing attr*/
392 7667 : parser->sax_state = SAX_STATE_TEXT_CONTENT;
393 7667 : xml_sax_node_start(parser);
394 7667 : return GF_FALSE;
395 0 : case '[':
396 0 : if (parser->init_state) {
397 0 : parser->current_pos+=1;
398 0 : if (parser->init_state==1) {
399 0 : format_sax_error(parser, 0, "Invalid <!DOCTYPE...> or <?xml...?>");
400 0 : return GF_TRUE;
401 : }
402 0 : parser->sax_state = SAX_STATE_ELEMENT;
403 0 : return GF_FALSE;
404 : }
405 : break;
406 0 : case '<':
407 0 : format_sax_error(parser, 0, "Invalid character '<'");
408 0 : return GF_FALSE;
409 : /*first char of attr name*/
410 60029 : default:
411 60029 : parser->att_name_start = parser->current_pos + 1;
412 60029 : break;
413 : }
414 60069 : parser->current_pos++;
415 60069 : if (parser->att_name_start) break;
416 : }
417 60032 : if (parser->current_pos == parser->line_size) return GF_TRUE;
418 : }
419 :
420 60061 : if (parser->init_state==2) {
421 80 : sep = strchr(parser->buffer + parser->att_name_start - 1, parser->in_quote ? parser->in_quote : ' ');
422 : /*not enough data*/
423 80 : if (!sep) return GF_TRUE;
424 80 : parser->current_pos = (u32) (sep - parser->buffer);
425 80 : parser->att_name_start = 0;
426 80 : if (parser->in_quote) {
427 40 : parser->current_pos++;
428 40 : parser->in_quote = 0;
429 : }
430 : return GF_FALSE;
431 : }
432 :
433 : /*looking for '"'*/
434 59981 : if (parser->att_name_start) {
435 : u32 i, first=1;
436 59981 : sep = strchr(parser->buffer + parser->att_name_start - 1, '=');
437 : /*not enough data*/
438 59981 : if (!sep) return GF_TRUE;
439 :
440 59949 : parser->current_pos = (u32) (sep - parser->buffer);
441 59949 : att = xml_get_sax_attribute(parser);
442 59949 : att->name_start = parser->att_name_start;
443 59949 : att->name_end = parser->current_pos + 1;
444 119921 : while (strchr(" \n\t", parser->buffer[att->name_end - 2])) {
445 : assert(att->name_end);
446 23 : att->name_end --;
447 : }
448 59949 : att->has_entities = GF_FALSE;
449 :
450 379552 : for (i=att->name_start; i<att->name_end; i++) {
451 319603 : char c = parser->buffer[i-1];
452 319603 : if ((c>='a') && (c<='z')) {}
453 33392 : else if ((c>='A') && (c<='Z')) {}
454 9889 : else if ((c==':') || (c=='_')) {}
455 :
456 5980 : else if (!first && ((c=='-') || (c=='.') || ((c>='0') && (c<='9')) )) {}
457 :
458 : else {
459 0 : format_sax_error(parser, att->name_start-1, "Invalid character \'%c\' for attribute name", c);
460 0 : return GF_TRUE;
461 : }
462 :
463 : first=0;
464 : }
465 :
466 59949 : parser->att_name_start = 0;
467 59949 : parser->current_pos++;
468 59949 : parser->sax_state = SAX_STATE_ATT_VALUE;
469 :
470 : }
471 : }
472 :
473 60426 : if (parser->sax_state == SAX_STATE_ATT_VALUE) {
474 60426 : att = &parser->sax_attrs[parser->nb_attrs-1];
475 : /*looking for first delimiter*/
476 60426 : if (!parser->att_sep) {
477 59956 : while (parser->current_pos < parser->line_size) {
478 59955 : u8 c = parser->buffer[parser->current_pos];
479 : switch (c) {
480 0 : case '\n':
481 0 : parser->line++;
482 6 : case ' ':
483 : case '\r':
484 : case '\t':
485 6 : parser->current_pos++;
486 6 : continue;
487 59949 : case '\'':
488 : case '"':
489 59949 : parser->att_sep = c;
490 59949 : att->val_start = parser->current_pos + 2;
491 59949 : break;
492 : default:
493 : break;
494 : }
495 59949 : parser->current_pos++;
496 59949 : if (parser->att_sep) break;
497 : }
498 59950 : if (parser->current_pos == parser->line_size) return GF_TRUE;
499 : }
500 :
501 60360 : att_retry:
502 :
503 : assert(parser->att_sep);
504 60360 : sep = strchr(parser->buffer + parser->current_pos, parser->att_sep);
505 60360 : if (!sep || !sep[1]) return GF_TRUE;
506 :
507 59949 : if (sep[1]==parser->att_sep) {
508 0 : format_sax_error(parser, (u32) (sep - parser->buffer), "Invalid character %c after attribute value separator %c ", sep[1], parser->att_sep);
509 0 : return GF_TRUE;
510 : }
511 :
512 59949 : if (!parser->init_state && (strchr(" />\n\t\r", sep[1])==NULL)) {
513 0 : parser->current_pos = (u32) (sep - parser->buffer + 1);
514 0 : goto att_retry;
515 : }
516 :
517 59949 : parser->current_pos = (u32) (sep - parser->buffer);
518 59949 : att->val_end = parser->current_pos + 1;
519 59949 : parser->current_pos++;
520 :
521 : /*"style" always at the beginning of the attributes for ease of parsing*/
522 59949 : if (!strncmp(parser->buffer + att->name_start-1, "style", 5)) {
523 182 : GF_XMLSaxAttribute prev = parser->sax_attrs[0];
524 182 : parser->sax_attrs[0] = *att;
525 182 : *att = prev;
526 : }
527 59949 : parser->att_sep = 0;
528 59949 : parser->sax_state = SAX_STATE_ATT_NAME;
529 59949 : parser->att_name_start = 0;
530 59949 : return GF_FALSE;
531 : }
532 : return GF_TRUE;
533 : }
534 :
535 :
536 : typedef struct
537 : {
538 : char *name;
539 : char *value;
540 : u32 namelen;
541 : u8 sep;
542 : } XML_Entity;
543 :
544 30882 : static void xml_sax_flush_text(GF_SAXParser *parser)
545 : {
546 : char *text, c;
547 30882 : if (!parser->text_start || parser->init_state || !parser->sax_text_content) return;
548 :
549 : assert(parser->text_start < parser->text_end);
550 :
551 29265 : c = parser->buffer[parser->text_end-1];
552 29265 : parser->buffer[parser->text_end-1] = 0;
553 29265 : text = parser->buffer + parser->text_start-1;
554 :
555 : /*solve XML built-in entities*/
556 29265 : if (strchr(text, '&') && strchr(text, ';')) {
557 64 : char *xml_text = xml_translate_xml_string(text);
558 64 : if (xml_text) {
559 64 : parser->sax_text_content(parser->sax_cbck, xml_text, (parser->sax_state==SAX_STATE_CDATA) ? GF_TRUE : GF_FALSE);
560 64 : gf_free(xml_text);
561 : }
562 : } else {
563 29201 : parser->sax_text_content(parser->sax_cbck, text, (parser->sax_state==SAX_STATE_CDATA) ? GF_TRUE : GF_FALSE);
564 : }
565 29265 : parser->buffer[parser->text_end-1] = c;
566 29265 : parser->text_start = parser->text_end = 0;
567 : }
568 :
569 29549 : static void xml_sax_store_text(GF_SAXParser *parser, u32 txt_len)
570 : {
571 29549 : if (!txt_len) return;
572 :
573 29549 : if (!parser->text_start) {
574 29536 : parser->text_start = parser->current_pos + 1;
575 29536 : parser->text_end = parser->text_start + txt_len;
576 29536 : parser->current_pos += txt_len;
577 : assert(parser->current_pos <= parser->line_size);
578 29536 : return;
579 : }
580 : /*contiguous text*/
581 13 : if (parser->text_end && (parser->text_end-1 == parser->current_pos)) {
582 0 : parser->text_end += txt_len;
583 0 : parser->current_pos += txt_len;
584 : assert(parser->current_pos <= parser->line_size);
585 0 : return;
586 : }
587 : /*need to flush*/
588 13 : xml_sax_flush_text(parser);
589 :
590 13 : parser->text_start = parser->current_pos + 1;
591 13 : parser->text_end = parser->text_start + txt_len;
592 13 : parser->current_pos += txt_len;
593 : assert(parser->current_pos <= parser->line_size);
594 : }
595 :
596 5 : static char *xml_get_current_text(GF_SAXParser *parser)
597 : {
598 : char *text, c;
599 5 : if (!parser->text_start) return NULL;
600 :
601 5 : c = parser->buffer[parser->text_end-1];
602 5 : parser->buffer[parser->text_end-1] = 0;
603 5 : text = gf_strdup(parser->buffer + parser->text_start-1);
604 5 : parser->buffer[parser->text_end-1] = c;
605 5 : parser->text_start = parser->text_end = 0;
606 5 : return text;
607 : }
608 :
609 5 : static void xml_sax_skip_doctype(GF_SAXParser *parser)
610 : {
611 10 : while (parser->current_pos < parser->line_size) {
612 5 : if (parser->buffer[parser->current_pos]=='>') {
613 5 : parser->sax_state = SAX_STATE_ELEMENT;
614 5 : parser->current_pos++;
615 5 : xml_sax_swap(parser);
616 5 : return;
617 : }
618 0 : parser->current_pos++;
619 : }
620 : }
621 :
622 6 : static void xml_sax_skip_xml_proc(GF_SAXParser *parser)
623 : {
624 49 : while (parser->current_pos + 1 < parser->line_size) {
625 43 : if ((parser->buffer[parser->current_pos]=='?') && (parser->buffer[parser->current_pos+1]=='>')) {
626 6 : parser->sax_state = SAX_STATE_ELEMENT;
627 6 : parser->current_pos++;
628 6 : xml_sax_swap(parser);
629 6 : return;
630 : }
631 37 : parser->current_pos++;
632 : }
633 : }
634 :
635 :
636 5 : static void xml_sax_parse_entity(GF_SAXParser *parser)
637 : {
638 : char szName[1024];
639 : u32 i = 0;
640 5 : XML_Entity *ent = (XML_Entity *)gf_list_last(parser->entities);
641 : char *skip_chars = " \t\n\r";
642 : i=0;
643 5 : if (ent && ent->value) ent = NULL;
644 5 : if (ent) skip_chars = NULL;
645 :
646 155 : while (parser->current_pos+i < parser->line_size) {
647 155 : u8 c = parser->buffer[parser->current_pos+i];
648 155 : if (skip_chars && strchr(skip_chars, c)) {
649 10 : if (c=='\n') parser->line++;
650 10 : parser->current_pos++;
651 10 : continue;
652 : }
653 145 : if (!ent && (c=='%')) {
654 0 : parser->current_pos+=i+1;
655 0 : parser->sax_state = SAX_STATE_SKIP_DOCTYPE;
656 5 : return;
657 : }
658 145 : else if (!ent && ((c=='\"') || (c=='\'')) ) {
659 5 : szName[i] = 0;
660 5 : GF_SAFEALLOC(ent, XML_Entity);
661 5 : if (!ent) {
662 0 : parser->sax_state = SAX_STATE_ALLOC_ERROR;
663 0 : return;
664 : }
665 5 : ent->name = gf_strdup(szName);
666 5 : ent->namelen = (u32) strlen(ent->name);
667 5 : ent->sep = c;
668 5 : parser->current_pos += 1+i;
669 : assert(parser->current_pos < parser->line_size);
670 5 : xml_sax_swap(parser);
671 : i=0;
672 5 : gf_list_add(parser->entities, ent);
673 5 : skip_chars = NULL;
674 140 : } else if (ent && c==ent->sep) {
675 5 : xml_sax_store_text(parser, i);
676 :
677 5 : ent->value = xml_get_current_text(parser);
678 5 : if (!ent->value) ent->value = gf_strdup("");
679 :
680 5 : parser->current_pos += 1;
681 : assert(parser->current_pos < parser->line_size);
682 5 : xml_sax_swap(parser);
683 5 : parser->sax_state = SAX_STATE_SKIP_DOCTYPE;
684 5 : return;
685 135 : } else if (!ent) {
686 30 : szName[i] = c;
687 30 : i++;
688 : } else {
689 105 : i++;
690 : }
691 : }
692 0 : xml_sax_store_text(parser, i);
693 : }
694 :
695 13 : static void xml_sax_cdata(GF_SAXParser *parser)
696 : {
697 13 : char *cd_end = strstr(parser->buffer + parser->current_pos, "]]>");
698 13 : if (!cd_end) {
699 0 : xml_sax_store_text(parser, parser->line_size - parser->current_pos);
700 : } else {
701 13 : u32 size = (u32) (cd_end - (parser->buffer + parser->current_pos));
702 13 : xml_sax_store_text(parser, size);
703 13 : xml_sax_flush_text(parser);
704 13 : parser->current_pos += 3;
705 : assert(parser->current_pos <= parser->line_size);
706 13 : parser->sax_state = SAX_STATE_TEXT_CONTENT;
707 : }
708 13 : }
709 :
710 1038 : static Bool xml_sax_parse_comments(GF_SAXParser *parser)
711 : {
712 1038 : char *end = strstr(parser->buffer + parser->current_pos, "-->");
713 1038 : if (!end) {
714 2 : if (parser->line_size>3)
715 2 : parser->current_pos = parser->line_size-3;
716 2 : xml_sax_swap(parser);
717 2 : return GF_FALSE;
718 : }
719 :
720 1036 : parser->current_pos += 3 + (u32) (end - (parser->buffer + parser->current_pos) );
721 : assert(parser->current_pos <= parser->line_size);
722 1036 : parser->sax_state = SAX_STATE_TEXT_CONTENT;
723 1036 : parser->text_start = parser->text_end = 0;
724 1036 : xml_sax_swap(parser);
725 1036 : return GF_TRUE;
726 : }
727 :
728 :
729 :
730 2523 : static GF_Err xml_sax_parse(GF_SAXParser *parser, Bool force_parse)
731 : {
732 : u32 i = 0;
733 : Bool is_text;
734 : u32 is_end;
735 : u8 c;
736 : char *elt, sep;
737 : u32 cdata_sep;
738 :
739 120693 : while (parser->current_pos<parser->line_size) {
740 230112 : if (!force_parse && parser->suspended) goto exit;
741 :
742 117762 : restart:
743 : is_text = GF_FALSE;
744 117762 : switch (parser->sax_state) {
745 : /*load an XML element*/
746 30498 : case SAX_STATE_TEXT_CONTENT:
747 : is_text = GF_TRUE;
748 33360 : case SAX_STATE_ELEMENT:
749 : elt = NULL;
750 : i=0;
751 200923 : while ((c = parser->buffer[parser->current_pos+i]) !='<') {
752 134846 : if ((parser->init_state==2) && (c ==']')) {
753 0 : parser->sax_state = SAX_STATE_ATT_NAME;
754 0 : parser->current_pos+=i+1;
755 0 : goto restart;
756 : }
757 134846 : i++;
758 134846 : if (c=='\n') parser->line++;
759 :
760 134846 : if (parser->current_pos+i==parser->line_size) {
761 643 : if ((parser->line_size>=2*XML_INPUT_SIZE) && !parser->init_state)
762 0 : parser->sax_state = SAX_STATE_SYNTAX_ERROR;
763 :
764 : goto exit;
765 : }
766 : }
767 32717 : if (is_text && i) {
768 29531 : xml_sax_store_text(parser, i);
769 29531 : parser->sax_state = SAX_STATE_ELEMENT;
770 3186 : } else if (i) {
771 898 : parser->current_pos += i;
772 : assert(parser->current_pos < parser->line_size);
773 : }
774 : is_end = 0;
775 : i = 0;
776 : cdata_sep = 0;
777 : while (1) {
778 252474 : c = parser->buffer[parser->current_pos+1+i];
779 252474 : if (!strncmp(parser->buffer+parser->current_pos+1+i, "!--", 3)) {
780 1036 : parser->sax_state = SAX_STATE_COMMENT;
781 1036 : i += 3;
782 1036 : break;
783 : }
784 251438 : if (!c) {
785 : goto exit;
786 : }
787 251429 : if ((c=='\t') || (c=='\r') || (c==' ') ) {
788 20753 : if (i) break;
789 0 : else parser->current_pos++;
790 : }
791 230676 : else if (c=='\n') {
792 3 : parser->line++;
793 3 : if (i) break;
794 0 : else parser->current_pos++;
795 : }
796 230673 : else if (c=='>') break;
797 220707 : else if (c=='=') break;
798 220707 : else if (c=='[') {
799 26 : i++;
800 26 : if (!cdata_sep) cdata_sep = 1;
801 : else {
802 : break;
803 : }
804 : }
805 220681 : else if (c=='/') {
806 7928 : is_end = !i ? 1 : 2;
807 7928 : i++;
808 212753 : } else if (c=='<') {
809 1 : if (parser->sax_state != SAX_STATE_COMMENT) {
810 1 : parser->sax_state = SAX_STATE_SYNTAX_ERROR;
811 1 : return GF_CORRUPTED_DATA;
812 : }
813 : } else {
814 212752 : i++;
815 : }
816 : /* if ((c=='[') && (parser->buffer[parser->elt_name_start-1 + i-2]=='A') ) break; */
817 220693 : if (parser->current_pos+1+i==parser->line_size) {
818 : goto exit;
819 : }
820 : }
821 31771 : if (i) {
822 31771 : parser->elt_name_start = parser->current_pos+1 + 1;
823 31771 : if (is_end==1) parser->elt_name_start ++;
824 31771 : if (is_end==2) parser->elt_name_end = parser->current_pos+1+i;
825 31380 : else parser->elt_name_end = parser->current_pos+1+i + 1;
826 : }
827 31771 : if (is_end) {
828 7919 : xml_sax_flush_text(parser);
829 7919 : parser->elt_end_pos = parser->file_pos + parser->current_pos + i;
830 7919 : if (is_end==2) {
831 391 : parser->sax_state = SAX_STATE_ELEMENT;
832 391 : xml_sax_node_start(parser);
833 391 : xml_sax_node_end(parser, GF_FALSE);
834 : } else {
835 7528 : parser->elt_end_pos += parser->elt_name_end - parser->elt_name_start;
836 7528 : xml_sax_node_end(parser, GF_TRUE);
837 : }
838 7919 : if (parser->sax_state == SAX_STATE_SYNTAX_ERROR) break;
839 7919 : parser->current_pos+=2+i;
840 7919 : parser->sax_state = SAX_STATE_TEXT_CONTENT;
841 7919 : break;
842 : }
843 23852 : if (!parser->elt_name_end) {
844 : return GF_CORRUPTED_DATA;
845 : }
846 23852 : sep = parser->buffer[parser->elt_name_end-1];
847 23852 : parser->buffer[parser->elt_name_end-1] = 0;
848 23852 : elt = parser->buffer + parser->elt_name_start-1;
849 :
850 23852 : parser->sax_state = SAX_STATE_ATT_NAME;
851 : assert(parser->elt_start_pos <= parser->file_pos + parser->current_pos);
852 23852 : parser->elt_start_pos = parser->file_pos + parser->current_pos;
853 :
854 23852 : if (!strncmp(elt, "!--", 3)) {
855 1036 : xml_sax_flush_text(parser);
856 1036 : parser->sax_state = SAX_STATE_COMMENT;
857 1036 : if (i>3) parser->current_pos -= (i-3);
858 : }
859 22816 : else if (!strcmp(elt, "?xml")) parser->init_state = 1;
860 21945 : else if (!strcmp(elt, "!DOCTYPE")) parser->init_state = 2;
861 21925 : else if (!strcmp(elt, "!ENTITY")) parser->sax_state = SAX_STATE_ENTITY;
862 21920 : else if (!strcmp(elt, "!ATTLIST") || !strcmp(elt, "!ELEMENT")) parser->sax_state = SAX_STATE_SKIP_DOCTYPE;
863 21920 : else if (!strcmp(elt, "![CDATA["))
864 13 : parser->sax_state = SAX_STATE_CDATA;
865 21907 : else if (elt[0]=='?') {
866 6 : i--;
867 6 : parser->sax_state = SAX_STATE_XML_PROC;
868 : }
869 : /*node found*/
870 : else {
871 21901 : xml_sax_flush_text(parser);
872 21901 : if (parser->init_state) {
873 871 : parser->init_state = 0;
874 : /*that's a bit ugly: since we solve entities when appending text, we need to
875 : reparse the current buffer*/
876 871 : if (gf_list_count(parser->entities)) {
877 : char *orig_buf;
878 : GF_Err e;
879 5 : parser->buffer[parser->elt_name_end-1] = sep;
880 5 : orig_buf = gf_strdup(parser->buffer + parser->current_pos);
881 5 : parser->current_pos = 0;
882 5 : parser->line_size = 0;
883 5 : parser->elt_start_pos = 0;
884 5 : parser->sax_state = SAX_STATE_TEXT_CONTENT;
885 5 : e = gf_xml_sax_parse_intern(parser, orig_buf);
886 5 : gf_free(orig_buf);
887 5 : return e;
888 : }
889 : }
890 : }
891 23847 : parser->current_pos+=1+i;
892 23847 : parser->buffer[parser->elt_name_end-1] = sep;
893 23847 : break;
894 1038 : case SAX_STATE_COMMENT:
895 1038 : if (!xml_sax_parse_comments(parser)) {
896 2 : xml_sax_swap(parser);
897 2 : goto exit;
898 : }
899 : break;
900 83335 : case SAX_STATE_ATT_NAME:
901 : case SAX_STATE_ATT_VALUE:
902 83335 : if (xml_sax_parse_attribute(parser))
903 : goto exit;
904 : break;
905 5 : case SAX_STATE_ENTITY:
906 5 : xml_sax_parse_entity(parser);
907 5 : break;
908 5 : case SAX_STATE_SKIP_DOCTYPE:
909 5 : xml_sax_skip_doctype(parser);
910 5 : break;
911 6 : case SAX_STATE_XML_PROC:
912 6 : xml_sax_skip_xml_proc(parser);
913 6 : break;
914 13 : case SAX_STATE_CDATA:
915 13 : xml_sax_cdata(parser);
916 13 : break;
917 : case SAX_STATE_SYNTAX_ERROR:
918 : return GF_CORRUPTED_DATA;
919 0 : case SAX_STATE_ALLOC_ERROR:
920 0 : return GF_OUT_OF_MEM;
921 0 : case SAX_STATE_DONE:
922 0 : return GF_EOS;
923 : }
924 : }
925 1872 : exit:
926 : #if 0
927 : if (is_text) {
928 : if (i) xml_sax_store_text(parser, i);
929 : /*DON'T FLUSH TEXT YET, wait for next '<' to do so otherwise we may corrupt xml base entities (', ...)*/
930 : }
931 : #endif
932 2517 : xml_sax_swap(parser);
933 :
934 2517 : if (parser->sax_state==SAX_STATE_SYNTAX_ERROR)
935 : return GF_CORRUPTED_DATA;
936 : else
937 2517 : return GF_OK;
938 : }
939 :
940 2898 : static GF_Err xml_sax_append_string(GF_SAXParser *parser, char *string)
941 : {
942 2898 : u32 size = parser->line_size;
943 2898 : u32 nl_size = (u32) strlen(string);
944 :
945 2898 : if (!nl_size) return GF_OK;
946 :
947 2898 : if ( (parser->alloc_size < size+nl_size+1)
948 : /* || (parser->alloc_size / 2 ) > size+nl_size+1 */
949 : )
950 : {
951 : parser->alloc_size = size+nl_size+1;
952 1948 : parser->alloc_size = 3 * parser->alloc_size / 2;
953 1948 : parser->buffer = (char*)gf_realloc(parser->buffer, sizeof(char) * parser->alloc_size);
954 1948 : if (!parser->buffer ) return GF_OUT_OF_MEM;
955 : }
956 2898 : memcpy(parser->buffer+size, string, sizeof(char)*nl_size);
957 2898 : parser->buffer[size+nl_size] = 0;
958 2898 : parser->line_size = size+nl_size;
959 2898 : return GF_OK;
960 : }
961 :
962 380 : static XML_Entity *gf_xml_locate_entity(GF_SAXParser *parser, char *ent_start, Bool *needs_text)
963 : {
964 : u32 i, count;
965 380 : u32 len = (u32) strlen(ent_start);
966 :
967 380 : *needs_text = GF_FALSE;
968 380 : count = gf_list_count(parser->entities);
969 :
970 375 : for (i=0; i<count; i++) {
971 380 : XML_Entity *ent = (XML_Entity *)gf_list_get(parser->entities, i);
972 380 : if (len < ent->namelen + 1) {
973 0 : if (strncmp(ent->name, ent_start, len))
974 : return NULL;
975 :
976 0 : *needs_text = GF_TRUE;
977 : return NULL;
978 : }
979 380 : if (!strncmp(ent->name, ent_start, ent->namelen) && (ent_start[ent->namelen]==';')) {
980 : return ent;
981 : }
982 : }
983 : return NULL;
984 : }
985 :
986 :
987 2138 : static GF_Err gf_xml_sax_parse_intern(GF_SAXParser *parser, char *current)
988 : {
989 : u32 count;
990 : /*solve entities*/
991 2138 : count = gf_list_count(parser->entities);
992 4656 : while (count) {
993 : char *entityEnd;
994 : XML_Entity *ent;
995 420 : char *entityStart = strstr(current, "&");
996 : Bool needs_text;
997 : u32 line_num;
998 :
999 : /*if in entity, the start of the entity is in the buffer !!*/
1000 420 : if (parser->in_entity) {
1001 : u32 len;
1002 : char *name;
1003 0 : entityEnd = strstr(current, ";");
1004 0 : if (!entityEnd) return xml_sax_append_string(parser, current);
1005 0 : entityStart = strrchr(parser->buffer, '&');
1006 :
1007 0 : entityEnd[0] = 0;
1008 0 : len = (u32) strlen(entityStart) + (u32) strlen(current) + 1;
1009 0 : name = (char*)gf_malloc(sizeof(char)*len);
1010 0 : sprintf(name, "%s%s;", entityStart+1, current);
1011 :
1012 0 : ent = gf_xml_locate_entity(parser, name, &needs_text);
1013 0 : gf_free(name);
1014 :
1015 0 : if (!ent && !needs_text) {
1016 0 : xml_sax_append_string(parser, current);
1017 0 : xml_sax_parse(parser, GF_TRUE);
1018 0 : entityEnd[0] = ';';
1019 : current = entityEnd;
1020 375 : continue;
1021 : }
1022 : assert(ent);
1023 : /*truncate input buffer*/
1024 0 : parser->line_size -= (u32) strlen(entityStart);
1025 0 : entityStart[0] = 0;
1026 :
1027 0 : parser->in_entity = GF_FALSE;
1028 0 : entityEnd[0] = ';';
1029 0 : current = entityEnd+1;
1030 : } else {
1031 420 : if (!entityStart) break;
1032 :
1033 380 : ent = gf_xml_locate_entity(parser, entityStart+1, &needs_text);
1034 :
1035 : /*store current string before entity start*/
1036 380 : entityStart[0] = 0;
1037 380 : xml_sax_append_string(parser, current);
1038 380 : xml_sax_parse(parser, GF_TRUE);
1039 380 : entityStart[0] = '&';
1040 :
1041 : /*this is not an entitiy*/
1042 380 : if (!ent && !needs_text) {
1043 375 : xml_sax_append_string(parser, "&");
1044 : current = entityStart+1;
1045 375 : continue;
1046 : }
1047 :
1048 5 : if (!ent) {
1049 0 : parser->in_entity = GF_TRUE;
1050 : /*store entity start*/
1051 0 : return xml_sax_append_string(parser, entityStart);
1052 : }
1053 5 : current = entityStart + ent->namelen + 2;
1054 : }
1055 : /*append entity*/
1056 5 : line_num = parser->line;
1057 5 : xml_sax_append_string(parser, ent->value);
1058 5 : xml_sax_parse(parser, GF_TRUE);
1059 5 : parser->line = line_num;
1060 :
1061 : }
1062 2138 : xml_sax_append_string(parser, current);
1063 2138 : return xml_sax_parse(parser, GF_FALSE);
1064 : }
1065 :
1066 : GF_EXPORT
1067 2133 : GF_Err gf_xml_sax_parse(GF_SAXParser *parser, const void *string)
1068 : {
1069 : GF_Err e;
1070 : char *current;
1071 : char *utf_conv = NULL;
1072 :
1073 2133 : if (parser->unicode_type < 0) return GF_BAD_PARAM;
1074 :
1075 2133 : if (parser->unicode_type>1) {
1076 0 : const u16 *sptr = (const u16 *)string;
1077 0 : u32 len = 2 * (u32) gf_utf8_wcslen(sptr);
1078 0 : utf_conv = (char *)gf_malloc(sizeof(char)*(len+1));
1079 0 : len = (u32) gf_utf8_wcstombs(utf_conv, len, &sptr);
1080 0 : if (len==(u32) -1) {
1081 0 : parser->sax_state = SAX_STATE_SYNTAX_ERROR;
1082 0 : gf_free(utf_conv);
1083 0 : return GF_CORRUPTED_DATA;
1084 : }
1085 0 : utf_conv[len] = 0;
1086 : current = utf_conv;
1087 : } else {
1088 : current = (char *)string;
1089 : }
1090 :
1091 2133 : e = gf_xml_sax_parse_intern(parser, current);
1092 2133 : if (utf_conv) gf_free(utf_conv);
1093 : return e;
1094 : }
1095 :
1096 :
1097 : GF_EXPORT
1098 1013 : GF_Err gf_xml_sax_init(GF_SAXParser *parser, unsigned char *BOM)
1099 : {
1100 : u32 offset;
1101 1013 : if (!BOM) {
1102 0 : parser->unicode_type = 0;
1103 0 : parser->sax_state = SAX_STATE_ELEMENT;
1104 0 : return GF_OK;
1105 : }
1106 :
1107 1013 : if (parser->unicode_type >= 0) return gf_xml_sax_parse(parser, BOM);
1108 :
1109 1013 : if ((BOM[0]==0xFF) && (BOM[1]==0xFE)) {
1110 0 : if (!BOM[2] && !BOM[3]) return GF_NOT_SUPPORTED;
1111 0 : parser->unicode_type = 2;
1112 0 : offset = 2;
1113 1013 : } else if ((BOM[0]==0xFE) && (BOM[1]==0xFF)) {
1114 0 : if (!BOM[2] && !BOM[3]) return GF_NOT_SUPPORTED;
1115 0 : parser->unicode_type = 1;
1116 0 : offset = 2;
1117 1013 : } else if ((BOM[0]==0xEF) && (BOM[1]==0xBB) && (BOM[2]==0xBF)) {
1118 : /*we handle UTF8 as asci*/
1119 9 : parser->unicode_type = 0;
1120 9 : offset = 3;
1121 : } else {
1122 1004 : parser->unicode_type = 0;
1123 : offset = 0;
1124 : }
1125 :
1126 : #ifdef GPAC_ENABLE_COVERAGE
1127 1013 : if (gf_sys_is_cov_mode()) {
1128 1005 : format_sax_error(NULL, 0, "");
1129 : }
1130 : #endif
1131 :
1132 1013 : parser->sax_state = SAX_STATE_ELEMENT;
1133 1013 : return gf_xml_sax_parse(parser, BOM + offset);
1134 : }
1135 :
1136 1019 : static void xml_sax_reset(GF_SAXParser *parser)
1137 : {
1138 5 : while (1) {
1139 1024 : XML_Entity *ent = (XML_Entity *)gf_list_last(parser->entities);
1140 1024 : if (!ent) break;
1141 5 : gf_list_rem_last(parser->entities);
1142 5 : if (ent->name) gf_free(ent->name);
1143 5 : if (ent->value) gf_free(ent->value);
1144 5 : gf_free(ent);
1145 : }
1146 1019 : if (parser->buffer) gf_free(parser->buffer);
1147 1019 : parser->buffer = NULL;
1148 1019 : parser->current_pos = 0;
1149 1019 : gf_free(parser->attrs);
1150 1019 : parser->attrs = NULL;
1151 1019 : gf_free(parser->sax_attrs);
1152 1019 : parser->sax_attrs = NULL;
1153 1019 : parser->nb_alloc_attrs = parser->nb_attrs = 0;
1154 1019 : }
1155 :
1156 :
1157 907 : static GF_Err xml_sax_read_file(GF_SAXParser *parser)
1158 : {
1159 : GF_Err e = GF_EOS;
1160 : unsigned char szLine[XML_INPUT_SIZE+2];
1161 :
1162 : #ifdef NO_GZIP
1163 : if (!parser->f_in) return GF_BAD_PARAM;
1164 : #else
1165 907 : if (!parser->gz_in) return GF_BAD_PARAM;
1166 : #endif
1167 :
1168 :
1169 1998 : while (!parser->suspended) {
1170 : #ifdef NO_GZIP
1171 : s32 read = (s32)gf_fread(szLine, XML_INPUT_SIZE, parser->f_in);
1172 : #else
1173 1881 : s32 read = gf_gzread(parser->gz_in, szLine, XML_INPUT_SIZE);
1174 : #endif
1175 1881 : if ((read<=0) /*&& !parser->node_depth*/) break;
1176 1092 : szLine[read] = 0;
1177 1092 : szLine[read+1] = 0;
1178 1092 : e = gf_xml_sax_parse(parser, szLine);
1179 1092 : if (e) break;
1180 1091 : if (parser->file_pos > parser->file_size) parser->file_size = parser->file_pos + 1;
1181 1091 : if (parser->on_progress) parser->on_progress(parser->sax_cbck, parser->file_pos, parser->file_size);
1182 : }
1183 :
1184 : #ifdef NO_GZIP
1185 : if (gf_feof(parser->f_in)) {
1186 : #else
1187 907 : if (gf_gzeof(parser->gz_in)) {
1188 : #endif
1189 789 : if (!e) e = GF_EOS;
1190 789 : if (parser->on_progress) parser->on_progress(parser->sax_cbck, parser->file_size, parser->file_size);
1191 :
1192 : #ifdef NO_GZIP
1193 : gf_fclose(parser->f_in);
1194 : parser->f_in = NULL;
1195 : #else
1196 789 : gf_gzclose(parser->gz_in);
1197 789 : parser->gz_in = 0;
1198 : #endif
1199 :
1200 789 : parser->elt_start_pos = parser->elt_end_pos = 0;
1201 789 : parser->elt_name_start = parser->elt_name_end = 0;
1202 789 : parser->att_name_start = 0;
1203 789 : parser->current_pos = 0;
1204 789 : parser->line_size = 0;
1205 789 : parser->att_sep = 0;
1206 789 : parser->file_pos = 0;
1207 789 : parser->file_size = 0;
1208 : parser->line_size = 0;
1209 : }
1210 : return e;
1211 : }
1212 :
1213 : GF_EXPORT
1214 940 : GF_Err gf_xml_sax_parse_file(GF_SAXParser *parser, const char *fileName, gf_xml_sax_progress OnProgress)
1215 : {
1216 : FILE *test;
1217 : GF_Err e;
1218 : u64 filesize;
1219 : #ifndef NO_GZIP
1220 : gzFile gzInput;
1221 : #endif
1222 : unsigned char szLine[6];
1223 :
1224 940 : parser->on_progress = OnProgress;
1225 :
1226 940 : if (!strncmp(fileName, "gmem://", 7)) {
1227 : u32 size;
1228 : u8 *xml_mem_address;
1229 27 : e = gf_blob_get(fileName, &xml_mem_address, &size, NULL);
1230 27 : if (e) return e;
1231 :
1232 27 : parser->file_size = size;
1233 : //copy possible BOM
1234 27 : memcpy(szLine, xml_mem_address, 4);
1235 27 : szLine[4] = szLine[5] = 0;
1236 :
1237 27 : parser->file_pos = 0;
1238 27 : parser->elt_start_pos = 0;
1239 27 : parser->current_pos = 0;
1240 :
1241 27 : e = gf_xml_sax_init(parser, szLine);
1242 27 : if (!e) {
1243 27 : e = gf_xml_sax_parse(parser, xml_mem_address+4);
1244 27 : if (parser->on_progress) parser->on_progress(parser->sax_cbck, parser->file_pos, parser->file_size);
1245 : }
1246 27 : gf_blob_release(fileName);
1247 :
1248 27 : parser->elt_start_pos = parser->elt_end_pos = 0;
1249 27 : parser->elt_name_start = parser->elt_name_end = 0;
1250 27 : parser->att_name_start = 0;
1251 27 : parser->current_pos = 0;
1252 27 : parser->line_size = 0;
1253 27 : parser->att_sep = 0;
1254 27 : parser->file_pos = 0;
1255 27 : parser->file_size = 0;
1256 : parser->line_size = 0;
1257 27 : return e;
1258 : }
1259 :
1260 : /*check file exists and gets its size (zlib doesn't support SEEK_END)*/
1261 913 : test = gf_fopen(fileName, "rb");
1262 913 : if (!test) return GF_URL_ERROR;
1263 :
1264 907 : filesize = gf_fsize(test);
1265 : assert(filesize < 0x80000000);
1266 907 : parser->file_size = (u32) filesize;
1267 907 : gf_fclose(test);
1268 :
1269 907 : parser->file_pos = 0;
1270 907 : parser->elt_start_pos = 0;
1271 907 : parser->current_pos = 0;
1272 : //open file and copy possible BOM
1273 : #ifdef NO_GZIP
1274 : parser->f_in = gf_fopen(fileName, "rt");
1275 : if (gf_fread(szLine, 4, parser->f_in) != 4) {
1276 : GF_LOG(GF_LOG_WARNING, GF_LOG_CORE, ("[XML] Error loading BOM\n"));
1277 : }
1278 : #else
1279 907 : gzInput = gf_gzopen(fileName, "rb");
1280 907 : if (!gzInput) return GF_IO_ERR;
1281 907 : parser->gz_in = gzInput;
1282 : /*init SAX parser (unicode setup)*/
1283 907 : gf_gzread(gzInput, szLine, 4);
1284 : #endif
1285 :
1286 907 : szLine[4] = szLine[5] = 0;
1287 907 : e = gf_xml_sax_init(parser, szLine);
1288 907 : if (e) return e;
1289 :
1290 907 : return xml_sax_read_file(parser);
1291 : }
1292 :
1293 : GF_EXPORT
1294 1 : Bool gf_xml_sax_binary_file(GF_SAXParser *parser)
1295 : {
1296 1 : if (!parser) return GF_FALSE;
1297 : #ifdef NO_GZIP
1298 : return GF_FALSE;
1299 : #else
1300 1 : if (!parser->gz_in) return GF_FALSE;
1301 0 : return (((z_stream*)parser->gz_in)->data_type==Z_BINARY) ? GF_TRUE : GF_FALSE;
1302 : #endif
1303 : }
1304 :
1305 : GF_EXPORT
1306 1019 : GF_SAXParser *gf_xml_sax_new(gf_xml_sax_node_start on_node_start,
1307 : gf_xml_sax_node_end on_node_end,
1308 : gf_xml_sax_text_content on_text_content,
1309 : void *cbck)
1310 : {
1311 : GF_SAXParser *parser;
1312 1019 : GF_SAFEALLOC(parser, GF_SAXParser);
1313 1019 : if (!parser) return NULL;
1314 1019 : parser->entities = gf_list_new();
1315 1019 : parser->unicode_type = -1;
1316 1019 : parser->sax_node_start = on_node_start;
1317 1019 : parser->sax_node_end = on_node_end;
1318 1019 : parser->sax_text_content = on_text_content;
1319 1019 : parser->sax_cbck = cbck;
1320 1019 : return parser;
1321 : }
1322 :
1323 : GF_EXPORT
1324 1019 : void gf_xml_sax_del(GF_SAXParser *parser)
1325 : {
1326 1019 : xml_sax_reset(parser);
1327 1019 : gf_list_del(parser->entities);
1328 : #ifdef NO_GZIP
1329 : if (parser->f_in) gf_fclose(parser->f_in);
1330 : #else
1331 1019 : if (parser->gz_in) gf_gzclose(parser->gz_in);
1332 : #endif
1333 1019 : gf_free(parser);
1334 1019 : }
1335 :
1336 : GF_EXPORT
1337 8 : GF_Err gf_xml_sax_suspend(GF_SAXParser *parser, Bool do_suspend)
1338 : {
1339 8 : parser->suspended = do_suspend;
1340 8 : if (!do_suspend) {
1341 : #ifdef NO_GZIP
1342 : if (parser->f_in) return xml_sax_read_file(parser);
1343 : #else
1344 0 : if (parser->gz_in) return xml_sax_read_file(parser);
1345 : #endif
1346 0 : return xml_sax_parse(parser, GF_FALSE);
1347 : }
1348 : return GF_OK;
1349 : }
1350 :
1351 :
1352 : GF_EXPORT
1353 11 : u32 gf_xml_sax_get_line(GF_SAXParser *parser) {
1354 11 : return parser->line + 1 ;
1355 : }
1356 :
1357 : #if 0 //unused
1358 : u32 gf_xml_sax_get_file_size(GF_SAXParser *parser)
1359 : {
1360 : #ifdef NO_GZIP
1361 : return parser->f_in ? parser->file_size : 0;
1362 : #else
1363 : return parser->gz_in ? parser->file_size : 0;
1364 : #endif
1365 : }
1366 :
1367 : u32 gf_xml_sax_get_file_pos(GF_SAXParser *parser)
1368 : {
1369 : #ifdef NO_GZIP
1370 : return parser->f_in ? parser->file_pos : 0;
1371 : #else
1372 : return parser->gz_in ? parser->file_pos : 0;
1373 : #endif
1374 : }
1375 : #endif
1376 :
1377 :
1378 :
1379 : GF_EXPORT
1380 5 : char *gf_xml_sax_peek_node(GF_SAXParser *parser, char *att_name, char *att_value, char *substitute, char *get_attr, char *end_pattern, Bool *is_substitute)
1381 : {
1382 : u32 state, att_len, alloc_size, _len;
1383 : #ifdef NO_GZIP
1384 : u64 pos;
1385 : #else
1386 : z_off_t pos;
1387 : #endif
1388 : Bool from_buffer;
1389 : Bool dobreak=GF_FALSE;
1390 : char szLine1[XML_INPUT_SIZE+2], szLine2[XML_INPUT_SIZE+2], *szLine, *cur_line, *sep, *start, first_c, *result;
1391 :
1392 :
1393 : #define CPYCAT_ALLOC(__str, __is_copy) _len = (u32) strlen(__str);\
1394 : if ( _len + (__is_copy ? 0 : strlen(szLine))>=alloc_size) {\
1395 : alloc_size = 1 + (u32) strlen(__str); \
1396 : if (!__is_copy) alloc_size += (u32) strlen(szLine); \
1397 : szLine = gf_realloc(szLine, alloc_size); \
1398 : }\
1399 : if (__is_copy) { memmove(szLine, __str, sizeof(char)*_len); szLine[_len] = 0; }\
1400 : else strcat(szLine, __str); \
1401 :
1402 : from_buffer=GF_FALSE;
1403 : #ifdef NO_GZIP
1404 : if (!parser->f_in) from_buffer=GF_TRUE;
1405 : #else
1406 5 : if (!parser->gz_in) from_buffer=GF_TRUE;
1407 : #endif
1408 :
1409 : result = NULL;
1410 :
1411 5 : szLine1[0] = szLine2[0] = 0;
1412 : pos=0;
1413 5 : if (!from_buffer) {
1414 : #ifdef NO_GZIP
1415 : pos = gf_ftell(parser->f_in);
1416 : #else
1417 5 : pos = (u32) gf_gztell(parser->gz_in);
1418 : #endif
1419 : }
1420 5 : att_len = (u32) strlen(parser->buffer + parser->att_name_start);
1421 5 : if (att_len<2*XML_INPUT_SIZE) att_len = 2*XML_INPUT_SIZE;
1422 : alloc_size = att_len;
1423 5 : szLine = (char *) gf_malloc(sizeof(char)*alloc_size);
1424 5 : strcpy(szLine, parser->buffer + parser->att_name_start);
1425 : cur_line = szLine;
1426 5 : att_len = (u32) strlen(att_value);
1427 : state = 0;
1428 5 : goto retry;
1429 :
1430 : while (1) {
1431 : u32 read;
1432 : u8 sep_char;
1433 0 : if (!from_buffer) {
1434 : #ifdef NO_GZIP
1435 : if (gf_feof(parser->f_in)) break;
1436 : #else
1437 0 : if (gf_gzeof(parser->gz_in)) break;
1438 : #endif
1439 : }
1440 :
1441 0 : if (dobreak) break;
1442 :
1443 0 : if (cur_line == szLine2) {
1444 : cur_line = szLine1;
1445 : } else {
1446 : cur_line = szLine2;
1447 : }
1448 0 : if (from_buffer) {
1449 : dobreak=GF_TRUE;
1450 : } else {
1451 : #ifdef NO_GZIP
1452 : read = (u32)gf_fread(cur_line, XML_INPUT_SIZE, parser->f_in);
1453 : #else
1454 0 : read = gf_gzread(parser->gz_in, cur_line, XML_INPUT_SIZE);
1455 : #endif
1456 0 : cur_line[read] = cur_line[read+1] = 0;
1457 :
1458 0 : CPYCAT_ALLOC(cur_line, 0);
1459 : }
1460 :
1461 0 : if (end_pattern) {
1462 0 : start = strstr(szLine, end_pattern);
1463 0 : if (start) {
1464 0 : start[0] = 0;
1465 : dobreak = GF_TRUE;
1466 : }
1467 : }
1468 :
1469 0 : retry:
1470 25 : if (state == 2) goto fetch_attr;
1471 25 : sep = strstr(szLine, att_name);
1472 25 : if (!sep && !state) {
1473 : state = 0;
1474 0 : start = strrchr(szLine, '<');
1475 0 : if (start) {
1476 0 : CPYCAT_ALLOC(start, 1);
1477 : } else {
1478 0 : CPYCAT_ALLOC(cur_line, 1);
1479 : }
1480 0 : continue;
1481 : }
1482 25 : if (!state) {
1483 : state = 1;
1484 : /*load next line*/
1485 25 : first_c = sep[0];
1486 25 : sep[0] = 0;
1487 25 : start = strrchr(szLine, '<');
1488 25 : if (!start)
1489 : goto exit;
1490 25 : sep[0] = first_c;
1491 50 : CPYCAT_ALLOC(start, 1);
1492 25 : sep = strstr(szLine, att_name);
1493 : }
1494 25 : sep = sep ? strchr(sep, '=') : NULL;
1495 25 : if (!sep) {
1496 : state = 0;
1497 0 : CPYCAT_ALLOC(cur_line, 1);
1498 0 : continue;
1499 : }
1500 25 : while (sep[0] && (sep[0] != '\"') && (sep[0] != '\'') ) sep++;
1501 25 : if (!sep[0]) continue;
1502 25 : sep_char = sep[0];
1503 25 : sep++;
1504 25 : while (sep[0] && strchr(" \n\r\t", sep[0]) ) sep++;
1505 25 : if (!sep[0]) continue;
1506 25 : if (!strchr(sep, sep_char))
1507 0 : continue;
1508 :
1509 : /*found*/
1510 25 : if (!strncmp(sep, att_value, att_len)) {
1511 : u32 sub_pos;
1512 5 : sep = szLine + 1;
1513 5 : while (strchr(" \t\r\n", sep[0])) sep++;
1514 : sub_pos = 0;
1515 55 : while (!strchr(" \t\r\n", sep[sub_pos])) sub_pos++;
1516 : first_c = sep[sub_pos];
1517 5 : sep[sub_pos] = 0;
1518 : state = 2;
1519 5 : if (!substitute || !get_attr || strcmp(sep, substitute) ) {
1520 5 : if (is_substitute) *is_substitute = GF_FALSE;
1521 5 : result = gf_strdup(sep);
1522 5 : sep[sub_pos] = first_c;
1523 5 : goto exit;
1524 : }
1525 0 : sep[sub_pos] = first_c;
1526 0 : fetch_attr:
1527 0 : sep = strstr(szLine + 1, get_attr);
1528 0 : if (!sep) {
1529 0 : CPYCAT_ALLOC(cur_line, 1);
1530 0 : continue;
1531 : }
1532 0 : sep += strlen(get_attr);
1533 0 : while (strchr("= \t\r\n", sep[0])) sep++;
1534 0 : sep++;
1535 : sub_pos = 0;
1536 0 : while (!strchr(" \t\r\n/>", sep[sub_pos])) sub_pos++;
1537 0 : sep[sub_pos-1] = 0;
1538 0 : result = gf_strdup(sep);
1539 0 : if (is_substitute) *is_substitute = GF_TRUE;
1540 : goto exit;
1541 : }
1542 : state = 0;
1543 40 : CPYCAT_ALLOC(sep, 1);
1544 20 : goto retry;
1545 : }
1546 0 : exit:
1547 5 : gf_free(szLine);
1548 :
1549 5 : if (!from_buffer) {
1550 : #ifdef NO_GZIP
1551 : gf_fseek(parser->f_in, pos, SEEK_SET);
1552 : #else
1553 5 : gf_gzrewind(parser->gz_in);
1554 5 : gf_gzseek(parser->gz_in, pos, SEEK_SET);
1555 : #endif
1556 : }
1557 5 : return result;
1558 : }
1559 :
1560 : GF_EXPORT
1561 2 : const char *gf_xml_sax_get_error(GF_SAXParser *parser)
1562 : {
1563 2 : return parser->err_msg;
1564 : }
1565 :
1566 :
1567 : struct _peek_type
1568 : {
1569 : GF_SAXParser *parser;
1570 : char *res;
1571 : };
1572 :
1573 117 : static void on_peek_node_start(void *cbk, const char *name, const char *ns, const GF_XMLAttribute *attributes, u32 nb_attributes)
1574 : {
1575 : struct _peek_type *pt = (struct _peek_type*)cbk;
1576 117 : pt->res = gf_strdup(name);
1577 117 : pt->parser->suspended = GF_TRUE;
1578 117 : }
1579 :
1580 : GF_EXPORT
1581 117 : char *gf_xml_get_root_type(const char *file, GF_Err *ret)
1582 : {
1583 : GF_Err e;
1584 : struct _peek_type pt;
1585 117 : pt.res = NULL;
1586 117 : pt.parser = gf_xml_sax_new(on_peek_node_start, NULL, NULL, &pt);
1587 117 : e = gf_xml_sax_parse_file(pt.parser, file, NULL);
1588 117 : if (ret) *ret = e;
1589 117 : gf_xml_sax_del(pt.parser);
1590 117 : return pt.res;
1591 : }
1592 :
1593 :
1594 : GF_EXPORT
1595 8 : u32 gf_xml_sax_get_node_start_pos(GF_SAXParser *parser)
1596 : {
1597 8 : return parser->elt_start_pos;
1598 : }
1599 :
1600 : GF_EXPORT
1601 2 : u32 gf_xml_sax_get_node_end_pos(GF_SAXParser *parser)
1602 : {
1603 2 : return parser->elt_end_pos;
1604 : }
1605 :
1606 : struct _tag_dom_parser
1607 : {
1608 : GF_SAXParser *parser;
1609 : GF_List *stack;
1610 : //root node being parsed
1611 : GF_XMLNode *root;
1612 : //usually only one :)
1613 : GF_List *root_nodes;
1614 : u32 depth;
1615 :
1616 : void (*OnProgress)(void *cbck, u64 done, u64 tot);
1617 : void *cbk;
1618 : };
1619 :
1620 :
1621 : GF_EXPORT
1622 28676 : void gf_xml_dom_node_reset(GF_XMLNode *node, Bool reset_attribs, Bool reset_children)
1623 : {
1624 28676 : if (!node) return;
1625 28676 : if (node->attributes && reset_attribs) {
1626 50886 : while (gf_list_count(node->attributes)) {
1627 37831 : GF_XMLAttribute *att = (GF_XMLAttribute *)gf_list_last(node->attributes);
1628 37831 : gf_list_rem_last(node->attributes);
1629 37831 : if (att->name) gf_free(att->name);
1630 37831 : if (att->value) gf_free(att->value);
1631 37831 : gf_free(att);
1632 : }
1633 : }
1634 :
1635 28676 : if (reset_children && node->content) {
1636 40887 : while (gf_list_count(node->content)) {
1637 27830 : GF_XMLNode *child = (GF_XMLNode *)gf_list_last(node->content);
1638 27830 : gf_list_rem_last(node->content);
1639 27830 : gf_xml_dom_node_del(child);
1640 : }
1641 : }
1642 : }
1643 :
1644 : GF_EXPORT
1645 28674 : void gf_xml_dom_node_del(GF_XMLNode *node)
1646 : {
1647 28674 : if (!node) return;
1648 28674 : gf_xml_dom_node_reset(node, GF_TRUE, GF_TRUE);
1649 28674 : if (node->attributes) gf_list_del(node->attributes);
1650 28674 : if (node->content) gf_list_del(node->content);
1651 28674 : if (node->ns) gf_free(node->ns);
1652 28674 : if (node->name) gf_free(node->name);
1653 28674 : gf_free(node);
1654 : }
1655 :
1656 13043 : static void on_dom_node_start(void *cbk, const char *name, const char *ns, const GF_XMLAttribute *attributes, u32 nb_attributes)
1657 : {
1658 : u32 i;
1659 : GF_DOMParser *par = (GF_DOMParser *) cbk;
1660 : GF_XMLNode *node;
1661 :
1662 13043 : if (par->root && !gf_list_count(par->stack)) {
1663 0 : par->parser->suspended = GF_TRUE;
1664 0 : return;
1665 : }
1666 :
1667 13043 : GF_SAFEALLOC(node, GF_XMLNode);
1668 13043 : if (!node) {
1669 0 : par->parser->sax_state = SAX_STATE_ALLOC_ERROR;
1670 0 : return;
1671 : }
1672 13043 : node->attributes = gf_list_new();
1673 13043 : node->content = gf_list_new();
1674 13043 : node->name = gf_strdup(name);
1675 13043 : if (ns) node->ns = gf_strdup(ns);
1676 13043 : gf_list_add(par->stack, node);
1677 13043 : if (!par->root) {
1678 583 : par->root = node;
1679 583 : gf_list_add(par->root_nodes, node);
1680 : }
1681 :
1682 38012 : for (i=0; i<nb_attributes; i++) {
1683 : GF_XMLAttribute *att;
1684 38012 : GF_SAFEALLOC(att, GF_XMLAttribute);
1685 38012 : if (! att) {
1686 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SAX] Failed to allocate attribute"));
1687 0 : par->parser->sax_state = SAX_STATE_ALLOC_ERROR;
1688 0 : return;
1689 : }
1690 38012 : att->name = gf_strdup(attributes[i].name);
1691 38012 : att->value = gf_strdup(attributes[i].value);
1692 38012 : gf_list_add(node->attributes, att);
1693 : }
1694 : }
1695 :
1696 13043 : static void on_dom_node_end(void *cbk, const char *name, const char *ns)
1697 : {
1698 : GF_DOMParser *par = (GF_DOMParser *)cbk;
1699 13043 : GF_XMLNode *last = (GF_XMLNode *)gf_list_last(par->stack);
1700 13043 : gf_list_rem_last(par->stack);
1701 :
1702 13043 : if (!last || (strlen(last->name)!=strlen(name)) || strcmp(last->name, name) || (!ns && last->ns) || (ns && !last->ns) || (ns && strcmp(last->ns, ns) ) ) {
1703 : s32 idx;
1704 0 : format_sax_error(par->parser, 0, "Invalid node stack: closing node is %s but %s was expected", name, last ? last->name : "unknown");
1705 0 : par->parser->suspended = GF_TRUE;
1706 0 : gf_xml_dom_node_del(last);
1707 0 : if (last == par->root)
1708 0 : par->root=NULL;
1709 0 : idx = gf_list_find(par->root_nodes, last);
1710 0 : if (idx != -1)
1711 0 : gf_list_rem(par->root_nodes, idx);
1712 : return;
1713 : }
1714 :
1715 13043 : if (last != par->root) {
1716 12460 : GF_XMLNode *node = (GF_XMLNode *)gf_list_last(par->stack);
1717 : assert(node->content);
1718 : assert(gf_list_find(node->content, last) == -1);
1719 12460 : gf_list_add(node->content, last);
1720 : }
1721 : }
1722 :
1723 15603 : static void on_dom_text_content(void *cbk, const char *content, Bool is_cdata)
1724 : {
1725 : GF_DOMParser *par = (GF_DOMParser *)cbk;
1726 : GF_XMLNode *node;
1727 15603 : GF_XMLNode *last = (GF_XMLNode *)gf_list_last(par->stack);
1728 15603 : if (!last) return;
1729 : assert(last->content);
1730 :
1731 15603 : GF_SAFEALLOC(node, GF_XMLNode);
1732 15603 : if (!node) {
1733 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SAX] Failed to allocate XML node"));
1734 0 : par->parser->sax_state = SAX_STATE_ALLOC_ERROR;
1735 0 : return;
1736 : }
1737 15603 : node->type = is_cdata ? GF_XML_CDATA_TYPE : GF_XML_TEXT_TYPE;
1738 15603 : node->name = gf_strdup(content);
1739 15603 : gf_list_add(last->content, node);
1740 : }
1741 :
1742 : GF_EXPORT
1743 580 : GF_DOMParser *gf_xml_dom_new()
1744 : {
1745 : GF_DOMParser *dom;
1746 580 : GF_SAFEALLOC(dom, GF_DOMParser);
1747 580 : if (!dom) return NULL;
1748 :
1749 580 : dom->root_nodes = gf_list_new();
1750 580 : return dom;
1751 : }
1752 :
1753 1758 : static void gf_xml_dom_reset(GF_DOMParser *dom, Bool full_reset)
1754 : {
1755 1758 : if (full_reset && dom->parser) {
1756 589 : gf_xml_sax_del(dom->parser);
1757 589 : dom->parser = NULL;
1758 : }
1759 :
1760 1758 : if (dom->stack) {
1761 589 : while (gf_list_count(dom->stack)) {
1762 0 : GF_XMLNode *n = (GF_XMLNode *)gf_list_last(dom->stack);
1763 0 : gf_list_rem_last(dom->stack);
1764 0 : if (dom->root==n) {
1765 0 : gf_list_del_item(dom->root_nodes, n);
1766 0 : dom->root = NULL;
1767 : }
1768 0 : gf_xml_dom_node_del(n);
1769 : }
1770 589 : gf_list_del(dom->stack);
1771 589 : dom->stack = NULL;
1772 : }
1773 1758 : if (full_reset && gf_list_count(dom->root_nodes) ) {
1774 1152 : while (gf_list_count(dom->root_nodes)) {
1775 576 : GF_XMLNode *n = (GF_XMLNode *)gf_list_last(dom->root_nodes);
1776 576 : gf_list_rem_last(dom->root_nodes);
1777 576 : gf_xml_dom_node_del(n);
1778 : }
1779 576 : dom->root = NULL;
1780 : }
1781 1758 : }
1782 :
1783 : GF_EXPORT
1784 580 : void gf_xml_dom_del(GF_DOMParser *parser)
1785 : {
1786 580 : if (!parser)
1787 : return;
1788 :
1789 580 : gf_xml_dom_reset(parser, GF_TRUE);
1790 580 : gf_list_del(parser->root_nodes);
1791 580 : gf_free(parser);
1792 : }
1793 :
1794 : GF_EXPORT
1795 7 : GF_XMLNode *gf_xml_dom_detach_root(GF_DOMParser *parser)
1796 : {
1797 : GF_XMLNode *root;
1798 7 : if (!parser)
1799 : return NULL;
1800 7 : root = parser->root;
1801 7 : gf_list_del_item(parser->root_nodes, root);
1802 7 : parser->root = gf_list_get(parser->root_nodes, 0);
1803 7 : return root;
1804 : }
1805 :
1806 46 : static void dom_on_progress(void *cbck, u64 done, u64 tot)
1807 : {
1808 : GF_DOMParser *dom = (GF_DOMParser *)cbck;
1809 46 : dom->OnProgress(dom->cbk, done, tot);
1810 46 : }
1811 :
1812 : GF_EXPORT
1813 512 : GF_Err gf_xml_dom_parse(GF_DOMParser *dom, const char *file, gf_xml_sax_progress OnProgress, void *cbk)
1814 : {
1815 : GF_Err e;
1816 512 : gf_xml_dom_reset(dom, GF_TRUE);
1817 512 : dom->stack = gf_list_new();
1818 512 : dom->parser = gf_xml_sax_new(on_dom_node_start, on_dom_node_end, on_dom_text_content, dom);
1819 512 : dom->OnProgress = OnProgress;
1820 512 : dom->cbk = cbk;
1821 512 : e = gf_xml_sax_parse_file(dom->parser, file, OnProgress ? dom_on_progress : NULL);
1822 512 : gf_xml_dom_reset(dom, GF_FALSE);
1823 512 : return e<0 ? e : GF_OK;
1824 : }
1825 :
1826 : GF_EXPORT
1827 77 : GF_Err gf_xml_dom_parse_string(GF_DOMParser *dom, char *string)
1828 : {
1829 : GF_Err e;
1830 77 : gf_xml_dom_reset(dom, GF_TRUE);
1831 77 : dom->stack = gf_list_new();
1832 77 : dom->parser = gf_xml_sax_new(on_dom_node_start, on_dom_node_end, on_dom_text_content, dom);
1833 77 : e = gf_xml_sax_init(dom->parser, (unsigned char *) string);
1834 77 : gf_xml_dom_reset(dom, GF_FALSE);
1835 77 : return e<0 ? e : GF_OK;
1836 : }
1837 :
1838 : #if 0 //unused
1839 : GF_XMLNode *gf_xml_dom_create_root(GF_DOMParser *parser, const char* name) {
1840 : GF_XMLNode * root;
1841 : if (!parser) return NULL;
1842 :
1843 : GF_SAFEALLOC(root, GF_XMLNode);
1844 : if (!root) return NULL;
1845 : root->name = gf_strdup(name);
1846 :
1847 : return root;
1848 : }
1849 : #endif
1850 :
1851 : GF_EXPORT
1852 757 : GF_XMLNode *gf_xml_dom_get_root(GF_DOMParser *parser)
1853 : {
1854 757 : return parser ? parser->root : NULL;
1855 : }
1856 : GF_EXPORT
1857 1 : const char *gf_xml_dom_get_error(GF_DOMParser *parser)
1858 : {
1859 1 : return gf_xml_sax_get_error(parser->parser);
1860 : }
1861 : GF_EXPORT
1862 1 : u32 gf_xml_dom_get_line(GF_DOMParser *parser)
1863 : {
1864 1 : return gf_xml_sax_get_line(parser->parser);
1865 : }
1866 :
1867 : GF_EXPORT
1868 5 : u32 gf_xml_dom_get_root_nodes_count(GF_DOMParser *parser)
1869 : {
1870 5 : return parser? gf_list_count(parser->root_nodes) : 0;
1871 : }
1872 :
1873 : GF_EXPORT
1874 5 : GF_XMLNode *gf_xml_dom_get_root_idx(GF_DOMParser *parser, u32 idx)
1875 : {
1876 5 : return parser ? (GF_XMLNode*)gf_list_get(parser->root_nodes, idx) : NULL;
1877 : }
1878 :
1879 :
1880 3147 : static void gf_xml_dom_node_serialize(GF_XMLNode *node, Bool content_only, Bool no_escape, char **str, u32 *alloc_size, u32 *size)
1881 : {
1882 : u32 i, count, vlen;
1883 : char *name;
1884 :
1885 : #define SET_STRING(v) \
1886 : vlen = (u32) strlen(v); \
1887 : if (vlen + (*size) >= (*alloc_size)) { \
1888 : (*alloc_size) += 1024; \
1889 : if (vlen + (*size) >= (*alloc_size)) (*alloc_size) = vlen + (*size) + 1;\
1890 : (*str) = gf_realloc((*str), (*alloc_size)); \
1891 : (*str)[(*size)] = 0; \
1892 : } \
1893 : strcat((*str), v); \
1894 : *size += vlen; \
1895 :
1896 3147 : switch (node->type) {
1897 0 : case GF_XML_CDATA_TYPE:
1898 0 : SET_STRING("![CDATA[");
1899 0 : SET_STRING(node->name);
1900 0 : SET_STRING("]]>");
1901 0 : return;
1902 1938 : case GF_XML_TEXT_TYPE:
1903 1938 : name = node->name;
1904 1938 : if ((name[0]=='\r') && (name[1]=='\n'))
1905 0 : name++;
1906 :
1907 1938 : if (no_escape) {
1908 16 : SET_STRING(name);
1909 : } else {
1910 : u32 tlen;
1911 : char szChar[2];
1912 1930 : szChar[1] = 0;
1913 1930 : tlen = (u32) strlen(name);
1914 121305 : for (i= 0; i<tlen; i++) {
1915 119375 : switch (name[i]) {
1916 0 : case '&':
1917 0 : SET_STRING("&");
1918 0 : break;
1919 2 : case '<':
1920 4 : SET_STRING("<");
1921 2 : break;
1922 2 : case '>':
1923 4 : SET_STRING(">");
1924 2 : break;
1925 0 : case '\'':
1926 0 : SET_STRING("'");
1927 0 : break;
1928 0 : case '\"':
1929 0 : SET_STRING(""");
1930 0 : break;
1931 :
1932 119371 : default:
1933 119371 : szChar[0] = name[i];
1934 238742 : SET_STRING(szChar);
1935 119371 : break;
1936 : }
1937 : }
1938 : }
1939 : return;
1940 : }
1941 :
1942 1209 : if (!content_only) {
1943 2414 : SET_STRING("<");
1944 1207 : if (node->ns) {
1945 68 : SET_STRING(node->ns);
1946 68 : SET_STRING(":");
1947 : }
1948 2414 : SET_STRING(node->name);
1949 1207 : count = gf_list_count(node->attributes);
1950 1207 : if (count > 0) {
1951 1242 : SET_STRING(" ");
1952 : }
1953 2663 : for (i=0; i<count; i++) {
1954 2663 : GF_XMLAttribute *att = (GF_XMLAttribute*)gf_list_get(node->attributes, i);
1955 5326 : SET_STRING(att->name);
1956 5326 : SET_STRING("=\"");
1957 5326 : SET_STRING(att->value);
1958 5326 : SET_STRING("\" ");
1959 : }
1960 :
1961 1207 : if (!gf_list_count(node->content)) {
1962 740 : SET_STRING("/>");
1963 370 : return;
1964 : }
1965 1674 : SET_STRING(">");
1966 : }
1967 :
1968 839 : count = gf_list_count(node->content);
1969 3870 : for (i=0; i<count; i++) {
1970 3031 : GF_XMLNode *child = (GF_XMLNode*)gf_list_get(node->content, i);
1971 3031 : gf_xml_dom_node_serialize(child, GF_FALSE, GF_FALSE, str, alloc_size, size);
1972 : }
1973 839 : if (!content_only) {
1974 1674 : SET_STRING("</");
1975 837 : if (node->ns) {
1976 44 : SET_STRING(node->ns);
1977 44 : SET_STRING(":");
1978 : }
1979 1674 : SET_STRING(node->name);
1980 1674 : SET_STRING(">");
1981 : }
1982 : }
1983 :
1984 : GF_EXPORT
1985 12 : char *gf_xml_dom_serialize(GF_XMLNode *node, Bool content_only, Bool no_escape)
1986 : {
1987 12 : u32 alloc_size = 0;
1988 12 : u32 size = 0;
1989 12 : char *str = NULL;
1990 12 : gf_xml_dom_node_serialize(node, content_only, no_escape, &str, &alloc_size, &size);
1991 12 : return str;
1992 : }
1993 :
1994 : GF_EXPORT
1995 104 : char *gf_xml_dom_serialize_root(GF_XMLNode *node, Bool content_only, Bool no_escape)
1996 : {
1997 : u32 alloc_size, size;
1998 104 : char *str = NULL;
1999 104 : gf_dynstrcat(&str, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", NULL);
2000 104 : if (!str) return NULL;
2001 :
2002 104 : alloc_size = size = (u32) strlen(str) + 1;
2003 104 : gf_xml_dom_node_serialize(node, content_only, no_escape, &str, &alloc_size, &size);
2004 104 : return str;
2005 : }
2006 :
2007 : #if 0 //unused
2008 : GF_XMLAttribute *gf_xml_dom_set_attribute(GF_XMLNode *node, const char* name, const char* value) {
2009 : GF_XMLAttribute *att;
2010 : if (!name || !value) return NULL;
2011 : if (!node->attributes) {
2012 : node->attributes = gf_list_new();
2013 : if (!node->attributes) return NULL;
2014 : }
2015 :
2016 : att = gf_xml_dom_create_attribute(name, value);
2017 : if (!att) return NULL;
2018 : gf_list_add(node->attributes, att);
2019 : return att;
2020 : }
2021 :
2022 : GF_XMLAttribute *gf_xml_dom_get_attribute(GF_XMLNode *node, const char* name) {
2023 : u32 i = 0;
2024 : GF_XMLAttribute *att;
2025 : if (!node || !name) return NULL;
2026 :
2027 : while ( (att = (GF_XMLAttribute*)gf_list_enum(node->attributes, &i))) {
2028 : if (!strcmp(att->name, name)) {
2029 : return att;
2030 : }
2031 : }
2032 :
2033 : return NULL;
2034 : }
2035 :
2036 : #endif
2037 :
2038 : GF_EXPORT
2039 198 : GF_XMLAttribute *gf_xml_dom_create_attribute(const char* name, const char* value) {
2040 : GF_XMLAttribute *att;
2041 198 : GF_SAFEALLOC(att, GF_XMLAttribute);
2042 198 : if (!att) return NULL;
2043 :
2044 198 : att->name = gf_strdup(name);
2045 198 : att->value = gf_strdup(value);
2046 198 : return att;
2047 : }
2048 :
2049 :
2050 : GF_EXPORT
2051 303 : GF_Err gf_xml_dom_append_child(GF_XMLNode *node, GF_XMLNode *child) {
2052 303 : if (!node || !child) return GF_BAD_PARAM;
2053 303 : if (!node->content) {
2054 0 : node->content = gf_list_new();
2055 0 : if (!node->content) return GF_OUT_OF_MEM;
2056 : }
2057 303 : return gf_list_add(node->content, child);
2058 : }
2059 :
2060 : #if 0
2061 : /*!
2062 : \brief Removes the node to the list of children of this node.
2063 :
2064 : Removes the node to the list of children of this node.
2065 : \warning Doesn't free the memory of the removed children.
2066 :
2067 : \param node the GF_XMLNode node
2068 : \param child the GF_XMLNode child to remove
2069 : \return Error code if any, otherwise GF_OK
2070 : */
2071 : GF_EXPORT
2072 : GF_Err gf_xml_dom_rem_child(GF_XMLNode *node, GF_XMLNode *child) {
2073 : s32 idx;
2074 : if (!node || !child || !node->content) return GF_BAD_PARAM;
2075 : idx = gf_list_find(node->content, child);
2076 : if (idx == -1) return GF_BAD_PARAM;
2077 : return gf_list_rem(node->content, idx);
2078 : }
2079 :
2080 : GF_XMLNode* gf_xml_dom_node_new(const char* ns, const char* name) {
2081 : GF_XMLNode* node;
2082 : GF_SAFEALLOC(node, GF_XMLNode);
2083 : if (!node) return NULL;
2084 : if (ns) {
2085 : node->ns = gf_strdup(ns);
2086 : if (!node->ns) {
2087 : gf_free(node);
2088 : return NULL;
2089 : }
2090 : }
2091 :
2092 : if (name) {
2093 : node->name = gf_strdup(name);
2094 : if (!node->name) {
2095 : gf_free(node->ns);
2096 : gf_free(node);
2097 : return NULL;
2098 : }
2099 : }
2100 : return node;
2101 : }
2102 : #endif //unused
2103 :
2104 : #include <gpac/base_coding.h>
2105 :
2106 : #define XML_SCAN_INT(_fmt, _value) \
2107 : {\
2108 : if (strstr(att->value, "0x")) { u32 __i; sscanf(att->value+2, "%x", &__i); _value = __i; }\
2109 : else if (strstr(att->value, "0X")) { u32 __i; sscanf(att->value+2, "%X", &__i); _value = __i; }\
2110 : else sscanf(att->value, _fmt, &_value); \
2111 : }\
2112 :
2113 :
2114 218 : GF_Err gf_xml_parse_bit_sequence_bs(GF_XMLNode *bsroot, const char *parent_url, GF_BitStream *bs)
2115 : {
2116 : u32 i, j;
2117 : GF_XMLNode *node;
2118 : GF_XMLAttribute *att;
2119 :
2120 218 : i=0;
2121 2708 : while ((node = (GF_XMLNode *) gf_list_enum(bsroot->content, &i))) {
2122 2272 : u32 nb_bits = 0;
2123 2272 : u32 size = 0;
2124 2272 : u64 offset = 0;
2125 2272 : s64 value = 0;
2126 : bin128 word128;
2127 2272 : Float val_float = 0;
2128 2272 : Double val_double = 0;
2129 : Bool use_word128 = GF_FALSE;
2130 : Bool use_text = GF_FALSE;
2131 : Bool big_endian = GF_TRUE;
2132 : Bool has_float = GF_FALSE;
2133 : Bool has_double = GF_FALSE;
2134 : const char *szFile = NULL;
2135 : const char *szString = NULL;
2136 : const char *szBase64 = NULL;
2137 : const char *szData = NULL;
2138 3515 : if (node->type) continue;
2139 :
2140 1029 : if (stricmp(node->name, "BS") ) {
2141 0 : gf_xml_parse_bit_sequence_bs(node, parent_url, bs);
2142 0 : continue;
2143 : }
2144 :
2145 1029 : j=0;
2146 3431 : while ( (att = (GF_XMLAttribute *)gf_list_enum(node->attributes, &j))) {
2147 1373 : if (!stricmp(att->name, "bits")) {
2148 341 : XML_SCAN_INT("%d", nb_bits);
2149 1032 : } else if (!stricmp(att->name, "value")) {
2150 185 : XML_SCAN_INT(LLD, value);
2151 847 : } else if (!stricmp(att->name, "float")) {
2152 1 : sscanf(att->value, "%f", &val_float);
2153 : has_float = GF_TRUE;
2154 846 : } else if (!stricmp(att->name, "double")) {
2155 1 : sscanf(att->value, "%lf", &val_double);
2156 : has_double = GF_TRUE;
2157 845 : } else if (!stricmp(att->name, "mediaOffset") || !stricmp(att->name, "dataOffset")) {
2158 1 : XML_SCAN_INT(LLU, offset);
2159 844 : } else if (!stricmp(att->name, "dataLength")) {
2160 1 : XML_SCAN_INT("%u", size);
2161 843 : } else if (!stricmp(att->name, "mediaFile") || !stricmp(att->name, "dataFile")) {
2162 1 : szFile = att->value;
2163 842 : } else if (!stricmp(att->name, "text") || !stricmp(att->name, "string")) {
2164 156 : szString = att->value;
2165 686 : } else if (!stricmp(att->name, "fcc")) {
2166 15 : value = GF_4CC(att->value[0], att->value[1], att->value[2], att->value[3]);
2167 15 : nb_bits = 32;
2168 671 : } else if (!stricmp(att->name, "ID128")) {
2169 576 : GF_Err e = gf_bin128_parse(att->value, word128);
2170 576 : if (e != GF_OK) {
2171 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[XML/NHML] Cannot parse ID128\n"));
2172 0 : return e;
2173 : }
2174 : use_word128 = GF_TRUE;
2175 95 : } else if (!stricmp(att->name, "textmode")) {
2176 0 : if (!strcmp(att->value, "yes")) use_text = GF_TRUE;
2177 95 : } else if (!stricmp(att->name, "data64")) {
2178 0 : szBase64 = att->value;
2179 95 : } else if (!stricmp(att->name, "data")) {
2180 48 : szData = att->value;
2181 48 : if (!strnicmp(szData, "0x", 2)) szData += 2;
2182 47 : } else if (!stricmp(att->name, "endian") && !stricmp(att->value, "little")) {
2183 : big_endian = GF_FALSE;
2184 : }
2185 : }
2186 1029 : if (szString) {
2187 156 : u32 len = (u32) strlen(szString);
2188 156 : if (nb_bits)
2189 156 : gf_bs_write_int(bs, len, nb_bits);
2190 :
2191 156 : gf_bs_write_data(bs, szString, len);
2192 873 : } else if (szBase64) {
2193 0 : u32 len = (u32) strlen(szBase64);
2194 0 : char *data = (char *) gf_malloc(sizeof(char)*len);
2195 : u32 ret;
2196 0 : if (!data ) return GF_OUT_OF_MEM;
2197 :
2198 0 : ret = (u32) gf_base64_decode((char *)szBase64, len, data, len);
2199 0 : if ((s32) ret >=0) {
2200 0 : gf_bs_write_int(bs, ret, nb_bits);
2201 0 : gf_bs_write_data(bs, data, ret);
2202 : } else {
2203 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[XML/NHML] Error decoding base64 %s\n", att->value));
2204 0 : gf_free(data);
2205 0 : return GF_BAD_PARAM;
2206 : }
2207 0 : gf_free(data);
2208 873 : } else if (szData) {
2209 48 : u32 len = (u32) strlen(szData);
2210 48 : char *data = (char *) gf_malloc(sizeof(char)*len/2);
2211 48 : if (!data) return GF_OUT_OF_MEM;
2212 :
2213 756 : for (j=0; j<len; j+=2) {
2214 : u32 v;
2215 : char szV[5];
2216 708 : sprintf(szV, "%c%c", szData[j], szData[j+1]);
2217 708 : sscanf(szV, "%x", &v);
2218 708 : data[j/2] = v;
2219 : }
2220 48 : gf_bs_write_int(bs, len/2, nb_bits);
2221 48 : gf_bs_write_data(bs, data, len/2);
2222 48 : gf_free(data);
2223 825 : } else if (has_float) {
2224 1 : gf_bs_write_float(bs, val_float);
2225 824 : } else if (has_double) {
2226 1 : gf_bs_write_double(bs, val_double);
2227 823 : } else if (nb_bits) {
2228 200 : if (!big_endian) {
2229 1 : if (nb_bits == 16)
2230 0 : gf_bs_write_u16_le(bs, (u32)value);
2231 1 : else if (nb_bits == 32)
2232 1 : gf_bs_write_u32_le(bs, (u32)value);
2233 : else {
2234 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[XML/NHML] Little-endian values can only be 16 or 32-bit\n"));
2235 : return GF_BAD_PARAM;
2236 : }
2237 : }
2238 : else {
2239 199 : if (nb_bits<33) gf_bs_write_int(bs, (s32) value, nb_bits);
2240 0 : else gf_bs_write_long_int(bs, value, nb_bits);
2241 : }
2242 623 : } else if (szFile) {
2243 : u32 read, remain;
2244 : char block[1024];
2245 : FILE *_tmp = NULL;
2246 1 : if (parent_url) {
2247 1 : char *f_url = gf_url_concatenate(parent_url, szFile);
2248 1 : _tmp = gf_fopen(f_url, use_text ? "rt" : "rb");
2249 1 : gf_free(f_url);
2250 : } else {
2251 0 : _tmp = gf_fopen(szFile, use_text ? "rt" : "rb");
2252 : }
2253 :
2254 1 : if (!_tmp) {
2255 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[XML/NHML] Error opening file %s\n", szFile));
2256 0 : return GF_URL_ERROR;
2257 : }
2258 :
2259 1 : if (!size) {
2260 0 : size = (u32) gf_fsize(_tmp);
2261 : //if offset only copy from offset until end
2262 0 : if ((u64) size > offset)
2263 0 : size -= (u32) offset;
2264 : }
2265 1 : remain = size;
2266 1 : gf_fseek(_tmp, offset, SEEK_SET);
2267 3 : while (remain) {
2268 : u32 bsize = remain;
2269 1 : if (bsize>1024) bsize=1024;
2270 1 : read = (u32) gf_fread(block, bsize, _tmp);
2271 1 : if ((s32) read < 0) {
2272 0 : gf_fclose(_tmp);
2273 0 : return GF_IO_ERR;
2274 : }
2275 :
2276 1 : gf_bs_write_data(bs, block, read);
2277 1 : remain -= bsize;
2278 : }
2279 1 : gf_fclose(_tmp);
2280 622 : } else if (use_word128) {
2281 576 : gf_bs_write_data(bs, (char *)word128, 16);
2282 : }
2283 : }
2284 : return GF_OK;
2285 : }
2286 :
2287 : GF_EXPORT
2288 218 : GF_Err gf_xml_parse_bit_sequence(GF_XMLNode *bsroot, const char *parent_url, u8 **data, u32 *data_size)
2289 : {
2290 218 : GF_BitStream *bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
2291 218 : if (!bs) return GF_OUT_OF_MEM;
2292 :
2293 218 : gf_xml_parse_bit_sequence_bs(bsroot, parent_url, bs);
2294 :
2295 218 : gf_bs_align(bs);
2296 218 : gf_bs_get_content(bs, data, data_size);
2297 218 : gf_bs_del(bs);
2298 218 : return GF_OK;
2299 : }
2300 :
2301 3695 : GF_Err gf_xml_get_element_check_namespace(const GF_XMLNode *n, const char *expected_node_name, const char *expected_ns_prefix) {
2302 : u32 i;
2303 : GF_XMLAttribute *att;
2304 :
2305 : /*check we are processing the expected node*/
2306 3695 : if (expected_node_name && strcmp(expected_node_name, n->name)) {
2307 : return GF_SG_UNKNOWN_NODE;
2308 : }
2309 :
2310 : /*check for previously declared prefix (to be manually provided)*/
2311 1009 : if (!n->ns) {
2312 : return GF_OK;
2313 : }
2314 19 : if (expected_ns_prefix && !strcmp(expected_ns_prefix, n->ns)) {
2315 : return GF_OK;
2316 : }
2317 :
2318 : /*look for new namespace in attributes*/
2319 5 : i = 0;
2320 30 : while ( (att = (GF_XMLAttribute*)gf_list_enum(n->attributes, &i)) ) {
2321 : const char *ns;
2322 21 : ns = strstr(att->name, ":");
2323 21 : if (!ns) continue;
2324 :
2325 9 : if (!strncmp(att->name, "xmlns", 5)) {
2326 4 : if (!strcmp(ns+1, n->ns)) {
2327 : return GF_OK;
2328 : }
2329 : } else {
2330 5 : GF_LOG(GF_LOG_DEBUG, GF_LOG_CORE, ("[XML] Unsupported attribute namespace \"%s\": ignoring\n", att->name));
2331 5 : continue;
2332 : }
2333 : }
2334 :
2335 4 : GF_LOG(GF_LOG_WARNING, GF_LOG_CORE, ("[XML] Unresolved namespace \"%s\" for node \"%s\"\n", n->ns, n->name));
2336 : return GF_BAD_PARAM;
2337 : }
2338 :
2339 1212 : void gf_xml_dump_string(FILE* file, const char *before, const char *str, const char *after)
2340 : {
2341 : size_t i;
2342 1212 : size_t len=str?strlen(str):0;
2343 :
2344 1212 : if (before) {
2345 1036 : gf_fprintf(file, "%s", before);
2346 : }
2347 :
2348 31036 : for (i = 0; i < len; i++) {
2349 31036 : switch (str[i]) {
2350 0 : case '&':
2351 0 : gf_fprintf(file, "%s", "&");
2352 0 : break;
2353 0 : case '<':
2354 0 : gf_fprintf(file, "%s", "<");
2355 0 : break;
2356 0 : case '>':
2357 0 : gf_fprintf(file, "%s", ">");
2358 0 : break;
2359 0 : case '\'':
2360 0 : gf_fprintf(file, "'");
2361 0 : break;
2362 0 : case '\"':
2363 0 : gf_fprintf(file, """);
2364 0 : break;
2365 :
2366 31036 : default:
2367 31036 : gf_fprintf(file, "%c", str[i]);
2368 31036 : break;
2369 : }
2370 : }
2371 :
2372 1212 : if (after) {
2373 1212 : gf_fprintf(file, "%s", after);
2374 : }
2375 1212 : }
2376 :
2377 : #endif /*GPAC_DISABLE_CORE_TOOLS*/
|