LCOV - code coverage report
Current view: top level - scene_manager - loader_svg.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 730 1092 66.8 %
Date: 2021-04-29 23:48:07 Functions: 28 31 90.3 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre, Cyril Concolato
       5             :  *                      Copyright (c) Telecom ParisTech 2000-2012
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / Scene Management 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/scene_manager.h>
      27             : #include <gpac/constants.h>
      28             : #include <gpac/utf.h>
      29             : #include <gpac/xml.h>
      30             : #include <gpac/events.h>
      31             : #include <gpac/internal/compositor_dev.h>
      32             : #include <gpac/internal/scenegraph_dev.h>
      33             : #include <gpac/internal/laser_dev.h>
      34             : #include <gpac/nodes_svg.h>
      35             : #include <gpac/base_coding.h>
      36             : 
      37             : #ifndef GPAC_DISABLE_SVG
      38             : 
      39             : typedef struct _st_entry
      40             : {
      41             :         struct _st_entry *next;
      42             :         /*as referred to by xlink-href*/
      43             :         char *stream_name;
      44             :         /*stream id*/
      45             :         u32 id;
      46             :         const char *nhml_info;
      47             : } SVG_SAFExternalStream;
      48             : 
      49             : typedef struct
      50             : {
      51             :         GF_SceneLoader *load;
      52             :         GF_Err last_error;
      53             :         GF_SAXParser *sax_parser;
      54             :         u32 has_root;
      55             : 
      56             :         /* stack of SVG nodes*/
      57             :         GF_List *node_stack;
      58             : 
      59             :         GF_List *deferred_hrefs;
      60             :         GF_List *deferred_animations;
      61             :         GF_List *deferred_listeners;
      62             :         /*non-linear parsing*/
      63             :         GF_List *peeked_nodes;
      64             : 
      65             :         /*LASeR parsing*/
      66             :         u32 command_depth;
      67             :         GF_StreamContext *laser_es;
      68             :         GF_AUContext *laser_au;
      69             :         GF_Command *command;
      70             : 
      71             :         /*SAF AU maps to OD AU and is used for each new media declaration*/
      72             :         GF_AUContext *saf_au;
      73             :         GF_StreamContext *saf_es;
      74             : 
      75             :         SVG_SAFExternalStream *streams;
      76             : 
      77             :         /*the namespace of the parent element. This is a shortcut to avoid querying the namespace list stored
      78             :         in the scene graph to find out the namespace of the current element.
      79             :         For example in <foo:bar><foo:test/></foo:bar>, it avoids looking for the namespace when parsing <foo:test>
      80             :         */
      81             :         u32 current_ns;
      82             : 
      83             :         /*if parser is used to parse a fragment, the root of the fragment is stored here*/
      84             :         GF_Node *fragment_root;
      85             : } GF_SVG_Parser;
      86             : 
      87             : typedef struct {
      88             :         /* Stage of the resolving:
      89             :             0: resolving attributes which depends on the target: from, to, by, values, type
      90             :                 1: resolving begin times
      91             :                 2: resolving end times */
      92             :         u32 resolve_stage;
      93             :         /* Animation element being deferred */
      94             :         SVG_Element *animation_elt;
      95             :         /* anim parent*/
      96             :         SVG_Element *anim_parent;
      97             :         /* target animated element*/
      98             :         SVG_Element *target;
      99             :         /* id of the target element when unresolved*/
     100             :         char *target_id;
     101             : 
     102             :         /* attributes which cannot be parsed until the type of the target attribute is known */
     103             :         char *type; /* only for animateTransform */
     104             :         char *to;
     105             :         char *from;
     106             :         char *by;
     107             :         char *values;
     108             : } SVG_DeferredAnimation;
     109             : 
     110             : typedef struct
     111             : {
     112             :         /*top of parsed sub-tree*/
     113             :         SVG_Element *node;
     114             :         /*the current element is animation that cannot be parsed completely
     115             :           upon reception of start tag of element but for which we may be able
     116             :           to parse at the end tag of the element (animateMotion)*/
     117             :         SVG_DeferredAnimation *anim;
     118             :         /*depth of unknown elements being skipped*/
     119             :         u32 unknown_depth;
     120             :         /*last child added, used to speed-up parsing*/
     121             :         GF_ChildNodeItem *last_child;
     122             : 
     123             :         /*the namespace of the parent element (used for restoring the context after the current node has been parsed)*/
     124             :         u32 current_ns;
     125             :         Bool has_ns;
     126             : } SVG_NodeStack;
     127             : 
     128          74 : static GF_Err svg_report(GF_SVG_Parser *parser, GF_Err e, char *format, ...)
     129             : {
     130             : #ifndef GPAC_DISABLE_LOG
     131          74 :         if (format && gf_log_tool_level_on(GF_LOG_PARSER, e ? GF_LOG_ERROR : GF_LOG_WARNING)) {
     132             :                 char szMsg[2048];
     133             :                 va_list args;
     134           5 :                 va_start(args, format);
     135             :                 vsnprintf(szMsg, 2048, format, args);
     136           5 :                 va_end(args);
     137           5 :                 GF_LOG((u32) (e ? GF_LOG_ERROR : GF_LOG_WARNING), GF_LOG_PARSER, ("[SVG Parsing] line %d - %s\n", gf_xml_sax_get_line(parser->sax_parser), szMsg));
     138             :         }
     139             : #endif
     140          74 :         if (e) {
     141           1 :                 parser->last_error = e;
     142           1 :                 gf_xml_sax_suspend(parser->sax_parser, GF_TRUE);
     143             :         }
     144          74 :         return e;
     145             : }
     146             : 
     147         233 : static void svg_progress(void *cbk, u64 done, u64 total)
     148             : {
     149             :         GF_SVG_Parser *parser = (GF_SVG_Parser *)cbk;
     150             : 
     151             :         /*notify MediaEvent*/
     152         233 :         if (parser->load && parser->load->is) {
     153         155 :                 parser->load->is->on_media_event(parser->load->is, GF_EVENT_MEDIA_PROGRESS);
     154         155 :                 if (done == total) {
     155          47 :                         parser->load->is->on_media_event(parser->load->is, GF_EVENT_MEDIA_LOAD_DONE);
     156             :                 }
     157             :         }
     158         233 :         gf_set_progress("SVG (Dynamic Attribute List) Parsing", done, total);
     159         233 : }
     160             : 
     161          14 : static SVG_SAFExternalStream *svg_saf_get_stream(GF_SVG_Parser *parser, u32 id, const char *name)
     162             : {
     163             :         SVG_SAFExternalStream *st;
     164          14 :         st = parser->streams;
     165          16 :         while (st) {
     166           4 :                 if (id == st->id) return st;
     167           4 :                 if (name && st->stream_name && !strcmp(name, st->stream_name) ) return st;
     168           2 :                 st = st->next;
     169             :         }
     170             :         return NULL;
     171             : }
     172             : 
     173           2 : static SVG_SAFExternalStream *svg_saf_get_next_available_stream(GF_SVG_Parser *parser)
     174             : {
     175             :         /*1 reserved for base laser stream*/
     176             :         u32 id = 1;
     177           2 :         SVG_SAFExternalStream *st = parser->streams;
     178             :         SVG_SAFExternalStream *prev = NULL;
     179             : 
     180           2 :         while (st) {
     181             :                 prev = st;
     182           0 :                 id = st->id;
     183           0 :                 st = st->next;
     184             :         }
     185           2 :         GF_SAFEALLOC(st, SVG_SAFExternalStream);
     186           2 :         if (!st) return NULL;
     187             : 
     188           2 :         if (prev) prev->next = st;
     189           2 :         else parser->streams = st;
     190           2 :         st->id = id+1;
     191             :         return st;
     192             : }
     193             : 
     194          14 : static void svg_lsr_set_v2(GF_SVG_Parser *parser)
     195             : {
     196             :         u32 i;
     197          14 :         if (parser->load->ctx && parser->load->ctx->root_od) {
     198          28 :                 for (i=0; i<gf_list_count(parser->load->ctx->root_od->ESDescriptors); i++) {
     199          28 :                         GF_ESD *esd = (GF_ESD *)gf_list_get(parser->load->ctx->root_od->ESDescriptors, i);
     200          28 :                         if (esd->decoderConfig->streamType==GF_STREAM_SCENE) {
     201          14 :                                 GF_LASERConfig *cfg = (GF_LASERConfig *)esd->decoderConfig->decoderSpecificInfo;
     202          14 :                                 if (cfg && (cfg->tag==GF_ODF_LASER_CFG_TAG)) {
     203          14 :                                         if (!cfg->extensionIDBits) cfg->extensionIDBits = 2;
     204             :                                 }
     205             :                         }
     206             :                 }
     207             :         }
     208          14 : }
     209             : 
     210             : 
     211         115 : static void svg_process_media_href(GF_SVG_Parser *parser, GF_Node *elt, XMLRI *iri)
     212             : {
     213         115 :         u32 tag = gf_node_get_tag(elt);
     214             : 
     215         115 :         if ((tag==TAG_SVG_image) || (tag==TAG_SVG_video) || (tag==TAG_SVG_audio)) {
     216          12 :                 SVG_SAFExternalStream *st = svg_saf_get_stream(parser, 0, iri->string+1);
     217          12 :                 if (!st && !strnicmp(iri->string, "stream:", 7))
     218           2 :                         st = svg_saf_get_stream(parser, 0, iri->string+7);
     219          12 :                 if (st) {
     220           2 :                         gf_free(iri->string);
     221           2 :                         iri->string = NULL;
     222           2 :                         iri->lsr_stream_id = st->id;
     223           2 :                         iri->type = XMLRI_STREAMID;
     224           2 :                         return;
     225             :                 }
     226             :         }
     227         113 :         if ((parser->load->flags & GF_SM_LOAD_EMBEDS_RES) && (iri->type==XMLRI_STRING) ) {
     228             :                 u32 size;
     229             :                 char *buffer;
     230             : 
     231           0 :                 GF_Err e = gf_file_load_data(iri->string, (u8 **) &buffer, &size);
     232           0 :                 if (e) return;
     233             : 
     234           0 :                 if (tag==TAG_SVG_script) {
     235             :                         GF_DOMText *dtext;
     236             :                         GF_DOMAttribute *att, *prev;
     237           0 :                         buffer[size]=0;
     238           0 :                         dtext = gf_dom_add_text_node(elt, buffer);
     239           0 :                         dtext->type = GF_DOM_TEXT_CDATA;
     240             : 
     241           0 :                         gf_free(iri->string);
     242           0 :                         iri->string=NULL;
     243             : 
     244             :                         /*delete attribute*/
     245           0 :                         att = ((GF_DOMNode*)elt)->attributes;
     246             :                         prev = NULL;
     247           0 :                         while(att) {
     248           0 :                                 if (att->tag!=TAG_XLINK_ATT_href) {
     249             :                                         prev = att;
     250           0 :                                         att = att->next;
     251           0 :                                         continue;
     252             :                                 }
     253           0 :                                 gf_svg_delete_attribute_value(att->data_type, att->data, elt->sgprivate->scenegraph);
     254           0 :                                 if (prev) prev->next = att->next;
     255           0 :                                 else ((GF_DOMNode*)elt)->attributes = att->next;
     256           0 :                                 gf_free(att);
     257           0 :                                 break;
     258             :                         }
     259             :                 } else {
     260             :                         char *mtype;
     261             :                         char *buf64;
     262             :                         u64 size64;
     263             :                         char *ext;
     264           0 :                         buf64 = (char *)gf_malloc((size_t)size*2);
     265           0 :                         size64 = gf_base64_encode(buffer, (u32)size, buf64, (u32)size*2);
     266           0 :                         buf64[size64] = 0;
     267             :                         mtype = "application/data";
     268           0 :                         ext = strchr(iri->string, '.');
     269           0 :                         if (ext) {
     270           0 :                                 if (!stricmp(ext, ".png")) mtype = "image/png";
     271           0 :                                 if (!stricmp(ext, ".jpg") || !stricmp(ext, ".jpeg")) mtype = "image/jpg";
     272             :                         }
     273           0 :                         gf_free(iri->string);
     274           0 :                         iri->string = (char *)gf_malloc(sizeof(char)*(40+(size_t)size64));
     275             :                         sprintf(iri->string, "data:%s;base64,%s", mtype, buf64);
     276           0 :                         gf_free(buf64);
     277           0 :                         gf_free(buffer);
     278             :                 }
     279             :         }
     280             : }
     281             : 
     282           0 : static void xsr_exec_command_list(GF_Node *node, void *par, Bool is_destroy)
     283             : {
     284             :         GF_DOMUpdates *up = (GF_DOMUpdates *)node;
     285           0 :         if (is_destroy || !up || (up->sgprivate->tag!=TAG_DOMUpdates)) return;
     286           0 :         gf_sg_command_apply_list(up->sgprivate->scenegraph, up->updates, 0);
     287             : }
     288             : 
     289         180 : static GF_Node *svg_find_node(GF_SVG_Parser *parser, char *ID)
     290             : {
     291             :         u32 i, count, tag;
     292             :         char *node_class;
     293         180 :         GF_Node *n = gf_sg_find_node_by_name(parser->load->scene_graph, ID);
     294         180 :         if (n) return n;
     295             : 
     296           0 :         count = gf_list_count(parser->peeked_nodes);
     297           0 :         for (i=0; i<count; i++) {
     298           0 :                 n = (GF_Node*)gf_list_get(parser->peeked_nodes, i);
     299           0 :                 if (!strcmp(gf_node_get_name(n), ID)) return n;
     300             :         }
     301           0 :         node_class = gf_xml_sax_peek_node(parser->sax_parser, "id", ID, NULL, NULL, NULL, NULL);
     302           0 :         if (!node_class) return NULL;
     303             : 
     304           0 :         tag = gf_xml_get_element_tag(node_class, parser->current_ns);
     305           0 :         n = gf_node_new(parser->load->scene_graph, tag);
     306             : 
     307           0 :         gf_free(node_class);
     308             : 
     309           0 :         if (n) {
     310           0 :                 gf_svg_parse_element_id(n, ID, GF_FALSE);
     311           0 :                 gf_list_add(parser->peeked_nodes, n);
     312             :         }
     313             :         return n;
     314             : }
     315             : 
     316         115 : static void svg_post_process_href(GF_SVG_Parser *parser, GF_Node *elt, XMLRI *iri)
     317             : {
     318             :         GF_Err e;
     319             : 
     320             :         /* Embed script if needed or clean data URL with proper mime type */
     321         115 :         svg_process_media_href(parser, elt, iri);
     322             : 
     323             :         /*keep data when encoding*/
     324         115 :         if ( !(parser->load->flags & GF_SM_LOAD_FOR_PLAYBACK)) return;
     325             : 
     326             :         /*unresolved, queue it...*/
     327          45 :         if ((iri->type==XMLRI_ELEMENTID) && !iri->target && iri->string) {
     328           0 :                 gf_list_add(parser->deferred_hrefs, iri);
     329             :         }
     330          45 :         if (iri->type != XMLRI_STRING) return;
     331          27 :         e = gf_node_store_embedded_data(iri, parser->load->localPath, parser->load->fileName);
     332          27 :         if (e) svg_report(parser, e, "Error storing embedded IRI data");
     333             : }
     334             : 
     335         164 : static void svg_delete_deferred_anim(SVG_DeferredAnimation *anim, GF_List *deferred_animations)
     336             : {
     337         164 :         if (deferred_animations) gf_list_del_item(deferred_animations, anim);
     338             : 
     339         164 :         if (anim->target_id) gf_free(anim->target_id);
     340         164 :         if (anim->to) gf_free(anim->to);
     341         164 :         if (anim->from) gf_free(anim->from);
     342         164 :         if (anim->by) gf_free(anim->by);
     343         164 :         if (anim->values) gf_free(anim->values);
     344         164 :         if (anim->type) gf_free(anim->type);
     345         164 :         gf_free(anim);
     346         164 : }
     347             : 
     348         262 : static Bool svg_parse_animation(GF_SVG_Parser *parser, GF_SceneGraph *sg, SVG_DeferredAnimation *anim, const char *nodeID, u32 force_type)
     349             : {
     350             :         GF_FieldInfo info;
     351             :         u32 tag;
     352             :         u8 anim_value_type = 0;
     353             : 
     354         262 :         if (anim->resolve_stage==0) {
     355             :                 /* Stage 0: parsing the animation attribute values
     356             :                                         for that we need to resolve the target first */
     357             : 
     358             :                 /* if we don't have a target, try to get it */
     359         224 :                 if (!anim->target)
     360         110 :                         anim->target = (SVG_Element *) gf_sg_find_node_by_name(sg, anim->target_id + 1);
     361             : 
     362             :                 /* if now we have a target, create the xlink:href attribute on the animation element and set it to the found target */
     363         224 :                 if (anim->target) {
     364             :                         XMLRI *iri;
     365         132 :                         gf_node_get_attribute_by_tag((GF_Node *)anim->animation_elt, TAG_XLINK_ATT_href, GF_TRUE, GF_FALSE, &info);
     366         132 :                         iri = (XMLRI *)info.far_ptr;
     367         132 :                         iri->type = XMLRI_ELEMENTID;
     368         132 :                         iri->target = anim->target;
     369         132 :                         gf_node_register_iri(sg, iri);
     370             :                 }
     371             : 
     372         224 :                 tag = gf_node_get_tag((GF_Node *)anim->animation_elt);
     373             :                 /* get the attribute name attribute if specified */
     374         224 :                 if (anim->type && (tag== TAG_SVG_animateTransform) ) {
     375          10 :                         gf_node_get_attribute_by_tag((GF_Node *)anim->animation_elt, TAG_SVG_ATT_transform_type, GF_TRUE, GF_FALSE, &info);
     376          10 :                         gf_svg_parse_attribute((GF_Node *)anim->animation_elt, &info, anim->type, 0);
     377          10 :                         switch(*(SVG_TransformType *) info.far_ptr) {
     378             :                         case SVG_TRANSFORM_TRANSLATE:
     379             :                                 anim_value_type = SVG_Transform_Translate_datatype;
     380             :                                 break;
     381           0 :                         case SVG_TRANSFORM_SCALE:
     382             :                                 anim_value_type = SVG_Transform_Scale_datatype;
     383           0 :                                 break;
     384           2 :                         case SVG_TRANSFORM_ROTATE:
     385             :                                 anim_value_type = SVG_Transform_Rotate_datatype;
     386           2 :                                 break;
     387           2 :                         case SVG_TRANSFORM_SKEWX:
     388             :                                 anim_value_type = SVG_Transform_SkewX_datatype;
     389           2 :                                 break;
     390           2 :                         case SVG_TRANSFORM_SKEWY:
     391             :                                 anim_value_type = SVG_Transform_SkewY_datatype;
     392           2 :                                 break;
     393           0 :                         case SVG_TRANSFORM_MATRIX:
     394             :                                 anim_value_type = SVG_Transform_datatype;
     395           0 :                                 break;
     396           0 :                         default:
     397           0 :                                 svg_report(parser, GF_OK, "unknown datatype for animate transform");
     398           0 :                                 return GF_FALSE;
     399             :                         }
     400             :                 }
     401         214 :                 else if (gf_node_get_attribute_by_tag((GF_Node *)anim->animation_elt, TAG_SVG_ATT_attributeName, GF_FALSE, GF_FALSE, &info) == GF_OK) {
     402         202 :                         SMIL_AttributeName *attname = (SMIL_AttributeName *)info.far_ptr;
     403             : 
     404             :                         /*parse the attribute name even if the target is not found, because a namespace could be specified and
     405             :                         only valid for the current node*/
     406         202 :                         if (!attname->type) {
     407             :                                 char *sep;
     408         114 :                                 char *name = attname->name;
     409         114 :                                 sep = strchr(name, ':');
     410         114 :                                 if (sep) {
     411           4 :                                         sep[0] = 0;
     412           4 :                                         attname->type = gf_sg_get_namespace_code(anim->animation_elt->sgprivate->scenegraph, name);
     413           4 :                                         sep[0] = ':';
     414           4 :                                         name = gf_strdup(sep+1);
     415           4 :                                         gf_free(attname->name);
     416           4 :                                         attname->name = name;
     417             :                                 } else {
     418         110 :                                         attname->type = parser->current_ns;
     419             :                                 }
     420             :                         }
     421             : 
     422             :                         /* the target is still not known stay in stage 0 */
     423         202 :                         if (!anim->target) return GF_FALSE;
     424             : 
     425         110 :                         gf_node_get_attribute_by_name((GF_Node *)anim->target, attname->name, attname->type, GF_TRUE, GF_TRUE, &info);
     426             :                         /*set the tag value to avoid parsing the name in the anim node_init phase*/
     427         110 :                         attname->tag = info.fieldIndex;
     428         110 :                         attname->type = 0;
     429         110 :                         anim_value_type = info.fieldType;
     430             :                 } else {
     431          12 :                         if (tag == TAG_SVG_animateMotion) {
     432             :                                 anim_value_type = SVG_Motion_datatype;
     433           4 :                         } else if (tag == TAG_SVG_discard) {
     434             :                                 /* there is no value to parse in discard, we can jump to the next stage */
     435           0 :                                 anim->resolve_stage = 1;
     436           0 :                                 return svg_parse_animation(parser, sg, anim, nodeID, 0);
     437             :                         } else {
     438           4 :                                 svg_report(parser, GF_OK, "Missing attributeName attribute on %s", gf_node_get_name((GF_Node *)anim->animation_elt));
     439           4 :                                 return GF_FALSE;
     440             :                         }
     441             :                 }
     442             : 
     443             :                 /* the target is still not known stay in stage 0 */
     444         128 :                 if (!anim->target) return GF_FALSE;
     445             : 
     446         128 :                 if (anim->to) {
     447             :                         /* now that we have a target, if there is a to value to parse, create the attribute and parse it */
     448          62 :                         gf_node_get_attribute_by_tag((GF_Node *)anim->animation_elt, TAG_SVG_ATT_to, GF_TRUE, GF_FALSE, &info);
     449          62 :                         gf_svg_parse_attribute((GF_Node *)anim->animation_elt, &info, anim->to, anim_value_type);
     450          62 :                         if (anim_value_type==XMLRI_datatype) {
     451           0 :                                 svg_post_process_href(parser, (GF_Node *) anim->target, (XMLRI*)((SMIL_AnimateValue *)info.far_ptr)->value);
     452             :                         }
     453             :                 }
     454         128 :                 if (anim->from) {
     455             :                         /* now that we have a target, if there is a from value to parse, create the attribute and parse it */
     456          60 :                         gf_node_get_attribute_by_tag((GF_Node *)anim->animation_elt, TAG_SVG_ATT_from, GF_TRUE, GF_FALSE, &info);
     457          60 :                         gf_svg_parse_attribute((GF_Node *)anim->animation_elt, &info, anim->from, anim_value_type);
     458          60 :                         if (anim_value_type==XMLRI_datatype)
     459           0 :                                 svg_post_process_href(parser,  (GF_Node *) anim->target, (XMLRI*)((SMIL_AnimateValue *)info.far_ptr)->value);
     460             :                 }
     461         128 :                 if (anim->by) {
     462             :                         /* now that we have a target, if there is a by value to parse, create the attribute and parse it */
     463           6 :                         gf_node_get_attribute_by_tag((GF_Node *)anim->animation_elt, TAG_SVG_ATT_by, GF_TRUE, GF_FALSE, &info);
     464           6 :                         gf_svg_parse_attribute((GF_Node *)anim->animation_elt, &info, anim->by, anim_value_type);
     465           6 :                         if (anim_value_type==XMLRI_datatype)
     466           0 :                                 svg_post_process_href(parser,  (GF_Node *) anim->target, (XMLRI*)((SMIL_AnimateValue *)info.far_ptr)->value);
     467             :                 }
     468         128 :                 if (anim->values) {
     469             :                         /* now that we have a target, if there is a 'values' value to parse, create the attribute and parse it */
     470          44 :                         gf_node_get_attribute_by_tag((GF_Node *)anim->animation_elt, TAG_SVG_ATT_values, GF_TRUE, GF_FALSE, &info);
     471          44 :                         gf_svg_parse_attribute((GF_Node *)anim->animation_elt, &info, anim->values, anim_value_type);
     472          44 :                         if (anim_value_type==XMLRI_datatype) {
     473             :                                 u32 i, count;
     474             :                                 SMIL_AnimateValues *anim_values;
     475           4 :                                 anim_values = (SMIL_AnimateValues *)info.far_ptr;
     476           4 :                                 count = gf_list_count(anim_values->values);
     477          18 :                                 for (i=0; i<count; i++) {
     478          14 :                                         XMLRI *iri = (XMLRI *)gf_list_get(anim_values->values, i);
     479          14 :                                         svg_post_process_href(parser,  (GF_Node *) anim->target, iri);
     480             :                                 }
     481             :                         }
     482             :                 }
     483         128 :                 anim->resolve_stage = 1;
     484             :         }
     485             : 
     486         166 :         if (anim->resolve_stage == 1) {
     487             :                 /* Stage 1: parsing the begin values
     488             :                                         we go into the next stage only if at least one begin value is resolved */
     489         158 :                 gf_node_get_attribute_by_tag((GF_Node *)anim->animation_elt, TAG_SVG_ATT_begin, GF_TRUE, GF_FALSE, &info);
     490         158 :                 if (gf_svg_resolve_smil_times((GF_Node *)anim->animation_elt, anim->target, *(GF_List **)info.far_ptr, GF_FALSE, nodeID)) {
     491         158 :                         anim->resolve_stage = 2;
     492           0 :                 } else if (force_type!=2) {
     493             :                         return GF_FALSE;
     494             :                 }
     495             :         }
     496             : 
     497         166 :         gf_node_get_attribute_by_tag((GF_Node *)anim->animation_elt, TAG_SVG_ATT_end, GF_TRUE, GF_FALSE, &info);
     498         166 :         if (!gf_svg_resolve_smil_times((GF_Node *)anim->animation_elt, anim->target, *(GF_List **)info.far_ptr, GF_TRUE, nodeID)) {
     499           0 :                 if (force_type!=2) return GF_FALSE;
     500             :         }
     501             : 
     502             :         /*animateMotion needs its children to be parsed before it can be initialized !! */
     503         166 :         if (force_type || gf_node_get_tag((GF_Node *)anim->animation_elt) != TAG_SVG_animateMotion) {
     504         158 :                 gf_node_init((GF_Node *)anim->animation_elt);
     505         158 :                 return GF_TRUE;
     506             :         } else {
     507             :                 return GF_FALSE;
     508             :         }
     509             : 
     510             : }
     511             : 
     512        2339 : static void svg_resolved_refs(GF_SVG_Parser *parser, GF_SceneGraph *sg, const char *nodeID)
     513             : {
     514             :         u32 count, i;
     515             : 
     516             :         /*check unresolved HREF*/
     517        2339 :         count = gf_list_count(parser->deferred_hrefs);
     518        2339 :         for (i=0; i<count; i++) {
     519             :                 GF_Node *targ;
     520           0 :                 XMLRI *iri = (XMLRI *)gf_list_get(parser->deferred_hrefs, i);
     521           0 :                 if (nodeID && strcmp(iri->string + 1, nodeID)) continue;
     522           0 :                 targ = gf_sg_find_node_by_name(sg, iri->string + 1);
     523           0 :                 if (targ) {
     524           0 :                         iri->type = XMLRI_ELEMENTID;
     525           0 :                         iri->target = targ;
     526           0 :                         gf_node_register_iri(sg, iri);
     527           0 :                         gf_free(iri->string);
     528           0 :                         iri->string = NULL;
     529           0 :                         gf_list_rem(parser->deferred_hrefs, i);
     530           0 :                         i--;
     531           0 :                         count--;
     532             :                 }
     533             :         }
     534             : 
     535             :         /*check unresolved listeners */
     536        2339 :         count = gf_list_count(parser->deferred_listeners);
     537        2339 :         for (i=0; i<count; i++) {
     538             :                 GF_FieldInfo info;
     539             :                 GF_Node *par;
     540           0 :                 SVG_Element *listener = (SVG_Element *)gf_list_get(parser->deferred_listeners, i);
     541             : 
     542             :                 par = NULL;
     543           0 :                 if (gf_node_get_attribute_by_tag((GF_Node *)listener, TAG_XMLEV_ATT_observer, GF_FALSE, GF_FALSE, &info) == GF_OK) {
     544           0 :                         XMLRI *observer = (XMLRI *)info.far_ptr;
     545           0 :                         if (observer->type == XMLRI_ELEMENTID) {
     546           0 :                                 if (!observer->target && observer->string && !strcmp(observer->string, nodeID) ) {
     547           0 :                                         observer->target = gf_sg_find_node_by_name(sg, (char*) nodeID);
     548             :                                 }
     549           0 :                                 par = (GF_Node *)observer->target;
     550             :                         }
     551           0 :                         if (!par) continue;
     552             :                 }
     553           0 :                 if (gf_node_get_attribute_by_tag((GF_Node *)listener, TAG_XMLEV_ATT_target, GF_FALSE, GF_FALSE, &info) == GF_OK) {
     554           0 :                         XMLRI *target = (XMLRI *)info.far_ptr;
     555           0 :                         if (target->type == XMLRI_ELEMENTID) {
     556           0 :                                 if (!target->target) continue;
     557             :                                 else {
     558           0 :                                         if (!par) par = (GF_Node*)target->target;
     559             :                                 }
     560             :                         }
     561             :                 }
     562             :                 assert(par);
     563           0 :                 gf_node_dom_listener_add((GF_Node *)par, (GF_Node *) listener);
     564           0 :                 gf_list_rem(parser->deferred_listeners, i);
     565           0 :                 i--;
     566           0 :                 count--;
     567             :         }
     568             : 
     569             :         /*check unresolved anims*/
     570        2339 :         count = gf_list_count(parser->deferred_animations);
     571        2427 :         for (i=0; i<count; i++) {
     572          88 :                 SVG_DeferredAnimation *anim = (SVG_DeferredAnimation *)gf_list_get(parser->deferred_animations, i);
     573             :                 /*resolve it - we don't check the name since it may be used in SMIL times, which we don't track at anim level*/
     574          88 :                 if (svg_parse_animation(parser, sg, anim, nodeID, 1)) {
     575          22 :                         svg_delete_deferred_anim(anim, parser->deferred_animations);
     576          22 :                         i--;
     577          22 :                         count--;
     578             :                 }
     579             :         }
     580        2339 : }
     581             : 
     582          68 : static void svg_init_root_element(GF_SVG_Parser *parser, SVG_Element *root_svg)
     583             : {
     584             :         GF_FieldInfo width_info, height_info;
     585             :         u32 svg_w, svg_h;
     586             :         svg_w = svg_h = 0;
     587          68 :         if (!gf_node_get_attribute_by_tag((GF_Node *)root_svg, TAG_SVG_ATT_width, GF_FALSE, GF_FALSE, &width_info)
     588           0 :                 && !gf_node_get_attribute_by_tag((GF_Node *)root_svg, TAG_SVG_ATT_height, GF_FALSE, GF_FALSE, &height_info)) {
     589           0 :                 SVG_Length * w = (SVG_Length *)width_info.far_ptr;
     590           0 :                 SVG_Length * h = (SVG_Length *)height_info.far_ptr;
     591           0 :                 if (w->type == SVG_NUMBER_VALUE) svg_w = FIX2INT(w->value);
     592           0 :                 if (h->type == SVG_NUMBER_VALUE) svg_h = FIX2INT(h->value);
     593           0 :                 gf_sg_set_scene_size_info(parser->load->scene_graph, svg_w, svg_h, GF_TRUE);
     594           0 :                 if (parser->load->ctx) {
     595           0 :                         parser->load->ctx->scene_width = svg_w;
     596           0 :                         parser->load->ctx->scene_height = svg_h;
     597             :                 }
     598             :         }
     599          68 :         if (parser->load->type == GF_SM_LOAD_XSR) {
     600             :                 assert(parser->command);
     601             :                 assert(parser->command->tag == GF_SG_LSR_NEW_SCENE);
     602           2 :                 parser->command->node = (GF_Node *)root_svg;
     603             :         }
     604          68 :         gf_sg_set_root_node(parser->load->scene_graph, (GF_Node *)root_svg);
     605          68 :         parser->has_root = 1;
     606          68 : }
     607             : 
     608        3903 : static void svg_check_namespace(GF_SVG_Parser *parser, const GF_XMLAttribute *attributes, u32 nb_attributes, Bool *has_ns)
     609             : {
     610             :         u32 i;
     611             :         /*parse all att to check for namespaces, to:
     612             :            - add the prefixed namespaces (xmlns:xxxx='...')
     613             :            - change the namespace for this element if no prefix (xmlns='...')*/
     614       10861 :         for (i=0; i<nb_attributes; i++) {
     615       10861 :                 GF_XMLAttribute *att = (GF_XMLAttribute *)&attributes[i];
     616       10861 :                 if (!att->value || !strlen(att->value)) continue;
     617       10859 :                 if (!strncmp(att->name, "xmlns", 5)) {
     618             :                         /* check if we have a prefix for this namespace */
     619         210 :                         char *qname = strchr(att->name, ':');
     620         210 :                         if (qname) {
     621         108 :                                 qname++;
     622             :                         }
     623             :                         /* Adds the namespace to the scene graph, either with a prefix or with NULL */
     624         210 :                         gf_sg_add_namespace(parser->load->scene_graph, att->value, qname);
     625             : 
     626         210 :                         if (!qname) {
     627             :                                 /* Only if there was no prefix, we change the namespace for the current element */
     628         102 :                                 parser->current_ns = gf_sg_get_namespace_code_from_name(parser->load->scene_graph, att->value);
     629             :                         }
     630             :                         /* Signal that when ending this element, namespaces will have to be removed */
     631         210 :                         *has_ns = GF_TRUE;
     632             :                 }
     633             :         }
     634        3903 : }
     635             : 
     636             : //#define SKIP_ALL
     637             : //#define SKIP_ATTS
     638             : //#define SKIP_ATTS_PARSING
     639             : //#define SKIP_INIT
     640             : 
     641             : //#define SKIP_UNKNOWN_NODES
     642             : 
     643        3619 : static SVG_Element *svg_parse_element(GF_SVG_Parser *parser, const char *name, const char *name_space, const GF_XMLAttribute *attributes, u32 nb_attributes, SVG_NodeStack *parent, Bool *has_ns)
     644             : {
     645             :         GF_FieldInfo info;
     646             :         u32     tag, i, count, ns, xmlns;
     647             :         Bool needs_init, has_id;
     648             :         SVG_Element *elt = NULL;
     649             :         const char *node_name = NULL;
     650             :         const char *ev_event, *ev_observer;
     651             :         SVG_DeferredAnimation *anim = NULL;
     652             :         char *ID = NULL;
     653             : 
     654        3619 :         GF_LOG(GF_LOG_DEBUG, GF_LOG_PARSER, ("[SVG Parsing] Parsing node %s\n", name));
     655             : 
     656        3619 :         *has_ns = GF_FALSE;
     657             : 
     658        3619 :         svg_check_namespace(parser, attributes, nb_attributes, has_ns);
     659             : 
     660       13904 :         for (i=0; i<nb_attributes; i++) {
     661       10285 :                 GF_XMLAttribute *att = (GF_XMLAttribute *)&attributes[i];
     662       10285 :                 if (!att->value || !strlen(att->value)) continue;
     663             :                 /* FIXME: This should be changed to reflect that xml:id has precedence over id if both are specified with different values */
     664       10285 :                 if (!stricmp(att->name, "id") || !stricmp(att->name, "xml:id")) {
     665        2339 :                         if (!ID) ID = att->value;
     666             :                 }
     667             :         }
     668             : 
     669             :         /* CHECK: overriding the element namespace with the parent one, if given ???
     670             :            This is wrong ??*/
     671        3619 :         xmlns = parser->current_ns;
     672        3619 :         if (name_space) {
     673          44 :                 xmlns = gf_sg_get_namespace_code(parser->load->scene_graph, (char *) name_space);
     674          44 :                 if (!xmlns) {
     675           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] line %d - XMLNS prefix %s not defined - skipping\n", gf_xml_sax_get_line(parser->sax_parser), name_space));
     676             :                         return NULL;
     677             :                 }
     678             :         }
     679             : 
     680             :         /* Translates the node type (called name) from a String into a unique numeric identifier in GPAC */
     681        3619 :         tag = xmlns ? gf_xml_get_element_tag(name, xmlns) : TAG_UndefinedNode;
     682        3619 :         if (tag == TAG_UndefinedNode) {
     683             : #ifdef SKIP_UNKNOWN_NODES
     684             :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_PARSER, ("[SVG Parsing] line %d - Unknown element %s - skipping\n", gf_xml_sax_get_line(parser->sax_parser), name));
     685             :                 return NULL;
     686             : #else
     687             :                 tag = TAG_DOMFullNode;
     688             : #endif
     689             :         }
     690             : 
     691             :         /* If this element has an ID, we look in the list of elements already created in advance (in case of reference) to see if it is there,
     692             :            in which case we will reuse it*/
     693             :         has_id = GF_FALSE;
     694        3619 :         count = gf_list_count(parser->peeked_nodes);
     695        3619 :         if (count && ID) {
     696           0 :                 for (i=0; i<count; i++) {
     697           0 :                         GF_Node *n = (GF_Node *)gf_list_get(parser->peeked_nodes, i);
     698           0 :                         const char *n_id = gf_node_get_name(n);
     699           0 :                         if (n_id && !strcmp(n_id, ID)) {
     700           0 :                                 gf_list_rem(parser->peeked_nodes, i);
     701             :                                 has_id = GF_TRUE;
     702             :                                 elt = (SVG_Element*)n;
     703             :                                 break;
     704             :                         }
     705             :                 }
     706             :         }
     707             : 
     708             :         /* If the element was found in the list of elements already created, we do not need to create it, we reuse it.
     709             :            Otherwise, we create it based on the tag */
     710             :         if (!has_id) {
     711             :                 /* Creates a node in the current scene graph */
     712        3619 :                 elt = (SVG_Element*)gf_node_new(parser->load->scene_graph, tag);
     713        3619 :                 if (!elt) {
     714           0 :                         parser->last_error = GF_SG_UNKNOWN_NODE;
     715           0 :                         return NULL;
     716             :                 }
     717             :                 /* CHECK: Why isn't this code in the gf_node_new call ?? */
     718        3619 :                 if (tag == TAG_DOMFullNode) {
     719             :                         GF_DOMFullNode *d = (GF_DOMFullNode *)elt;
     720         138 :                         d->name = gf_strdup(name);
     721         138 :                         d->ns = xmlns;
     722         138 :                         if (ID)
     723           2 :                                 gf_svg_parse_element_id((GF_Node *)d, ID, GF_FALSE);
     724             :                 }
     725             :         }
     726             : 
     727             :         /* We indicate that the element is used by its parent (reference counting for safe deleting) */
     728        3619 :         gf_node_register((GF_Node *)elt, (parent ? (GF_Node *)parent->node : NULL));
     729             :         /* We attach this element as the last child of its parent */
     730        3619 :         if (parent && elt) gf_node_list_add_child_last( & parent->node->children, (GF_Node*)elt, & parent->last_child);
     731             : 
     732             :         /* By default, all elements will need initialization for rendering, except some that will explicitly set it to 0 */
     733             :         needs_init = GF_TRUE;
     734             : 
     735        3619 :         if (gf_svg_is_animation_tag(tag)) {
     736         134 :                 GF_SAFEALLOC(anim, SVG_DeferredAnimation);
     737         134 :                 if (!anim) {
     738           0 :                         parser->last_error = GF_OUT_OF_MEM;
     739           0 :                         return NULL;
     740             :                 }
     741             :                 /*default anim target is parent node*/
     742         134 :                 anim->animation_elt = elt;
     743         134 :                 if (!parent) {
     744          10 :                         if (parser->command) {
     745          10 :                                 anim->target = anim->anim_parent = (SVG_Element*) parser->command->node;
     746             :                         }
     747             :                 } else {
     748         124 :                         anim->target = anim->anim_parent = parent->node;
     749             :                 }
     750        3485 :         } else if (gf_svg_is_timing_tag(tag)) {
     751             :                 /* warning: we use the SVG_DeferredAnimation structure for some timing nodes which are not
     752             :                    animations, but we put the parse stage at 1 (timing) see svg_parse_animation. */
     753          30 :                 GF_SAFEALLOC(anim, SVG_DeferredAnimation);
     754          30 :                 if (!anim) {
     755           0 :                         parser->last_error = GF_OUT_OF_MEM;
     756           0 :                         return NULL;
     757             :                 }
     758             :                 /*default anim target is parent node*/
     759          30 :                 anim->animation_elt = elt;
     760          30 :                 if (!parent) {
     761           6 :                         if (parser->command) {
     762           6 :                                 anim->target = anim->anim_parent = (SVG_Element*) parser->command->node;
     763             :                         }
     764             :                 } else {
     765          24 :                         anim->target = anim->anim_parent = parent->node;
     766             :                 }
     767          30 :                 anim->resolve_stage = 1;
     768        3455 :         } else if ((tag == TAG_SVG_script) || (tag==TAG_SVG_handler)) {
     769             :                 /* Scripts and handlers don't render and have no initialization phase */
     770             :                 needs_init = GF_FALSE;
     771             :         }
     772             : 
     773             :         ev_event = ev_observer = NULL;
     774             : 
     775             : #ifdef SKIP_ATTS
     776             :         nb_attributes = 0;
     777             : #endif
     778             : 
     779             :         /*set the root of the SVG tree BEFORE processing events in order to have it setup for script init (e.g. load events, including in root svg)*/
     780        3619 :         if ((tag == TAG_SVG_svg) && !parser->has_root) {
     781          68 :                 svg_init_root_element(parser, elt);
     782             :         }
     783             : 
     784             :         /*parse all att*/
     785       10285 :         for (i=0; i<nb_attributes; i++) {
     786       10285 :                 GF_XMLAttribute *att = (GF_XMLAttribute *)&attributes[i];
     787             :                 char *att_name = NULL;
     788       10285 :                 if (!att->value || !strlen(att->value)) continue;
     789             : 
     790             :                 /* first determine in which namespace is the attribute and store the result in ns,
     791             :                 then shift the char buffer to point to the local name of the attribute*/
     792             :                 ns = xmlns;
     793       10285 :                 att_name = strchr(att->name, ':');
     794       10285 :                 if (att_name) {
     795         527 :                         if (!strncmp(att->name, "xmlns", 5)) {
     796          98 :                                 ns = gf_sg_get_namespace_code(parser->load->scene_graph, att_name+1);
     797          98 :                                 att_name = att->name;
     798             :                         } else {
     799         429 :                                 att_name[0] = 0;
     800         429 :                                 ns = gf_sg_get_namespace_code(parser->load->scene_graph, att->name);
     801         429 :                                 att_name[0] = ':';
     802         429 :                                 att_name++;
     803             :                         }
     804             :                 } else {
     805             :                         att_name = att->name;
     806             :                 }
     807             : 
     808             :                 /* Begin of special cases of attributes */
     809             : 
     810             :                 /* CHECK: Shouldn't namespaces be checked here ? */
     811       10285 :                 if (!stricmp(att_name, "style")) {
     812          55 :                         gf_svg_parse_style((GF_Node *)elt, att->value);
     813          55 :                         continue;
     814             :                 }
     815             : 
     816             :                 /* Some attributes of the animation elements cannot be parsed (into typed values) until the type of value is known,
     817             :                    we defer the parsing and store them temporarily as strings */
     818       10230 :                 if (anim) {
     819         855 :                         if (!stricmp(att_name, "to")) {
     820          66 :                                 anim->to = gf_strdup(att->value);
     821          66 :                                 continue;
     822             :                         }
     823         789 :                         if (!stricmp(att_name, "from")) {
     824          62 :                                 anim->from = gf_strdup(att->value);
     825          62 :                                 continue;
     826             :                         }
     827         727 :                         if (!stricmp(att_name, "by")) {
     828           8 :                                 anim->by = gf_strdup(att->value);
     829           8 :                                 continue;
     830             :                         }
     831         719 :                         if (!stricmp(att_name, "values")) {
     832          46 :                                 anim->values = gf_strdup(att->value);
     833          46 :                                 continue;
     834             :                         }
     835         673 :                         if ((tag == TAG_SVG_animateTransform) && !stricmp(att_name, "type")) {
     836          10 :                                 anim->type = gf_strdup(att->value);
     837          10 :                                 continue;
     838             :                         }
     839             :                 }
     840             : 
     841             :                 /* Special case for xlink:href attributes */
     842       10038 :                 if ((ns == GF_XMLNS_XLINK) && !stricmp(att_name, "href") ) {
     843             : 
     844         147 :                         if (gf_svg_is_animation_tag(tag)) {
     845             :                                 /* For xlink:href in animation elements,
     846             :                                 we try to locate the target of the xlink:href to determine the type of values to be animated */
     847             :                                 assert(anim);
     848          46 :                                 anim->target_id = gf_strdup(att->value);
     849             :                                 /*The target may be NULL, if it has not yet been parsed, we will try to resolve it later on */
     850          46 :                                 anim->target = (SVG_Element *) gf_sg_find_node_by_name(parser->load->scene_graph, anim->target_id + 1);
     851          46 :                                 continue;
     852             :                         } else {
     853             :                                 /* For xlink:href attribute on elements other than animation elements,
     854             :                                    we create the attribute, parse it and try to do some special process it */
     855             :                                 XMLRI *iri = NULL;
     856         101 :                                 if (gf_node_get_attribute_by_tag((GF_Node *)elt, TAG_XLINK_ATT_href, GF_TRUE, GF_FALSE, &info)==GF_OK) {
     857         101 :                                         gf_svg_parse_attribute((GF_Node *)elt, &info, att->value, 0);
     858         101 :                                         iri = (XMLRI *)info.far_ptr;
     859             : 
     860             :                                         /* extract streamID ref or data URL and store as file */
     861         101 :                                         svg_post_process_href(parser, (GF_Node *)elt, iri);
     862         101 :                                         continue;
     863             :                                 }
     864             :                         }
     865             :                 }
     866             : 
     867             :                 /* For the XML Event handler element, we need to defer the parsing of some attributes */
     868        9891 :                 if ((tag == TAG_SVG_handler) && (ns == GF_XMLNS_XMLEV)) {
     869           0 :                         if (!stricmp(att_name, "event") ) {
     870           0 :                                 ev_event = att->value;
     871           0 :                                 continue;
     872             :                         }
     873           0 :                         if (!stricmp(att_name, "observer") ) {
     874           0 :                                 ev_observer = att->value;
     875           0 :                                 continue;
     876             :                         }
     877             :                 }
     878             : 
     879             :                 /*laser specific stuff*/
     880        9891 :                 if (ns == GF_XMLNS_LASER) {
     881             :                         /* CHECK: we should probably check the namespace of the attribute here */
     882          32 :                         if (!stricmp(att_name, "scale") ) {
     883           2 :                                 if (gf_node_get_attribute_by_tag((GF_Node *)elt, TAG_SVG_ATT_transform, GF_TRUE, GF_TRUE, &info)==GF_OK) {
     884             :                                         SVG_Point pt;
     885           2 :                                         SVG_Transform *mat = (SVG_Transform *)info.far_ptr;
     886           2 :                                         svg_parse_point(&pt, att->value);
     887           2 :                                         gf_mx2d_add_scale(&mat->mat, pt.x, pt.y);
     888           2 :                                         continue;
     889             :                                 }
     890             :                         }
     891          30 :                         if (!stricmp(att_name, "translation") ) {
     892           0 :                                 if (gf_node_get_attribute_by_tag((GF_Node *)elt, TAG_SVG_ATT_transform, GF_TRUE, GF_TRUE, &info)==GF_OK) {
     893             :                                         SVG_Point pt;
     894           0 :                                         SVG_Transform *mat = (SVG_Transform *)info.far_ptr;
     895           0 :                                         svg_parse_point(&pt, att->value);
     896           0 :                                         gf_mx2d_add_translation(&mat->mat, pt.x, pt.y);
     897           0 :                                         continue;
     898             :                                 }
     899             :                         }
     900             :                 }
     901             : 
     902             :                 /* For all attributes of the form 'on...', like 'onclick' we create a listener for the event on the current element,
     903             :                    we connect the listener to a handler that contains the code in the 'on...' attribute. */
     904             :                 /* CHECK: we should probably check the namespace of the attribute and of the element here */
     905        9889 :                 if (!strncmp(att_name, "on", 2)) {
     906           0 :                         u32 evtType = gf_dom_event_type_by_name(att_name + 2);
     907           0 :                         if (evtType != GF_EVENT_UNKNOWN) {
     908           0 :                                 SVG_handlerElement *handler = gf_dom_listener_build((GF_Node *) elt, evtType, 0);
     909           0 :                                 gf_dom_add_text_node((GF_Node *)handler, gf_strdup(att->value) );
     910           0 :                                 gf_node_init((GF_Node *)handler);
     911           0 :                                 continue;
     912             :                         }
     913           0 :                         svg_report(parser, GF_OK, "Skipping unknown event handler %s on node %s", att->name, name);
     914             :                 }
     915             : 
     916             :                 /* end of special cases of attributes */
     917             : 
     918             :                 /* General attribute creation and parsing */
     919        9889 :                 if (gf_node_get_attribute_by_name((GF_Node *)elt, att_name, ns, GF_TRUE, GF_FALSE, &info)==GF_OK) {
     920             : #ifndef SKIP_ATTS_PARSING
     921        9889 :                         GF_Err e = gf_svg_parse_attribute((GF_Node *)elt, &info, att->value, 0);
     922        9889 :                         if (e) {
     923           0 :                                 svg_report(parser, e, "Error parsing attribute %s on node %s", att->name, name);
     924           0 :                                 continue;
     925             :                         }
     926        9889 :                         if (info.fieldType == SVG_ID_datatype) {
     927             :                                 /*"when both 'id' and 'xml:id'  are specified on the same element but with different values,
     928             :                                 the SVGElement::id field must return either of the values but should give precedence to
     929             :                                 the 'xml:id'  attribute."*/
     930        2333 :                                 if (!node_name || (info.fieldIndex == TAG_XML_ATT_id)) {
     931        2333 :                                         node_name = *(SVG_ID *)info.far_ptr;
     932             :                                         /* Check if ID start with a digit, which is not a valid ID for a node according to XML (see http://www.w3.org/TR/xml/#id) */
     933        2333 :                                         if (isdigit(node_name[0])) {
     934           0 :                                                 svg_report(parser, GF_BAD_PARAM, "Invalid value %s for node %s %s", node_name, name, att->name);
     935             :                                                 node_name = NULL;
     936             :                                         }
     937             :                                 }
     938             :                         } else {
     939        7556 :                                 switch (info.fieldIndex) {
     940          10 :                                 case TAG_SVG_ATT_syncMaster:
     941             :                                 case TAG_SVG_ATT_focusHighlight:
     942             :                                 case TAG_SVG_ATT_initialVisibility:
     943             :                                 case TAG_SVG_ATT_fullscreen:
     944             :                                 case TAG_SVG_ATT_requiredFonts:
     945             :                                         /*switch LASeR Configuration to v2 because these attributes are not part of v1*/
     946          10 :                                         svg_lsr_set_v2(parser);
     947          10 :                                         break;
     948             :                                 }
     949             :                         }
     950             : #endif
     951        9889 :                         continue;
     952             :                 }
     953             : 
     954             :                 /* all other attributes (??? failed to be created) should fall in this category */
     955           0 :                 svg_report(parser, GF_OK, "Skipping attribute %s on node %s", att->name, name);
     956             :         }
     957             : 
     958             :         /* When a handler element specifies the event attribute, an implicit listener is defined */
     959        3619 :         if (ev_event) {
     960             :                 GF_Node *node = (GF_Node *)elt;
     961             :                 SVG_Element *listener;
     962             :                 u32 type;
     963           0 :                 listener = (SVG_Element *) gf_node_new(node->sgprivate->scenegraph, TAG_SVG_listener);
     964             :                 /*We don't want to insert the implicit listener in the DOM. However remember
     965             :                 the listener at the handler level in case the handler gets destroyed*/
     966           0 :                 gf_node_set_private(node, (GF_Node*)listener );
     967           0 :                 gf_node_register((GF_Node*)listener, NULL);
     968             : 
     969             :                 /* this listener listens to the given type of event */
     970           0 :                 type = gf_dom_event_type_by_name(ev_event);
     971           0 :                 gf_node_get_attribute_by_tag(node, TAG_XMLEV_ATT_event, GF_TRUE, GF_FALSE, &info);
     972           0 :                 ((XMLEV_Event *)info.far_ptr)->type = type;
     973           0 :                 gf_node_get_attribute_by_tag((GF_Node *)listener, TAG_XMLEV_ATT_event, GF_TRUE, GF_FALSE, &info);
     974           0 :                 ((XMLEV_Event *)info.far_ptr)->type = type;
     975           0 :                 gf_node_get_attribute_by_tag((GF_Node *)listener, TAG_XMLEV_ATT_handler, GF_TRUE, GF_FALSE, &info);
     976           0 :                 ((XMLRI *)info.far_ptr)->target = node;
     977             : 
     978           0 :                 if (ev_observer) {
     979             :                         /* An observer was specified, so it needs to be used */
     980           0 :                         gf_node_get_attribute_by_tag((GF_Node *)listener, TAG_XMLEV_ATT_observer, GF_TRUE, GF_FALSE, &info);
     981           0 :                         gf_svg_parse_attribute((GF_Node *)elt, &info, (char*)ev_observer, 0);
     982             :                 } else {
     983             :                         /* No observer specified, this listener listens with the parent of the handler as the event target */
     984           0 :                         gf_node_get_attribute_by_tag((GF_Node *)listener, TAG_XMLEV_ATT_target, GF_TRUE, GF_FALSE, &info);
     985           0 :                         ((XMLRI *)info.far_ptr)->target = parent->node;
     986             :                 }
     987             :                 /* if the target was found (already parsed), we are fine, otherwise we need to try to find it again,
     988             :                    we place the listener in the deferred listener list */
     989           0 :                 if ( ((XMLRI *)info.far_ptr)->target)
     990           0 :                         gf_node_dom_listener_add(((XMLRI *)info.far_ptr)->target, (GF_Node *) listener);
     991             :                 else
     992           0 :                         gf_list_add(parser->deferred_listeners, listener);
     993             :         }
     994             : 
     995        3619 :         if (!node_name && ID)
     996             :                 node_name = ID;
     997             : 
     998             :         /* if the new element has an id, we try to resolve deferred references (including animations, href and listeners (just above)*/
     999        3619 :         if (node_name) {
    1000        2339 :                 if (!has_id) {
    1001             :                         /* if the element was already created before this call, we don't need to get a numerical id, we have it already */
    1002        2339 :                         gf_svg_parse_element_id((GF_Node *)elt, node_name, parser->command_depth ? GF_TRUE : GF_FALSE);
    1003             :                 }
    1004        2339 :                 svg_resolved_refs(parser, parser->load->scene_graph, node_name);
    1005             :         }
    1006             : 
    1007             :         /* if the new element is an animation, now that all specified attributes have been found,
    1008             :            we can start parsing them */
    1009        3619 :         if (anim) {
    1010             :                 /*FIXME - we need to parse from/to/values but not initialize the stack*/
    1011             : //              if (parser->load->flags & GF_SM_LOAD_FOR_PLAYBACK) {
    1012             :                 needs_init = GF_FALSE;
    1013         164 :                 if (svg_parse_animation(parser, parser->load->scene_graph, anim, NULL, 0)) {
    1014         132 :                         svg_delete_deferred_anim(anim, NULL);
    1015             :                 } else {
    1016          32 :                         gf_list_add(parser->deferred_animations, anim);
    1017             :                 }
    1018             : //              } else {
    1019             : //                      svg_delete_deferred_anim(anim, NULL);
    1020             : //              }
    1021             :         }
    1022             : 
    1023             : #ifndef SKIP_INIT
    1024        3455 :         if (needs_init) {
    1025             :                 /* For elements that need it, we initialize the rendering stack */
    1026        3443 :                 gf_node_init((GF_Node *)elt);
    1027             :         }
    1028             : #endif
    1029             : 
    1030        3619 :         if (parent && elt) {
    1031             :                 /*mark parent element as dirty (new child added) and invalidate parent graph for progressive rendering*/
    1032        3467 :                 gf_node_dirty_set((GF_Node *)parent->node, GF_SG_CHILD_DIRTY, GF_TRUE);
    1033             :                 /*request scene redraw*/
    1034        3467 :                 if (parser->load->scene_graph->NodeCallback) {
    1035        2248 :                         parser->load->scene_graph->NodeCallback(parser->load->scene_graph->userpriv, GF_SG_CALLBACK_MODIFIED, NULL, NULL);
    1036             :                 }
    1037             :         }
    1038             : 
    1039             :         /*If we are in playback mode, we register (reference counting for safe deleting) the listener element with the element that uses it */
    1040        3619 :         if ((parser->load->flags & GF_SM_LOAD_FOR_PLAYBACK) && elt && (tag==TAG_SVG_listener)) {
    1041             :                 Bool post_pone = GF_FALSE;
    1042             :                 SVG_Element *par = NULL;
    1043             :                 SVG_Element *listener = (SVG_Element *)elt;
    1044             : 
    1045           0 :                 if (gf_node_get_attribute_by_tag((GF_Node *)listener, TAG_XMLEV_ATT_observer, GF_FALSE, GF_FALSE, &info) == GF_OK) {
    1046           0 :                         XMLRI *observer = (XMLRI *)info.far_ptr;
    1047           0 :                         if (observer->type == XMLRI_ELEMENTID) {
    1048           0 :                                 if (!observer->target) post_pone = GF_TRUE;
    1049             :                                 else par = (SVG_Element *)observer->target;
    1050             :                         }
    1051             :                 }
    1052             : 
    1053           0 :                 if (gf_node_get_attribute_by_tag((GF_Node *)listener, TAG_XMLEV_ATT_target, GF_FALSE, GF_FALSE, &info) == GF_OK) {
    1054           0 :                         XMLRI *target = (XMLRI *)info.far_ptr;
    1055           0 :                         if (!par && (target->type == XMLRI_ELEMENTID)) {
    1056           0 :                                 if (!target->target) post_pone = GF_TRUE;
    1057             :                                 else par = (SVG_Element *)target->target;
    1058             :                         }
    1059             :                 }
    1060             :                 /*check handler, create it if not specified*/
    1061           0 :                 if (parent && (gf_node_get_attribute_by_tag((GF_Node *)listener, TAG_XMLEV_ATT_handler, GF_TRUE, GF_FALSE, &info) == GF_OK)) {
    1062           0 :                         XMLRI *handler = (XMLRI *)info.far_ptr;
    1063           0 :                         if (!handler->target) {
    1064           0 :                                 if (!handler->string) handler->target = parent->node;
    1065             :                         }
    1066             :                 }
    1067             :                 /*if event is a key event, register it with root*/
    1068           0 :                 if (!par && gf_node_get_attribute_by_tag((GF_Node *)listener, TAG_XMLEV_ATT_event, GF_FALSE, GF_FALSE, &info) == GF_OK) {
    1069           0 :                         XMLEV_Event *ev = (XMLEV_Event *)info.far_ptr;
    1070           0 :                         if ((ev->type>=GF_EVENT_KEYUP) && (ev->type<=GF_EVENT_TEXTINPUT)) par = (SVG_Element*) listener->sgprivate->scenegraph->RootNode;
    1071             :                 }
    1072             : 
    1073           0 :                 if (post_pone) {
    1074           0 :                         gf_list_add(parser->deferred_listeners, listener);
    1075             :                 } else {
    1076           0 :                         if (!par && parent) par = parent->node;
    1077           0 :                         gf_node_dom_listener_add((GF_Node *)par, (GF_Node *) listener);
    1078             :                 }
    1079             :         }
    1080             :         return elt;
    1081             : }
    1082             : 
    1083             : 
    1084         182 : static GF_Err lsr_parse_command(GF_SVG_Parser *parser, const GF_XMLAttribute *attributes, u32 nb_attributes)
    1085             : {
    1086             :         GF_FieldInfo info;
    1087             :         GF_Node *opNode;
    1088             :         Bool is_replace = GF_FALSE;
    1089             :         char *atNode = NULL;
    1090             :         char *atAtt = NULL;
    1091             :         char *atOperandNode = NULL;
    1092             :         char *atOperandAtt = NULL;
    1093             :         char *atValue = NULL;
    1094             :         char *atPoint = NULL;
    1095             :         char *atInteger = NULL;
    1096             :         char *atEvent = NULL;
    1097             :         char *atString = NULL;
    1098             :         GF_CommandField *field;
    1099             :         s32 index = -1;
    1100             :         u32 i;
    1101         182 :         switch (parser->command->tag) {
    1102             :         case GF_SG_LSR_NEW_SCENE:
    1103             :                 return GF_OK;
    1104             :         case GF_SG_LSR_DELETE:
    1105          10 :                 for (i=0; i<nb_attributes; i++) {
    1106          10 :                         GF_XMLAttribute *att = (GF_XMLAttribute *) &attributes[i];
    1107          10 :                         if (!strcmp(att->name, "ref")) atNode = att->value;
    1108           4 :                         else if (!strcmp(att->name, "attributeName")) atAtt = att->value;
    1109           2 :                         else if (!strcmp(att->name, "index")) index = atoi(att->value);
    1110             :                 }
    1111           6 :                 if (!atNode) return svg_report(parser, GF_BAD_PARAM, "Missing node ref for command");
    1112             :                 /*should be a XML IDREF, not an XML IRI*/
    1113           6 :                 if (atNode[0]=='#') atNode++;
    1114             : 
    1115           6 :                 parser->command->node = svg_find_node(parser, atNode);
    1116           6 :                 if (!parser->command->node) return svg_report(parser, GF_BAD_PARAM, "Cannot find node node ref %s for command", atNode);
    1117           6 :                 if (atAtt) {
    1118           2 :                         if (!strcmp(atAtt, "children")) {
    1119           0 :                                 field = gf_sg_command_field_new(parser->command);
    1120           0 :                                 field->pos = index;
    1121           0 :                                 field->fieldIndex = 0;
    1122           0 :                                 field->fieldType = 0;
    1123             :                         } else {
    1124           2 :                                 if (gf_node_get_attribute_by_name(parser->command->node, atAtt, parser->current_ns, GF_FALSE, GF_FALSE, &info)==GF_OK) {
    1125           2 :                                         field = gf_sg_command_field_new(parser->command);
    1126           2 :                                         field->pos = index;
    1127           2 :                                         field->fieldIndex = info.fieldIndex;
    1128           2 :                                         field->fieldType = info.fieldType;
    1129             :                                 }
    1130             :                         }
    1131           4 :                 } else if (index>=0) {
    1132           0 :                         field = gf_sg_command_field_new(parser->command);
    1133           0 :                         field->pos = index;
    1134             :                 }
    1135           6 :                 gf_node_register(parser->command->node, NULL);
    1136           6 :                 return GF_OK;
    1137          58 :         case GF_SG_LSR_REPLACE:
    1138             :                 is_replace = GF_TRUE;
    1139          62 :         case GF_SG_LSR_ADD:
    1140             :         case GF_SG_LSR_INSERT:
    1141         254 :                 for (i=0; i<nb_attributes; i++) {
    1142         192 :                         GF_XMLAttribute *att = (GF_XMLAttribute *)&attributes[i];
    1143         192 :                         if (!strcmp(att->name, "ref")) atNode = att->value;
    1144         130 :                         else if (!strcmp(att->name, "operandElementId")) atOperandNode = att->value;
    1145         128 :                         else if (!strcmp(att->name, "operandAttributeName")) atOperandAtt = att->value;
    1146         126 :                         else if (!strcmp(att->name, "value")) atValue = att->value;
    1147          76 :                         else if (!strcmp(att->name, "attributeName")) atAtt = att->value;
    1148             :                         /*replace only*/
    1149          16 :                         else if (!strcmp(att->name, "index")) index = atoi(att->value);
    1150             :                 }
    1151          62 :                 if (!atNode) return svg_report(parser, GF_BAD_PARAM, "Missing node ref for command");
    1152          62 :                 parser->command->node = svg_find_node(parser, atNode);
    1153          62 :                 if (!parser->command->node) return svg_report(parser, GF_BAD_PARAM, "Cannot find node node ref %s for command", atNode);
    1154             :                 /*child or node replacement*/
    1155          62 :                 if ( (is_replace || (parser->command->tag==GF_SG_LSR_INSERT)) && (!atAtt || !strcmp(atAtt, "children")) ) {
    1156           6 :                         field = gf_sg_command_field_new(parser->command);
    1157           6 :                         field->pos = index;
    1158           6 :                         if (atAtt) field->fieldIndex = TAG_LSR_ATT_children;
    1159           6 :                         gf_node_register(parser->command->node, NULL);
    1160           6 :                         return GF_OK;
    1161             :                 }
    1162          56 :                 if (!atAtt) return svg_report(parser, GF_BAD_PARAM, "Missing attribute name for command");
    1163          56 :                 if (!strcmp(atAtt, "textContent")) {
    1164           4 :                         field = gf_sg_command_field_new(parser->command);
    1165           4 :                         field->pos = -1;
    1166           4 :                         field->fieldIndex = (u32) -1;
    1167           4 :                         field->fieldType = DOM_String_datatype;
    1168           4 :                         gf_node_register(parser->command->node, NULL);
    1169           4 :                         if (atValue) {
    1170           0 :                                 field->field_ptr = gf_svg_create_attribute_value(field->fieldType);
    1171           0 :                                 *(SVG_String *)field->field_ptr = gf_strdup(atValue);
    1172             :                         }
    1173             :                         return GF_OK;
    1174             :                 }
    1175          52 :                 if (!strcmp(atAtt, "scale") || !strcmp(atAtt, "translation") || !strcmp(atAtt, "rotation")) {
    1176           0 :                         if (!strcmp(atAtt, "scale")) {
    1177           0 :                                 info.fieldType = SVG_Transform_Scale_datatype;
    1178           0 :                                 info.fieldIndex = TAG_LSR_ATT_scale;
    1179             :                         }
    1180           0 :                         else if (!strcmp(atAtt, "translation")) {
    1181           0 :                                 info.fieldType = SVG_Transform_Translate_datatype;
    1182           0 :                                 info.fieldIndex = TAG_LSR_ATT_translation;
    1183             :                         }
    1184             :                         else /*if (!strcmp(atAtt, "rotation")) */ {
    1185           0 :                                 info.fieldType = SVG_Transform_Rotate_datatype;
    1186           0 :                                 info.fieldIndex = TAG_LSR_ATT_rotation;
    1187             :                         }
    1188             :                 } else {
    1189             :                         /*FIXME - handle namespace properly here !!*/
    1190          52 :                         info.fieldIndex = gf_xml_get_attribute_tag(parser->command->node, atAtt, (strchr(atAtt, ':')==NULL) ? parser->current_ns : 0);
    1191          52 :                         info.fieldType = gf_xml_get_attribute_type(info.fieldIndex);
    1192             : 
    1193             : #ifndef GPAC_DISABLE_LASER
    1194             :                         /*
    1195             :                                                 if (gf_lsr_anim_type_from_attribute(info.fieldIndex)<0) {
    1196             :                                                         return svg_report(parser, GF_BAD_PARAM, "Attribute %s of element %s is not updatable\n", atAtt, gf_node_get_class_name(parser->command->node));
    1197             :                                                 }
    1198             :                         */
    1199             : #endif /*GPAC_DISABLE_LASER*/
    1200             :                 }
    1201             : 
    1202             :                 opNode = NULL;
    1203          52 :                 if (atOperandNode) {
    1204           2 :                         opNode = gf_sg_find_node_by_name(parser->load->scene_graph, atOperandNode);
    1205           2 :                         if (!opNode) return svg_report(parser, GF_BAD_PARAM, "Cannot find operand element %s for command", atOperandNode);
    1206             :                 }
    1207          52 :                 if (!atValue && (!atOperandNode || !atOperandAtt) ) return svg_report(parser, GF_BAD_PARAM, "Missing attribute value for command");
    1208          52 :                 field = gf_sg_command_field_new(parser->command);
    1209          52 :                 field->pos = index;
    1210          52 :                 field->fieldIndex = info.fieldIndex;
    1211          52 :                 field->fieldType = info.fieldType;
    1212          52 :                 if (atValue) {
    1213             :                         GF_FieldInfo nf;
    1214          50 :                         nf.fieldType = info.fieldType;
    1215          50 :                         field->field_ptr = nf.far_ptr = gf_svg_create_attribute_value(info.fieldType);
    1216          50 :                         if (field->field_ptr) {
    1217          50 :                                 gf_svg_parse_attribute(parser->command->node, &nf, atValue, (u8) info.fieldType);
    1218          50 :                                 if (info.fieldType==XMLRI_datatype)
    1219           0 :                                         svg_process_media_href(parser, parser->command->node, (XMLRI*)field->field_ptr);
    1220             :                         }
    1221           2 :                 } else if (opNode) {
    1222           2 :                         parser->command->fromNodeID = gf_node_get_id(opNode);
    1223             :                         /*FIXME - handle namespace properly here !!*/
    1224           2 :                         parser->command->fromFieldIndex = gf_xml_get_attribute_tag(opNode, atOperandAtt, parser->current_ns);
    1225             :                 }
    1226          52 :                 gf_node_register(parser->command->node, NULL);
    1227          52 :                 return GF_OK;
    1228             :         case GF_SG_LSR_ACTIVATE:
    1229             :         case GF_SG_LSR_DEACTIVATE:
    1230           4 :                 for (i=0; i<nb_attributes; i++) {
    1231           4 :                         GF_XMLAttribute *att = (GF_XMLAttribute *) &attributes[i];
    1232           4 :                         if (!strcmp(att->name, "ref")) atNode = att->value;
    1233             :                 }
    1234           4 :                 if (!atNode) return svg_report(parser, GF_BAD_PARAM, "Missing node ref for command");
    1235             :                 /*should be a XML IDREF, not an XML IRI*/
    1236           4 :                 if (atNode[0]=='#') atNode++;
    1237           4 :                 parser->command->node = svg_find_node(parser, atNode);
    1238           4 :                 if (!parser->command->node) return svg_report(parser, GF_BAD_PARAM, "Cannot find node ref %s for command", atNode);
    1239           4 :                 gf_node_register(parser->command->node, NULL);
    1240             : 
    1241             :                 /*switch to V2*/
    1242           4 :                 svg_lsr_set_v2(parser);
    1243             : 
    1244           4 :                 return GF_OK;
    1245             :         case GF_SG_LSR_SEND_EVENT:
    1246         290 :                 for (i=0; i<nb_attributes; i++) {
    1247         290 :                         GF_XMLAttribute *att = (GF_XMLAttribute *) &attributes[i];
    1248         290 :                         if (!strcmp(att->name, "ref")) atNode = att->value;
    1249         182 :                         else if (!strcmp(att->name, "event")) atEvent = att->value;
    1250          74 :                         else if (!strcmp(att->name, "pointvalue")) atPoint = att->value;
    1251          60 :                         else if (!strcmp(att->name, "intvalue")) atInteger = att->value;
    1252          50 :                         else if (!strcmp(att->name, "stringvalue")) atString = att->value;
    1253             :                 }
    1254             : 
    1255         108 :                 if (!atEvent) return svg_report(parser, GF_BAD_PARAM, "Missing event name for command");
    1256         108 :                 if (!atNode) return svg_report(parser, GF_BAD_PARAM, "Missing node ref for command");
    1257             :                 /*should be a XML IDREF, not an XML IRI*/
    1258         108 :                 if (atNode[0]=='#') atNode++;
    1259         108 :                 parser->command->node = svg_find_node(parser, atNode);
    1260         108 :                 if (!parser->command->node) return svg_report(parser, GF_BAD_PARAM, "Cannot find node node ref %s for command", atNode);
    1261         108 :                 gf_node_register(parser->command->node, NULL);
    1262             : 
    1263         108 :                 parser->command->send_event_name = gf_dom_event_type_by_name(atEvent);
    1264             : 
    1265         108 :                 parser->command->send_event_integer = 0;
    1266         108 :                 if (atString) {
    1267          50 :                         u32 key = gf_dom_get_key_type(atString);
    1268          50 :                         if (key == GF_KEY_UNIDENTIFIED) {
    1269           2 :                                 parser->command->send_event_string = gf_strdup(atString);
    1270             :                         } else {
    1271          48 :                                 parser->command->send_event_integer = key;
    1272             :                         }
    1273             :                 }
    1274         118 :                 if (atInteger) parser->command->send_event_integer = atoi(atInteger);
    1275         108 :                 if (atPoint) {
    1276             :                         SVG_Point pt;
    1277          14 :                         svg_parse_point(&pt, atPoint);
    1278          14 :                         parser->command->send_event_x = FIX2INT(pt.x);
    1279          14 :                         parser->command->send_event_y = FIX2INT(pt.y);
    1280             :                 }
    1281             :                 return GF_OK;
    1282           0 :         default:
    1283           0 :                 return GF_NOT_SUPPORTED;
    1284             :         }
    1285             : }
    1286             : 
    1287             : 
    1288         442 : static u32 lsr_get_command_by_name(const char *name)
    1289             : {
    1290         442 :         if (!strcmp(name, "NewScene")) return GF_SG_LSR_NEW_SCENE;
    1291         438 :         else if (!strcmp(name, "RefreshScene")) return GF_SG_LSR_REFRESH_SCENE;
    1292         438 :         else if (!strcmp(name, "Add")) return GF_SG_LSR_ADD;
    1293         438 :         else if (!strcmp(name, "Replace")) return GF_SG_LSR_REPLACE;
    1294         328 :         else if (!strcmp(name, "Delete")) return GF_SG_LSR_DELETE;
    1295         318 :         else if (!strcmp(name, "Insert")) return GF_SG_LSR_INSERT;
    1296         310 :         else if (!strcmp(name, "Restore")) return GF_SG_LSR_RESTORE;
    1297         310 :         else if (!strcmp(name, "Save")) return GF_SG_LSR_SAVE;
    1298         310 :         else if (!strcmp(name, "Clean")) return GF_SG_LSR_CLEAN;
    1299         310 :         else if (!strcmp(name, "SendEvent")) return GF_SG_LSR_SEND_EVENT;
    1300          94 :         else if (!strcmp(name, "Activate")) return GF_SG_LSR_ACTIVATE;
    1301          90 :         else if (!strcmp(name, "Deactivate")) return GF_SG_LSR_DEACTIVATE;
    1302          86 :         return GF_SG_UNDEFINED;
    1303             : }
    1304             : 
    1305           2 : static GF_ESD *lsr_parse_header(GF_SVG_Parser *parser, const char *name, const char *name_space, const GF_XMLAttribute *attributes, u32 nb_attributes)
    1306             : {
    1307             :         u32 i;
    1308           2 :         if (!strcmp(name, "LASeRHeader")) {
    1309             :                 GF_ESD *esd;
    1310           2 :                 GF_LASERConfig *lsrc = (GF_LASERConfig *) gf_odf_desc_new(GF_ODF_LASER_CFG_TAG);
    1311          14 :                 for (i=0; i<nb_attributes; i++) {
    1312          14 :                         GF_XMLAttribute *att = (GF_XMLAttribute *) &attributes[i];
    1313          14 :                         if (!strcmp(att->name, "profile")) lsrc->profile = !strcmp(att->value, "full") ? 1 : 0;
    1314          12 :                         else if (!strcmp(att->name, "level")) lsrc->level = atoi(att->value);
    1315          14 :                         else if (!strcmp(att->name, "resolution")) lsrc->resolution = atoi(att->value);
    1316          12 :                         else if (!strcmp(att->name, "timeResolution")) lsrc->time_resolution = atoi(att->value);
    1317          10 :                         else if (!strcmp(att->name, "coordBits")) lsrc->coord_bits = atoi(att->value);
    1318           6 :                         else if (!strcmp(att->name, "scaleBits_minus_coordBits")) lsrc->scale_bits_minus_coord_bits = atoi(att->value);
    1319           8 :                         else if (!strcmp(att->name, "colorComponentBits")) lsrc->colorComponentBits = atoi(att->value);
    1320           4 :                         else if (!strcmp(att->name, "newSceneIndicator")) lsrc->newSceneIndicator = (!strcmp(att->value, "yes") || !strcmp(att->value, "true")) ? 1 : 0;
    1321           4 :                         else if (!strcmp(att->name, "useFullRequestHost")) lsrc->fullRequestHost = (!strcmp(att->value, "yes") || !strcmp(att->value, "true")) ? 1 : 0;
    1322           2 :                         else if (!strcmp(att->name, "pathComponents")) lsrc->fullRequestHost = atoi(att->value);
    1323           2 :                         else if (!strcmp(att->name, "extensionIDBits")) lsrc->extensionIDBits = atoi(att->value);
    1324             :                         /*others are ignored in GPAC atm*/
    1325             :                 }
    1326           2 :                 esd = gf_odf_desc_esd_new(2);
    1327           2 :                 gf_odf_desc_del((GF_Descriptor *)esd->decoderConfig->decoderSpecificInfo);
    1328           2 :                 esd->decoderConfig->decoderSpecificInfo = (GF_DefaultDescriptor *) lsrc;
    1329           2 :                 esd->decoderConfig->streamType = GF_STREAM_SCENE;
    1330           2 :                 esd->decoderConfig->objectTypeIndication = GF_CODECID_LASER;
    1331           2 :                 esd->slConfig->timestampResolution = lsrc->time_resolution ? lsrc->time_resolution : 1000;
    1332             :                 return esd;
    1333             :         }
    1334             :         return NULL;
    1335             : }
    1336             : 
    1337             : 
    1338        3817 : static void svg_node_start(void *sax_cbck, const char *name, const char *name_space, const GF_XMLAttribute *attributes, u32 nb_attributes)
    1339             : {
    1340             : #ifndef SKIP_ALL
    1341             :         GF_SVG_Parser *parser = (GF_SVG_Parser *)sax_cbck;
    1342             :         SVG_NodeStack *stack, *parent;
    1343             :         SVG_Element *elt;
    1344             :         SVG_Element *cond = NULL;
    1345             :         u32 xmlns;
    1346             :         Bool has_ns;
    1347             : 
    1348        3817 :         parent = (SVG_NodeStack *)gf_list_last(parser->node_stack);
    1349             : 
    1350             :         /*switch to conditional*/
    1351        3817 :         if (parent && parent->node->sgprivate->tag==TAG_LSR_conditional) {
    1352             :                 cond = parent->node;
    1353             :                 parent = NULL;
    1354             :         }
    1355             : 
    1356             :         /* If the loader was created with the DIMS type and this is the root element, restore the stream and AU
    1357             :         context - in DIMS? we only have one stream an dcommands are stacked in the last AU of the stream*/
    1358        3809 :         if (!parent && (parser->load->type == GF_SM_LOAD_DIMS) && parser->load->ctx) {
    1359             : 
    1360             :                 /*if not created, do it now*/
    1361           0 :                 if (!gf_list_count(parser->load->ctx->streams)) {
    1362           0 :                         parser->laser_es = gf_sm_stream_new(parser->load->ctx, 1, GF_STREAM_SCENE, GF_CODECID_DIMS);
    1363           0 :                         if (!parser->laser_es) {
    1364           0 :                                 svg_report(parser, GF_OUT_OF_MEM, NULL);
    1365           0 :                                 return;
    1366             :                         }
    1367           0 :                         parser->laser_es->timeScale = 1000;
    1368             :                         /* Create a default AU to behave as other streams (LASeR, BIFS)
    1369             :                            but it is left empty, there is no notion of REPLACE Scene or NEw Scene,
    1370             :                            the RAP is the graph */
    1371           0 :                         parser->laser_au = gf_sm_stream_au_new(parser->laser_es, 0, 0, GF_TRUE);
    1372           0 :                         if (!parser->laser_au) {
    1373           0 :                                 svg_report(parser, GF_OUT_OF_MEM, NULL);
    1374           0 :                                 return;
    1375             :                         }
    1376             :                 } else {
    1377           0 :                         parser->laser_es = gf_list_get(parser->load->ctx->streams, 0);
    1378           0 :                         parser->laser_au = gf_list_last(parser->laser_es->AUs);
    1379             :                 }
    1380             :         }
    1381             : 
    1382             :         /*saf setup*/
    1383        3817 :         if ((!parent && (parser->load->type!=GF_SM_LOAD_SVG)) || cond) {
    1384             :                 u32 com_type;
    1385             : 
    1386         284 :                 has_ns=GF_FALSE;
    1387         284 :                 svg_check_namespace(parser, attributes, nb_attributes, &has_ns);
    1388             : 
    1389             :                 /*nothing to do, the context is already created*/
    1390         284 :                 if (!strcmp(name, "SAFSession")) return;
    1391             :                 /*nothing to do, wait for the laser (or other) header before creating stream)*/
    1392         282 :                 if (!strcmp(name, "sceneHeader")) return;
    1393             :                 /*nothing to do, wait for the laser (or other) header before creating stream)*/
    1394         280 :                 if (!strcmp(name, "LASeRHeader")) {
    1395             :                         GF_ESD *esd;
    1396             : 
    1397           2 :                         if (!parser->load->ctx) {
    1398           0 :                                 svg_report(parser, GF_BAD_PARAM, "Invalid parser context");
    1399           0 :                                 return;
    1400             :                         }
    1401           2 :                         esd = lsr_parse_header(parser, name, name_space, attributes, nb_attributes);
    1402           2 :                         if (!esd) {
    1403           0 :                                 svg_report(parser, GF_BAD_PARAM, "Invalid LASER Header");
    1404           0 :                                 return;
    1405             :                         }
    1406             :                         /*TODO find a better way of assigning an ID to the laser stream...*/
    1407           2 :                         esd->ESID = 1;
    1408           2 :                         parser->laser_es = gf_sm_stream_new(parser->load->ctx, esd->ESID, esd->decoderConfig->streamType, esd->decoderConfig->objectTypeIndication);
    1409           2 :                         if (!parser->laser_es) {
    1410           0 :                                 svg_report(parser, GF_OUT_OF_MEM, NULL);
    1411           0 :                                 return;
    1412             :                         }
    1413           2 :                         if (!parser->load->ctx->root_od) {
    1414           2 :                                 parser->load->ctx->root_od = (GF_ObjectDescriptor *) gf_odf_desc_new(GF_ODF_IOD_TAG);
    1415           2 :                                 if (!parser->load->ctx->root_od) {
    1416           0 :                                         svg_report(parser, GF_OUT_OF_MEM, NULL);
    1417           0 :                                         return;
    1418             :                                 }
    1419             :                         }
    1420           2 :                         gf_list_add(parser->load->ctx->root_od->ESDescriptors, esd);
    1421           2 :                         parser->laser_es->timeScale = esd->slConfig->timestampResolution;
    1422           2 :                         return;
    1423             :                 }
    1424         278 :                 if (!strcmp(name, "sceneUnit") ) {
    1425             :                         u32 time, i;
    1426             :                         Bool rap;
    1427             :                         time = 0;
    1428             :                         rap =  GF_FALSE;
    1429           6 :                         if (!gf_list_count(parser->laser_es->AUs)) rap = GF_TRUE;
    1430           4 :                         for (i=0; i<nb_attributes; i++) {
    1431           4 :                                 GF_XMLAttribute *att = (GF_XMLAttribute *) &attributes[i];
    1432           8 :                                 if (!strcmp(att->name, "time")) time = atoi(att->value);
    1433           0 :                                 else if (!strcmp(att->name, "rap")) rap = !strcmp(att->value, "yes") ? GF_TRUE : GF_FALSE;
    1434             :                         }
    1435             :                         /*create new laser unit*/
    1436           6 :                         parser->laser_au = gf_sm_stream_au_new(parser->laser_es, time, 0, rap);
    1437           6 :                         if (!parser->laser_au) {
    1438           0 :                                 svg_report(parser, GF_OUT_OF_MEM, NULL);
    1439           0 :                                 return;
    1440             :                         }
    1441             :                         return;
    1442             :                 }
    1443             : 
    1444         272 :                 if (!strcmp(name, "StreamHeader") || !strcmp(name, "RemoteStreamHeader")
    1445             :                         /*SAF & SAFML are just a pain ...*/
    1446         272 :                         || !strcmp(name, "mediaHeader") || !strcmp(name, "imageHeader")
    1447             :                    ) {
    1448             :                         char *url = NULL;
    1449             :                         char *src = NULL;
    1450             :                         const char *ID = NULL;
    1451             :                         u32 time, codecid, ST, i, ts_res;
    1452             :                         GF_ODUpdate *odU;
    1453             :                         GF_ObjectDescriptor *od;
    1454             :                         SVG_SAFExternalStream*st;
    1455             :                         /*create a SAF stream*/
    1456           2 :                         if (!parser->saf_es && parser->load->ctx) {
    1457           2 :                                 GF_ESD *esd = (GF_ESD*)gf_odf_desc_esd_new(2);
    1458           2 :                                 esd->ESID = 0xFFFE;
    1459           2 :                                 esd->decoderConfig->streamType = GF_STREAM_OD;
    1460           2 :                                 esd->decoderConfig->objectTypeIndication = 1;
    1461           2 :                                 parser->saf_es = gf_sm_stream_new(parser->load->ctx, esd->ESID, GF_STREAM_OD, GF_CODECID_OD_V1);
    1462           2 :                                 if (!parser->saf_es) {
    1463           0 :                                         svg_report(parser, GF_OUT_OF_MEM, NULL);
    1464           0 :                                         return;
    1465             :                                 }
    1466           2 :                                 if (!parser->load->ctx->root_od) {
    1467           0 :                                         parser->load->ctx->root_od = (GF_ObjectDescriptor *) gf_odf_desc_new(GF_ODF_IOD_TAG);
    1468           0 :                                         if (!parser->load->ctx->root_od) {
    1469           0 :                                                 svg_report(parser, GF_OUT_OF_MEM, NULL);
    1470           0 :                                                 return;
    1471             :                                         }
    1472             :                                 }
    1473           2 :                                 parser->saf_es->timeScale = 1000;
    1474           2 :                                 gf_list_add(parser->load->ctx->root_od->ESDescriptors, esd);
    1475             :                         }
    1476             :                         time = 0;
    1477             :                         ts_res = 1000;
    1478             :                         codecid = ST = 0;
    1479           4 :                         for (i=0; i<nb_attributes; i++) {
    1480           4 :                                 GF_XMLAttribute *att = (GF_XMLAttribute *) &attributes[i];
    1481           4 :                                 if (!strcmp(att->name, "time")) time = atoi(att->value);
    1482           4 :                                 else if (!strcmp(att->name, "rap")) ;//rap = !strcmp(att->value, "yes") ? 1 : 0;
    1483           4 :                                 else if (!strcmp(att->name, "url")) url = gf_strdup(att->value);
    1484           2 :                                 else if (!strcmp(att->name, "streamID")) ID = att->value;
    1485           0 :                                 else if (!strcmp(att->name, "objectTypeIndication")) codecid = atoi(att->value);
    1486           0 :                                 else if (!strcmp(att->name, "codecID")) {
    1487           0 :                                         codecid = GF_4CC(att->value[0],att->value[1],att->value[2],att->value[3]);
    1488             :                                 }
    1489           0 :                                 else if (!strcmp(att->name, "streamType")) ST = atoi(att->value);
    1490           0 :                                 else if (!strcmp(att->name, "timeStampResolution")) ts_res = atoi(att->value);
    1491           0 :                                 else if (!strcmp(att->name, "source")) src = att->value;
    1492             : 
    1493             :                         }
    1494           2 :                         if (!strcmp(name, "imageHeader")) ST = 4;
    1495             : 
    1496             :                         /*create new SAF stream*/
    1497           2 :                         st = svg_saf_get_next_available_stream(parser);
    1498           2 :                         st->stream_name = ID ? gf_strdup(ID) : NULL;
    1499             : 
    1500             :                         /*create new SAF unit*/
    1501           2 :                         parser->saf_au = gf_sm_stream_au_new(parser->saf_es, time, 0, GF_FALSE);
    1502           2 :                         if (!parser->saf_au) {
    1503           0 :                                 svg_report(parser, GF_OUT_OF_MEM, NULL);
    1504           0 :                                 return;
    1505             :                         }
    1506             : 
    1507           2 :                         odU = (GF_ODUpdate *) gf_odf_com_new(GF_ODF_OD_UPDATE_TAG);
    1508           2 :                         if (!odU) {
    1509           0 :                                 svg_report(parser, GF_OUT_OF_MEM, NULL);
    1510           0 :                                 return;
    1511             :                         }
    1512           2 :                         gf_list_add(parser->saf_au->commands, odU);
    1513           2 :                         od = (GF_ObjectDescriptor *) gf_odf_desc_new(GF_ODF_OD_TAG);
    1514           2 :                         if (!od) {
    1515           0 :                                 svg_report(parser, GF_OUT_OF_MEM, NULL);
    1516           0 :                                 return;
    1517             :                         }
    1518           2 :                         gf_list_add(odU->objectDescriptors, od);
    1519           2 :                         od->objectDescriptorID = st->id;
    1520             : 
    1521           2 :                         if (url) {
    1522           2 :                                 od->URLString = url;
    1523             :                         } else {
    1524             :                                 GF_MuxInfo *mux;
    1525           0 :                                 GF_ESD *esd = (GF_ESD*)gf_odf_desc_esd_new(2);
    1526           0 :                                 if (!esd) {
    1527           0 :                                         svg_report(parser, GF_OUT_OF_MEM, NULL);
    1528           0 :                                         return;
    1529             :                                 }
    1530           0 :                                 gf_list_add(od->ESDescriptors, esd);
    1531           0 :                                 esd->decoderConfig->objectTypeIndication = codecid;
    1532           0 :                                 esd->decoderConfig->streamType = ST;
    1533           0 :                                 esd->ESID = st->id;
    1534             : 
    1535           0 :                                 mux = (GF_MuxInfo *)gf_odf_desc_new(GF_ODF_MUXINFO_TAG);
    1536           0 :                                 if (!mux) {
    1537           0 :                                         svg_report(parser, GF_OUT_OF_MEM, NULL);
    1538           0 :                                         return;
    1539             :                                 }
    1540           0 :                                 gf_list_add(esd->extensionDescriptors, mux);
    1541             : 
    1542             :                                 /*global source for stream, don't use nhml dumping*/
    1543           0 :                                 if (src) {
    1544           0 :                                         mux->file_name = gf_strdup(src);
    1545           0 :                                         st->nhml_info = NULL;
    1546             :                                 } else {
    1547             :                                         FILE *nhml;
    1548             :                                         char szName[1024];
    1549           0 :                                         if (parser->load->localPath) {
    1550             :                                                 strcpy(szName, parser->load->localPath);
    1551             :                                                 strcat(szName, "/");
    1552           0 :                                                 strcat(szName, ID ? ID : "");
    1553             :                                         } else {
    1554           0 :                                                 strcpy(szName, ID ? ID : "");
    1555             :                                         }
    1556             :                                         strcat(szName, "_temp.nhml");
    1557           0 :                                         mux->file_name = gf_strdup(szName);
    1558           0 :                                         st->nhml_info = mux->file_name;
    1559           0 :                                         nhml = gf_fopen(st->nhml_info, "wt");
    1560           0 :                                         if (nhml) {
    1561           0 :                                                 gf_fprintf(nhml, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
    1562           0 :                                                 gf_fprintf(nhml, "<NHNTStream version=\"1.0\" timeScale=\"%d\" streamType=\"%d\" objectTypeIndication=\"%d\" inRootOD=\"no\" trackID=\"%d\">\n", ts_res, ST, codecid, st->id);
    1563           0 :                                                 gf_fclose(nhml);
    1564             :                                         } else {
    1565           0 :                                                 GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[LASeR Parser] Error opening nhml file %s while preparing import\n", st->nhml_info));
    1566             :                                         }
    1567           0 :                                         mux->delete_file = GF_TRUE;
    1568             :                                 }
    1569             :                         }
    1570             :                         return;
    1571             :                 }
    1572         270 :                 if (!strcmp(name, "mediaUnit") || !strcmp(name, "imageUnit") ) {
    1573             :                         FILE *nhml;
    1574             :                         char *id = NULL;
    1575             :                         char *src = NULL;
    1576             :                         SVG_SAFExternalStream*st;
    1577             :                         u32 i, rap, time, offset, length;
    1578             :                         rap = time = offset = length = 0;
    1579           0 :                         for (i=0; i<nb_attributes; i++) {
    1580           0 :                                 GF_XMLAttribute *att = (GF_XMLAttribute *) &attributes[i];
    1581           0 :                                 if (!strcmp(att->name, "time")) time = atoi(att->value);
    1582           0 :                                 else if (!strcmp(att->name, "source")) src = att->value;
    1583           0 :                                 else if (!strcmp(att->name, "ref")) id = att->value;
    1584           0 :                                 else if (!strcmp(att->name, "rap")) rap = !strcmp(att->value, "yes") ? 1 : 0;
    1585           0 :                                 else if (!strcmp(att->name, "startOffset")) offset = atoi(att->value);
    1586           0 :                                 else if (!strcmp(att->name, "length")) length = atoi(att->value);
    1587             :                         }
    1588           0 :                         st = svg_saf_get_stream(parser, 0, id);
    1589           0 :                         if (!st || !st->nhml_info) {
    1590             :                                 return;
    1591             :                         }
    1592           0 :                         nhml = gf_fopen(st->nhml_info, "a+t");
    1593           0 :                         gf_fprintf(nhml, "<NHNTSample ");
    1594           0 :                         if (time) gf_fprintf(nhml, "DTS=\"%d\" ", time);
    1595           0 :                         if (length) gf_fprintf(nhml, "dataLength=\"%d\" ", length);
    1596           0 :                         if (offset) gf_fprintf(nhml, "mediaOffset=\"%d\" ", offset);
    1597           0 :                         if (rap) gf_fprintf(nhml, "isRAP=\"yes\" ");
    1598           0 :                         if (src) gf_fprintf(nhml, "mediaFile=\"%s\" ", src);
    1599           0 :                         gf_fprintf(nhml, "/>\n");
    1600           0 :                         gf_fclose(nhml);
    1601           0 :                         return;
    1602             :                 }
    1603         270 :                 if (!strcmp(name, "endOfStream") ) {
    1604             :                         FILE *nhml;
    1605             :                         char *id = NULL;
    1606             :                         u32 i;
    1607             :                         SVG_SAFExternalStream*st;
    1608           0 :                         for (i=0; i<nb_attributes; i++) {
    1609           0 :                                 GF_XMLAttribute *att = (GF_XMLAttribute *) &attributes[i];
    1610           0 :                                 if (!strcmp(att->name, "ref")) id = att->value;
    1611             :                         }
    1612           0 :                         st = svg_saf_get_stream(parser, 0, id);
    1613           0 :                         if (!st || !st->nhml_info) {
    1614             :                                 return;
    1615             :                         }
    1616           0 :                         nhml = gf_fopen(st->nhml_info, "a+t");
    1617           0 :                         gf_fprintf(nhml, "</NHNTStream>\n");
    1618           0 :                         gf_fclose(nhml);
    1619           0 :                         return;
    1620             :                 }
    1621             : 
    1622         270 :                 if (!strcmp(name, "endOfSAFSession") ) {
    1623             :                         return;
    1624             :                 }
    1625             : 
    1626         268 :                 if ((parser->load->type==GF_SM_LOAD_XSR) && !parser->laser_au && !cond) {
    1627           0 :                         if (parser->load->flags & GF_SM_LOAD_CONTEXT_READY) {
    1628             :                                 assert(parser->laser_es);
    1629           0 :                                 parser->laser_au = gf_sm_stream_au_new(parser->laser_es, 0, 0, GF_FALSE);
    1630           0 :                                 if (!parser->laser_au) {
    1631           0 :                                         svg_report(parser, GF_OUT_OF_MEM, NULL);
    1632           0 :                                         return;
    1633             :                                 }
    1634             :                         } else {
    1635           0 :                                 svg_report(parser, GF_BAD_PARAM, "LASeR sceneUnit not defined for command %s", name);
    1636           0 :                                 return;
    1637             :                         }
    1638             :                 }
    1639             :                 /*command parsing*/
    1640         268 :                 com_type = lsr_get_command_by_name(name);
    1641         268 :                 if (com_type != GF_SG_UNDEFINED) {
    1642             :                         SVG_NodeStack *top;
    1643             :                         GF_Err e;
    1644         182 :                         parser->command = gf_sg_command_new(parser->load->scene_graph, com_type);
    1645         182 :                         if (!parser->command) {
    1646           0 :                                 svg_report(parser, GF_OUT_OF_MEM, NULL);
    1647           0 :                                 return;
    1648             :                         }
    1649             : 
    1650             :                         /*this is likely a conditional start - update unknown depth level*/
    1651         182 :                         top = (SVG_NodeStack*)gf_list_last(parser->node_stack);
    1652         182 :                         if (top) {
    1653           8 :                                 top->unknown_depth ++;
    1654           8 :                                 parser->command_depth++;
    1655             :                         }
    1656             : 
    1657         182 :                         e = lsr_parse_command(parser, attributes, nb_attributes);
    1658         182 :                         if (e!= GF_OK) {
    1659           0 :                                 parser->command->node = NULL;
    1660           0 :                                 gf_sg_command_del(parser->command);
    1661           0 :                                 parser->command = NULL;
    1662           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[LASeR Parser] Error parsing %s command - skipping\n", (parser->load->type==GF_SM_LOAD_XSR) ? "LASeR" : "DIMS"));
    1663             :                                 return;
    1664             :                         }
    1665             : 
    1666         182 :                         if (cond) {
    1667           8 :                                 GF_DOMUpdates *up = cond->children ? (GF_DOMUpdates *)cond->children->node : NULL;
    1668           6 :                                 if (!up) {
    1669           2 :                                         up = gf_dom_add_updates_node((GF_Node*)cond);
    1670             : 
    1671           2 :                                         if (parser->load->flags & GF_SM_LOAD_FOR_PLAYBACK) {
    1672           0 :                                                 gf_node_set_callback_function((GF_Node*)up, xsr_exec_command_list);
    1673             :                                         }
    1674             :                                 }
    1675           8 :                                 gf_list_add(up->updates, parser->command);
    1676         174 :                         } else if (parser->laser_au) {
    1677         174 :                                 gf_list_add(parser->laser_au->commands, parser->command);
    1678             :                         }
    1679         182 :                         switch (com_type) {
    1680           2 :                         case GF_SG_LSR_NEW_SCENE:
    1681             :                         case GF_SG_LSR_REFRESH_SCENE:
    1682           2 :                                 if (parser->laser_au) parser->laser_au->flags |= GF_SM_AU_RAP;
    1683             :                                 break;
    1684             :                         }
    1685         182 :                         parser->current_ns = GF_XMLNS_SVG;
    1686         182 :                         return;
    1687             :                 }
    1688             :         }
    1689             : 
    1690        3619 :         if (!parent && !parser->command && (parser->load->flags & GF_SM_LOAD_CONTEXT_STREAMING)) {
    1691           0 :                 gf_sg_reset(parser->load->scene_graph);
    1692           0 :                 parser->has_root = 0;
    1693             :         }
    1694             : 
    1695             :         /*something not supported happened (bad command name, bad root, ...) */
    1696        3619 :         if ((parser->has_root==1) && !parent && !parser->command)
    1697             :                 return;
    1698             : 
    1699        3619 :         xmlns = parser->current_ns;
    1700        3619 :         has_ns = GF_FALSE;
    1701             : 
    1702        3619 :         elt = svg_parse_element(parser, name, name_space, attributes, nb_attributes, parent, &has_ns);
    1703        3619 :         if (!elt) {
    1704           0 :                 if (parent) parent->unknown_depth++;
    1705           0 :                 else if (cond) parser->command_depth++;
    1706             :                 return;
    1707             :         }
    1708        3619 :         GF_SAFEALLOC(stack, SVG_NodeStack);
    1709        3619 :         if (!stack) {
    1710           0 :                 parser->last_error = GF_OUT_OF_MEM;
    1711           0 :                 return;
    1712             :         }
    1713        3619 :         stack->node = elt;
    1714        3619 :         stack->current_ns = xmlns;
    1715        3619 :         stack->has_ns = has_ns;
    1716        3619 :         gf_list_add(parser->node_stack, stack);
    1717             : 
    1718        3689 :         if ( (gf_node_get_tag((GF_Node *)elt) == TAG_SVG_svg) &&
    1719         140 :                 (!parser->has_root || (parser->command && !parser->command->node) )
    1720             :            ) {
    1721             : 
    1722           0 :                 if (!parser->has_root) svg_init_root_element(parser, elt);
    1723           0 :                 if (parser->command) parser->command->node = (GF_Node*)elt;
    1724        3619 :         } else if (!parent && parser->has_root && parser->command) {
    1725          86 :                 GF_CommandField *field = (GF_CommandField *)gf_list_get(parser->command->command_fields, 0);
    1726          86 :                 if (field) {
    1727             :                         /*either not assigned or textContent*/
    1728          84 :                         if (field->new_node && (field->new_node->sgprivate->tag==TAG_DOMText)) {
    1729           4 :                                 gf_node_unregister(field->new_node, NULL);
    1730           4 :                                 field->new_node = NULL;
    1731             :                         }
    1732          84 :                         if (field->new_node) {
    1733           4 :                                 field->field_ptr = &field->node_list;
    1734           4 :                                 gf_node_list_add_child(& field->node_list, field->new_node);
    1735           4 :                                 field->new_node = NULL;
    1736           4 :                                 gf_node_list_add_child( & field->node_list, (GF_Node*) elt);
    1737          80 :                         } else if (field->node_list) {
    1738          74 :                                 gf_node_list_add_child(& field->node_list, (GF_Node*) elt);
    1739             :                         } else {
    1740           6 :                                 field->new_node = (GF_Node*)elt;
    1741           6 :                                 field->field_ptr = &field->new_node;
    1742             :                         }
    1743             :                 } else {
    1744             :                         assert(parser->command->tag==GF_SG_LSR_NEW_SCENE);
    1745             :                         assert(gf_node_get_tag((GF_Node *)elt) == TAG_SVG_svg);
    1746           2 :                         if(!parser->command->node)
    1747           0 :                                 parser->command->node = (GF_Node *)elt;
    1748             :                 }
    1749        3533 :         } else if (!parser->has_root ) {
    1750           0 :                 gf_list_del_item(parser->node_stack, stack);
    1751           0 :                 gf_free(stack);
    1752           0 :                 gf_node_unregister((GF_Node *)elt, NULL);
    1753        3533 :         } else if ((parser->has_root==2) && !parser->fragment_root) {
    1754           0 :                 parser->fragment_root = (GF_Node *)elt;
    1755             :         }
    1756             : #endif
    1757             : }
    1758             : 
    1759        3817 : static void svg_node_end(void *sax_cbck, const char *name, const char *name_space)
    1760             : {
    1761             : #ifndef SKIP_ALL
    1762             : #ifdef SKIP_UNKNOWN_NODES
    1763             :         u32 ns;
    1764             : #endif
    1765             :         GF_SVG_Parser *parser = (GF_SVG_Parser *)sax_cbck;
    1766        3817 :         SVG_NodeStack *top = (SVG_NodeStack *)gf_list_last(parser->node_stack);
    1767             : 
    1768        3817 :         if (!top) {
    1769         190 :                 if (parser->laser_au && !strcmp(name, "sceneUnit")) {
    1770           6 :                         parser->laser_au = NULL;
    1771           6 :                         return;
    1772             :                 }
    1773         184 :                 if (parser->command) {
    1774         174 :                         u32 com_type = lsr_get_command_by_name(name);
    1775         174 :                         if (com_type == parser->command->tag) {
    1776         172 :                                 if (parser->load->type==GF_SM_LOAD_DIMS && parser->load->flags & GF_SM_LOAD_FOR_PLAYBACK) {
    1777           0 :                                         gf_sg_command_apply(parser->load->scene_graph, parser->command, 0);
    1778           0 :                                         gf_sg_command_del(parser->command);
    1779             :                                 }
    1780         172 :                                 parser->command = NULL;
    1781         172 :                                 return;
    1782             :                         }
    1783             :                 }
    1784             :                 /*error*/
    1785             :                 return;
    1786             :         }
    1787             : 
    1788             : #ifdef SKIP_UNKNOWN_NODES
    1789             :         ns = parser->current_ns;
    1790             :         if (name_space)
    1791             :                 ns = gf_sg_get_namespace_code(parser->load->scene_graph, (char *) name_space);
    1792             : 
    1793             :         /*only remove created nodes ... */
    1794             :         if (gf_xml_get_element_tag(name, ns) != TAG_UndefinedNode)
    1795             : #endif
    1796             :         {
    1797             :                 const char *the_name;
    1798             :                 Bool mismatch = GF_FALSE;
    1799        3627 :                 SVG_Element *node = top->node;
    1800             :                 /*check node name...*/
    1801        3627 :                 the_name = gf_node_get_class_name((GF_Node *)node);
    1802        3627 :                 if (name_space && strstr(the_name, name_space) && strstr(the_name, name) ) {}
    1803        3583 :                 else if (!strcmp(the_name, name) ) {}
    1804             :                 else mismatch = GF_TRUE;
    1805             : 
    1806             :                 if (mismatch) {
    1807           8 :                         if (top->unknown_depth) {
    1808           8 :                                 top->unknown_depth--;
    1809           8 :                                 return;
    1810             :                         } else {
    1811           0 :                                 svg_report(parser, GF_BAD_PARAM, "SVG depth mismatch: expecting </%s> got </%s>", the_name, name);
    1812           0 :                                 return;
    1813             :                         }
    1814             :                 }
    1815        3619 :                 parser->current_ns = top->current_ns;
    1816        3619 :                 if (top->has_ns) gf_xml_pop_namespaces(top->node);
    1817        3619 :                 gf_free(top);
    1818        3619 :                 gf_list_rem_last(parser->node_stack);
    1819             : 
    1820        3619 :                 if (parser->load->flags & GF_SM_LOAD_FOR_PLAYBACK) {
    1821        2296 :                         switch (node->sgprivate->tag) {
    1822           1 :                         case TAG_SVG_animateMotion:
    1823             :                                 /*
    1824             :                                 try to init animateMotion once all children have been parsed
    1825             :                                 to make sure we get the mpath child if any, however, we are still not sure
    1826             :                                 if the target is known. We can force initialisation
    1827             :                                 because mpath children (if any have been parsed)
    1828             :                                 */
    1829             :                         {
    1830             :                                 u32 i, count;
    1831             :                                 SVG_DeferredAnimation *anim = NULL;
    1832           1 :                                 count = gf_list_count(parser->deferred_animations);
    1833           3 :                                 for (i = 0; i < count; i++) {
    1834           3 :                                         anim = gf_list_get(parser->deferred_animations, i);
    1835           3 :                                         if (anim->animation_elt == node) break;
    1836             :                                         else anim = NULL;
    1837             :                                 }
    1838           1 :                                 if (anim) {
    1839           1 :                                         if (svg_parse_animation(parser, gf_node_get_graph((GF_Node *)node), anim, NULL, 1)) {
    1840           1 :                                                 svg_delete_deferred_anim(anim, parser->deferred_animations);
    1841             :                                         }
    1842             :                                 }
    1843             :                         }
    1844             :                         break;
    1845           4 :                         case TAG_SVG_script:
    1846             :                         case TAG_SVG_handler:
    1847             :                                 /*init script once text script is loaded*/
    1848           4 :                                 gf_node_init((GF_Node *)node);
    1849           4 :                                 break;
    1850             :                         }
    1851             :                         /*if we have associated event listeners, trigger the onLoad, only in playback mode */
    1852        2296 :                         if (node->sgprivate->interact && node->sgprivate->interact->dom_evt) {
    1853             :                                 GF_DOM_Event evt;
    1854             :                                 memset(&evt, 0, sizeof(GF_DOM_Event));
    1855           2 :                                 evt.type = GF_EVENT_LOAD;
    1856           2 :                                 gf_dom_event_fire((GF_Node*)node, &evt);
    1857             :                         }
    1858             : 
    1859             :                 }
    1860             :         }
    1861             : #ifdef SKIP_UNKNOWN_NODES
    1862             :         else {
    1863             :                 if (top->unknown_depth) {
    1864             :                         top->unknown_depth--;
    1865             :                         if (!top->unknown_depth) {
    1866             :                                 /*this is not 100% correct, we should track which unsupported node changed the namespace*/
    1867             :                                 parser->current_ns = top->current_ns;
    1868             :                                 if (parser->command_depth) parser->command_depth --;
    1869             :                         }
    1870             :                 } else if (parser->command_depth) {
    1871             :                         parser->command_depth--;
    1872             :                 } else {
    1873             :                         svg_report(parser, GF_BAD_PARAM, "SVG depth mismatch");
    1874             :                 }
    1875             :         }
    1876             : #endif
    1877             : 
    1878             : #endif //SKIP_ALL
    1879             : }
    1880             : 
    1881        6047 : static void svg_text_content(void *sax_cbck, const char *text_content, Bool is_cdata)
    1882             : {
    1883             : #ifndef SKIP_ALL
    1884             :         GF_SVG_Parser *parser = (GF_SVG_Parser *)sax_cbck;
    1885        6047 :         SVG_NodeStack *top = (SVG_NodeStack *)gf_list_last(parser->node_stack);
    1886        6047 :         SVG_Element *elt = (top ? top->node : NULL);
    1887             :         GF_DOMText *text;
    1888             :         Bool skip_text;
    1889             :         u32 tag;
    1890             : 
    1891        6047 :         if (top && top->unknown_depth && !parser->command_depth) return;
    1892        6047 :         if (!elt && !parser->command) return;
    1893             : 
    1894        5855 :         tag = (elt ? gf_node_get_tag((GF_Node *)elt) : 0);
    1895             : 
    1896             :         /*if top is a conditional, create a new text node*/
    1897        5855 :         if (!elt || tag == TAG_LSR_conditional) {
    1898             :                 GF_CommandField *field;
    1899         110 :                 if (!parser->command) return;
    1900             : 
    1901         110 :                 field = (GF_CommandField *)gf_list_get(parser->command->command_fields, 0);
    1902         110 :                 if (parser->command->tag == GF_SG_LSR_NEW_SCENE || parser->command->tag == GF_SG_LSR_ADD) return;
    1903             : 
    1904         106 :                 if (!field || field->field_ptr) return;
    1905             : 
    1906           8 :                 if (field->new_node) {
    1907           0 :                         svg_report(parser, GF_OK, "Warning: LASeR cannot replace children with a mix of text nodes and elements - ignoring text\n");
    1908           0 :                         return;
    1909             :                 }
    1910             : 
    1911             :                 /*create a text node but don't register it with any node*/
    1912           8 :                 text = gf_dom_new_text_node(parser->load->scene_graph);
    1913           8 :                 gf_node_register((GF_Node *)text, NULL);
    1914           8 :                 text->textContent = gf_strdup(text_content);
    1915             : 
    1916           8 :                 if (field->new_node) {
    1917           0 :                         field->field_ptr = &field->node_list;
    1918           0 :                         gf_node_list_add_child(& field->node_list, field->new_node);
    1919           0 :                         field->new_node = NULL;
    1920           0 :                         gf_node_list_add_child( & field->node_list, (GF_Node*) text);
    1921           8 :                 } else if (field->node_list) {
    1922           0 :                         gf_node_list_add_child(& field->node_list, (GF_Node*) text);
    1923             :                 } else {
    1924           8 :                         field->new_node = (GF_Node*)text;
    1925           8 :                         field->field_ptr = &field->new_node;
    1926             :                 }
    1927             :                 return;
    1928             :         }
    1929             :         skip_text = GF_TRUE;
    1930             :         switch (tag) {
    1931             :         case TAG_DOMFullNode:
    1932             :         case TAG_SVG_a:
    1933             :         case TAG_SVG_title:
    1934             :         case TAG_SVG_desc:
    1935             :         case TAG_SVG_metadata:
    1936             :         case TAG_SVG_text:
    1937             :         case TAG_SVG_tspan:
    1938             :         case TAG_SVG_textArea:
    1939             :                 skip_text = GF_FALSE;
    1940             :                 break;
    1941             :         /*for script and handlers only add text if not empty*/
    1942          24 :         case TAG_SVG_handler:
    1943             :         case TAG_SVG_script:
    1944             :         {
    1945          24 :                 u32 i, len = (u32) strlen(text_content);
    1946          82 :                 for (i=0; i<len; i++) {
    1947          64 :                         if (!strchr(" \n\r\t", text_content[i])) {
    1948             :                                 skip_text = GF_FALSE;
    1949             :                                 break;
    1950             :                         }
    1951             :                 }
    1952             :         }
    1953             :         break;
    1954             :         }
    1955             : 
    1956          24 :         if (!skip_text) {
    1957         638 :                 text = gf_dom_add_text_node((GF_Node *)elt, gf_strdup(text_content));
    1958         638 :                 text->type = is_cdata ? GF_DOM_TEXT_CDATA : GF_DOM_TEXT_REGULAR;
    1959         638 :                 gf_node_changed((GF_Node *)text, NULL);
    1960             :         }
    1961             : #endif
    1962             : }
    1963             : 
    1964          69 : static GF_SVG_Parser *svg_new_parser(GF_SceneLoader *load)
    1965             : {
    1966             :         GF_SVG_Parser *parser;
    1967          69 :         switch (load->type) {
    1968           2 :         case GF_SM_LOAD_XSR:
    1969           2 :                 if (!load->ctx) return NULL;
    1970             :                 break;
    1971             :         case GF_SM_LOAD_SVG:
    1972             :         case GF_SM_LOAD_DIMS:
    1973             :                 break;
    1974             :         default:
    1975             :                 return NULL;
    1976             :         }
    1977             : 
    1978          69 :         GF_SAFEALLOC(parser, GF_SVG_Parser);
    1979          69 :         if (!parser) {
    1980             :                 return NULL;
    1981             :         }
    1982          69 :         parser->node_stack = gf_list_new();
    1983          69 :         parser->deferred_hrefs = gf_list_new();
    1984          69 :         parser->deferred_animations = gf_list_new();
    1985          69 :         parser->deferred_listeners = gf_list_new();
    1986          69 :         parser->peeked_nodes = gf_list_new();
    1987             : 
    1988          69 :         parser->sax_parser = gf_xml_sax_new(svg_node_start, svg_node_end, svg_text_content, parser);
    1989          69 :         parser->load = load;
    1990          69 :         load->loader_priv = parser;
    1991          69 :         if (load->ctx) load->ctx->is_pixel_metrics = GF_TRUE;
    1992             : 
    1993             :         /*to cope with old files not signaling XMLNS, add the SVG NS by default*/
    1994          69 :         gf_sg_add_namespace(parser->load->scene_graph, "http://www.w3.org/2000/svg", NULL);
    1995          69 :         parser->current_ns = GF_XMLNS_SVG;
    1996             : 
    1997             : #ifdef GPAC_ENABLE_COVERAGE
    1998          69 :         if (gf_sys_is_cov_mode()) {
    1999          69 :                 svg_report(parser, GF_OK, NULL);
    2000             :         }
    2001             : #endif
    2002             : 
    2003             :         return parser;
    2004             : }
    2005             : 
    2006          68 : static void svg_flush_animations(GF_SVG_Parser *parser)
    2007             : {
    2008          68 :         if (!parser) return;
    2009          77 :         while (gf_list_count(parser->deferred_animations)) {
    2010           9 :                 SVG_DeferredAnimation *anim = (SVG_DeferredAnimation *)gf_list_get(parser->deferred_animations, 0);
    2011           9 :                 svg_parse_animation(parser, parser->load->scene_graph, anim, NULL, 2);
    2012           9 :                 svg_delete_deferred_anim(anim, parser->deferred_animations);
    2013             :         }
    2014             : }
    2015             : 
    2016         136 : static void gf_sm_svg_flush_state(GF_SVG_Parser *parser)
    2017             : {
    2018         136 :         while (gf_list_count(parser->node_stack)) {
    2019           0 :                 SVG_NodeStack *st = (SVG_NodeStack *)gf_list_last(parser->node_stack);
    2020           0 :                 gf_list_rem_last(parser->node_stack);
    2021           0 :                 gf_free(st);
    2022             :         }
    2023             :         /*FIXME - if there still are som deferred listeners, we should pass them to the scene graph
    2024             :         and wait for the parent to be defined*/
    2025         136 :         while (gf_list_count(parser->deferred_listeners)) {
    2026           0 :                 GF_Node *l = (GF_Node *)gf_list_last(parser->deferred_listeners);
    2027           0 :                 gf_list_rem_last(parser->deferred_listeners);
    2028             :                 /*listeners not resolved are not inserted in the tree - destroy them*/
    2029           0 :                 gf_node_register(l, NULL);
    2030           0 :                 gf_node_unregister(l, NULL);
    2031             :         }
    2032         136 : }
    2033             : 
    2034          69 : static GF_Err gf_sm_load_initialize_svg(GF_SceneLoader *load, const char *str_data, Bool is_fragment)
    2035             : {
    2036             :         GF_Err e;
    2037             :         GF_SVG_Parser *parser;
    2038             : 
    2039          69 :         if (str_data) {
    2040             :                 char BOM[6];
    2041           1 :                 BOM[0] = str_data[0];
    2042           1 :                 BOM[1] = str_data[1];
    2043           1 :                 BOM[2] = str_data[2];
    2044           1 :                 BOM[3] = str_data[3];
    2045           1 :                 BOM[4] = BOM[5] = 0;
    2046           1 :                 parser = svg_new_parser(load);
    2047           1 :                 if (!parser) return GF_BAD_PARAM;
    2048             : 
    2049           1 :                 if (is_fragment) parser->has_root = 2;
    2050           1 :                 e = gf_xml_sax_init(parser->sax_parser, (unsigned char*)BOM);
    2051           1 :                 if (e) {
    2052           0 :                         svg_report(parser, e, "Error initializing SAX parser: %s", gf_xml_sax_get_error(parser->sax_parser) );
    2053           0 :                         return e;
    2054             :                 }
    2055           1 :                 str_data += 4;
    2056             : 
    2057          68 :         } else if (load->fileName) {
    2058          68 :                 parser = svg_new_parser(load);
    2059          68 :                 if (!parser) return GF_BAD_PARAM;
    2060             :         } else {
    2061             :                 return GF_BAD_PARAM;
    2062             :         }
    2063             : 
    2064             :         /*chunk parsing*/
    2065          69 :         if (load->flags & GF_SM_LOAD_CONTEXT_READY) {
    2066             :                 u32 i;
    2067             :                 GF_StreamContext *sc;
    2068           0 :                 if (!load->ctx) return GF_BAD_PARAM;
    2069             : 
    2070             :                 /*restore context - note that base layer are ALWAYS declared BEFORE enhancement layers with gpac parsers*/
    2071           0 :                 i=0;
    2072           0 :                 while ((sc = (GF_StreamContext*)gf_list_enum(load->ctx->streams, &i))) {
    2073           0 :                         switch (sc->streamType) {
    2074           0 :                         case GF_STREAM_SCENE:
    2075           0 :                                 if (!parser->laser_es) parser->laser_es = sc;
    2076             :                                 break;
    2077             :                         default:
    2078             :                                 break;
    2079             :                         }
    2080             :                 }
    2081             :                 /*need at least one scene stream - FIXME - accept SVG as root? */
    2082           0 :                 if (!parser->laser_es) return GF_BAD_PARAM;
    2083           0 :                 GF_LOG(GF_LOG_INFO, GF_LOG_PARSER, ("SVG: MPEG-4 LASeR / DIMS Scene Chunk Parsing"));
    2084             :         } else {
    2085          69 :                 GF_LOG(GF_LOG_INFO, GF_LOG_PARSER, ("[Parser] %s Scene Parsing: %s\n", ((load->type==GF_SM_LOAD_SVG) ? "SVG" : ((load->type==GF_SM_LOAD_XSR) ? "LASeR" : "DIMS")), load->fileName));
    2086             :         }
    2087             : 
    2088          69 :         if (str_data)
    2089           1 :                 return gf_xml_sax_parse(parser->sax_parser, str_data);
    2090             : 
    2091             :         return GF_OK;
    2092             : }
    2093             : 
    2094             : 
    2095          68 : GF_Err load_svg_run(GF_SceneLoader *load)
    2096             : {
    2097             :         u32 in_time;
    2098             :         GF_Err e;
    2099          68 :         GF_SVG_Parser *parser = (GF_SVG_Parser *)load->loader_priv;
    2100             : 
    2101          68 :         if (!parser) {
    2102          68 :                 e = gf_sm_load_initialize_svg(load, NULL, GF_FALSE);
    2103          68 :                 if (e) return e;
    2104          68 :                 parser = (GF_SVG_Parser *)load->loader_priv;
    2105             :         }
    2106             : 
    2107          68 :         in_time = gf_sys_clock();
    2108          68 :         e = gf_xml_sax_parse_file(parser->sax_parser, (const char *)load->fileName, svg_progress);
    2109          68 :         if (parser->last_error<0) e = parser->last_error;
    2110             :         
    2111          68 :         if (e<0) return svg_report(parser, e, "Unable to parse file %s: %s", load->fileName, gf_xml_sax_get_error(parser->sax_parser) );
    2112          67 :         GF_LOG(GF_LOG_INFO, GF_LOG_PARSER, ("[Parser] Scene parsed and Scene Graph built in %d ms\n", gf_sys_clock() - in_time));
    2113             : 
    2114          67 :         svg_flush_animations(parser);
    2115          67 :         gf_sm_svg_flush_state(parser);
    2116          67 :         return e;
    2117             : 
    2118             : }
    2119             : 
    2120         117 : static void load_svg_done(GF_SceneLoader *load)
    2121             : {
    2122             :         SVG_SAFExternalStream *st;
    2123         117 :         GF_SVG_Parser *parser = (GF_SVG_Parser *)load->loader_priv;
    2124         117 :         if (!parser) return;
    2125             : 
    2126          69 :         gf_sm_svg_flush_state(parser);
    2127             : 
    2128          69 :         gf_list_del(parser->node_stack);
    2129          69 :         gf_list_del(parser->deferred_hrefs);
    2130          69 :         gf_list_del(parser->deferred_listeners);
    2131          69 :         gf_list_del(parser->peeked_nodes);
    2132             :         /* reset animations */
    2133          69 :         gf_list_del(parser->deferred_animations);
    2134          69 :         if (parser->sax_parser) {
    2135          69 :                 gf_xml_sax_del(parser->sax_parser);
    2136             :         }
    2137          69 :         st = parser->streams;
    2138         140 :         while (st) {
    2139           2 :                 SVG_SAFExternalStream *next = st->next;
    2140           2 :                 gf_free(st->stream_name);
    2141           2 :                 gf_free(st);
    2142             :                 st = next;
    2143             :         }
    2144          69 :         gf_free(parser);
    2145          69 :         load->loader_priv = NULL;
    2146             : }
    2147             : 
    2148           1 : GF_Err load_svg_parse_string(GF_SceneLoader *load, const char *str)
    2149             : {
    2150             :         GF_Err e;
    2151           1 :         GF_SVG_Parser *parser = (GF_SVG_Parser *)load->loader_priv;
    2152             : 
    2153           1 :         if (!parser) {
    2154           1 :                 e = gf_sm_load_initialize_svg(load, str, GF_FALSE);
    2155           1 :                 parser = (GF_SVG_Parser *)load->loader_priv;
    2156             :         } else {
    2157           0 :                 e = gf_xml_sax_parse(parser->sax_parser, str);
    2158             :         }
    2159           1 :         if (e<0) svg_report(parser, e, "Unable to parse chunk: %s", parser ? gf_xml_sax_get_error(parser->sax_parser) : "no parser");
    2160           1 :         else e = parser->last_error;
    2161             :         
    2162             : 
    2163           1 :         svg_flush_animations(parser);
    2164             : 
    2165             :         /*if error move to done state and wait for next XML chunk*/
    2166           1 :         if (e) load_svg_done(load);
    2167             : 
    2168           1 :         return e;
    2169             : }
    2170             : 
    2171           0 : static GF_Err load_svg_suspend(GF_SceneLoader *load, Bool suspend)
    2172             : {
    2173           0 :         GF_SVG_Parser *parser = (GF_SVG_Parser *)load->loader_priv;
    2174           0 :         if (parser) gf_xml_sax_suspend(parser->sax_parser, suspend);
    2175           0 :         return GF_OK;
    2176             : }
    2177             : 
    2178             : 
    2179          69 : GF_Err gf_sm_load_init_svg(GF_SceneLoader *load)
    2180             : {
    2181          69 :         load->process = load_svg_run;
    2182          69 :         load->done = load_svg_done;
    2183          69 :         load->parse_string = load_svg_parse_string;
    2184          69 :         load->suspend = load_svg_suspend;
    2185             : 
    2186          69 :         return GF_OK;
    2187             : 
    2188             : }
    2189             : 
    2190           0 : GF_Node *gf_sm_load_svg_from_string(GF_SceneGraph *in_scene, char *node_str)
    2191             : {
    2192             :         GF_Err e;
    2193             :         GF_SVG_Parser *parser;
    2194             :         GF_Node *node;
    2195             :         GF_SceneLoader ctx;
    2196             :         memset(&ctx, 0, sizeof(GF_SceneLoader));
    2197           0 :         ctx.scene_graph = in_scene;
    2198           0 :         ctx.type = GF_SM_LOAD_SVG;
    2199             : 
    2200           0 :         e = gf_sm_load_initialize_svg(&ctx, node_str, GF_TRUE);
    2201             : 
    2202           0 :         parser = (GF_SVG_Parser *)ctx.loader_priv;
    2203             : 
    2204           0 :         if (e != GF_OK) {
    2205           0 :                 if (parser) {
    2206           0 :                         if (parser->fragment_root) gf_node_unregister(parser->fragment_root, NULL);
    2207           0 :                         parser->fragment_root=NULL;
    2208             :                 }
    2209           0 :                 load_svg_done(&ctx);
    2210           0 :                 return NULL;
    2211             :         }
    2212             : 
    2213           0 :         node = parser ? parser->fragment_root : NULL;
    2214             :         /*don't register*/
    2215           0 :         if (node) node->sgprivate->num_instances--;
    2216           0 :         load_svg_done(&ctx);
    2217           0 :         return node;
    2218             : }
    2219             : 
    2220             : #endif
    2221             : 

Generated by: LCOV version 1.13