1 /*
2  *			GPAC - Multimedia Framework C SDK
3  *
4  *			Authors: Jean Le Feuvre - Cyril Concolato
5  *			Copyright (c) Telecom ParisTech 2000-2020
6  *					All rights reserved
7  *
8  *  This file is part of GPAC / SVG Scene Graph sub-project
9  *
10  *  GPAC is free software, TYPE, 0 }, 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, TYPE, 0 }, 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, TYPE, 0 }, 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, TYPE, 0 }, see the file COPYING.  If not, write to
22  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23  *
24  */
25 
26 
27 #include <gpac/internal/scenegraph_dev.h>
28 
29 #ifndef GPAC_DISABLE_SVG
30 
31 #include <gpac/nodes_svg.h>
32 
33 enum
34 {
35 	/*no specific criteria*/
36 	GF_SVG_ATTOPT_NONE = 0,
37 	/*attribute only valid for SMIL anims*/
38 	GF_SVG_ATTOPT_SMIL = 1,
39 	/*attribute only valid for TEXT*/
40 	GF_SVG_ATTOPT_TEXT = 2,
41 	/*attribute only valid for cursor*/
42 	GF_SVG_ATTOPT_CURSOR = 3,
43 	/*attribute only valid for listener*/
44 	GF_SVG_ATTOPT_LISTENER = 4,
45 	/*attribute only valid for filters*/
46 	GF_SVG_ATTOPT_FILTER = 5,
47 } GF_SVGAttOption;
48 
49 /* unused XBL tags (deprecated)
50 
51 	TAG_XBL_ATT_RANGE_FIRST = TAG_SVG_ATT_RANGE_FIRST + 256,
52 	TAG_XBL_ATT_id = TAG_XBL_ATT_RANGE_FIRST,
53 	TAG_XBL_ATT_extends,
54 	TAG_XBL_ATT_display,
55 	TAG_XBL_ATT_inheritstyle,
56 	TAG_XBL_ATT_includes,
57 	TAG_XBL_ATT_name,
58 	TAG_XBL_ATT_implements,
59 	TAG_XBL_ATT_type,
60 	TAG_XBL_ATT_readonly,
61 	TAG_XBL_ATT_onget,
62 	TAG_XBL_ATT_onset,
63 	TAG_XBL_ATT_event,
64 	TAG_XBL_ATT_action,
65 	TAG_XBL_ATT_phase,
66 	TAG_XBL_ATT_button,
67 	TAG_XBL_ATT_modifiers,
68 	TAG_XBL_ATT_keycode,
69 	TAG_XBL_ATT_key,
70 	TAG_XBL_ATT_charcode,
71 	TAG_XBL_ATT_clickcount,
72 	TAG_XBL_ATT_command,
73 	TAG_XBL_ATT_preventdefault,
74 	TAG_XBL_ATT_src,
75 */
76 static const struct xml_att_def {
77 	const char *name;
78 	u32 tag;
79 	u32 type;
80 	u32 opts;
81 	u32 xmlns;
82 } xml_attributes [] =
83 {
84 	/*XML base*/
85 	{ "id", TAG_XML_ATT_id, SVG_ID_datatype, 0, GF_XMLNS_XML } ,
86 	{ "base", TAG_XML_ATT_base, XMLRI_datatype, 0, GF_XMLNS_XML } ,
87 	{ "lang", TAG_XML_ATT_lang, SVG_LanguageID_datatype, 0, GF_XMLNS_XML } ,
88 	{ "space", TAG_XML_ATT_space, XML_Space_datatype, 0, GF_XMLNS_XML } ,
89 
90 	/*XLINK*/
91 	{ "type", TAG_XLINK_ATT_type, DOM_String_datatype, 0, GF_XMLNS_XLINK },
92 	{ "role", TAG_XLINK_ATT_role, XMLRI_datatype, 0, GF_XMLNS_XLINK },
93 	{ "arcrole", TAG_XLINK_ATT_arcrole, XMLRI_datatype, 0, GF_XMLNS_XLINK },
94 	{ "title", TAG_XLINK_ATT_title, DOM_String_datatype, 0, GF_XMLNS_XLINK },
95 	{ "href", TAG_XLINK_ATT_href, XMLRI_datatype, 0, GF_XMLNS_XLINK },
96 	{ "show", TAG_XLINK_ATT_show, DOM_String_datatype, 0, GF_XMLNS_XLINK },
97 	{ "actuate", TAG_XLINK_ATT_actuate, DOM_String_datatype, 0, GF_XMLNS_XLINK },
98 
99 	/*XML Events*/
100 	{ "event", TAG_XMLEV_ATT_event, XMLEV_Event_datatype, 0, GF_XMLNS_XMLEV },
101 	{ "phase", TAG_XMLEV_ATT_phase, XMLEV_Phase_datatype, 0, GF_XMLNS_XMLEV },
102 	{ "propagate", TAG_XMLEV_ATT_propagate, XMLEV_Propagate_datatype, 0, GF_XMLNS_XMLEV },
103 	{ "defaultAction", TAG_XMLEV_ATT_defaultAction, XMLEV_DefaultAction_datatype, 0, GF_XMLNS_XMLEV },
104 	{ "observer", TAG_XMLEV_ATT_observer, XML_IDREF_datatype, 0, GF_XMLNS_XMLEV },
105 	{ "target", TAG_XMLEV_ATT_target, XML_IDREF_datatype, 0, GF_XMLNS_XMLEV },
106 	{ "handler", TAG_XMLEV_ATT_handler, XMLRI_datatype, 0, GF_XMLNS_XMLEV },
107 
108 
109 	{ "id", TAG_SVG_ATT_id, SVG_ID_datatype, 0, GF_XMLNS_SVG } ,
110 	{ "class", TAG_SVG_ATT__class, DOM_String_datatype, 0, GF_XMLNS_SVG },
111 	{ "requiredFeatures", TAG_SVG_ATT_requiredFeatures, XMLRI_List_datatype, 0, GF_XMLNS_SVG },
112 	{ "requiredExtensions", TAG_SVG_ATT_requiredExtensions, XMLRI_List_datatype, 0, GF_XMLNS_SVG },
113 	{ "requiredFormats", TAG_SVG_ATT_requiredFormats, DOM_StringList_datatype, 0, GF_XMLNS_SVG },
114 	{ "requiredFonts", TAG_SVG_ATT_requiredFonts, DOM_StringList_datatype, 0, GF_XMLNS_SVG },
115 	{ "systemLanguage", TAG_SVG_ATT_systemLanguage, DOM_StringList_datatype, 0, GF_XMLNS_SVG },
116 	{ "display", TAG_SVG_ATT_display, SVG_Display_datatype, 0, GF_XMLNS_SVG },
117 	{ "visibility", TAG_SVG_ATT_visibility, SVG_Visibility_datatype, 0, GF_XMLNS_SVG },
118 	{ "image-rendering", TAG_SVG_ATT_image_rendering, SVG_RenderingHint_datatype, 0, GF_XMLNS_SVG },
119 	{ "pointer-events", TAG_SVG_ATT_pointer_events, SVG_PointerEvents_datatype, 0, GF_XMLNS_SVG },
120 	{ "shape-rendering", TAG_SVG_ATT_shape_rendering, SVG_RenderingHint_datatype, 0, GF_XMLNS_SVG },
121 	{ "text-rendering", TAG_SVG_ATT_text_rendering, SVG_RenderingHint_datatype, 0, GF_XMLNS_SVG },
122 	{ "audio-level", TAG_SVG_ATT_audio_level, SVG_Number_datatype, 0, GF_XMLNS_SVG },
123 	{ "viewport-fill", TAG_SVG_ATT_viewport_fill, SVG_Paint_datatype, 0, GF_XMLNS_SVG },
124 	{ "viewport-fill-opacity", TAG_SVG_ATT_viewport_fill_opacity, SVG_Number_datatype, 0, GF_XMLNS_SVG },
125 	{ "overflow", TAG_SVG_ATT_overflow, DOM_String_datatype, 0, GF_XMLNS_SVG },
126 	{ "fill-opacity", TAG_SVG_ATT_fill_opacity, SVG_Number_datatype, 0, GF_XMLNS_SVG },
127 	{ "stroke-opacity", TAG_SVG_ATT_stroke_opacity, SVG_Number_datatype, 0, GF_XMLNS_SVG },
128 	{ "fill-rule", TAG_SVG_ATT_fill_rule, SVG_FillRule_datatype, 0, GF_XMLNS_SVG },
129 	{ "stroke", TAG_SVG_ATT_stroke, SVG_Paint_datatype, 0, GF_XMLNS_SVG },
130 	{ "stroke-dasharray", TAG_SVG_ATT_stroke_dasharray, SVG_StrokeDashArray_datatype, 0, GF_XMLNS_SVG },
131 	{ "stroke-dashoffset", TAG_SVG_ATT_stroke_dashoffset, SVG_Length_datatype, 0, GF_XMLNS_SVG },
132 	{ "stroke-linecap", TAG_SVG_ATT_stroke_linecap, SVG_StrokeLineCap_datatype, 0, GF_XMLNS_SVG },
133 	{ "stroke-linejoin", TAG_SVG_ATT_stroke_linejoin, SVG_StrokeLineJoin_datatype, 0, GF_XMLNS_SVG },
134 	{ "stroke-miterlimit", TAG_SVG_ATT_stroke_miterlimit, SVG_Number_datatype, 0, GF_XMLNS_SVG },
135 	{ "stroke-width", TAG_SVG_ATT_stroke_width, SVG_Length_datatype, 0, GF_XMLNS_SVG },
136 	{ "color", TAG_SVG_ATT_color, SVG_Paint_datatype, 0, GF_XMLNS_SVG },
137 	{ "color-rendering", TAG_SVG_ATT_color_rendering, SVG_RenderingHint_datatype, 0, GF_XMLNS_SVG },
138 	{ "vector-effect", TAG_SVG_ATT_vector_effect, SVG_VectorEffect_datatype, 0, GF_XMLNS_SVG },
139 	{ "solid-color", TAG_SVG_ATT_solid_color, SVG_Paint_datatype, 0, GF_XMLNS_SVG },
140 	{ "solid-opacity", TAG_SVG_ATT_solid_opacity, SVG_Number_datatype, 0, GF_XMLNS_SVG },
141 	{ "display-align", TAG_SVG_ATT_display_align, SVG_DisplayAlign_datatype, 0, GF_XMLNS_SVG },
142 	{ "line-increment", TAG_SVG_ATT_line_increment, SVG_Number_datatype, 0, GF_XMLNS_SVG },
143 	{ "stop-color", TAG_SVG_ATT_stop_color, SVG_Paint_datatype, 0, GF_XMLNS_SVG },
144 	{ "stop-opacity", TAG_SVG_ATT_stop_opacity, SVG_Number_datatype, 0, GF_XMLNS_SVG },
145 	{ "font-family", TAG_SVG_ATT_font_family, SVG_FontFamily_datatype, 0, GF_XMLNS_SVG },
146 	{ "font-size", TAG_SVG_ATT_font_size, SVG_FontSize_datatype, 0, GF_XMLNS_SVG },
147 	{ "font-style", TAG_SVG_ATT_font_style, SVG_FontStyle_datatype, 0, GF_XMLNS_SVG },
148 	{ "font-variant", TAG_SVG_ATT_font_variant, SVG_FontVariant_datatype, 0, GF_XMLNS_SVG },
149 	{ "font-weight", TAG_SVG_ATT_font_weight, SVG_FontWeight_datatype, 0, GF_XMLNS_SVG },
150 	{ "text-anchor", TAG_SVG_ATT_text_anchor, SVG_TextAnchor_datatype, 0, GF_XMLNS_SVG },
151 	{ "text-align", TAG_SVG_ATT_text_align, SVG_TextAlign_datatype, 0, GF_XMLNS_SVG },
152 	{ "text-decoration", TAG_SVG_ATT_text_decoration, DOM_String_datatype, 0, GF_XMLNS_SVG },
153 	{ "focusHighlight", TAG_SVG_ATT_focusHighlight, SVG_FocusHighlight_datatype, 0, GF_XMLNS_SVG },
154 	{ "externalResourcesRequired", TAG_SVG_ATT_externalResourcesRequired, SVG_Boolean_datatype, 0, GF_XMLNS_SVG },
155 	{ "focusable", TAG_SVG_ATT_focusable, SVG_Focusable_datatype, 0, GF_XMLNS_SVG },
156 	{ "nav-next", TAG_SVG_ATT_nav_next, SVG_Focus_datatype, 0, GF_XMLNS_SVG },
157 	{ "nav-prev", TAG_SVG_ATT_nav_prev, SVG_Focus_datatype, 0, GF_XMLNS_SVG },
158 	{ "nav-up", TAG_SVG_ATT_nav_up, SVG_Focus_datatype, 0, GF_XMLNS_SVG },
159 	{ "nav-up-right", TAG_SVG_ATT_nav_up_right, SVG_Focus_datatype, 0, GF_XMLNS_SVG },
160 	{ "nav-right", TAG_SVG_ATT_nav_right, SVG_Focus_datatype, 0, GF_XMLNS_SVG },
161 	{ "nav-down-right", TAG_SVG_ATT_nav_down_right, SVG_Focus_datatype, 0, GF_XMLNS_SVG },
162 	{ "nav-down", TAG_SVG_ATT_nav_down, SVG_Focus_datatype, 0, GF_XMLNS_SVG },
163 	{ "nav-down-left", TAG_SVG_ATT_nav_down_left, SVG_Focus_datatype, 0, GF_XMLNS_SVG },
164 	{ "nav-left", TAG_SVG_ATT_nav_left, SVG_Focus_datatype, 0, GF_XMLNS_SVG },
165 	{ "nav-up-left", TAG_SVG_ATT_nav_up_left, SVG_Focus_datatype, 0, GF_XMLNS_SVG },
166 	{ "transform", TAG_SVG_ATT_transform, SVG_Transform_datatype, 0, GF_XMLNS_SVG },
167 	{ "target", TAG_SVG_ATT_target, DOM_String_datatype, 0, GF_XMLNS_SVG },
168 	{ "attributeName", TAG_SVG_ATT_attributeName, SMIL_AttributeName_datatype, 0, GF_XMLNS_SVG },
169 	{ "attributeType", TAG_SVG_ATT_attributeType, SMIL_AttributeType_datatype, 0, GF_XMLNS_SVG },
170 	{ "begin", TAG_SVG_ATT_begin, SMIL_Times_datatype, 0, GF_XMLNS_SVG },
171 	{ "dur", TAG_SVG_ATT_dur, SMIL_Duration_datatype, 0, GF_XMLNS_SVG },
172 	{ "end", TAG_SVG_ATT_end, SMIL_Times_datatype, 0, GF_XMLNS_SVG },
173 	{ "repeatCount", TAG_SVG_ATT_repeatCount, SMIL_RepeatCount_datatype, 0, GF_XMLNS_SVG },
174 	{ "repeatDur", TAG_SVG_ATT_repeatDur, SMIL_Duration_datatype, 0, GF_XMLNS_SVG },
175 	{ "restart", TAG_SVG_ATT_restart, SMIL_Restart_datatype, 0, GF_XMLNS_SVG },
176 	{ "min", TAG_SVG_ATT_min, SMIL_Duration_datatype, 0, GF_XMLNS_SVG },
177 	{ "max", TAG_SVG_ATT_max, SMIL_Duration_datatype, 0, GF_XMLNS_SVG },
178 	{ "to", TAG_SVG_ATT_to, SMIL_AnimateValue_datatype, 0, GF_XMLNS_SVG },
179 	{ "calcMode", TAG_SVG_ATT_calcMode, SMIL_CalcMode_datatype, 0, GF_XMLNS_SVG },
180 	{ "values", TAG_SVG_ATT_values, SMIL_AnimateValues_datatype, 0, GF_XMLNS_SVG },
181 	{ "keyTimes", TAG_SVG_ATT_keyTimes, SMIL_KeyTimes_datatype, 0, GF_XMLNS_SVG },
182 	{ "keySplines", TAG_SVG_ATT_keySplines, SMIL_KeySplines_datatype, 0, GF_XMLNS_SVG },
183 	{ "from", TAG_SVG_ATT_from, SMIL_AnimateValue_datatype, 0, GF_XMLNS_SVG },
184 	{ "by", TAG_SVG_ATT_by, SMIL_AnimateValue_datatype, 0, GF_XMLNS_SVG },
185 	{ "additive", TAG_SVG_ATT_additive, SMIL_Additive_datatype, 0, GF_XMLNS_SVG },
186 	{ "accumulate", TAG_SVG_ATT_accumulate, SMIL_Accumulate_datatype, 0, GF_XMLNS_SVG },
187 	{ "path", TAG_SVG_ATT_path, SVG_PathData_datatype, 0, GF_XMLNS_SVG },
188 	{ "keyPoints", TAG_SVG_ATT_keyPoints, SMIL_KeyPoints_datatype, 0, GF_XMLNS_SVG },
189 	{ "origin", TAG_SVG_ATT_origin, DOM_String_datatype, 0, GF_XMLNS_SVG },
190 	{ "clipBegin", TAG_SVG_ATT_clipBegin, SVG_Clock_datatype, 0, GF_XMLNS_SVG },
191 	{ "clipEnd", TAG_SVG_ATT_clipEnd, SVG_Clock_datatype, 0, GF_XMLNS_SVG },
192 	{ "syncBehavior", TAG_SVG_ATT_syncBehavior, SMIL_SyncBehavior_datatype, 0, GF_XMLNS_SVG },
193 	{ "syncTolerance", TAG_SVG_ATT_syncTolerance, SMIL_SyncTolerance_datatype, 0, GF_XMLNS_SVG },
194 	{ "syncMaster", TAG_SVG_ATT_syncMaster, SVG_Boolean_datatype, 0, GF_XMLNS_SVG },
195 	{ "syncReference", TAG_SVG_ATT_syncReference, XMLRI_datatype, 0, GF_XMLNS_SVG },
196 	{ "width", TAG_SVG_ATT_width, SVG_Length_datatype, 0, GF_XMLNS_SVG },
197 	{ "height", TAG_SVG_ATT_height, SVG_Length_datatype, 0, GF_XMLNS_SVG },
198 	{ "preserveAspectRatio", TAG_SVG_ATT_preserveAspectRatio, SVG_PreserveAspectRatio_datatype, 0, GF_XMLNS_SVG },
199 	{ "initialVisibility", TAG_SVG_ATT_initialVisibility, SVG_InitialVisibility_datatype, 0, GF_XMLNS_SVG },
200 	{ "cx", TAG_SVG_ATT_cx, SVG_Coordinate_datatype, 0, GF_XMLNS_SVG },
201 	{ "cy", TAG_SVG_ATT_cy, SVG_Coordinate_datatype, 0, GF_XMLNS_SVG },
202 	{ "r", TAG_SVG_ATT_r, SVG_Length_datatype, 0, GF_XMLNS_SVG },
203 	{ "rx", TAG_SVG_ATT_rx, SVG_Length_datatype, 0, GF_XMLNS_SVG },
204 	{ "ry", TAG_SVG_ATT_ry, SVG_Length_datatype, 0, GF_XMLNS_SVG },
205 	{ "horiz-adv-x", TAG_SVG_ATT_horiz_adv_x, SVG_Number_datatype, 0, GF_XMLNS_SVG },
206 	{ "horiz-origin-x", TAG_SVG_ATT_horiz_origin_x, SVG_Number_datatype, 0, GF_XMLNS_SVG },
207 	{ "font-stretch", TAG_SVG_ATT_font_stretch, DOM_String_datatype, 0, GF_XMLNS_SVG },
208 	{ "unicode-range", TAG_SVG_ATT_unicode_range, DOM_String_datatype, 0, GF_XMLNS_SVG },
209 	{ "panose-1", TAG_SVG_ATT_panose_1, DOM_String_datatype, 0, GF_XMLNS_SVG },
210 	{ "widths", TAG_SVG_ATT_widths, DOM_String_datatype, 0, GF_XMLNS_SVG },
211 	{ "bbox", TAG_SVG_ATT_bbox, DOM_String_datatype, 0, GF_XMLNS_SVG },
212 	{ "units-per-em", TAG_SVG_ATT_units_per_em, SVG_Number_datatype, 0, GF_XMLNS_SVG },
213 	{ "stemv", TAG_SVG_ATT_stemv, SVG_Number_datatype, 0, GF_XMLNS_SVG },
214 	{ "stemh", TAG_SVG_ATT_stemh, SVG_Number_datatype, 0, GF_XMLNS_SVG },
215 	{ "slope", TAG_SVG_ATT_slope, SVG_Number_datatype, 0, GF_XMLNS_SVG },
216 	{ "cap-height", TAG_SVG_ATT_cap_height, SVG_Number_datatype, 0, GF_XMLNS_SVG },
217 	{ "x-height", TAG_SVG_ATT_x_height, SVG_Number_datatype, 0, GF_XMLNS_SVG },
218 	{ "accent-height", TAG_SVG_ATT_accent_height, SVG_Number_datatype, 0, GF_XMLNS_SVG },
219 	{ "ascent", TAG_SVG_ATT_ascent, SVG_Number_datatype, 0, GF_XMLNS_SVG },
220 	{ "descent", TAG_SVG_ATT_descent, SVG_Number_datatype, 0, GF_XMLNS_SVG },
221 	{ "ideographic", TAG_SVG_ATT_ideographic, SVG_Number_datatype, 0, GF_XMLNS_SVG },
222 	{ "alphabetic", TAG_SVG_ATT_alphabetic, SVG_Number_datatype, 0, GF_XMLNS_SVG },
223 	{ "mathematical", TAG_SVG_ATT_mathematical, SVG_Number_datatype, 0, GF_XMLNS_SVG },
224 	{ "hanging", TAG_SVG_ATT_hanging, SVG_Number_datatype, 0, GF_XMLNS_SVG },
225 	{ "underline-position", TAG_SVG_ATT_underline_position, SVG_Number_datatype, 0, GF_XMLNS_SVG },
226 	{ "underline-thickness", TAG_SVG_ATT_underline_thickness, SVG_Number_datatype, 0, GF_XMLNS_SVG },
227 	{ "strikethrough-position", TAG_SVG_ATT_strikethrough_position, SVG_Number_datatype, 0, GF_XMLNS_SVG },
228 	{ "strikethrough-thickness", TAG_SVG_ATT_strikethrough_thickness, SVG_Number_datatype, 0, GF_XMLNS_SVG },
229 	{ "overline-position", TAG_SVG_ATT_overline_position, SVG_Number_datatype, 0, GF_XMLNS_SVG },
230 	{ "overline-thickness", TAG_SVG_ATT_overline_thickness, SVG_Number_datatype, 0, GF_XMLNS_SVG },
231 	{ "d", TAG_SVG_ATT_d, SVG_PathData_datatype, 0, GF_XMLNS_SVG },
232 	{ "unicode", TAG_SVG_ATT_unicode, DOM_String_datatype, 0, GF_XMLNS_SVG },
233 	{ "glyph-name", TAG_SVG_ATT_glyph_name, DOM_String_datatype, 0, GF_XMLNS_SVG },
234 	{ "arabic-form", TAG_SVG_ATT_arabic_form, DOM_String_datatype, 0, GF_XMLNS_SVG },
235 	{ "lang", TAG_SVG_ATT_lang, DOM_StringList_datatype, 0, GF_XMLNS_SVG },
236 	{ "u1", TAG_SVG_ATT_u1, DOM_String_datatype, 0, GF_XMLNS_SVG },
237 	{ "g1", TAG_SVG_ATT_g1, DOM_String_datatype, 0, GF_XMLNS_SVG },
238 	{ "u2", TAG_SVG_ATT_u2, DOM_String_datatype, 0, GF_XMLNS_SVG },
239 	{ "g2", TAG_SVG_ATT_g2, DOM_String_datatype, 0, GF_XMLNS_SVG },
240 	{ "k", TAG_SVG_ATT_k, SVG_Number_datatype, 0, GF_XMLNS_SVG },
241 	{ "opacity", TAG_SVG_ATT_opacity, SVG_Number_datatype, 0, GF_XMLNS_SVG },
242 	{ "x1", TAG_SVG_ATT_x1, SVG_Coordinate_datatype, 0, GF_XMLNS_SVG },
243 	{ "y1", TAG_SVG_ATT_y1, SVG_Coordinate_datatype, 0, GF_XMLNS_SVG },
244 	{ "x2", TAG_SVG_ATT_x2, SVG_Coordinate_datatype, 0, GF_XMLNS_SVG },
245 	{ "y2", TAG_SVG_ATT_y2, SVG_Coordinate_datatype, 0, GF_XMLNS_SVG },
246 	{ "gradientUnits", TAG_SVG_ATT_gradientUnits, SVG_GradientUnit_datatype, 0, GF_XMLNS_SVG },
247 	{ "filterUnits", TAG_SVG_ATT_filterUnits, SVG_GradientUnit_datatype, 0, GF_XMLNS_SVG },
248 	{ "spreadMethod", TAG_SVG_ATT_spreadMethod, SVG_SpreadMethod_datatype, 0, GF_XMLNS_SVG },
249 	{ "gradientTransform", TAG_SVG_ATT_gradientTransform, SVG_Transform_datatype, 0, GF_XMLNS_SVG },
250 	{ "pathLength", TAG_SVG_ATT_pathLength, SVG_Number_datatype, 0, GF_XMLNS_SVG },
251 	{ "points", TAG_SVG_ATT_points, SVG_Points_datatype, 0, GF_XMLNS_SVG },
252 	{ "mediaSize", TAG_SVG_ATT_mediaSize, SVG_Number_datatype, 0, GF_XMLNS_SVG },
253 	{ "mediaTime", TAG_SVG_ATT_mediaTime, DOM_String_datatype, 0, GF_XMLNS_SVG },
254 	{ "mediaCharacterEncoding", TAG_SVG_ATT_mediaCharacterEncoding, DOM_String_datatype, 0, GF_XMLNS_SVG },
255 	{ "mediaContentEncodings", TAG_SVG_ATT_mediaContentEncodings, DOM_String_datatype, 0, GF_XMLNS_SVG },
256 	{ "bandwidth", TAG_SVG_ATT_bandwidth, SVG_Number_datatype, 0, GF_XMLNS_SVG },
257 	{ "fx", TAG_SVG_ATT_fx, SVG_Coordinate_datatype, 0, GF_XMLNS_SVG },
258 	{ "fy", TAG_SVG_ATT_fy, SVG_Coordinate_datatype, 0, GF_XMLNS_SVG },
259 	{ "size", TAG_SVG_ATT_size, LASeR_Size_datatype, 0, GF_XMLNS_SVG },
260 	{ "choice", TAG_SVG_ATT_choice, LASeR_Choice_datatype, 0, GF_XMLNS_LASER },
261 	{ "delta", TAG_SVG_ATT_delta, LASeR_Size_datatype, 0, GF_XMLNS_LASER },
262 	{ "offset", TAG_SVG_ATT_offset, SVG_Number_datatype, 0, GF_XMLNS_SVG },
263 	{ "syncBehaviorDefault", TAG_SVG_ATT_syncBehaviorDefault, SMIL_SyncBehavior_datatype, 0, GF_XMLNS_SVG },
264 	{ "syncToleranceDefault", TAG_SVG_ATT_syncToleranceDefault, SMIL_SyncTolerance_datatype, 0, GF_XMLNS_SVG },
265 	{ "viewBox", TAG_SVG_ATT_viewBox, SVG_ViewBox_datatype, 0, GF_XMLNS_SVG },
266 	{ "zoomAndPan", TAG_SVG_ATT_zoomAndPan, SVG_ZoomAndPan_datatype, 0, GF_XMLNS_SVG },
267 	{ "version", TAG_SVG_ATT_version, DOM_String_datatype, 0, GF_XMLNS_SVG },
268 	{ "baseProfile", TAG_SVG_ATT_baseProfile, DOM_String_datatype, 0, GF_XMLNS_SVG },
269 	{ "snapshotTime", TAG_SVG_ATT_snapshotTime, SVG_Clock_datatype, 0, GF_XMLNS_SVG },
270 	{ "timelineBegin", TAG_SVG_ATT_timelineBegin, SVG_TimelineBegin_datatype, 0, GF_XMLNS_SVG },
271 	{ "playbackOrder", TAG_SVG_ATT_playbackOrder, SVG_PlaybackOrder_datatype, 0, GF_XMLNS_SVG },
272 	{ "editable", TAG_SVG_ATT_editable, SVG_Boolean_datatype, 0, GF_XMLNS_SVG },
273 	{ "transformBehavior", TAG_SVG_ATT_transformBehavior, SVG_TransformBehavior_datatype, 0, GF_XMLNS_SVG },
274 	{ "overlay", TAG_SVG_ATT_overlay, SVG_Overlay_datatype, 0, GF_XMLNS_SVG },
275 	{ "fullscreen", TAG_SVG_ATT_fullscreen, SVG_Boolean_datatype, 0, GF_XMLNS_SVG },
276 	{ "motionTransform", TAG_SVG_ATT_motionTransform, SVG_Motion_datatype, 0, GF_XMLNS_SVG },
277 	/*SMIL anim fill*/
278 	{ "fill", TAG_SVG_ATT_smil_fill, SMIL_Fill_datatype, GF_SVG_ATTOPT_SMIL, GF_XMLNS_SVG },
279 	/*regular paint fill*/
280 	{ "fill", TAG_SVG_ATT_fill, SVG_Paint_datatype, 0, GF_XMLNS_SVG },
281 	/*filter*/
282 	{ "filter", TAG_SVG_ATT_filter, SVG_Paint_datatype, 0, GF_XMLNS_SVG },
283 	/*text rotate*/
284 	{ "rotate", TAG_SVG_ATT_text_rotate, SVG_Numbers_datatype, GF_SVG_ATTOPT_TEXT, GF_XMLNS_SVG },
285 	/*regular matrix rotate*/
286 	{ "rotate", TAG_SVG_ATT_rotate, SVG_Rotate_datatype, 0, GF_XMLNS_SVG },
287 	/*SMIL anim type*/
288 	{ "type", TAG_SVG_ATT_transform_type, SVG_TransformType_datatype, GF_SVG_ATTOPT_SMIL, GF_XMLNS_SVG },
289 	/*Filter componentTransfer type*/
290 	{ "type", TAG_SVG_ATT_filter_transfer_type, SVG_Filter_TransferType_datatype, GF_SVG_ATTOPT_FILTER, GF_XMLNS_SVG },
291 	/*regular content type*/
292 	{ "type", TAG_SVG_ATT_type, SVG_ContentType_datatype, 0, GF_XMLNS_SVG },
293 	/*text x*/
294 	{ "x", TAG_SVG_ATT_text_x, SVG_Coordinates_datatype, GF_SVG_ATTOPT_TEXT, GF_XMLNS_SVG },
295 	/*regular x position*/
296 	{ "x", TAG_SVG_ATT_x, SVG_Coordinate_datatype, 0, GF_XMLNS_SVG },
297 	/*text y*/
298 	{ "y", TAG_SVG_ATT_text_y, SVG_Coordinates_datatype, GF_SVG_ATTOPT_TEXT, GF_XMLNS_SVG },
299 	/*regular y position*/
300 	{ "y", TAG_SVG_ATT_y, SVG_Coordinate_datatype, 0, GF_XMLNS_SVG },
301 
302 	/*filters*/
303 	{ "tableValues", TAG_SVG_ATT_filter_table_values, SVG_Numbers_datatype, 0, GF_XMLNS_SVG },
304 	{ "intercept", TAG_SVG_ATT_filter_intercept, SVG_Number_datatype, 0, GF_XMLNS_SVG },
305 	{ "amplitude", TAG_SVG_ATT_filter_amplitude, SVG_Number_datatype, 0, GF_XMLNS_SVG },
306 	{ "exponent", TAG_SVG_ATT_filter_exponent, SVG_Number_datatype, 0, GF_XMLNS_SVG },
307 
308 	/*LASeR*/
309 	{ "enabled", TAG_LSR_ATT_enabled, SVG_Boolean_datatype, 0, GF_XMLNS_LASER },
310 	/*cursor x*/
311 	{ "x", TAG_SVG_ATT_cursorManager_x, SVG_Length_datatype, GF_SVG_ATTOPT_CURSOR, GF_XMLNS_LASER },
312 	/*cursor y*/
313 	{ "y", TAG_SVG_ATT_cursorManager_y, SVG_Length_datatype, GF_SVG_ATTOPT_CURSOR, GF_XMLNS_LASER },
314 
315 	/*XBL*/
316 #if 0
317 	{ "id", TAG_XBL_ATT_id, DOM_String_datatype, 0, GF_XMLNS_XBL },
318 	{ "extends", TAG_XBL_ATT_extends, DOM_String_datatype, 0, GF_XMLNS_XBL },
319 	{ "display", TAG_XBL_ATT_display, DOM_String_datatype, 0, GF_XMLNS_XBL },
320 	{ "inheritstyle", TAG_XBL_ATT_inheritstyle, DOM_String_datatype, 0, GF_XMLNS_XBL },
321 	{ "includes", TAG_XBL_ATT_includes, DOM_String_datatype, 0, GF_XMLNS_XBL },
322 	{ "name", TAG_XBL_ATT_name, DOM_String_datatype, 0, GF_XMLNS_XBL },
323 	{ "implements", TAG_XBL_ATT_implements, DOM_String_datatype, 0, GF_XMLNS_XBL },
324 	{ "type", TAG_XBL_ATT_type, DOM_String_datatype, 0, GF_XMLNS_XBL },
325 	{ "readonly", TAG_XBL_ATT_readonly, DOM_String_datatype, 0, GF_XMLNS_XBL },
326 	{ "onget", TAG_XBL_ATT_onget, DOM_String_datatype, 0, GF_XMLNS_XBL },
327 	{ "onset", TAG_XBL_ATT_onset, DOM_String_datatype, 0, GF_XMLNS_XBL },
328 	{ "event", TAG_XBL_ATT_event, DOM_String_datatype, 0, GF_XMLNS_XBL },
329 	{ "action", TAG_XBL_ATT_action, DOM_String_datatype, 0, GF_XMLNS_XBL },
330 	{ "phase", TAG_XBL_ATT_phase, DOM_String_datatype, 0, GF_XMLNS_XBL },
331 	{ "button", TAG_XBL_ATT_button, DOM_String_datatype, 0, GF_XMLNS_XBL },
332 	{ "modifiers", TAG_XBL_ATT_modifiers, DOM_String_datatype, 0, GF_XMLNS_XBL },
333 	{ "keycode", TAG_XBL_ATT_keycode, DOM_String_datatype, 0, GF_XMLNS_XBL },
334 	{ "key", TAG_XBL_ATT_key, DOM_String_datatype, 0, GF_XMLNS_XBL },
335 	{ "charcode", TAG_XBL_ATT_charcode, DOM_String_datatype, 0, GF_XMLNS_XBL },
336 	{ "clickcount", TAG_XBL_ATT_clickcount, DOM_String_datatype, 0, GF_XMLNS_XBL },
337 	{ "command", TAG_XBL_ATT_command, DOM_String_datatype, 0, GF_XMLNS_XBL },
338 	{ "preventdefault", TAG_XBL_ATT_preventdefault, DOM_String_datatype, 0, GF_XMLNS_XBL },
339 	{ "src", TAG_XBL_ATT_src, DOM_String_datatype, 0, GF_XMLNS_XBL },
340 #endif
341 	/*GPAC SVG Extensions*/
342 	{ "use-as-primary", TAG_GSVG_ATT_useAsPrimary, SVG_Boolean_datatype, 0, GF_XMLNS_SVG_GPAC_EXTENSION},
343 	{ "depthOffset", TAG_GSVG_ATT_depthOffset, SVG_Number_datatype, 0, GF_XMLNS_SVG_GPAC_EXTENSION},
344 	{ "depthGain", TAG_GSVG_ATT_depthGain, SVG_Number_datatype, 0, GF_XMLNS_SVG_GPAC_EXTENSION},
345 
346 };
347 
gf_xml_push_namespaces(GF_DOMNode * elt)348 void gf_xml_push_namespaces(GF_DOMNode *elt)
349 {
350 	GF_DOMAttribute *att = elt->attributes;
351 	while (att) {
352 		if (att->tag==TAG_DOM_ATT_any) {
353 			GF_DOMFullAttribute *datt = (GF_DOMFullAttribute*)att;
354 			if (datt->name && !strncmp(datt->name, "xmlns", 5)) {
355 				char *qname = datt->name+5;
356 				gf_sg_add_namespace(elt->sgprivate->scenegraph, *(DOM_String *) datt->data, qname[0] ? qname+1 : NULL);
357 			}
358 		}
359 		att = att->next;
360 	}
361 }
362 
gf_xml_pop_namespaces(GF_DOMNode * elt)363 void gf_xml_pop_namespaces(GF_DOMNode *elt)
364 {
365 	GF_DOMAttribute *att = elt->attributes;
366 	while (att) {
367 		if (att->tag==TAG_DOM_ATT_any) {
368 			GF_DOMFullAttribute *datt = (GF_DOMFullAttribute*)att;
369 			if (datt->name && !strncmp(datt->name, "xmlns", 5)) {
370 				char *qname = datt->name+5;
371 				gf_sg_remove_namespace(elt->sgprivate->scenegraph, *(DOM_String *) datt->data, qname[0] ? qname+1 : NULL);
372 			}
373 		}
374 		att = att->next;
375 	}
376 }
377 
378 
gf_xml_get_namespace(GF_DOMNode * elt,const char * attribute_name)379 static u32 gf_xml_get_namespace(GF_DOMNode *elt, const char *attribute_name)
380 {
381 	GF_DOMAttribute *att = elt->attributes;
382 	while (att) {
383 		if (att->tag==TAG_DOM_ATT_any) {
384 			GF_DOMFullAttribute *datt = (GF_DOMFullAttribute*)att;
385 			if (datt->name && !strncmp(datt->name, "xmlns", 5) && !strcmp(datt->name+6, attribute_name)) {
386 				return gf_xml_get_namespace_id(*(DOM_String *)  datt->data);
387 			}
388 		}
389 		att = att->next;
390 	}
391 	if (!elt->sgprivate->parents) return 0;
392 	return gf_xml_get_namespace((GF_DOMNode*)elt->sgprivate->parents->node, attribute_name);
393 }
394 
gf_xml_get_namespace_qname(GF_DOMNode * elt,u32 ns)395 static char *gf_xml_get_namespace_qname(GF_DOMNode *elt, u32 ns)
396 {
397 	GF_DOMAttribute *att = elt->attributes;
398 	while (att) {
399 		if (att->tag==TAG_DOM_ATT_any) {
400 			GF_DOMFullAttribute *datt = (GF_DOMFullAttribute*)att;
401 			if (datt->name && !strncmp(datt->name, "xmlns", 5) && (gf_xml_get_namespace_id(*(DOM_String *)  datt->data)==ns)) {
402 				if (datt->name[5]) return datt->name+6;
403 				return NULL;
404 			}
405 		}
406 		att = att->next;
407 	}
408 	if (!elt->sgprivate->parents) return NULL;
409 	return gf_xml_get_namespace_qname((GF_DOMNode*)elt->sgprivate->parents->node, ns);
410 }
411 
gf_xml_get_attribute_tag(GF_Node * elt,char * attribute_name,GF_NamespaceType ns)412 u32 gf_xml_get_attribute_tag(GF_Node *elt, char *attribute_name, GF_NamespaceType ns)
413 {
414 	u32 i, count;
415 	count = sizeof(xml_attributes) / sizeof(struct xml_att_def);
416 
417 	if (!ns) {
418 		char *ns_sep = strchr(attribute_name, ':');
419 		if (ns_sep) {
420 			ns_sep[0] = 0;
421 			ns = gf_sg_get_namespace_code(elt->sgprivate->scenegraph, attribute_name);
422 			if (ns==GF_XMLNS_UNDEFINED) ns = gf_xml_get_namespace((GF_DOMNode*)elt, attribute_name);
423 			ns_sep[0] = ':';
424 			attribute_name = ++ns_sep;
425 		} else {
426 			ns = gf_xml_get_element_namespace(elt);
427 			if (!ns) ns = gf_sg_get_namespace_code(elt->sgprivate->scenegraph, NULL);
428 		}
429 	}
430 
431 	for (i=0; i<count; i++) {
432 		if (strcmp(xml_attributes[i].name, attribute_name)) continue;
433 		if (xml_attributes[i].xmlns != ns) continue;
434 
435 		switch (xml_attributes[i].opts) {
436 		case GF_SVG_ATTOPT_SMIL:
437 			switch (elt->sgprivate->tag) {
438 			case TAG_SVG_animate:
439 			case TAG_SVG_animateColor:
440 			case TAG_SVG_animateMotion:
441 			case TAG_SVG_animateTransform:
442 			case TAG_SVG_animation:
443 			case TAG_SVG_audio:
444 			case TAG_SVG_video:
445 			case TAG_SVG_set:
446 				return xml_attributes[i].tag;
447 			default:
448 				break;
449 			}
450 			break;
451 		case GF_SVG_ATTOPT_TEXT:
452 			if (elt->sgprivate->tag == TAG_SVG_text)
453 				return xml_attributes[i].tag;
454 			break;
455 		case GF_SVG_ATTOPT_CURSOR:
456 			if (elt->sgprivate->tag == TAG_LSR_cursorManager)
457 				return xml_attributes[i].tag;
458 			break;
459 		case GF_SVG_ATTOPT_LISTENER:
460 			if (elt->sgprivate->tag == TAG_SVG_listener)
461 				return xml_attributes[i].tag;
462 			break;
463 		case GF_SVG_ATTOPT_FILTER:
464 			switch (elt->sgprivate->tag) {
465 			case TAG_SVG_filter:
466 			case TAG_SVG_feDistantLight:
467 			case TAG_SVG_fePointLight:
468 			case TAG_SVG_feSpotLight:
469 			case TAG_SVG_feBlend:
470 			case TAG_SVG_feColorMatrix:
471 			case TAG_SVG_feComponentTransfer:
472 			case TAG_SVG_feFuncR:
473 			case TAG_SVG_feFuncG:
474 			case TAG_SVG_feFuncB:
475 			case TAG_SVG_feFuncA:
476 			case TAG_SVG_feComposite:
477 			case TAG_SVG_feConvolveMatrix:
478 			case TAG_SVG_feDiffuseLighting:
479 			case TAG_SVG_feDisplacementMap:
480 			case TAG_SVG_feFlood:
481 			case TAG_SVG_feGaussianBlur:
482 			case TAG_SVG_feImage:
483 			case TAG_SVG_feMerge:
484 			case TAG_SVG_feMorphology:
485 			case TAG_SVG_feOffset:
486 			case TAG_SVG_feSpecularLighting:
487 			case TAG_SVG_feTile:
488 			case TAG_SVG_feTurbulence:
489 				return xml_attributes[i].tag;
490 			default:
491 				break;
492 			}
493 			break;
494 		default:
495 			return xml_attributes[i].tag;
496 		}
497 	}
498 	return TAG_DOM_ATT_any;
499 }
500 
gf_xml_get_attribute_type(u32 tag)501 u32 gf_xml_get_attribute_type(u32 tag)
502 {
503 	u32 i, count;
504 	count = sizeof(xml_attributes) / sizeof(struct xml_att_def);
505 	for (i=0; i<count; i++) {
506 		if (xml_attributes[i].tag==tag) return xml_attributes[i].type;
507 	}
508 	return DOM_String_datatype;
509 }
510 
gf_svg_get_attribute_name(GF_Node * node,u32 tag)511 const char*gf_svg_get_attribute_name(GF_Node *node, u32 tag)
512 {
513 	u32 i, count, ns;
514 
515 	//ns = gf_sg_get_namespace_code(node->sgprivate->scenegraph, NULL);
516 	ns = gf_xml_get_element_namespace(node);
517 	count = sizeof(xml_attributes) / sizeof(struct xml_att_def);
518 	for (i=0; i<count; i++) {
519 		if (xml_attributes[i].tag==tag) {
520 			char *xmlns;
521 			if (ns == xml_attributes[i].xmlns)
522 				return xml_attributes[i].name;
523 
524 			xmlns = (char *) gf_xml_get_namespace_qname((GF_DOMNode*)node, xml_attributes[i].xmlns);
525 			if (xmlns) {
526 				sprintf(node->sgprivate->scenegraph->szNameBuffer, "%s:%s", xmlns, xml_attributes[i].name);
527 				return node->sgprivate->scenegraph->szNameBuffer;
528 			}
529 			return xml_attributes[i].name;
530 		}
531 	}
532 	return 0;
533 }
gf_xml_create_attribute(GF_Node * node,u32 tag)534 GF_DOMAttribute *gf_xml_create_attribute(GF_Node *node, u32 tag)
535 {
536 	u32 type = gf_xml_get_attribute_type(tag);
537 	return gf_node_create_attribute_from_datatype(type, tag);
538 }
539 
540 static const struct xml_elt_def {
541 	const char *name;
542 	u32 tag;
543 	u32 xmlns;
544 } xml_elements [] =
545 {
546 	{ "listener", TAG_SVG_listener, GF_XMLNS_XMLEV},
547 	/*SVG*/
548 	{ "a", TAG_SVG_a, GF_XMLNS_SVG },
549 	{ "animate", TAG_SVG_animate, GF_XMLNS_SVG },
550 	{ "animateColor", TAG_SVG_animateColor, GF_XMLNS_SVG },
551 	{ "animateMotion", TAG_SVG_animateMotion, GF_XMLNS_SVG },
552 	{ "animateTransform", TAG_SVG_animateTransform, GF_XMLNS_SVG },
553 	{ "animation", TAG_SVG_animation, GF_XMLNS_SVG },
554 	{ "audio", TAG_SVG_audio, GF_XMLNS_SVG },
555 	{ "circle", TAG_SVG_circle, GF_XMLNS_SVG },
556 	{ "defs", TAG_SVG_defs, GF_XMLNS_SVG },
557 	{ "desc", TAG_SVG_desc, GF_XMLNS_SVG },
558 	{ "discard", TAG_SVG_discard, GF_XMLNS_SVG },
559 	{ "ellipse", TAG_SVG_ellipse, GF_XMLNS_SVG },
560 	{ "font", TAG_SVG_font, GF_XMLNS_SVG },
561 	{ "font-face", TAG_SVG_font_face, GF_XMLNS_SVG },
562 	{ "font-face-src", TAG_SVG_font_face_src, GF_XMLNS_SVG },
563 	{ "font-face-uri", TAG_SVG_font_face_uri, GF_XMLNS_SVG },
564 	{ "foreignObject", TAG_SVG_foreignObject, GF_XMLNS_SVG },
565 	{ "g", TAG_SVG_g, GF_XMLNS_SVG },
566 	{ "glyph", TAG_SVG_glyph, GF_XMLNS_SVG },
567 	{ "handler", TAG_SVG_handler, GF_XMLNS_SVG },
568 	{ "hkern", TAG_SVG_hkern, GF_XMLNS_SVG },
569 	{ "image", TAG_SVG_image, GF_XMLNS_SVG },
570 	{ "line", TAG_SVG_line, GF_XMLNS_SVG },
571 	{ "linearGradient", TAG_SVG_linearGradient, GF_XMLNS_SVG },
572 	{ "metadata", TAG_SVG_metadata, GF_XMLNS_SVG },
573 	{ "missing-glyph", TAG_SVG_missing_glyph, GF_XMLNS_SVG },
574 	{ "mpath", TAG_SVG_mpath, GF_XMLNS_SVG },
575 	{ "path", TAG_SVG_path, GF_XMLNS_SVG },
576 	{ "polygon", TAG_SVG_polygon, GF_XMLNS_SVG },
577 	{ "polyline", TAG_SVG_polyline, GF_XMLNS_SVG },
578 	{ "prefetch", TAG_SVG_prefetch, GF_XMLNS_SVG },
579 	{ "radialGradient", TAG_SVG_radialGradient, GF_XMLNS_SVG },
580 	{ "rect", TAG_SVG_rect, GF_XMLNS_SVG },
581 	{ "script", TAG_SVG_script, GF_XMLNS_SVG },
582 	{ "set", TAG_SVG_set, GF_XMLNS_SVG },
583 	{ "solidColor", TAG_SVG_solidColor, GF_XMLNS_SVG },
584 	{ "stop", TAG_SVG_stop, GF_XMLNS_SVG },
585 	{ "svg", TAG_SVG_svg, GF_XMLNS_SVG },
586 	{ "switch", TAG_SVG_switch, GF_XMLNS_SVG },
587 	{ "tbreak", TAG_SVG_tbreak, GF_XMLNS_SVG },
588 	{ "text", TAG_SVG_text, GF_XMLNS_SVG },
589 	{ "textArea", TAG_SVG_textArea, GF_XMLNS_SVG },
590 	{ "title", TAG_SVG_title, GF_XMLNS_SVG },
591 	{ "tspan", TAG_SVG_tspan, GF_XMLNS_SVG },
592 	{ "use", TAG_SVG_use, GF_XMLNS_SVG },
593 	{ "video", TAG_SVG_video, GF_XMLNS_SVG },
594 	{ "filter", TAG_SVG_filter, GF_XMLNS_SVG },
595 	{ "feDistantLight", TAG_SVG_feDistantLight, GF_XMLNS_SVG },
596 	{ "fePointLight", TAG_SVG_fePointLight, GF_XMLNS_SVG },
597 	{ "feSpotLight", TAG_SVG_feSpotLight, GF_XMLNS_SVG },
598 	{ "feBlend", TAG_SVG_feBlend, GF_XMLNS_SVG },
599 	{ "feColorMatrix", TAG_SVG_feColorMatrix, GF_XMLNS_SVG },
600 	{ "feComponentTransfer", TAG_SVG_feComponentTransfer, GF_XMLNS_SVG },
601 	{ "feFuncR", TAG_SVG_feFuncR, GF_XMLNS_SVG },
602 	{ "feFuncG", TAG_SVG_feFuncG, GF_XMLNS_SVG },
603 	{ "feFuncB", TAG_SVG_feFuncB, GF_XMLNS_SVG },
604 	{ "feFuncA", TAG_SVG_feFuncA, GF_XMLNS_SVG },
605 	{ "feComposite", TAG_SVG_feComposite, GF_XMLNS_SVG },
606 	{ "feConvolveMatrix", TAG_SVG_feConvolveMatrix, GF_XMLNS_SVG },
607 	{ "feDiffuseLighting", TAG_SVG_feDiffuseLighting, GF_XMLNS_SVG },
608 	{ "feDisplacementMap", TAG_SVG_feDisplacementMap, GF_XMLNS_SVG },
609 	{ "feFlood", TAG_SVG_feFlood, GF_XMLNS_SVG },
610 	{ "feGaussianBlur", TAG_SVG_feGaussianBlur, GF_XMLNS_SVG },
611 	{ "feImage", TAG_SVG_feImage, GF_XMLNS_SVG },
612 	{ "feMerge", TAG_SVG_feMerge, GF_XMLNS_SVG },
613 	{ "feMorphology", TAG_SVG_feMorphology, GF_XMLNS_SVG },
614 	{ "feOffset", TAG_SVG_feOffset, GF_XMLNS_SVG },
615 	{ "feSpecularLighting", TAG_SVG_feSpecularLighting, GF_XMLNS_SVG },
616 	{ "feTile", TAG_SVG_feTile, GF_XMLNS_SVG },
617 	{ "feTurbulence", TAG_SVG_feTurbulence, GF_XMLNS_SVG },
618 
619 	/*LASeR*/
620 	{ "conditional", TAG_LSR_conditional, GF_XMLNS_LASER },
621 	{ "rectClip", TAG_LSR_rectClip, GF_XMLNS_LASER },
622 	{ "cursorManager", TAG_LSR_cursorManager, GF_XMLNS_LASER },
623 	{ "selector", TAG_LSR_selector, GF_XMLNS_LASER },
624 	{ "simpleLayout", TAG_LSR_simpleLayout, GF_XMLNS_LASER },
625 	{ "updates", TAG_LSR_updates, GF_XMLNS_LASER },
626 
627 };
628 
629 GF_EXPORT
gf_xml_get_element_tag(const char * element_name,u32 ns)630 u32 gf_xml_get_element_tag(const char *element_name, u32 ns)
631 {
632 	u32 i, count;
633 //	if (!element_name) return TAG_UndefinedNode;
634 	count = sizeof(xml_elements) / sizeof(struct xml_elt_def);
635 	for (i=0; i<count; i++) {
636 		if (!strcmp(xml_elements[i].name, element_name)) {
637 			if (!ns || (xml_elements[i].xmlns==ns) )
638 				return xml_elements[i].tag;
639 		}
640 	}
641 	return TAG_UndefinedNode;
642 }
643 
gf_xml_get_element_name(GF_Node * n)644 const char *gf_xml_get_element_name(GF_Node *n)
645 {
646 	u32 i, count, ns;
647 
648 	ns = n ? gf_sg_get_namespace_code(n->sgprivate->scenegraph, NULL) : 0;
649 	count = sizeof(xml_elements) / sizeof(struct xml_elt_def);
650 	for (i=0; i<count; i++) {
651 		if (n && n->sgprivate && (n->sgprivate->tag==xml_elements[i].tag)) {
652 			char *xmlns;
653 			if (ns == xml_elements[i].xmlns)
654 				return xml_elements[i].name;
655 
656 			xmlns = (char *) gf_sg_get_namespace_qname(n->sgprivate->scenegraph, xml_elements[i].xmlns);
657 			if (xmlns) {
658 				sprintf(n->sgprivate->scenegraph->szNameBuffer, "%s:%s", xmlns, xml_elements[i].name);
659 				return n->sgprivate->scenegraph->szNameBuffer;
660 			}
661 			return xml_elements[i].name;
662 		}
663 	}
664 	return "UndefinedNode";
665 }
666 
gf_xml_get_element_namespace(GF_Node * n)667 GF_NamespaceType gf_xml_get_element_namespace(GF_Node *n)
668 {
669 	u32 i, count;
670 	if (n->sgprivate->tag==TAG_DOMFullNode) {
671 		GF_DOMFullNode *elt = (GF_DOMFullNode *)n;
672 		return elt->ns;
673 	}
674 
675 	count = sizeof(xml_elements) / sizeof(struct xml_elt_def);
676 	for (i=0; i<count; i++) {
677 		if (n->sgprivate->tag==xml_elements[i].tag) return xml_elements[i].xmlns;
678 	}
679 	return GF_XMLNS_UNDEFINED;
680 }
681 
gf_node_get_attribute_count(GF_Node * node)682 u32 gf_node_get_attribute_count(GF_Node *node)
683 {
684 	u32 count = 0;
685 	GF_DOMAttribute *atts;
686 	if (!node) return 0;
687 	atts =  ((GF_DOMNode *)node)->attributes;
688 	while (atts) {
689 		count++;
690 		atts = atts->next;
691 	}
692 	return count;
693 }
694 
gf_node_get_attribute_info(GF_Node * node,GF_FieldInfo * info)695 GF_Err gf_node_get_attribute_info(GF_Node *node, GF_FieldInfo *info)
696 {
697 	GF_DOMNode *dom = (GF_DOMNode *)node;
698 	GF_DOMAttribute *atts = dom->attributes;
699 	while (atts) {
700 		if (atts->tag == info->fieldIndex) {
701 			info->fieldType = atts->data_type;
702 			info->far_ptr  = atts->data;
703 			return GF_OK;
704 		}
705 		atts = atts->next;
706 	}
707 	info->fieldType = 0;
708 	info->far_ptr  = NULL;
709 	return GF_NOT_SUPPORTED;
710 }
711 
gf_node_delete_attributes(GF_Node * node)712 void gf_node_delete_attributes(GF_Node *node)
713 {
714 	GF_DOMAttribute *att = ((GF_DOMNode*)node)->attributes;
715 	while(att) {
716 		GF_DOMAttribute *tmp;
717 		gf_svg_delete_attribute_value(att->data_type, att->data, node->sgprivate->scenegraph);
718 		tmp = att;
719 		att = att->next;
720 		if (tmp->tag==TAG_DOM_ATT_any) {
721 			gf_free( ((GF_DOMFullAttribute*)tmp)->name);
722 		}
723 		gf_free(tmp);
724 	}
725 }
726 
gf_node_create_attribute_from_datatype(u32 data_type,u32 attribute_tag)727 SVGAttribute *gf_node_create_attribute_from_datatype(u32 data_type, u32 attribute_tag)
728 {
729 	SVGAttribute *att;
730 	if (!data_type) return NULL;
731 
732 	GF_SAFEALLOC(att, SVGAttribute);
733 	if (!att) return NULL;
734 	att->data_type = (u16) data_type;
735 	att->tag = (u16) attribute_tag;
736 	att->data = gf_svg_create_attribute_value(att->data_type);
737 	return att;
738 }
739 
740 GF_EXPORT
gf_node_get_attribute_by_name(GF_Node * node,char * name,u32 xmlns_code,Bool create_if_not_found,Bool set_default,GF_FieldInfo * field)741 GF_Err gf_node_get_attribute_by_name(GF_Node *node, char *name, u32 xmlns_code, Bool create_if_not_found, Bool set_default, GF_FieldInfo *field)
742 {
743 	u32 attribute_tag = gf_xml_get_attribute_tag(node, name, xmlns_code);
744 	if (attribute_tag == TAG_DOM_ATT_any) {
745 		u32 len = 0;
746 		const char *ns = NULL;
747 		SVGAttribute *last_att = NULL;
748 		GF_DOMFullAttribute *att = (GF_DOMFullAttribute *) ((SVG_Element*)node)->attributes;
749 		if (xmlns_code) ns = gf_sg_get_namespace_qname(node->sgprivate->scenegraph, xmlns_code);
750 		if (ns) len = (u32) strlen(ns);
751 
752 		while (att) {
753 			if (((u32) att->tag == TAG_DOM_ATT_any) &&
754 			        ((!ns && !strcmp(name, att->name)) || (ns && !strncmp(att->name, ns, len) && !strcmp(att->name+len+1, name)))
755 			   ) {
756 				field->fieldIndex = att->tag;
757 				field->fieldType = att->data_type;
758 				field->far_ptr = att->data;
759 				return GF_OK;
760 			}
761 			last_att = (SVGAttribute *) att;
762 			att = (GF_DOMFullAttribute *) att->next;
763 		}
764 		if (create_if_not_found) {
765 			GF_SAFEALLOC(att, GF_DOMFullAttribute);
766 			if (!att) return GF_OUT_OF_MEM;
767 			att->data_type = (u16) DOM_String_datatype;
768 			att->tag = (u16) TAG_DOM_ATT_any;
769 			att->data = gf_svg_create_attribute_value(att->data_type);
770 
771 			att->name = gf_strdup(name);
772 			if (!xmlns_code)
773 				att->xmlns = gf_xml_get_element_namespace(node);
774 			else
775 				att->xmlns = xmlns_code;
776 
777 			if (last_att) last_att->next = (SVGAttribute *)att;
778 			else ((SVG_Element*)node)->attributes = (SVGAttribute *)att;
779 
780 			field->far_ptr = att->data;
781 			field->fieldType = att->data_type;
782 			field->fieldIndex = att->tag;
783 			return GF_OK;
784 		}
785 		return GF_NOT_SUPPORTED;
786 	}
787 	return gf_node_get_attribute_by_tag(node, attribute_tag, create_if_not_found, set_default, field);
788 }
789 
790 
attributes_set_default_value(GF_Node * node,SVGAttribute * att)791 static void attributes_set_default_value(GF_Node *node, SVGAttribute *att)
792 {
793 	u32 node_tag = node->sgprivate->tag;
794 	switch (att->tag) {
795 	case TAG_SVG_ATT_width:
796 	case TAG_SVG_ATT_height:
797 		if (node_tag == TAG_SVG_svg) {
798 			SVG_Length *len = att->data;
799 			len->type = SVG_NUMBER_PERCENTAGE;
800 			len->value = INT2FIX(100);
801 		}
802 		break;
803 	case TAG_SVG_ATT_x2:
804 		if (node_tag == TAG_SVG_linearGradient) {
805 			((SVG_Number *)att->data)->value = FIX_ONE;
806 		}
807 		break;
808 	case TAG_SVG_ATT_cx:
809 	case TAG_SVG_ATT_cy:
810 	case TAG_SVG_ATT_fx:
811 	case TAG_SVG_ATT_fy:
812 	case TAG_SVG_ATT_r:
813 		if (node_tag == TAG_SVG_radialGradient) {
814 			((SVG_Number *)att->data)->value = FIX_ONE/2;
815 		}
816 		break;
817 	case TAG_SVG_ATT_dur:
818 		if (node_tag == TAG_SVG_video ||
819 		        node_tag == TAG_SVG_audio ||
820 		        node_tag == TAG_SVG_animation)
821 		{
822 			((SMIL_Duration *)att->data)->type = SMIL_DURATION_MEDIA;
823 		} else {
824 			/*is this correct?*/
825 			((SMIL_Duration *)att->data)->type = SMIL_DURATION_INDEFINITE;
826 		}
827 		break;
828 	case TAG_SVG_ATT_min:
829 		((SMIL_Duration *)att->data)->type = SMIL_DURATION_DEFINED;
830 		break;
831 	case TAG_SVG_ATT_repeatDur:
832 		((SMIL_Duration *)att->data)->type = SMIL_DURATION_INDEFINITE;
833 		break;
834 	case TAG_SVG_ATT_calcMode:
835 		if (node_tag == TAG_SVG_animateMotion)
836 			*((SMIL_CalcMode *)att->data) = SMIL_CALCMODE_PACED;
837 		else
838 			*((SMIL_CalcMode *)att->data) = SMIL_CALCMODE_LINEAR;
839 		break;
840 	case TAG_SVG_ATT_color:
841 		((SVG_Paint *)att->data)->type = SVG_PAINT_COLOR;
842 		((SVG_Paint *)att->data)->color.type = SVG_COLOR_INHERIT;
843 		break;
844 	case TAG_SVG_ATT_solid_color:
845 	case TAG_SVG_ATT_stop_color:
846 		((SVG_Paint *)att->data)->type = SVG_PAINT_COLOR;
847 		((SVG_Paint *)att->data)->color.type = SVG_COLOR_RGBCOLOR;
848 		break;
849 	case TAG_SVG_ATT_opacity:
850 	case TAG_SVG_ATT_solid_opacity:
851 	case TAG_SVG_ATT_stop_opacity:
852 	case TAG_SVG_ATT_audio_level:
853 	case TAG_SVG_ATT_viewport_fill_opacity:
854 		((SVG_Number *)att->data)->value = FIX_ONE;
855 		break;
856 	case TAG_SVG_ATT_display:
857 		*((SVG_Display *)att->data) = SVG_DISPLAY_INLINE;
858 		break;
859 	case TAG_SVG_ATT_fill:
860 	case TAG_SVG_ATT_stroke:
861 		((SVG_Paint *)att->data)->type = SVG_PAINT_INHERIT;
862 		break;
863 	case TAG_SVG_ATT_stroke_dasharray:
864 		((SVG_StrokeDashArray *)att->data)->type = SVG_STROKEDASHARRAY_INHERIT;
865 		break;
866 	case TAG_SVG_ATT_fill_opacity:
867 	case TAG_SVG_ATT_stroke_opacity:
868 	case TAG_SVG_ATT_stroke_width:
869 	case TAG_SVG_ATT_font_size:
870 	case TAG_SVG_ATT_line_increment:
871 	case TAG_SVG_ATT_stroke_dashoffset:
872 	case TAG_SVG_ATT_stroke_miterlimit:
873 		((SVG_Number *)att->data)->type = SVG_NUMBER_INHERIT;
874 		break;
875 	case TAG_SVG_ATT_vector_effect:
876 		*((SVG_VectorEffect *)att->data) = SVG_VECTOREFFECT_NONE;
877 		break;
878 	case TAG_SVG_ATT_fill_rule:
879 		*((SVG_FillRule *)att->data) = SVG_FILLRULE_INHERIT;
880 		break;
881 	case TAG_SVG_ATT_font_weight:
882 		*((SVG_FontWeight *)att->data) = SVG_FONTWEIGHT_INHERIT;
883 		break;
884 	case TAG_SVG_ATT_visibility:
885 		*((SVG_Visibility *)att->data) = SVG_VISIBILITY_INHERIT;
886 		break;
887 	case TAG_SVG_ATT_smil_fill:
888 		*((SMIL_Fill *)att->data) = SMIL_FILL_REMOVE;
889 		break;
890 	case TAG_XMLEV_ATT_defaultAction:
891 		*((XMLEV_DefaultAction *)att->data) = XMLEVENT_DEFAULTACTION_PERFORM;
892 		break;
893 	case TAG_SVG_ATT_zoomAndPan:
894 		*((SVG_ZoomAndPan *)att->data) = SVG_ZOOMANDPAN_MAGNIFY;
895 		break;
896 	case TAG_SVG_ATT_stroke_linecap:
897 		*(SVG_StrokeLineCap*)att->data = SVG_STROKELINECAP_INHERIT;
898 		break;
899 	case TAG_SVG_ATT_stroke_linejoin:
900 		*(SVG_StrokeLineJoin*)att->data = SVG_STROKELINEJOIN_INHERIT;
901 		break;
902 
903 	case TAG_SVG_ATT_transform:
904 		gf_mx2d_init(((SVG_Transform*)att->data)->mat);
905 		break;
906 
907 
908 	/*all default=0 values (don't need init)*/
909 	case TAG_SVG_ATT_font_family:
910 	case TAG_SVG_ATT_font_style:
911 	case TAG_SVG_ATT_text_anchor:
912 	case TAG_SVG_ATT_x:
913 	case TAG_SVG_ATT_y:
914 		break;
915 
916 	default:
917 		GF_LOG(GF_LOG_DEBUG, GF_LOG_SCENE, ("[Scene] Cannot create default value for SVG attribute %s\n", gf_svg_get_attribute_name(node, att->tag)));
918 	}
919 }
920 
921 GF_EXPORT
gf_node_get_attribute_by_tag(GF_Node * node,u32 attribute_tag,Bool create_if_not_found,Bool set_default,GF_FieldInfo * field)922 GF_Err gf_node_get_attribute_by_tag(GF_Node *node, u32 attribute_tag, Bool create_if_not_found, Bool set_default, GF_FieldInfo *field)
923 {
924 	SVG_Element *elt = (SVG_Element *)node;
925 	SVGAttribute *att = elt->attributes;
926 	SVGAttribute *last_att = NULL;
927 
928 	while (att) {
929 		if ((u32) att->tag == attribute_tag) {
930 			field->fieldIndex = att->tag;
931 			field->fieldType = att->data_type;
932 			field->far_ptr  = att->data;
933 			return GF_OK;
934 		}
935 		last_att = att;
936 		att = att->next;
937 	}
938 
939 	if (create_if_not_found) {
940 		/* field not found create one */
941 		att = gf_xml_create_attribute(node, attribute_tag);
942 		if (att) {
943 			if (!elt->attributes) elt->attributes = att;
944 			else last_att->next = att;
945 			field->far_ptr = att->data;
946 			field->fieldType = att->data_type;
947 			field->fieldIndex = att->tag;
948 			/* attribute name should not be called, if needed use gf_svg_get_attribute_name(att->tag);*/
949 			field->name = NULL;
950 			if (set_default) attributes_set_default_value(node, att);
951 			return GF_OK;
952 		}
953 	}
954 
955 	return GF_NOT_SUPPORTED;
956 }
957 
958 GF_EXPORT
gf_node_register_iri(GF_SceneGraph * sg,XMLRI * target)959 void gf_node_register_iri(GF_SceneGraph *sg, XMLRI *target)
960 {
961 #ifndef GPAC_DISABLE_SVG
962 	if (gf_list_find(sg->xlink_hrefs, target)<0) {
963 		gf_list_add(sg->xlink_hrefs, target);
964 	}
965 #endif
966 }
967 
968 GF_EXPORT
gf_node_unregister_iri(GF_SceneGraph * sg,XMLRI * target)969 void gf_node_unregister_iri(GF_SceneGraph *sg, XMLRI *target)
970 {
971 #ifndef GPAC_DISABLE_SVG
972 	gf_list_del_item(sg->xlink_hrefs, target);
973 #endif
974 }
975 
gf_xml_node_clone(GF_SceneGraph * inScene,GF_Node * orig,GF_Node * cloned_parent,char * inst_id,Bool deep)976 GF_Node *gf_xml_node_clone(GF_SceneGraph *inScene, GF_Node *orig, GF_Node *cloned_parent, char *inst_id, Bool deep)
977 {
978 	GF_DOMAttribute *att;
979 	GF_Node *clone;
980 	if (!orig) return NULL;
981 	clone = gf_node_new(inScene, orig->sgprivate->tag);
982 	if (!clone) return NULL;
983 
984 	if (orig->sgprivate->tag == TAG_DOMText) {
985 		GF_DOMText *n_src,*n_dst;
986 		n_src = (GF_DOMText *)orig;
987 		n_dst = (GF_DOMText *)clone;
988 		n_dst->type = n_src->type;
989 		n_dst->textContent = gf_strdup(n_src->textContent);
990 	} else {
991 		if (orig->sgprivate->tag == TAG_DOMFullNode) {
992 			GF_DOMFullNode *n_src,*n_dst;
993 			n_src = (GF_DOMFullNode *)orig;
994 			n_dst = (GF_DOMFullNode *)clone;
995 			n_dst->ns = n_src->ns;
996 			n_dst->name = gf_strdup(n_src->name);
997 		}
998 
999 		att = ((GF_DOMNode *)orig)->attributes;
1000 		while (att) {
1001 			GF_FieldInfo dst, src;
1002 			/*create by name*/
1003 			if (att->tag==TAG_DOM_ATT_any) {
1004 				gf_node_get_attribute_by_name(clone, ((GF_DOMFullAttribute*)att)->name, 0, 1, 0, &dst);
1005 			} else {
1006 				gf_node_get_attribute_by_tag(clone, att->tag, 1, 0, &dst);
1007 			}
1008 			src.far_ptr = att->data;
1009 			src.fieldType = att->data_type;
1010 			src.fieldIndex = att->tag;
1011 			gf_svg_attributes_copy(&dst, &src, 0);
1012 			if (att->tag==TAG_XLINK_ATT_href) {
1013 				XMLRI *iri = (XMLRI *)att->data;
1014 				if (iri->target == gf_node_get_parent(orig, 0)) {
1015 					((XMLRI *)dst.far_ptr)->target = cloned_parent;
1016 				} else {
1017 					((XMLRI *)dst.far_ptr)->target = NULL;
1018 				}
1019 			}
1020 			att = att->next;
1021 		}
1022 	}
1023 	if (cloned_parent) {
1024 		gf_node_list_add_child( & ((GF_ParentNode*)cloned_parent)->children, clone);
1025 		gf_node_register(clone, cloned_parent);
1026 		/*TO CLARIFY: can we init the node right now or should we wait for insertion in the scene tree ?*/
1027 		gf_node_init(clone);
1028 	}
1029 	if (deep) {
1030 		GF_ChildNodeItem *child = ((GF_ParentNode *)orig)->children;
1031 		while (child) {
1032 			gf_node_clone(inScene, child->node, clone, inst_id, 1);
1033 			child = child->next;
1034 		}
1035 	}
1036 	return clone;
1037 }
1038 
1039 /*TODO FIXME, this is ugly, add proper cache system*/
1040 #include <gpac/base_coding.h>
1041 
1042 
check_existing_file(char * base_file,char * ext,char * data,u32 data_size,u32 idx)1043 static u32 check_existing_file(char *base_file, char *ext, char *data, u32 data_size, u32 idx)
1044 {
1045 	char szFile[GF_MAX_PATH];
1046 	u64 fsize;
1047 	FILE *f;
1048 
1049 	sprintf(szFile, "%s%04X%s", base_file, idx, ext);
1050 
1051 	f = gf_fopen(szFile, "rb");
1052 	if (!f) return 0;
1053 
1054 	fsize = gf_fsize(f);
1055 	if (fsize==data_size) {
1056 		u32 offset=0;
1057 		char cache[1024];
1058 
1059 		while (fsize) {
1060 			u32 read = (u32) gf_fread(cache, 1024, f);
1061 			if ((s32) read < 0) return 0;
1062 			fsize -= read;
1063 			if (memcmp(cache, data+offset, sizeof(char)*read)) break;
1064 			offset+=read;
1065 		}
1066 		gf_fclose(f);
1067 		f = NULL;
1068 		/*same file*/
1069 		if (!fsize) return 2;
1070 	}
1071 	if (f)
1072 		gf_fclose(f);
1073 	return 1;
1074 }
1075 
1076 
1077 GF_EXPORT
gf_node_store_embedded_data(XMLRI * iri,const char * cache_dir,const char * base_filename)1078 GF_Err gf_node_store_embedded_data(XMLRI *iri, const char *cache_dir, const char *base_filename)
1079 {
1080 	char szFile[GF_MAX_PATH], buf[20], *sep, *data=NULL, *ext;
1081 	u32 data_size=0, idx;
1082 	Bool existing;
1083 
1084 	if (!cache_dir || !base_filename || !iri || !iri->string || strncmp(iri->string, "data:", 5)) return GF_OK;
1085 
1086 	/*handle "data:" scheme when cache is specified*/
1087 	strcpy(szFile, cache_dir);
1088 	data_size = (u32) strlen(szFile);
1089 	if (szFile[data_size-1] != GF_PATH_SEPARATOR) {
1090 		szFile[data_size] = GF_PATH_SEPARATOR;
1091 		szFile[data_size+1] = 0;
1092 	}
1093 
1094 	sep = strrchr(base_filename, GF_PATH_SEPARATOR);
1095 #ifdef WIN32
1096 	if (!sep) sep = strrchr(base_filename, '/');
1097 #endif
1098 	if (!sep) sep = (char *) base_filename;
1099 	else sep += 1;
1100 	strcat(szFile, sep);
1101 
1102 	sep = gf_file_ext_start(szFile);
1103 	if (sep) sep[0] = 0;
1104 	strcat(szFile, "_img_");
1105 
1106 	/*get mime type*/
1107 	sep = (char *)iri->string + 5;
1108 	if (!strncmp(sep, "image/jpg", 9) || !strncmp(sep, "image/jpeg", 10)) ext = ".jpg";
1109 	else if (!strncmp(sep, "image/png", 9)) ext = ".png";
1110 	else if (!strncmp(sep, "image/svg+xml", 13)) ext = ".svg";
1111 	else return GF_BAD_PARAM;
1112 
1113 
1114 	data = NULL;
1115 	sep = strchr(iri->string, ';');
1116 	if (!strncmp(sep, ";base64,", 8)) {
1117 		sep += 8;
1118 		data_size = 2 * (u32) strlen(sep);
1119 		data = (char*)gf_malloc(sizeof(char)*data_size);
1120 		if (!data) return GF_OUT_OF_MEM;
1121 		data_size = gf_base64_decode(sep, (u32) strlen(sep), data, data_size);
1122 	}
1123 	else if (!strncmp(sep, ";base16,", 8)) {
1124 		data_size = 2 * (u32) strlen(sep);
1125 		data = (char*)gf_malloc(sizeof(char)*data_size);
1126 		if (!data) return GF_OUT_OF_MEM;
1127 		sep += 8;
1128 		data_size = gf_base16_decode(sep, (u32) strlen(sep), data, data_size);
1129 	}
1130 	if (!data || !data_size) return GF_OK;
1131 
1132 	iri->type = XMLRI_STRING;
1133 
1134 	existing = 0;
1135 	idx = 0;
1136 	while (1) {
1137 		u32 res = check_existing_file(szFile, ext, data, data_size, idx);
1138 		if (!res) break;
1139 		if (res==2) {
1140 			existing = 1;
1141 			break;
1142 		}
1143 		idx++;
1144 	}
1145 	sprintf(buf, "%04X", idx);
1146 	strcat(szFile, buf);
1147 	strcat(szFile, ext);
1148 
1149 	if (!existing) {
1150 		FILE *f = gf_fopen(szFile, "wb");
1151 		if (!f) {
1152 			gf_free(data);
1153 			gf_free(iri->string);
1154 			iri->string = NULL;
1155 			return GF_IO_ERR;
1156 		}
1157 		gf_fwrite(data, data_size, f);
1158 		gf_fclose(f);
1159 	}
1160 	gf_free(data);
1161 	gf_free(iri->string);
1162 	iri->string = gf_strdup(szFile);
1163 	return GF_OK;
1164 }
1165 
1166 
1167 #endif /*GPAC_DISABLE_SVG*/
1168 
1169