add blend mode tests
[swfdec.git] / swfdec / swfdec_xml_node.c
blob1d061bbfe420fc6ee8c23d12a286bfc4934082ca
1 /* Swfdec
2 * Copyright (C) 2007-2008 Benjamin Otte <otte@gnome.org>
3 * 2007 Pekka Lampila <pekka.lampila@iki.fi>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301 USA
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
25 #include <string.h>
27 #include "swfdec_xml_node.h"
28 #include "swfdec_xml.h"
29 #include "swfdec_as_array.h"
30 #include "swfdec_as_native_function.h"
31 #include "swfdec_as_object.h"
32 #include "swfdec_as_strings.h"
33 #include "swfdec_debug.h"
34 #include "swfdec_internal.h"
35 #include "swfdec_as_internal.h"
36 #include "swfdec_load_object.h"
37 #include "swfdec_player_internal.h"
39 G_DEFINE_TYPE (SwfdecXmlNode, swfdec_xml_node, SWFDEC_TYPE_AS_RELAY)
41 static void
42 swfdec_xml_node_mark (SwfdecGcObject *object)
44 SwfdecXmlNode *node = SWFDEC_XML_NODE (object);
46 if (node->name != NULL)
47 swfdec_as_string_mark (node->name);
48 if (node->value != NULL)
49 swfdec_as_string_mark (node->value);
50 if (node->parent != NULL)
51 swfdec_gc_object_mark (node->parent);
52 if (node->children != NULL)
53 swfdec_as_object_mark (node->children);
54 if (node->attributes != NULL)
55 swfdec_as_object_mark (node->attributes);
56 if (node->child_nodes != NULL)
57 swfdec_as_object_mark (node->child_nodes);
59 SWFDEC_GC_OBJECT_CLASS (swfdec_xml_node_parent_class)->mark (object);
62 static void
63 swfdec_xml_node_class_init (SwfdecXmlNodeClass *klass)
65 SwfdecGcObjectClass *gc_class = SWFDEC_GC_OBJECT_CLASS (klass);
67 gc_class->mark = swfdec_xml_node_mark;
70 static void
71 swfdec_xml_node_init (SwfdecXmlNode *xml_node)
75 /*** AS CODE ***/
77 gint32
78 swfdec_xml_node_num_children (SwfdecXmlNode *node)
80 g_return_val_if_fail (SWFDEC_IS_VALID_XML_NODE (node), 0);
82 return swfdec_as_array_get_length (node->children);
85 SwfdecXmlNode *
86 swfdec_xml_node_get_child (SwfdecXmlNode *node, gint32 index_)
88 SwfdecAsValue val;
90 g_return_val_if_fail (SWFDEC_IS_VALID_XML_NODE (node), NULL);
91 g_return_val_if_fail (index_ >= 0, NULL);
93 if (index_ >= swfdec_xml_node_num_children (node))
94 return NULL;
96 swfdec_as_array_get_value (node->children, index_, &val);
98 g_return_val_if_fail (SWFDEC_AS_VALUE_IS_OBJECT (val), NULL);
99 g_return_val_if_fail (SWFDEC_IS_VALID_XML_NODE (
100 SWFDEC_AS_VALUE_GET_OBJECT (val)->relay), NULL);
102 return SWFDEC_XML_NODE (SWFDEC_AS_VALUE_GET_OBJECT (val)->relay);
105 static gint32
106 swfdec_xml_node_index_of_child (SwfdecXmlNode *node, SwfdecXmlNode *child)
108 gint32 num, i;
110 g_return_val_if_fail (SWFDEC_IS_VALID_XML_NODE (node), -1);
111 g_return_val_if_fail (SWFDEC_IS_VALID_XML_NODE (child), -1);
113 num = swfdec_xml_node_num_children (node);
114 for (i = 0; i < num; i++) {
115 if (swfdec_xml_node_get_child (node, i) == child)
116 return i;
119 return -1;
122 static void
123 swfdec_xml_node_update_child_nodes (SwfdecXmlNode *node)
125 SwfdecAsValue val;
126 SwfdecAsValue *vals;
127 gint32 num, i;
129 g_return_if_fail (SWFDEC_IS_VALID_XML_NODE (node));
131 // remove old
132 val = swfdec_as_value_from_integer (swfdec_gc_object_get_context (node), 0);
133 swfdec_as_object_set_variable (node->child_nodes,
134 SWFDEC_AS_STR_length, &val);
136 // add everything
137 num = swfdec_xml_node_num_children (node);
138 vals = g_malloc (sizeof (SwfdecAsValue) * num);
139 for (i = 0; i < num; i++) {
140 SWFDEC_AS_VALUE_SET_OBJECT (&vals[i], swfdec_as_relay_get_as_object (
141 SWFDEC_AS_RELAY (swfdec_xml_node_get_child (node, i))));
143 swfdec_as_array_append_with_flags (node->child_nodes, num, vals,
144 SWFDEC_AS_VARIABLE_CONSTANT);
145 g_free (vals);
148 const char *
149 swfdec_xml_node_get_attribute (SwfdecXmlNode *node, const char *name)
151 SwfdecAsValue val;
153 g_return_val_if_fail (SWFDEC_IS_VALID_XML_NODE (node), NULL);
154 g_return_val_if_fail (name != NULL, NULL);
156 if (swfdec_as_object_get_variable (node->attributes, name, &val)) {
157 return swfdec_as_value_to_string (swfdec_gc_object_get_context (node), val);
158 } else {
159 return NULL;
163 static const char *
164 swfdec_xml_node_getNamespaceForPrefix (SwfdecXmlNode *node, const char *prefix)
166 const char *var;
167 SwfdecAsValue val;
169 g_return_val_if_fail (SWFDEC_IS_VALID_XML_NODE (node), NULL);
171 if (prefix == NULL || strlen (prefix) == 0) {
172 var = swfdec_as_context_get_string (swfdec_gc_object_get_context (node),
173 "xmlns");
174 } else {
175 var = swfdec_as_context_give_string (swfdec_gc_object_get_context (node),
176 g_strconcat ("xmlns:", prefix, NULL));
179 do {
180 swfdec_as_object_get_variable (node->attributes, var, &val);
181 if (!SWFDEC_AS_VALUE_IS_UNDEFINED (val)) {
182 return swfdec_as_value_to_string (swfdec_gc_object_get_context (node), val);
184 node = node->parent;
185 } while (node != NULL);
187 return NULL;
190 typedef struct {
191 const char *namespace;
192 const char *variable;
193 } ForeachFindNamespaceData;
195 static gboolean
196 swfdec_xml_node_foreach_find_namespace (SwfdecAsObject *object,
197 const char *variable, SwfdecAsValue *value, guint flags, gpointer data)
199 const char *uri;
200 ForeachFindNamespaceData *fdata = data;
202 // check whether it's namespace variable (xmlns or xmlns:*)
203 if (strlen (variable) < strlen("xmlns"))
204 return TRUE;
206 if (g_ascii_strncasecmp (variable, "xmlns", strlen("xmlns")))
207 return TRUE;
209 if (variable[strlen("xmlns")] != '\0' && variable[strlen("xmlns")] != ':')
210 return TRUE;
212 // ok, now check if the uri is the one we are searching for
213 uri = swfdec_as_value_to_string (object->context, *value);
214 if (!g_ascii_strcasecmp (uri, fdata->namespace)) {
215 fdata->variable = variable;
216 return FALSE;
217 } else {
218 return TRUE;
222 static const char *
223 swfdec_xml_node_getPrefixForNamespace (SwfdecXmlNode *node,
224 const char *namespace)
226 ForeachFindNamespaceData fdata;
228 g_return_val_if_fail (SWFDEC_IS_VALID_XML_NODE (node), NULL);
229 g_return_val_if_fail (namespace != NULL, NULL);
231 fdata.namespace = namespace;
232 fdata.variable = NULL;
234 do {
235 swfdec_as_object_foreach (node->attributes,
236 swfdec_xml_node_foreach_find_namespace, &fdata);
237 node = node->parent;
238 } while (node != NULL && fdata.variable == NULL);
240 if (fdata.variable != NULL) {
241 const char *p;
243 p = strchr (fdata.variable, ':');
244 if (p == NULL || *(p + 1) == '\0')
245 return SWFDEC_AS_STR_EMPTY;
247 return swfdec_as_context_get_string (swfdec_gc_object_get_context (node),
248 p + 1);
249 } else {
250 return NULL;
254 static void
255 swfdec_xml_node_get_nodeType (SwfdecAsContext *cx, SwfdecAsObject *object,
256 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
258 SwfdecXmlNode *node;
260 SWFDEC_AS_CHECK (SWFDEC_TYPE_XML_NODE, &node, "");
262 if (!SWFDEC_IS_VALID_XML_NODE (node))
263 return;
265 *ret = swfdec_as_value_from_integer (cx, node->type);
268 static void
269 swfdec_xml_node_get_nodeValue (SwfdecAsContext *cx, SwfdecAsObject *object,
270 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
272 SwfdecXmlNode *node;
274 SWFDEC_AS_CHECK (SWFDEC_TYPE_XML_NODE, &node, "");
276 if (!SWFDEC_IS_VALID_XML_NODE (node))
277 return;
279 if (node->value != NULL) {
280 SWFDEC_AS_VALUE_SET_STRING (ret, node->value);
281 } else {
282 SWFDEC_AS_VALUE_SET_NULL (ret);
286 static void
287 swfdec_xml_node_set_nodeValue (SwfdecAsContext *cx, SwfdecAsObject *object,
288 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
290 SwfdecXmlNode *node;
291 const char *value;
293 SWFDEC_AS_CHECK (SWFDEC_TYPE_XML_NODE, &node, "s", &value);
295 if (!SWFDEC_IS_VALID_XML_NODE (node))
296 return;
298 node->value = value;
299 SWFDEC_AS_VALUE_SET_STRING (ret, value);
302 static void
303 swfdec_xml_node_get_nodeName (SwfdecAsContext *cx, SwfdecAsObject *object,
304 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
306 SwfdecXmlNode *node;
308 SWFDEC_AS_CHECK (SWFDEC_TYPE_XML_NODE, &node, "");
310 if (!SWFDEC_IS_VALID_XML_NODE (node))
311 return;
313 if (node->name != NULL) {
314 SWFDEC_AS_VALUE_SET_STRING (ret, node->name);
315 } else {
316 SWFDEC_AS_VALUE_SET_NULL (ret);
320 static void
321 swfdec_xml_node_set_nodeName (SwfdecAsContext *cx, SwfdecAsObject *object,
322 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
324 SwfdecXmlNode *node;
325 const char *name;
327 SWFDEC_AS_CHECK (SWFDEC_TYPE_XML_NODE, &node, "s", &name);
329 if (!SWFDEC_IS_VALID_XML_NODE (node))
330 return;
332 // special case
333 if (SWFDEC_AS_VALUE_IS_UNDEFINED (argv[0]))
334 return;
336 node->name = name;
337 SWFDEC_AS_VALUE_SET_STRING (ret, name);
340 static const char *
341 swfdec_xml_node_get_prefix (SwfdecXmlNode *node)
343 const char *p;
345 g_return_val_if_fail (SWFDEC_IS_VALID_XML_NODE (node), NULL);
347 if (node->name == NULL)
348 return NULL;
350 p = strchr (node->name, ':');
351 if (p == NULL || *(p + 1) == '\0')
352 return NULL;
354 return swfdec_as_context_give_string (swfdec_gc_object_get_context (node),
355 g_strndup (node->name, p - node->name));
358 static void
359 swfdec_xml_node_do_get_prefix (SwfdecAsContext *cx, SwfdecAsObject *object,
360 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
362 const char *prefix;
363 SwfdecXmlNode *node;
365 SWFDEC_AS_CHECK (SWFDEC_TYPE_XML_NODE, &node, "");
367 if (!SWFDEC_IS_VALID_XML_NODE (node))
368 return;
370 if (node->name == NULL) {
371 SWFDEC_AS_VALUE_SET_NULL (ret);
372 return;
375 prefix = swfdec_xml_node_get_prefix (node);
376 if (prefix != NULL) {
377 SWFDEC_AS_VALUE_SET_STRING (ret, prefix);
378 } else {
379 SWFDEC_AS_VALUE_SET_STRING (ret, SWFDEC_AS_STR_EMPTY);
383 static void
384 swfdec_xml_node_get_localName (SwfdecAsContext *cx, SwfdecAsObject *object,
385 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
387 const char *p, *name;
388 SwfdecXmlNode *node;
390 SWFDEC_AS_CHECK (SWFDEC_TYPE_XML_NODE, &node, "");
392 if (!SWFDEC_IS_VALID_XML_NODE (node))
393 return;
395 if (node->name == NULL) {
396 SWFDEC_AS_VALUE_SET_NULL (ret);
397 return;
400 name = node->name;
401 p = strchr (name, ':');
402 if (p == NULL || *(p + 1) == '\0') {
403 SWFDEC_AS_VALUE_SET_STRING (ret, name);
404 return;
406 p++;
408 SWFDEC_AS_VALUE_SET_STRING (ret,
409 swfdec_as_context_get_string (cx, p));
412 static void
413 swfdec_xml_node_get_namespaceURI (SwfdecAsContext *cx, SwfdecAsObject *object,
414 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
416 const char *uri;
417 SwfdecXmlNode *node;
419 SWFDEC_AS_CHECK (SWFDEC_TYPE_XML_NODE, &node, "");
421 if (!SWFDEC_IS_VALID_XML_NODE (node))
422 return;
424 if (node->name == NULL) {
425 SWFDEC_AS_VALUE_SET_NULL (ret);
426 return;
429 uri = swfdec_xml_node_getNamespaceForPrefix (node,
430 swfdec_xml_node_get_prefix (node));
431 if (uri != NULL) {
432 SWFDEC_AS_VALUE_SET_STRING (ret, uri);
433 } else {
434 SWFDEC_AS_VALUE_SET_STRING (ret, SWFDEC_AS_STR_EMPTY);
438 static void
439 swfdec_xml_node_get_attributes (SwfdecAsContext *cx, SwfdecAsObject *object,
440 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
442 SwfdecXmlNode *node;
444 SWFDEC_AS_CHECK (SWFDEC_TYPE_XML_NODE, &node, "");
446 if (!SWFDEC_IS_VALID_XML_NODE (node))
447 return;
449 SWFDEC_AS_VALUE_SET_OBJECT (ret, node->attributes);
452 static void
453 swfdec_xml_node_get_parentNode (SwfdecAsContext *cx, SwfdecAsObject *object,
454 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
456 SwfdecXmlNode *node;
458 SWFDEC_AS_CHECK (SWFDEC_TYPE_XML_NODE, &node, "");
460 if (!SWFDEC_IS_VALID_XML_NODE (node))
461 return;
463 if (node->parent != NULL) {
464 SWFDEC_AS_VALUE_SET_OBJECT (ret,
465 swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (node->parent)));
466 } else {
467 SWFDEC_AS_VALUE_SET_NULL (ret);
471 static SwfdecXmlNode *
472 swfdec_xml_node_previousSibling (SwfdecXmlNode *node)
474 gint32 i;
476 if (node->parent == NULL)
477 return NULL;
479 i = swfdec_xml_node_index_of_child (node->parent, node);
480 g_assert (i >= 0);
482 if (i <= 0)
483 return NULL;
485 return swfdec_xml_node_get_child (node->parent, i - 1);
488 static void
489 swfdec_xml_node_get_previousSibling (SwfdecAsContext *cx,
490 SwfdecAsObject *object, guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
492 SwfdecXmlNode *sibling;
493 SwfdecXmlNode *node;
495 SWFDEC_AS_CHECK (SWFDEC_TYPE_XML_NODE, &node, "");
497 if (!SWFDEC_IS_VALID_XML_NODE (node))
498 return;
500 sibling = swfdec_xml_node_previousSibling (node);
501 if (sibling != NULL) {
502 SWFDEC_AS_VALUE_SET_OBJECT (ret, swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (sibling)));
503 } else {
504 SWFDEC_AS_VALUE_SET_NULL (ret);
508 static SwfdecXmlNode *
509 swfdec_xml_node_nextSibling (SwfdecXmlNode *node)
511 gint32 i;
513 if (node->parent == NULL)
514 return NULL;
516 i = swfdec_xml_node_index_of_child (node->parent, node);
517 g_assert (i >= 0);
519 return swfdec_xml_node_get_child (node->parent, i + 1);
522 static void
523 swfdec_xml_node_get_nextSibling (SwfdecAsContext *cx, SwfdecAsObject *object,
524 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
526 SwfdecXmlNode *sibling;
527 SwfdecXmlNode *node;
529 SWFDEC_AS_CHECK (SWFDEC_TYPE_XML_NODE, &node, "");
531 if (!SWFDEC_IS_VALID_XML_NODE (node))
532 return;
534 sibling = swfdec_xml_node_nextSibling (node);
535 if (sibling != NULL) {
536 SWFDEC_AS_VALUE_SET_OBJECT (ret, swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (sibling)));
537 } else {
538 SWFDEC_AS_VALUE_SET_NULL (ret);
542 static void
543 swfdec_xml_node_get_firstChild (SwfdecAsContext *cx, SwfdecAsObject *object,
544 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
546 SwfdecXmlNode *child;
547 SwfdecXmlNode *node;
549 SWFDEC_AS_CHECK (SWFDEC_TYPE_XML_NODE, &node, "");
551 if (!SWFDEC_IS_VALID_XML_NODE (node))
552 return;
554 child = swfdec_xml_node_get_child (node, 0);
555 if (child != NULL) {
556 SWFDEC_AS_VALUE_SET_OBJECT (ret, swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (child)));
557 } else {
558 SWFDEC_AS_VALUE_SET_NULL (ret);
562 static void
563 swfdec_xml_node_get_lastChild (SwfdecAsContext *cx, SwfdecAsObject *object,
564 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
566 gint32 num;
567 SwfdecXmlNode *child;
568 SwfdecXmlNode *node;
570 SWFDEC_AS_CHECK (SWFDEC_TYPE_XML_NODE, &node, "");
572 if (!SWFDEC_IS_VALID_XML_NODE (node))
573 return;
575 num = swfdec_xml_node_num_children (node);
576 if (num == 0) {
577 SWFDEC_AS_VALUE_SET_NULL (ret);
578 return;
581 child = swfdec_xml_node_get_child (node, num - 1);
582 g_assert (child != NULL);
584 SWFDEC_AS_VALUE_SET_OBJECT (ret, swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (child)));
587 static void
588 swfdec_xml_node_get_childNodes (SwfdecAsContext *cx, SwfdecAsObject *object,
589 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
591 SwfdecXmlNode *node;
593 SWFDEC_AS_CHECK (SWFDEC_TYPE_XML_NODE, &node, "");
595 if (!SWFDEC_IS_VALID_XML_NODE (node))
596 return;
598 SWFDEC_AS_VALUE_SET_OBJECT (ret, node->child_nodes);
601 SWFDEC_AS_NATIVE (253, 7, swfdec_xml_node_do_getNamespaceForPrefix)
602 void
603 swfdec_xml_node_do_getNamespaceForPrefix (SwfdecAsContext *cx,
604 SwfdecAsObject *object, guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
606 const char *namespace, *prefix;
607 SwfdecXmlNode *node;
609 SWFDEC_AS_CHECK (SWFDEC_TYPE_XML_NODE, &node, "|s", &prefix);
611 if (!SWFDEC_IS_VALID_XML_NODE (node))
612 return;
614 if (argc < 1) {
615 SWFDEC_AS_VALUE_SET_NULL (ret);
616 return;
619 namespace = swfdec_xml_node_getNamespaceForPrefix (node, prefix);
621 if (namespace != NULL) {
622 SWFDEC_AS_VALUE_SET_STRING (ret, namespace);
623 } else {
624 SWFDEC_AS_VALUE_SET_NULL (ret);
628 SWFDEC_AS_NATIVE (253, 8, swfdec_xml_node_do_getPrefixForNamespace)
629 void
630 swfdec_xml_node_do_getPrefixForNamespace (SwfdecAsContext *cx,
631 SwfdecAsObject *object, guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
633 const char *namespace, *prefix;
634 SwfdecXmlNode *node;
636 SWFDEC_AS_CHECK (SWFDEC_TYPE_XML_NODE, &node, "|s", &namespace);
638 if (!SWFDEC_IS_VALID_XML_NODE (node))
639 return;
641 if (argc < 1) {
642 SWFDEC_AS_VALUE_SET_NULL (ret);
643 return;
646 prefix = swfdec_xml_node_getPrefixForNamespace (node, namespace);
648 if (prefix != NULL) {
649 SWFDEC_AS_VALUE_SET_STRING (ret, prefix);
650 } else {
651 SWFDEC_AS_VALUE_SET_NULL (ret);
655 static gboolean
656 swfdec_xml_node_foreach_copy_attributes (SwfdecAsObject *object,
657 const char *variable, SwfdecAsValue *value, guint flags, gpointer data)
659 SwfdecAsObject *target = data;
660 swfdec_as_object_set_variable (target, variable, value);
661 return TRUE;
664 static void
665 swfdec_xml_node_copy_attributes (SwfdecXmlNode *node, SwfdecXmlNode *target)
667 swfdec_as_object_foreach (node->attributes,
668 swfdec_xml_node_foreach_copy_attributes, target->attributes);
671 static SwfdecXmlNode *
672 swfdec_xml_node_clone (SwfdecAsContext *cx, SwfdecXmlNode *node, gboolean deep)
674 SwfdecXmlNode *new;
676 g_assert (SWFDEC_IS_AS_CONTEXT (cx));
677 g_assert (SWFDEC_IS_VALID_XML_NODE (node));
679 new = swfdec_xml_node_new (cx, SWFDEC_XML_NODE_ELEMENT, SWFDEC_AS_STR_EMPTY);
681 new->valid = TRUE;
682 new->type = node->type;
683 new->name = node->name;
684 new->value = node->value;
686 swfdec_xml_node_copy_attributes (node, new);
688 if (deep) {
689 SwfdecAsValue val;
690 SwfdecXmlNode *child, *child_new;
691 gint32 num, i;
693 num = swfdec_xml_node_num_children (node);
695 for (i = 0; i < num; i++) {
696 child = swfdec_xml_node_get_child (node, i);
697 child_new = swfdec_xml_node_clone (cx, child, TRUE);
698 child_new->parent = new;
699 SWFDEC_AS_VALUE_SET_OBJECT (&val, swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (child_new)));
700 swfdec_as_array_push (new->children, &val);
703 swfdec_xml_node_update_child_nodes (new);
706 return new;
709 SWFDEC_AS_NATIVE (253, 1, swfdec_xml_node_cloneNode)
710 void
711 swfdec_xml_node_cloneNode (SwfdecAsContext *cx, SwfdecAsObject *object,
712 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
714 gboolean deep = FALSE;
715 SwfdecXmlNode *new, *node;
717 SWFDEC_AS_CHECK (SWFDEC_TYPE_XML_NODE, &node, "|b", &deep);
719 if (!SWFDEC_IS_VALID_XML_NODE (node))
720 return;
722 new = swfdec_xml_node_clone (cx, node, deep);
724 SWFDEC_AS_VALUE_SET_OBJECT (ret, swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (new)));
727 void
728 swfdec_xml_node_removeNode (SwfdecXmlNode *node)
730 gint32 i;
732 g_return_if_fail (SWFDEC_IS_VALID_XML_NODE (node));
734 if (node->parent == NULL)
735 return;
737 i = swfdec_xml_node_index_of_child (node->parent, node);
738 g_assert (i >= 0);
740 swfdec_as_array_remove (node->parent->children, i);
741 swfdec_xml_node_update_child_nodes (node->parent);
742 node->parent = NULL;
745 SWFDEC_AS_NATIVE (253, 2, swfdec_xml_node_do_removeNode)
746 void
747 swfdec_xml_node_do_removeNode (SwfdecAsContext *cx, SwfdecAsObject *object,
748 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
750 SwfdecXmlNode *node;
752 SWFDEC_AS_CHECK (SWFDEC_TYPE_XML_NODE, &node, "");
754 if (!SWFDEC_IS_VALID_XML_NODE (node))
755 return;
757 swfdec_xml_node_removeNode (node);
760 void
761 swfdec_xml_node_removeChildren (SwfdecXmlNode *node)
763 gint32 num, i;
765 g_return_if_fail (SWFDEC_IS_VALID_XML_NODE (node));
767 num = swfdec_xml_node_num_children (node);
769 for (i = 0; i < num; i++) {
770 swfdec_xml_node_removeNode (swfdec_xml_node_get_child (node, 0));
774 static void
775 swfdec_xml_node_insertAt (SwfdecXmlNode *node, SwfdecXmlNode *child, gint32 ind)
777 SwfdecAsValue val;
779 g_assert (SWFDEC_IS_VALID_XML_NODE (node));
780 g_assert (SWFDEC_IS_VALID_XML_NODE (child));
781 g_assert (ind >= 0);
783 if (swfdec_gc_object_get_context (node)->version >= 8) {
784 SwfdecXmlNode *parent = node;
785 while (parent != NULL) {
786 if (parent == child)
787 return;
788 parent = parent->parent;
792 // remove the previous parent of the child
793 swfdec_xml_node_removeNode (child);
795 // insert child to node's child_nodes array
796 SWFDEC_AS_VALUE_SET_OBJECT (&val, swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (child)));
797 swfdec_as_array_insert (node->children, ind, &val);
798 swfdec_xml_node_update_child_nodes (node);
800 // set node as parent of child
801 child->parent = node;
804 SWFDEC_AS_NATIVE (253, 3, swfdec_xml_node_insertBefore)
805 void
806 swfdec_xml_node_insertBefore (SwfdecAsContext *cx, SwfdecAsObject *object,
807 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
809 gint32 i;
810 SwfdecAsObject *child, *point;
811 SwfdecXmlNode *node, *child_node, *point_node;
813 SWFDEC_AS_CHECK (SWFDEC_TYPE_XML_NODE, &node, "oo", &child, &point);
815 if (!SWFDEC_IS_VALID_XML_NODE (node) ||
816 !SWFDEC_IS_VALID_XML_NODE (child->relay) ||
817 !SWFDEC_IS_VALID_XML_NODE (point->relay))
818 return;
820 child_node = SWFDEC_XML_NODE (child->relay);
821 point_node = SWFDEC_XML_NODE (point->relay);
823 // special case
824 if (swfdec_xml_node_index_of_child (node, child_node) != -1)
825 return;
827 i = swfdec_xml_node_index_of_child (node, point_node);
829 if (i != -1) {
830 swfdec_xml_node_insertAt (node, child_node, i);
834 void
835 swfdec_xml_node_appendChild (SwfdecXmlNode *node, SwfdecXmlNode *child)
837 g_return_if_fail (SWFDEC_IS_VALID_XML_NODE (node));
838 g_return_if_fail (SWFDEC_IS_VALID_XML_NODE (child));
839 g_return_if_fail (node->children != NULL);
841 swfdec_xml_node_insertAt (node, child,
842 swfdec_as_array_get_length (node->children));
845 SWFDEC_AS_NATIVE (253, 4, swfdec_xml_node_do_appendChild)
846 void
847 swfdec_xml_node_do_appendChild (SwfdecAsContext *cx, SwfdecAsObject *object,
848 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
850 SwfdecAsObject *child;
851 SwfdecXmlNode *node, *child_node;
853 SWFDEC_AS_CHECK (SWFDEC_TYPE_XML_NODE, &node, "o", &child);
855 if (!SWFDEC_IS_VALID_XML_NODE (node) ||
856 !SWFDEC_IS_VALID_XML_NODE (child->relay))
857 return;
859 child_node = SWFDEC_XML_NODE (child->relay);
861 // special case
862 if (swfdec_xml_node_index_of_child (node, child_node) != -1)
863 return;
865 swfdec_xml_node_appendChild (node, child_node);
868 SWFDEC_AS_NATIVE (253, 5, swfdec_xml_node_hasChildNodes)
869 void
870 swfdec_xml_node_hasChildNodes (SwfdecAsContext *cx, SwfdecAsObject *object,
871 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
873 SwfdecXmlNode *node;
875 SWFDEC_AS_CHECK (SWFDEC_TYPE_XML_NODE, &node, "");
877 if (!SWFDEC_IS_VALID_XML_NODE (node))
878 return;
880 SWFDEC_AS_VALUE_SET_BOOLEAN (ret,
881 swfdec_xml_node_num_children (node) > 0);
884 static gboolean
885 swfdec_xml_node_foreach_string_append_attribute (SwfdecAsObject *object,
886 const char *variable, SwfdecAsValue *value, guint flags, gpointer data)
888 GString *string = *(GString **)data;
889 char *escaped;
891 string = g_string_append (string, " ");
892 string = g_string_append (string, variable);
893 string = g_string_append (string, "=\"");
894 escaped =
895 swfdec_xml_escape (swfdec_as_value_to_string (object->context, *value));
896 string = g_string_append (string, escaped);
897 g_free (escaped);
898 string = g_string_append (string, "\"");
900 return TRUE;
903 static const char *
904 swfdec_xml_node_toString (SwfdecXmlNode *node)
906 GString *string;
908 g_assert (SWFDEC_IS_VALID_XML_NODE (node));
910 string = g_string_new ("");
911 if (SWFDEC_IS_XML (node)) {
912 if (SWFDEC_XML (node)->xml_decl != NULL)
913 string = g_string_append (string, SWFDEC_XML (node)->xml_decl);
914 if (SWFDEC_XML (node)->doc_type_decl != NULL)
915 string = g_string_append (string, SWFDEC_XML (node)->doc_type_decl);
918 switch (node->type) {
919 case SWFDEC_XML_NODE_ELEMENT:
921 SwfdecXmlNode *child;
922 gint32 i, num;
923 gboolean visible;
925 if (node->name == NULL) {
926 visible = FALSE;
927 } else {
928 visible = TRUE;
931 if (visible) {
932 string = g_string_append (string, "<");
933 string = g_string_append (string, node->name);
935 swfdec_as_object_foreach (node->attributes,
936 swfdec_xml_node_foreach_string_append_attribute, &string);
939 num = swfdec_xml_node_num_children (node);
941 if (num > 0) {
942 if (visible)
943 string = g_string_append (string, ">");
945 for (i = 0; i < num; i++) {
946 child = swfdec_xml_node_get_child (node, i);
947 g_assert (child != NULL);
948 string = g_string_append (string, swfdec_xml_node_toString (child));
951 if (visible) {
952 string = g_string_append (string, "</");
953 string = g_string_append (string, node->name);
954 string = g_string_append (string, ">");
956 } else {
957 if (visible)
958 string = g_string_append (string, " />");
961 break;
963 case SWFDEC_XML_NODE_TEXT:
964 default:
966 char *escaped = swfdec_xml_escape (node->value);
967 string = g_string_append (string, escaped);
968 g_free (escaped);
969 break;
973 return swfdec_as_context_give_string (swfdec_gc_object_get_context (node),
974 g_string_free (string, FALSE));
977 SWFDEC_AS_NATIVE (253, 6, swfdec_xml_node_do_toString)
978 void
979 swfdec_xml_node_do_toString (SwfdecAsContext *cx, SwfdecAsObject *object,
980 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
982 SwfdecXmlNode *node;
984 SWFDEC_AS_CHECK (SWFDEC_TYPE_XML_NODE, &node, "");
986 if (!SWFDEC_IS_VALID_XML_NODE (node))
987 return;
989 SWFDEC_AS_VALUE_SET_STRING (ret, swfdec_xml_node_toString (node));
992 void
993 swfdec_xml_node_init_values (SwfdecXmlNode *node, int type, const char* value)
995 SwfdecAsContext *cx;
997 g_return_if_fail (SWFDEC_IS_XML_NODE (node));
998 g_return_if_fail (value != NULL);
1000 cx = swfdec_gc_object_get_context (node);
1002 node->valid = TRUE;
1003 node->parent = NULL;
1004 node->children = swfdec_as_array_new (cx);
1005 node->attributes = swfdec_as_object_new_empty (cx);
1006 node->type = type;
1007 if (node->type == SWFDEC_XML_NODE_ELEMENT) {
1008 node->name = value;
1009 } else {
1010 node->value = value;
1013 node->child_nodes = swfdec_as_array_new (cx);
1016 static void
1017 swfdec_xml_node_init_properties (SwfdecAsContext *cx)
1019 SwfdecAsValue val;
1020 SwfdecAsObject *node, *proto;
1022 // FIXME: We should only initialize if the prototype Object has not been
1023 // initialized by any object's constructor with native properties
1024 // (TextField, TextFormat, XML, XMLNode at least)
1026 g_return_if_fail (SWFDEC_IS_AS_CONTEXT (cx));
1028 swfdec_as_object_get_variable (cx->global, SWFDEC_AS_STR_XMLNode, &val);
1029 if (!SWFDEC_AS_VALUE_IS_OBJECT (val))
1030 return;
1031 node = SWFDEC_AS_VALUE_GET_OBJECT (val);
1033 swfdec_as_object_get_variable (node, SWFDEC_AS_STR_prototype, &val);
1034 if (!SWFDEC_AS_VALUE_IS_OBJECT (val))
1035 return;
1036 proto = SWFDEC_AS_VALUE_GET_OBJECT (val);
1038 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_nodeType,
1039 swfdec_xml_node_get_nodeType, NULL);
1040 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_nodeValue,
1041 swfdec_xml_node_get_nodeValue, swfdec_xml_node_set_nodeValue);
1042 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_nodeName,
1043 swfdec_xml_node_get_nodeName, swfdec_xml_node_set_nodeName);
1044 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_prefix,
1045 swfdec_xml_node_do_get_prefix, NULL);
1046 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_localName,
1047 swfdec_xml_node_get_localName, NULL);
1048 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_namespaceURI,
1049 swfdec_xml_node_get_namespaceURI, NULL);
1050 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_attributes,
1051 swfdec_xml_node_get_attributes, NULL);
1052 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_parentNode,
1053 swfdec_xml_node_get_parentNode, NULL);
1054 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_previousSibling,
1055 swfdec_xml_node_get_previousSibling, NULL);
1056 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_nextSibling,
1057 swfdec_xml_node_get_nextSibling, NULL);
1058 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_firstChild,
1059 swfdec_xml_node_get_firstChild, NULL);
1060 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_lastChild,
1061 swfdec_xml_node_get_lastChild, NULL);
1062 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_childNodes,
1063 swfdec_xml_node_get_childNodes, NULL);
1066 SwfdecXmlNode *
1067 swfdec_xml_node_new_no_properties (SwfdecAsContext *context,
1068 SwfdecXmlNodeType type, const char* value)
1070 SwfdecXmlNode *node;
1071 SwfdecAsObject *object;
1073 g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (context), NULL);
1074 g_return_val_if_fail (value != NULL, NULL);
1076 object = swfdec_as_object_new (context, NULL);
1077 swfdec_as_object_set_constructor_by_name (object,
1078 SWFDEC_AS_STR_XMLNode, NULL);
1080 node = g_object_new (SWFDEC_TYPE_XML_NODE, "context", context, NULL);
1081 swfdec_as_object_set_relay (object, SWFDEC_AS_RELAY (node));
1082 swfdec_xml_node_init_values (node, type, value);
1084 return node;
1087 SwfdecXmlNode *
1088 swfdec_xml_node_new (SwfdecAsContext *context, SwfdecXmlNodeType type,
1089 const char* value)
1091 g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (context), NULL);
1093 swfdec_xml_node_init_properties (context);
1095 return swfdec_xml_node_new_no_properties (context, type, value);
1098 SWFDEC_AS_NATIVE (253, 0, swfdec_xml_node_construct)
1099 void
1100 swfdec_xml_node_construct (SwfdecAsContext *cx, SwfdecAsObject *object,
1101 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
1103 SwfdecXmlNode *node;
1104 const char *value;
1105 int type;
1107 if (!swfdec_as_context_is_constructing (cx))
1108 return;
1110 SWFDEC_AS_CHECK (0, NULL, "is", &type, &value);
1112 if (SWFDEC_AS_VALUE_IS_UNDEFINED (argv[0]) ||
1113 SWFDEC_AS_VALUE_IS_UNDEFINED (argv[1]))
1114 return;
1116 swfdec_xml_node_init_properties (cx);
1118 node = g_object_new (SWFDEC_TYPE_XML_NODE, "context", cx, NULL);
1119 swfdec_as_object_set_relay (object, SWFDEC_AS_RELAY (node));
1120 swfdec_xml_node_init_values (node, type, value);
1122 SWFDEC_AS_VALUE_SET_OBJECT (ret, object);