convert swfdec_as_value_to_number() to use a SwfdecValue
[swfdec.git] / swfdec / swfdec_xml.c
blob706d9207db15966ffed4017f1daf1ed5af51d32c
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 <math.h>
26 #include <string.h>
28 #include "swfdec_xml.h"
29 #include "swfdec_xml_node.h"
30 #include "swfdec_as_native_function.h"
31 #include "swfdec_as_array.h"
32 #include "swfdec_as_object.h"
33 #include "swfdec_as_strings.h"
34 #include "swfdec_debug.h"
35 #include "swfdec_internal.h"
36 #include "swfdec_as_internal.h"
37 #include "swfdec_player_internal.h"
39 G_DEFINE_TYPE (SwfdecXml, swfdec_xml, SWFDEC_TYPE_XML_NODE)
41 static void
42 swfdec_xml_mark (SwfdecGcObject *object)
44 SwfdecXml *xml = SWFDEC_XML (object);
46 if (xml->xml_decl != NULL)
47 swfdec_as_string_mark (xml->xml_decl);
48 if (xml->doc_type_decl != NULL)
49 swfdec_as_string_mark (xml->doc_type_decl);
51 swfdec_as_value_mark (&xml->content_type);
52 swfdec_as_value_mark (&xml->loaded);
54 SWFDEC_GC_OBJECT_CLASS (swfdec_xml_parent_class)->mark (object);
57 static void
58 swfdec_xml_class_init (SwfdecXmlClass *klass)
60 SwfdecGcObjectClass *gc_class = SWFDEC_GC_OBJECT_CLASS (klass);
62 gc_class->mark = swfdec_xml_mark;
65 static void
66 swfdec_xml_init (SwfdecXml *xml)
68 SWFDEC_AS_VALUE_SET_STRING (&xml->content_type,
69 SWFDEC_AS_STR_application_x_www_form_urlencoded);
72 typedef struct {
73 const char character;
74 const char *escaped;
75 } EntityConversion;
77 static EntityConversion xml_entities[] = {
78 { '&', "&amp;" },
79 { '"', "&quot;" },
80 { '\'', "&apos;" },
81 { '<', "&lt;" },
82 { '>', "&gt;" },
83 { '\xa0', "&nbsp;" },
84 { '\0', NULL }
87 char *
88 swfdec_xml_escape_len (const char *orginal, gssize length)
90 int i;
91 const char *p, *start;
92 GString *string;
94 string = g_string_new ("");
96 // Note: we don't escape non-breaking space to &nbsp;
97 p = start = orginal;
98 while (*(p += strcspn (p, "&<>\"'")) != '\0' && p - orginal < length) {
99 string = g_string_append_len (string, start, p - start);
101 // escape it
102 for (i = 0; xml_entities[i].escaped != NULL; i++) {
103 if (xml_entities[i].character == *p) {
104 string = g_string_append (string, xml_entities[i].escaped);
105 break;
108 g_assert (xml_entities[i].escaped != NULL);
110 p++;
111 start = p;
113 string = g_string_append_len (string, start, length - (start - orginal));
115 return g_string_free (string, FALSE);
118 char *
119 swfdec_xml_escape (const char *orginal)
121 return swfdec_xml_escape_len (orginal, strlen (orginal));
124 char *
125 swfdec_xml_unescape_len (SwfdecAsContext *cx, const char *orginal,
126 gssize length, gboolean unescape_nbsp)
128 int i;
129 const char *p, *start, *end;
130 GString *string;
132 string = g_string_new ("");
134 p = start = orginal;
135 end = orginal + length;
136 while ((p = memchr (p, '&', end - p)) != NULL) {
137 string = g_string_append_len (string, start, p - start);
139 for (i = 0; xml_entities[i].escaped != NULL; i++) {
140 if (!g_ascii_strncasecmp (p, xml_entities[i].escaped,
141 strlen (xml_entities[i].escaped))) {
142 // FIXME: Do this cleaner
143 if (xml_entities[i].character == '\xa0') {
144 if (unescape_nbsp)
145 string = g_string_append_c (string, '\xc2');
146 else
147 continue;
149 string = g_string_append_c (string, xml_entities[i].character);
150 p += strlen (xml_entities[i].escaped);
151 break;
154 if (xml_entities[i].escaped == NULL) {
155 string = g_string_append_c (string, '&');
156 p++;
159 start = p;
161 string = g_string_append_len (string, start, length - (start - orginal));
163 return g_string_free (string, FALSE);
166 char *
167 swfdec_xml_unescape (SwfdecAsContext *cx, const char *orginal)
169 return swfdec_xml_unescape_len (cx, orginal, strlen (orginal), TRUE);
172 // this is never declared, only available as ASnative (100, 5)
173 SWFDEC_AS_NATIVE (100, 5, swfdec_xml_do_escape)
174 void
175 swfdec_xml_do_escape (SwfdecAsContext *cx, SwfdecAsObject *object,
176 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
178 const char *s;
179 char *escaped;
181 SWFDEC_AS_CHECK (0, NULL, "s", &s);
183 escaped = swfdec_xml_escape (s);
184 SWFDEC_AS_VALUE_SET_STRING (ret, swfdec_as_context_give_string (cx, escaped));
187 static void
188 swfdec_xml_get_ignoreWhite (SwfdecAsContext *cx, SwfdecAsObject *object,
189 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
191 SwfdecXml *xml;
193 SWFDEC_AS_CHECK (SWFDEC_TYPE_XML, &xml, "");
195 SWFDEC_AS_VALUE_SET_BOOLEAN (ret, xml->ignore_white);
198 static void
199 swfdec_xml_set_ignoreWhite (SwfdecAsContext *cx, SwfdecAsObject *object,
200 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
202 SwfdecXml *xml;
203 char *ignore;
205 SWFDEC_AS_CHECK (SWFDEC_TYPE_XML, &xml, "s", &ignore);
207 // special case
208 if (SWFDEC_AS_VALUE_IS_UNDEFINED (argv[0]))
209 return;
211 xml->ignore_white =
212 swfdec_as_value_to_boolean (cx, argv[0]);
215 static void
216 swfdec_xml_get_xmlDecl (SwfdecAsContext *cx, SwfdecAsObject *object,
217 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
219 SwfdecXml *xml;
221 SWFDEC_AS_CHECK (SWFDEC_TYPE_XML, &xml, "");
223 if (xml->xml_decl != NULL) {
224 SWFDEC_AS_VALUE_SET_STRING (ret, xml->xml_decl);
225 } else {
226 SWFDEC_AS_VALUE_SET_UNDEFINED (ret);
230 static void
231 swfdec_xml_set_xmlDecl (SwfdecAsContext *cx, SwfdecAsObject *object,
232 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
234 SwfdecXml *xml;
235 const char *s;
237 SWFDEC_AS_CHECK (SWFDEC_TYPE_XML, &xml, "s", &s);
239 // special case
240 if (SWFDEC_AS_VALUE_IS_UNDEFINED (argv[0]))
241 return;
243 xml->xml_decl = s;
246 static void
247 swfdec_xml_get_docTypeDecl (SwfdecAsContext *cx, SwfdecAsObject *object,
248 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
250 SwfdecXml *xml;
252 SWFDEC_AS_CHECK (SWFDEC_TYPE_XML, &xml, "");
254 if (xml->doc_type_decl != NULL) {
255 SWFDEC_AS_VALUE_SET_STRING (ret, xml->doc_type_decl);
256 } else {
257 SWFDEC_AS_VALUE_SET_UNDEFINED (ret);
261 static void
262 swfdec_xml_set_docTypeDecl (SwfdecAsContext *cx, SwfdecAsObject *object,
263 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
265 SwfdecXml *xml;
266 const char *s;
268 SWFDEC_AS_CHECK (SWFDEC_TYPE_XML, &xml, "s", &s);
270 // special case
271 if (SWFDEC_AS_VALUE_IS_UNDEFINED (argv[0]))
272 return;
274 xml->doc_type_decl = s;
277 static void
278 swfdec_xml_get_contentType (SwfdecAsContext *cx, SwfdecAsObject *object,
279 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
281 SwfdecXml *xml;
283 SWFDEC_AS_CHECK (SWFDEC_TYPE_XML, &xml, "");
285 *ret = xml->content_type;
288 static void
289 swfdec_xml_set_contentType (SwfdecAsContext *cx, SwfdecAsObject *object,
290 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
292 SwfdecXml *xml;
293 SwfdecAsValue val;
295 SWFDEC_AS_CHECK (SWFDEC_TYPE_XML, &xml, "v", &val);
297 // special case
298 if (SWFDEC_AS_VALUE_IS_UNDEFINED (val))
299 return;
301 xml->content_type = val;
304 static void
305 swfdec_xml_get_loaded (SwfdecAsContext *cx, SwfdecAsObject *object,
306 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
308 SwfdecXml *xml;
310 SWFDEC_AS_CHECK (SWFDEC_TYPE_XML, &xml, "");
312 *ret = xml->loaded;
315 static void
316 swfdec_xml_set_loaded (SwfdecAsContext *cx, SwfdecAsObject *object,
317 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
319 SwfdecXml *xml;
320 const char *ignore;
322 SWFDEC_AS_CHECK (SWFDEC_TYPE_XML, &xml, "s", &ignore);
324 // special case
325 if (SWFDEC_AS_VALUE_IS_UNDEFINED (argv[0]))
326 return;
328 SWFDEC_AS_VALUE_SET_BOOLEAN (&xml->loaded,
329 swfdec_as_value_to_boolean (cx, argv[0]));
332 static void
333 swfdec_xml_get_status (SwfdecAsContext *cx, SwfdecAsObject *object,
334 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
336 SwfdecXml *xml;
338 SWFDEC_AS_CHECK (SWFDEC_TYPE_XML, &xml, "");
340 swfdec_as_value_set_integer (cx, ret, xml->status);
343 static void
344 swfdec_xml_set_status (SwfdecAsContext *cx, SwfdecAsObject *object,
345 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
347 double d;
348 SwfdecXml *xml;
349 const char *ignore;
351 SWFDEC_AS_CHECK (SWFDEC_TYPE_XML, &xml, "s", &ignore);
353 // special case
354 if (SWFDEC_AS_VALUE_IS_UNDEFINED (argv[0]))
355 return;
357 d = swfdec_as_value_to_number (cx, *&argv[0]);
358 if (!isfinite (d))
359 xml->status = 0;
360 else
361 xml->status = d;
364 static const char *
365 swfdec_xml_parse_xmlDecl (SwfdecXml *xml, SwfdecXmlNode *node, const char *p)
367 const char *end;
368 GString *string;
370 g_assert (p != NULL);
371 g_return_val_if_fail (g_ascii_strncasecmp (p, "<?xml", strlen ("<?xml")) == 0,
372 strchr (p, '\0'));
373 g_return_val_if_fail (SWFDEC_IS_XML (xml), strchr (p, '\0'));
375 end = strstr (p, "?>");
376 if (end == NULL) {
377 xml->status = XML_PARSE_STATUS_XMLDECL_NOT_TERMINATED;
378 return strchr (p, '\0');
381 end += strlen ("?>");
383 string = g_string_new ((xml->xml_decl != NULL ? xml->xml_decl : ""));
384 string = g_string_append_len (string, p, end - p);
385 xml->xml_decl = swfdec_as_context_give_string (
386 swfdec_gc_object_get_context (xml), g_string_free (string, FALSE));
388 // in version 5 parsing xmlDecl or docType always adds undefined element to
389 // the childNodes array
390 if (swfdec_gc_object_get_context (xml)->version < 6)
391 SWFDEC_FIXME ("Need to add undefined element to childNodes array");
393 g_return_val_if_fail (end > p, strchr (p, '\0'));
395 return end;
398 static const char *
399 swfdec_xml_parse_docTypeDecl (SwfdecXml *xml, SwfdecXmlNode *node,
400 const char *p)
402 const char *end;
403 int open;
405 g_assert (p != NULL);
406 g_return_val_if_fail (
407 g_ascii_strncasecmp (p, "<!DOCTYPE", strlen ("<!DOCTYPE")) == 0,
408 strchr (p, '\0'));
409 g_return_val_if_fail (SWFDEC_IS_XML (xml), strchr (p, '\0'));
411 end = p + 1;
412 open = 1;
413 do {
414 end += strcspn (end, "<>");
415 if (*end == '<') {
416 open++;
417 end++;
418 } else if (*end == '>') {
419 open--;
420 end++;
422 } while (*end != '\0' && open > 0);
424 if (*end == '\0') {
425 xml->status = XML_PARSE_STATUS_DOCTYPEDECL_NOT_TERMINATED;
426 } else {
427 xml->doc_type_decl = swfdec_as_context_give_string (
428 swfdec_gc_object_get_context (xml), g_strndup (p, end - p));
430 // in version 5 parsing xmlDecl or docType always adds undefined element to
431 // the childNodes array
432 if (swfdec_gc_object_get_context (xml)->version < 6)
433 SWFDEC_FIXME ("Need to add undefined element to childNodes array");
436 g_return_val_if_fail (end > p, strchr (p, '\0'));
438 return end;
441 static const char *
442 swfdec_xml_parse_comment (SwfdecXml *xml, const char *p)
444 const char *end;
446 g_assert (p != NULL);
447 g_return_val_if_fail (strncmp (p, "<!--", strlen ("<!--")) == 0,
448 strchr (p, '\0'));
449 g_return_val_if_fail (SWFDEC_IS_XML (xml), strchr (p, '\0'));
451 end = strstr (p, "-->");
453 if (end == NULL) {
454 xml->status = XML_PARSE_STATUS_COMMENT_NOT_TERMINATED;
455 return strchr (p, '\0');
458 end += strlen("-->");
460 g_return_val_if_fail (end > p, strchr (p, '\0'));
462 return end;
465 static void
466 swfdec_xml_add_id_map (SwfdecXml *xml, SwfdecXmlNode *node, const char *id)
468 SwfdecAsObject *object;
469 SwfdecAsContext *context;
470 SwfdecAsValue val;
472 g_return_if_fail (SWFDEC_IS_XML (xml));
473 g_return_if_fail (SWFDEC_IS_XML_NODE (xml));
474 g_return_if_fail (id != NULL && id != SWFDEC_AS_STR_EMPTY);
476 context = swfdec_gc_object_get_context (xml);
477 object = swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (xml));
478 if (context->version >= 8) {
479 if (swfdec_as_object_get_variable (object,
480 SWFDEC_AS_STR_idMap, &val)) {
481 if (SWFDEC_AS_VALUE_IS_OBJECT (val)) {
482 object = SWFDEC_AS_VALUE_GET_OBJECT (val);
483 } else {
484 return;
486 } else {
487 object = swfdec_as_object_new_empty (context);
488 SWFDEC_AS_VALUE_SET_OBJECT (&val, object);
489 swfdec_as_object_set_variable (swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (xml)),
490 SWFDEC_AS_STR_idMap, &val);
494 SWFDEC_AS_VALUE_SET_OBJECT (&val, swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (node)));
495 swfdec_as_object_set_variable (object, id, &val);
498 static const char *
499 swfdec_xml_parse_attribute (SwfdecXml *xml, SwfdecXmlNode *node, const char *p)
501 SwfdecAsContext *cx;
502 SwfdecAsValue val;
503 const char *end, *name;
504 char *text;
506 g_return_val_if_fail (SWFDEC_IS_XML (xml), strchr (p, '\0'));
507 g_return_val_if_fail (SWFDEC_IS_XML_NODE (node), strchr (p, '\0'));
508 g_return_val_if_fail ((*p != '>' && *p != '\0'), p);
510 end = p + strcspn (p, "=> \r\n\t");
511 if (end - p <= 0) {
512 xml->status = XML_PARSE_STATUS_ELEMENT_MALFORMED;
513 return strchr (p, '\0');
516 cx = swfdec_gc_object_get_context (node);
517 text = g_strndup (p, end - p);
518 name = swfdec_as_context_give_string (cx, swfdec_xml_unescape (cx, text));
519 g_free (text);
521 p = end + strspn (end, " \r\n\t");
522 if (*p != '=') {
523 xml->status = XML_PARSE_STATUS_ELEMENT_MALFORMED;
524 return strchr (p, '\0');
526 p = p + 1 + strspn (p + 1, " \r\n\t");
528 if (*p != '"' && *p != '\'') {
529 xml->status = XML_PARSE_STATUS_ELEMENT_MALFORMED;
530 return strchr (p, '\0');
533 end = p + 1;
534 do {
535 end = strchr (end, *p);
536 } while (end != NULL && *(end - 1) == '\\');
538 if (end == NULL) {
539 xml->status = XML_PARSE_STATUS_ATTRIBUTE_NOT_TERMINATED;
540 return strchr (p, '\0');
543 if (!swfdec_as_object_get_variable (node->attributes, name, NULL)) {
544 char *unescaped;
545 const char *value;
547 unescaped = swfdec_xml_unescape_len (cx, p + 1, end - (p + 1), TRUE);
548 value = swfdec_as_context_give_string (cx, unescaped);
549 SWFDEC_AS_VALUE_SET_STRING (&val, value);
551 swfdec_as_object_set_variable (node->attributes, name, &val);
554 g_return_val_if_fail (end + 1 > p, strchr (p, '\0'));
556 return end + 1;
559 static const char *
560 swfdec_xml_parse_tag (SwfdecXml *xml, SwfdecXmlNode **node, const char *p)
562 SwfdecAsObject *object;
563 SwfdecAsContext *cx;
564 SwfdecXmlNode *child = NULL; // supress warning
565 char *name;
566 const char *end;
567 gboolean close;
569 g_assert (p != NULL);
570 g_return_val_if_fail (*p == '<', strchr (p, '\0'));
571 g_return_val_if_fail (SWFDEC_IS_XML (xml), strchr (p, '\0'));
573 object = swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (xml));
574 cx = swfdec_gc_object_get_context (xml);
576 // closing tag or opening tag?
577 if (*(p + 1) == '/') {
578 close = TRUE;
579 p++;
580 } else {
581 close = FALSE;
584 // find the end of the name
585 end = p + strcspn (p, "> \r\n\t");
587 // don't count trailing / as part of the name if it's followed by >
588 // note we do this for close tags also, so <test/ ></test/> doesn't work
589 if (*end == '>' && *(end - 1) == '/')
590 end = end - 1;
592 if (end - (p + 1) <= 0 || *end == '\0') {
593 xml->status = XML_PARSE_STATUS_ELEMENT_MALFORMED;
594 return strchr (p, '\0');
597 name = g_strndup (p + 1 , end - (p + 1));
599 if (close) {
600 end = strchr (end, '>');
601 if (end == NULL)
602 end = strchr (p, '\0');
603 } else {
604 // create the new element
605 child = swfdec_xml_node_new_no_properties (cx, SWFDEC_XML_NODE_ELEMENT,
606 swfdec_as_context_give_string (cx, name));
607 end = end + strspn (end, " \r\n\t");
608 while (*end != '\0' && *end != '>' && (*end != '/' || *(end + 1) != '>')) {
609 end = swfdec_xml_parse_attribute (xml, child, end);
610 end = end + strspn (end, " \r\n\t");
612 if (*end == '/')
613 end += 1;
616 if (*end == '\0') {
617 if (xml->status == XML_PARSE_STATUS_OK)
618 xml->status = XML_PARSE_STATUS_ELEMENT_MALFORMED;
619 if (close)
620 g_free (name);
621 return end;
624 if (close) {
625 if ((*node)->parent != NULL && !g_ascii_strcasecmp ((*node)->name, name)) {
626 *node = (*node)->parent;
627 } else {
628 /* error */
629 SwfdecXmlNode *iter = *node;
630 while (iter != NULL && (iter->name == NULL || g_ascii_strcasecmp (iter->name, name))) {
631 iter = iter->parent;
633 if (iter != NULL) {
634 xml->status = XML_PARSE_STATUS_TAG_NOT_CLOSED;
635 } else {
636 xml->status = XML_PARSE_STATUS_TAG_MISMATCH;
639 g_free (name);
640 } else {
641 const char *id;
643 swfdec_xml_node_appendChild (*node, child);
645 id = swfdec_xml_node_get_attribute (child, SWFDEC_AS_STR_id);
646 if (id != NULL)
647 swfdec_xml_add_id_map (xml, child, id);
649 if (*(end - 1) != '/')
650 *node = child;
653 end += 1;
655 g_return_val_if_fail (end > p, strchr (p, '\0'));
657 return end;
660 static const char *
661 swfdec_xml_parse_cdata (SwfdecXml *xml, SwfdecXmlNode *node, const char *p)
663 SwfdecAsContext *cx;
664 SwfdecXmlNode *child;
665 const char *end;
666 char *text;
668 g_assert (p != NULL);
669 g_return_val_if_fail (strncmp (p, "<![CDATA[", strlen ("<![CDATA[")) == 0,
670 strchr (p, '\0'));
671 g_return_val_if_fail (SWFDEC_IS_XML (xml), strchr (p, '\0'));
673 p += strlen ("<![CDATA[");
675 end = strstr (p, "]]>");
677 if (end == NULL) {
678 xml->status = XML_PARSE_STATUS_CDATA_NOT_TERMINATED;
679 return strchr (p, '\0');
682 text = g_strndup (p, end - p);
684 cx = swfdec_gc_object_get_context (xml);
685 child = swfdec_xml_node_new_no_properties (cx, SWFDEC_XML_NODE_TEXT,
686 swfdec_as_context_give_string (cx, text));
687 swfdec_xml_node_appendChild (node, child);
689 end += strlen("]]>");
691 g_return_val_if_fail (end > p, strchr (p, '\0'));
693 return end;
696 static const char *
697 swfdec_xml_parse_text (SwfdecXml *xml, SwfdecXmlNode *node,
698 const char *p, gboolean ignore_white)
700 SwfdecXmlNode *child;
701 const char *end;
702 char *text, *unescaped;
704 g_assert (p != NULL);
705 g_return_val_if_fail (*p != '\0', p);
706 g_return_val_if_fail (SWFDEC_IS_XML (xml), strchr (p, '\0'));
708 end = strchr (p, '<');
709 if (end == NULL)
710 end = strchr (p, '\0');
712 if (!ignore_white || strspn (p, " \t\r\n") < (gsize)(end - p))
714 SwfdecAsContext *cx = swfdec_gc_object_get_context (xml);
715 text = g_strndup (p, end - p);
716 unescaped = swfdec_xml_unescape (cx, text);
717 g_free (text);
718 child = swfdec_xml_node_new_no_properties (cx, SWFDEC_XML_NODE_TEXT,
719 swfdec_as_context_give_string (cx, unescaped));
720 swfdec_xml_node_appendChild (node, child);
723 g_return_val_if_fail (end > p, strchr (p, '\0'));
725 return end;
728 static void
729 swfdec_xml_parseXML (SwfdecXml *xml, const char *value)
731 SwfdecAsObject *object;
732 SwfdecXmlNode *node;
733 const char *p;
734 gboolean ignore_white;
736 g_return_if_fail (SWFDEC_IS_XML (xml));
737 g_return_if_fail (value != NULL);
739 object = swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (xml));
740 node = SWFDEC_XML_NODE (xml);
742 swfdec_xml_node_removeChildren (SWFDEC_XML_NODE (xml));
743 xml->xml_decl = NULL;
744 xml->doc_type_decl = NULL;
745 xml->status = XML_PARSE_STATUS_OK;
747 p = value;
749 // special case: we only use the ignoreWhite set at the start
750 ignore_white = xml->ignore_white;
752 while (xml->status == XML_PARSE_STATUS_OK && *p != '\0') {
753 if (*p == '<') {
754 if (g_ascii_strncasecmp (p + 1, "?xml", strlen ("?xml")) == 0) {
755 p = swfdec_xml_parse_xmlDecl (xml, node, p);
756 } else if (g_ascii_strncasecmp (p + 1, "!DOCTYPE", strlen ("!DOCTYPE")) == 0) {
757 p = swfdec_xml_parse_docTypeDecl (xml, node, p);
758 } else if (strncmp (p + 1, "!--", strlen ("!--")) == 0) {
759 p = swfdec_xml_parse_comment (xml, p);
760 } else if (g_ascii_strncasecmp (p + 1, "![CDATA", strlen ("![CDATA")) == 0) {
761 p = swfdec_xml_parse_cdata (xml, node, p);
762 } else {
763 p = swfdec_xml_parse_tag (xml, &node, p);
765 } else {
766 p = swfdec_xml_parse_text (xml, node, p, ignore_white);
768 g_assert (p != NULL);
771 if (xml->status == XML_PARSE_STATUS_OK && node != SWFDEC_XML_NODE (xml))
772 xml->status = XML_PARSE_STATUS_TAG_NOT_CLOSED;
775 // this is an old XML parsing function that is only available trough the
776 // ASnative code
777 SWFDEC_AS_NATIVE (300, 0, swfdec_xml_do_oldParseXML)
778 void
779 swfdec_xml_do_oldParseXML (SwfdecAsContext *cx, SwfdecAsObject *object,
780 guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
782 SWFDEC_STUB ("XML.oldParseXML (not-really-named)");
785 SWFDEC_AS_NATIVE (253, 12, swfdec_xml_do_parseXML)
786 void
787 swfdec_xml_do_parseXML (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc,
788 SwfdecAsValue *argv, SwfdecAsValue *rval)
790 SwfdecXml *xml;
791 const char *s;
793 SWFDEC_AS_CHECK (SWFDEC_TYPE_XML, &xml, "s", &s);
795 if (SWFDEC_AS_VALUE_IS_UNDEFINED (argv[0]))
796 return;
798 swfdec_xml_parseXML (xml, s);
801 SWFDEC_AS_NATIVE (253, 10, swfdec_xml_createElement)
802 void
803 swfdec_xml_createElement (SwfdecAsContext *cx, SwfdecAsObject *object,
804 guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
806 SwfdecXmlNode *node;
807 SwfdecXml *xml;
808 const char *s;
810 SWFDEC_AS_CHECK (SWFDEC_TYPE_XML, &xml, "s", &s);
812 // special case
813 if (SWFDEC_AS_VALUE_IS_UNDEFINED (argv[0]))
814 return;
816 node = swfdec_xml_node_new (cx, SWFDEC_XML_NODE_ELEMENT, s);
818 SWFDEC_AS_VALUE_SET_OBJECT (rval, swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (node)));
821 SWFDEC_AS_NATIVE (253, 11, swfdec_xml_createTextNode)
822 void
823 swfdec_xml_createTextNode (SwfdecAsContext *cx, SwfdecAsObject *object,
824 guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
826 SwfdecXmlNode *node;
827 SwfdecXml *xml;
828 const char *s;
830 SWFDEC_AS_CHECK (SWFDEC_TYPE_XML, &xml, "s", &s);
832 // special case
833 if (SWFDEC_AS_VALUE_IS_UNDEFINED (argv[0]))
834 return;
836 node = swfdec_xml_node_new (cx, SWFDEC_XML_NODE_TEXT, s);
838 SWFDEC_AS_VALUE_SET_OBJECT (rval, swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (node)));
841 static void
842 swfdec_xml_init_properties (SwfdecAsContext *cx)
844 SwfdecAsValue val;
845 SwfdecAsObject *xml, *proto;
847 // FIXME: We should only initialize if the prototype Object has not been
848 // initialized by any object's constructor with native properties
849 // (TextField, TextFormat, XML, XMLNode at least)
851 g_return_if_fail (SWFDEC_IS_AS_CONTEXT (cx));
853 swfdec_as_object_get_variable (cx->global, SWFDEC_AS_STR_XML, &val);
854 if (!SWFDEC_AS_VALUE_IS_OBJECT (val))
855 return;
856 xml = SWFDEC_AS_VALUE_GET_OBJECT (val);
858 swfdec_as_object_get_variable (xml, SWFDEC_AS_STR_prototype, &val);
859 if (!SWFDEC_AS_VALUE_IS_OBJECT (val))
860 return;
861 proto = SWFDEC_AS_VALUE_GET_OBJECT (val);
863 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_ignoreWhite,
864 swfdec_xml_get_ignoreWhite, swfdec_xml_set_ignoreWhite);
865 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_status,
866 swfdec_xml_get_status, swfdec_xml_set_status);
867 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_xmlDecl,
868 swfdec_xml_get_xmlDecl, swfdec_xml_set_xmlDecl);
869 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_docTypeDecl,
870 swfdec_xml_get_docTypeDecl, swfdec_xml_set_docTypeDecl);
872 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_contentType,
873 swfdec_xml_get_contentType, swfdec_xml_set_contentType);
874 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_loaded,
875 swfdec_xml_get_loaded, swfdec_xml_set_loaded);
878 SWFDEC_AS_NATIVE (253, 9, swfdec_xml_construct)
879 void
880 swfdec_xml_construct (SwfdecAsContext *cx, SwfdecAsObject *object,
881 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
883 SwfdecXml *xml;
885 if (!swfdec_as_context_is_constructing (cx))
886 return;
888 swfdec_xml_init_properties (cx);
890 xml = g_object_new (SWFDEC_TYPE_XML, "context", cx, NULL);
891 swfdec_xml_node_init_values (SWFDEC_XML_NODE (xml), SWFDEC_XML_NODE_ELEMENT, SWFDEC_AS_STR_EMPTY);
892 SWFDEC_XML_NODE (xml)->name = NULL;
893 swfdec_as_object_set_relay (object, SWFDEC_AS_RELAY (xml));
895 /* ??? */
896 if (!SWFDEC_IS_VALID_XML_NODE (xml))
897 return;
899 if (argc >= 1 && !SWFDEC_AS_VALUE_IS_UNDEFINED (argv[0])) {
900 swfdec_xml_parseXML (xml, swfdec_as_value_to_string (cx, argv[0]));
904 SwfdecXml *
905 swfdec_xml_new_no_properties (SwfdecAsContext *context, const char *str,
906 gboolean ignore_white)
908 SwfdecAsObject *object;
909 SwfdecXml *xml;
911 g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (context), NULL);
913 xml = g_object_new (SWFDEC_TYPE_XML, "context", context, NULL);
914 xml->ignore_white = ignore_white;
915 swfdec_xml_node_init_values (SWFDEC_XML_NODE (xml),
916 SWFDEC_XML_NODE_ELEMENT, SWFDEC_AS_STR_EMPTY);
918 object = swfdec_as_object_new (context, NULL);
919 swfdec_as_object_set_constructor_by_name (object, SWFDEC_AS_STR_XML, NULL);
920 swfdec_as_object_set_relay (object, SWFDEC_AS_RELAY (xml));
922 if (str != NULL)
923 swfdec_xml_parseXML (xml, str);
925 return xml;
928 SwfdecXml *
929 swfdec_xml_new (SwfdecAsContext *context, const char *str,
930 gboolean ignore_white)
932 g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (context), NULL);
934 swfdec_xml_init_properties (context);
936 return swfdec_xml_new_no_properties (context, str, ignore_white);