LCOV - code coverage report
Current view: top level - utils - xml_parser.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 975 1196 81.5 %
Date: 2021-04-29 23:48:07 Functions: 61 61 100.0 %

          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], "&amp;", sizeof(char)*5)) {
      84          20 :                                 value[j] = '&';
      85          20 :                                 j++;
      86          20 :                                 i+= 5;
      87             :                         }
      88         452 :                         else if (!strnicmp(&str[i], "&lt;", sizeof(char)*4)) {
      89          71 :                                 value[j] = '<';
      90          71 :                                 j++;
      91          71 :                                 i+= 4;
      92             :                         }
      93         381 :                         else if (!strnicmp(&str[i], "&gt;", sizeof(char)*4)) {
      94         117 :                                 value[j] = '>';
      95         117 :                                 j++;
      96         117 :                                 i+= 4;
      97             :                         }
      98         264 :                         else if (!strnicmp(&str[i], "&apos;", sizeof(char)*6)) {
      99          30 :                                 value[j] = '\'';
     100          30 :                                 j++;
     101          30 :                                 i+= 6;
     102             :                         }
     103         234 :                         else if (!strnicmp(&str[i], "&quot;", 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 (&apos;, ...)*/
     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("&amp;");
    1918           0 :                                         break;
    1919           2 :                                 case '<':
    1920           4 :                                         SET_STRING("&lt;");
    1921           2 :                                         break;
    1922           2 :                                 case '>':
    1923           4 :                                         SET_STRING("&gt;");
    1924           2 :                                         break;
    1925           0 :                                 case '\'':
    1926           0 :                                         SET_STRING("&apos;");
    1927           0 :                                         break;
    1928           0 :                                 case '\"':
    1929           0 :                                         SET_STRING("&quot;");
    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", "&amp;");
    2352           0 :                         break;
    2353           0 :                 case '<':
    2354           0 :                         gf_fprintf(file, "%s", "&lt;");
    2355           0 :                         break;
    2356           0 :                 case '>':
    2357           0 :                         gf_fprintf(file, "%s", "&gt;");
    2358           0 :                         break;
    2359           0 :                 case '\'':
    2360           0 :                         gf_fprintf(file, "&apos;");
    2361           0 :                         break;
    2362           0 :                 case '\"':
    2363           0 :                         gf_fprintf(file, "&quot;");
    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*/

Generated by: LCOV version 1.13