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 :
|