add a test for just-fixed crasher
[swfdec.git] / swfdec / swfdec_xml.c
blob988d7be71db637bc5128f50db3541ea369bb3cad
1 /* Swfdec
2 * Copyright (C) 2007 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_GC_OBJECT_CLASS (swfdec_xml_parent_class)->mark (object);
54 static void
55 swfdec_xml_class_init (SwfdecXmlClass *klass)
57 SwfdecGcObjectClass *gc_class = SWFDEC_GC_OBJECT_CLASS (klass);
59 gc_class->mark = swfdec_xml_mark;
62 static void
63 swfdec_xml_init (SwfdecXml *xml)
67 typedef struct {
68 const char character;
69 const char *escaped;
70 } EntityConversion;
72 static EntityConversion xml_entities[] = {
73 { '&', "&amp;" },
74 { '"', "&quot;" },
75 { '\'', "&apos;" },
76 { '<', "&lt;" },
77 { '>', "&gt;" },
78 { '\xa0', "&nbsp;" },
79 { '\0', NULL }
82 char *
83 swfdec_xml_escape_len (const char *orginal, gssize length)
85 int i;
86 const char *p, *start;
87 GString *string;
89 string = g_string_new ("");
91 // Note: we don't escape non-breaking space to &nbsp;
92 p = start = orginal;
93 while (*(p += strcspn (p, "&<>\"'")) != '\0' && p - orginal < length) {
94 string = g_string_append_len (string, start, p - start);
96 // escape it
97 for (i = 0; xml_entities[i].escaped != NULL; i++) {
98 if (xml_entities[i].character == *p) {
99 string = g_string_append (string, xml_entities[i].escaped);
100 break;
103 g_assert (xml_entities[i].escaped != NULL);
105 p++;
106 start = p;
108 string = g_string_append_len (string, start, length - (start - orginal));
110 return g_string_free (string, FALSE);
113 char *
114 swfdec_xml_escape (const char *orginal)
116 return swfdec_xml_escape_len (orginal, strlen (orginal));
119 char *
120 swfdec_xml_unescape_len (SwfdecAsContext *cx, const char *orginal,
121 gssize length, gboolean unescape_nbsp)
123 int i;
124 const char *p, *start, *end;
125 GString *string;
127 string = g_string_new ("");
129 p = start = orginal;
130 end = orginal + length;
131 while ((p = memchr (p, '&', end - p)) != NULL) {
132 string = g_string_append_len (string, start, p - start);
134 for (i = 0; xml_entities[i].escaped != NULL; i++) {
135 if (!g_ascii_strncasecmp (p, xml_entities[i].escaped,
136 strlen (xml_entities[i].escaped))) {
137 // FIXME: Do this cleaner
138 if (xml_entities[i].character == '\xa0') {
139 if (unescape_nbsp)
140 string = g_string_append_c (string, '\xc2');
141 else
142 continue;
144 string = g_string_append_c (string, xml_entities[i].character);
145 p += strlen (xml_entities[i].escaped);
146 break;
149 if (xml_entities[i].escaped == NULL) {
150 string = g_string_append_c (string, '&');
151 p++;
154 start = p;
156 string = g_string_append_len (string, start, length - (start - orginal));
158 return g_string_free (string, FALSE);
161 char *
162 swfdec_xml_unescape (SwfdecAsContext *cx, const char *orginal)
164 return swfdec_xml_unescape_len (cx, orginal, strlen (orginal), TRUE);
167 // this is never declared, only available as ASnative (100, 5)
168 SWFDEC_AS_NATIVE (100, 5, swfdec_xml_do_escape)
169 void
170 swfdec_xml_do_escape (SwfdecAsContext *cx, SwfdecAsObject *object,
171 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
173 char *escaped;
175 if (argc < 1)
176 return;
178 escaped = swfdec_xml_escape (swfdec_as_value_to_string (cx, &argv[0]));
179 SWFDEC_AS_VALUE_SET_STRING (ret, swfdec_as_context_give_string (cx, escaped));
182 static void
183 swfdec_xml_get_ignoreWhite (SwfdecAsContext *cx, SwfdecAsObject *object,
184 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
186 if (!SWFDEC_IS_XML (object))
187 return;
189 SWFDEC_AS_VALUE_SET_BOOLEAN (ret, SWFDEC_XML (object)->ignore_white);
192 static void
193 swfdec_xml_set_ignoreWhite (SwfdecAsContext *cx, SwfdecAsObject *object,
194 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
196 if (!SWFDEC_IS_XML (object))
197 return;
199 if (argc < 1)
200 return;
202 // special case
203 if (SWFDEC_AS_VALUE_IS_UNDEFINED (&argv[0]))
204 return;
206 // special case, call toString of objects
207 if (SWFDEC_AS_VALUE_IS_OBJECT (&argv[0]))
208 swfdec_as_value_to_string (cx, &argv[0]);
210 SWFDEC_XML (object)->ignore_white =
211 swfdec_as_value_to_boolean (cx, &argv[0]);
214 static void
215 swfdec_xml_get_xmlDecl (SwfdecAsContext *cx, SwfdecAsObject *object,
216 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
218 if (!SWFDEC_IS_XML (object))
219 return;
221 if (SWFDEC_XML (object)->xml_decl != NULL) {
222 SWFDEC_AS_VALUE_SET_STRING (ret, SWFDEC_XML (object)->xml_decl);
223 } else {
224 SWFDEC_AS_VALUE_SET_UNDEFINED (ret);
228 static void
229 swfdec_xml_set_xmlDecl (SwfdecAsContext *cx, SwfdecAsObject *object,
230 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
232 if (!SWFDEC_IS_XML (object))
233 return;
235 if (argc < 1)
236 return;
238 // special case
239 if (SWFDEC_AS_VALUE_IS_UNDEFINED (&argv[0]))
240 return;
242 SWFDEC_XML (object)->xml_decl = swfdec_as_value_to_string (cx, &argv[0]);
245 static void
246 swfdec_xml_get_docTypeDecl (SwfdecAsContext *cx, SwfdecAsObject *object,
247 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
249 if (!SWFDEC_IS_XML (object))
250 return;
252 if (SWFDEC_XML (object)->doc_type_decl != NULL) {
253 SWFDEC_AS_VALUE_SET_STRING (ret, SWFDEC_XML (object)->doc_type_decl);
254 } else {
255 SWFDEC_AS_VALUE_SET_UNDEFINED (ret);
259 static void
260 swfdec_xml_set_docTypeDecl (SwfdecAsContext *cx, SwfdecAsObject *object,
261 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
263 if (!SWFDEC_IS_XML (object))
264 return;
266 if (argc < 1)
267 return;
269 // special case
270 if (SWFDEC_AS_VALUE_IS_UNDEFINED (&argv[0]))
271 return;
273 SWFDEC_XML (object)->doc_type_decl =
274 swfdec_as_value_to_string (cx, &argv[0]);
277 static void
278 swfdec_xml_get_contentType (SwfdecAsContext *cx, SwfdecAsObject *object,
279 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
281 if (!SWFDEC_IS_XML (object))
282 return;
284 *ret = SWFDEC_XML (object)->content_type;
287 static void
288 swfdec_xml_set_contentType (SwfdecAsContext *cx, SwfdecAsObject *object,
289 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
291 if (!SWFDEC_IS_XML (object))
292 return;
294 if (argc < 1)
295 return;
297 // special case
298 if (SWFDEC_AS_VALUE_IS_UNDEFINED (&argv[0]))
299 return;
301 SWFDEC_XML (object)->content_type = argv[0];
304 static void
305 swfdec_xml_get_loaded (SwfdecAsContext *cx, SwfdecAsObject *object,
306 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
308 if (!SWFDEC_IS_XML (object))
309 return;
311 *ret = SWFDEC_XML (object)->loaded;
314 static void
315 swfdec_xml_set_loaded (SwfdecAsContext *cx, SwfdecAsObject *object,
316 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
318 if (!SWFDEC_IS_XML (object))
319 return;
321 if (argc < 1)
322 return;
324 // special case, call toString of objects
325 if (SWFDEC_AS_VALUE_IS_OBJECT (&argv[0]))
326 swfdec_as_value_to_string (cx, &argv[0]);
328 // special case
329 if (SWFDEC_AS_VALUE_IS_UNDEFINED (&argv[0]))
330 return;
332 SWFDEC_AS_VALUE_SET_BOOLEAN (&SWFDEC_XML (object)->loaded,
333 swfdec_as_value_to_boolean (cx, &argv[0]));
336 static void
337 swfdec_xml_get_status (SwfdecAsContext *cx, SwfdecAsObject *object,
338 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
340 if (!SWFDEC_IS_XML (object))
341 return;
343 SWFDEC_AS_VALUE_SET_INT (ret, SWFDEC_XML (object)->status);
346 static void
347 swfdec_xml_set_status (SwfdecAsContext *cx, SwfdecAsObject *object,
348 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
350 double d;
352 if (!SWFDEC_IS_XML (object))
353 return;
355 if (argc < 1)
356 return;
358 // special case
359 if (SWFDEC_AS_VALUE_IS_UNDEFINED (&argv[0]))
360 return;
362 swfdec_as_value_to_string (cx, &argv[0]);
363 d = swfdec_as_value_to_number (cx, &argv[0]);
364 if (!isfinite (d))
365 SWFDEC_XML (object)->status = 0;
366 else
367 SWFDEC_XML (object)->status = d;
370 static const char *
371 swfdec_xml_parse_xmlDecl (SwfdecXml *xml, SwfdecXmlNode *node, const char *p)
373 const char *end;
374 GString *string;
376 g_assert (p != NULL);
377 g_return_val_if_fail (g_ascii_strncasecmp (p, "<?xml", strlen ("<?xml")) == 0,
378 strchr (p, '\0'));
379 g_return_val_if_fail (SWFDEC_IS_XML (xml), strchr (p, '\0'));
381 end = strstr (p, "?>");
382 if (end == NULL) {
383 xml->status = XML_PARSE_STATUS_XMLDECL_NOT_TERMINATED;
384 return strchr (p, '\0');
387 end += strlen ("?>");
389 string = g_string_new ((xml->xml_decl != NULL ? xml->xml_decl : ""));
390 string = g_string_append_len (string, p, end - p);
391 xml->xml_decl = swfdec_as_context_give_string (
392 swfdec_gc_object_get_context (xml), g_string_free (string, FALSE));
394 // in version 5 parsing xmlDecl or docType always adds undefined element to
395 // the childNodes array
396 if (swfdec_gc_object_get_context (xml)->version < 6)
397 SWFDEC_FIXME ("Need to add undefined element to childNodes array");
399 g_return_val_if_fail (end > p, strchr (p, '\0'));
401 return end;
404 static const char *
405 swfdec_xml_parse_docTypeDecl (SwfdecXml *xml, SwfdecXmlNode *node,
406 const char *p)
408 const char *end;
409 int open;
411 g_assert (p != NULL);
412 g_return_val_if_fail (
413 g_ascii_strncasecmp (p, "<!DOCTYPE", strlen ("<!DOCTYPE")) == 0,
414 strchr (p, '\0'));
415 g_return_val_if_fail (SWFDEC_IS_XML (xml), strchr (p, '\0'));
417 end = p + 1;
418 open = 1;
419 do {
420 end += strcspn (end, "<>");
421 if (*end == '<') {
422 open++;
423 end++;
424 } else if (*end == '>') {
425 open--;
426 end++;
428 } while (*end != '\0' && open > 0);
430 if (*end == '\0') {
431 xml->status = XML_PARSE_STATUS_DOCTYPEDECL_NOT_TERMINATED;
432 } else {
433 xml->doc_type_decl = swfdec_as_context_give_string (
434 swfdec_gc_object_get_context (xml), g_strndup (p, end - p));
436 // in version 5 parsing xmlDecl or docType always adds undefined element to
437 // the childNodes array
438 if (swfdec_gc_object_get_context (xml)->version < 6)
439 SWFDEC_FIXME ("Need to add undefined element to childNodes array");
442 g_return_val_if_fail (end > p, strchr (p, '\0'));
444 return end;
447 static const char *
448 swfdec_xml_parse_comment (SwfdecXml *xml, const char *p)
450 const char *end;
452 g_assert (p != NULL);
453 g_return_val_if_fail (strncmp (p, "<!--", strlen ("<!--")) == 0,
454 strchr (p, '\0'));
455 g_return_val_if_fail (SWFDEC_IS_XML (xml), strchr (p, '\0'));
457 end = strstr (p, "-->");
459 if (end == NULL) {
460 xml->status = XML_PARSE_STATUS_COMMENT_NOT_TERMINATED;
461 return strchr (p, '\0');
464 end += strlen("-->");
466 g_return_val_if_fail (end > p, strchr (p, '\0'));
468 return end;
471 static void
472 swfdec_xml_add_id_map (SwfdecXml *xml, SwfdecXmlNode *node, const char *id)
474 SwfdecAsObject *object;
475 SwfdecAsValue val;
477 g_return_if_fail (SWFDEC_IS_XML (xml));
478 g_return_if_fail (SWFDEC_IS_XML_NODE (xml));
479 g_return_if_fail (id != NULL && id != SWFDEC_AS_STR_EMPTY);
481 if (swfdec_gc_object_get_context (xml)->version >= 8) {
482 if (swfdec_as_object_get_variable (SWFDEC_AS_OBJECT (xml),
483 SWFDEC_AS_STR_idMap, &val)) {
484 if (SWFDEC_AS_VALUE_IS_OBJECT (&val)) {
485 object = SWFDEC_AS_VALUE_GET_OBJECT (&val);
486 } else {
487 return;
489 } else {
490 object = swfdec_as_object_new_empty (swfdec_gc_object_get_context (xml));
491 SWFDEC_AS_VALUE_SET_OBJECT (&val, object);
492 swfdec_as_object_set_variable (SWFDEC_AS_OBJECT (xml),
493 SWFDEC_AS_STR_idMap, &val);
495 } else {
496 object = SWFDEC_AS_OBJECT (xml);
499 SWFDEC_AS_VALUE_SET_OBJECT (&val, SWFDEC_AS_OBJECT (node));
500 swfdec_as_object_set_variable (object, id, &val);
503 static const char *
504 swfdec_xml_parse_attribute (SwfdecXml *xml, SwfdecXmlNode *node, const char *p)
506 SwfdecAsValue val;
507 const char *end, *name;
508 char *text;
510 g_return_val_if_fail (SWFDEC_IS_XML (xml), strchr (p, '\0'));
511 g_return_val_if_fail (SWFDEC_IS_XML_NODE (node), strchr (p, '\0'));
512 g_return_val_if_fail ((*p != '>' && *p != '\0'), p);
514 end = p + strcspn (p, "=> \r\n\t");
515 if (end - p <= 0) {
516 xml->status = XML_PARSE_STATUS_ELEMENT_MALFORMED;
517 return strchr (p, '\0');
520 text = g_strndup (p, end - p);
521 name = swfdec_as_context_give_string (swfdec_gc_object_get_context (node),
522 swfdec_xml_unescape (swfdec_gc_object_get_context (xml), text));
523 g_free (text);
525 p = end + strspn (end, " \r\n\t");
526 if (*p != '=') {
527 xml->status = XML_PARSE_STATUS_ELEMENT_MALFORMED;
528 return strchr (p, '\0');
530 p = p + 1 + strspn (p + 1, " \r\n\t");
532 if (*p != '"' && *p != '\'') {
533 xml->status = XML_PARSE_STATUS_ELEMENT_MALFORMED;
534 return strchr (p, '\0');
537 end = p + 1;
538 do {
539 end = strchr (end, *p);
540 } while (end != NULL && *(end - 1) == '\\');
542 if (end == NULL) {
543 xml->status = XML_PARSE_STATUS_ATTRIBUTE_NOT_TERMINATED;
544 return strchr (p, '\0');
547 if (!swfdec_as_object_get_variable (node->attributes, name, NULL)) {
548 char *unescaped;
549 const char *value;
551 unescaped = swfdec_xml_unescape_len (swfdec_gc_object_get_context (xml),
552 p + 1, end - (p + 1), TRUE);
553 value = swfdec_as_context_give_string (swfdec_gc_object_get_context (node),
554 unescaped);
555 SWFDEC_AS_VALUE_SET_STRING (&val, value);
557 swfdec_as_object_set_variable (node->attributes, name, &val);
560 g_return_val_if_fail (end + 1 > p, strchr (p, '\0'));
562 return end + 1;
565 static const char *
566 swfdec_xml_parse_tag (SwfdecXml *xml, SwfdecXmlNode **node, const char *p)
568 SwfdecAsObject *object;
569 SwfdecXmlNode *child = NULL; // surpress warning
570 char *name;
571 const char *end;
572 gboolean close;
574 g_assert (p != NULL);
575 g_return_val_if_fail (*p == '<', strchr (p, '\0'));
576 g_return_val_if_fail (SWFDEC_IS_XML (xml), strchr (p, '\0'));
578 object = SWFDEC_AS_OBJECT (xml);
580 // closing tag or opening tag?
581 if (*(p + 1) == '/') {
582 close = TRUE;
583 p++;
584 } else {
585 close = FALSE;
588 // find the end of the name
589 end = p + strcspn (p, "> \r\n\t");
591 // don't count trailing / as part of the name if it's followed by >
592 // note we do this for close tags also, so <test/ ></test/> doesn't work
593 if (*end == '>' && *(end - 1) == '/')
594 end = end - 1;
596 if (end - (p + 1) <= 0 || *end == '\0') {
597 xml->status = XML_PARSE_STATUS_ELEMENT_MALFORMED;
598 return strchr (p, '\0');
601 name = g_strndup (p + 1 , end - (p + 1));
603 // create the new element
604 if (!close) {
605 child = swfdec_xml_node_new_no_properties (
606 swfdec_gc_object_get_context (*node), SWFDEC_XML_NODE_ELEMENT,
607 swfdec_as_context_give_string (swfdec_gc_object_get_context (*node),
608 name));
609 if (child == NULL)
610 return strchr (p, '\0');
613 if (close) {
614 end = strchr (end, '>');
615 if (end == NULL)
616 end = strchr (p, '\0');
617 } else {
618 end = end + strspn (end, " \r\n\t");
619 while (*end != '\0' && *end != '>' && (*end != '/' || *(end + 1) != '>')) {
620 end = swfdec_xml_parse_attribute (xml, child, end);
621 end = end + strspn (end, " \r\n\t");
623 if (*end == '/')
624 end += 1;
627 if (*end == '\0') {
628 if (xml->status == XML_PARSE_STATUS_OK)
629 xml->status = XML_PARSE_STATUS_ELEMENT_MALFORMED;
630 if (close)
631 g_free (name);
632 return end;
635 if (close) {
636 if ((*node)->parent != NULL && !g_ascii_strcasecmp ((*node)->name, name))
638 *node = (*node)->parent;
640 else // error
642 SwfdecXmlNode *iter = *node;
643 while (iter != NULL && (iter->name == NULL || g_ascii_strcasecmp (iter->name, name))) {
644 iter = iter->parent;
646 if (iter != NULL) {
647 xml->status = XML_PARSE_STATUS_TAG_NOT_CLOSED;
648 } else {
649 xml->status = XML_PARSE_STATUS_TAG_MISMATCH;
652 g_free (name);
653 } else {
654 const char *id;
656 swfdec_xml_node_appendChild (*node, child);
658 id = swfdec_xml_node_get_attribute (child, SWFDEC_AS_STR_id);
659 if (id != NULL)
660 swfdec_xml_add_id_map (xml, child, id);
662 if (*(end - 1) != '/')
663 *node = child;
666 end += 1;
668 g_return_val_if_fail (end > p, strchr (p, '\0'));
670 return end;
673 static const char *
674 swfdec_xml_parse_cdata (SwfdecXml *xml, SwfdecXmlNode *node, const char *p)
676 SwfdecXmlNode *child;
677 const char *end;
678 char *text;
680 g_assert (p != NULL);
681 g_return_val_if_fail (strncmp (p, "<![CDATA[", strlen ("<![CDATA[")) == 0,
682 strchr (p, '\0'));
683 g_return_val_if_fail (SWFDEC_IS_XML (xml), strchr (p, '\0'));
685 p += strlen ("<![CDATA[");
687 end = strstr (p, "]]>");
689 if (end == NULL) {
690 xml->status = XML_PARSE_STATUS_CDATA_NOT_TERMINATED;
691 return strchr (p, '\0');
694 text = g_strndup (p, end - p);
696 child = swfdec_xml_node_new_no_properties (
697 swfdec_gc_object_get_context (node), SWFDEC_XML_NODE_TEXT,
698 swfdec_as_context_give_string (swfdec_gc_object_get_context (xml), text));
699 if (child == NULL)
700 return strchr (p, '\0');
701 swfdec_xml_node_appendChild (node, child);
703 end += strlen("]]>");
705 g_return_val_if_fail (end > p, strchr (p, '\0'));
707 return end;
710 static const char *
711 swfdec_xml_parse_text (SwfdecXml *xml, SwfdecXmlNode *node,
712 const char *p, gboolean ignore_white)
714 SwfdecXmlNode *child;
715 const char *end;
716 char *text, *unescaped;
718 g_assert (p != NULL);
719 g_return_val_if_fail (*p != '\0', p);
720 g_return_val_if_fail (SWFDEC_IS_XML (xml), strchr (p, '\0'));
722 end = strchr (p, '<');
723 if (end == NULL)
724 end = strchr (p, '\0');
726 if (!ignore_white || strspn (p, " \t\r\n") < (gsize)(end - p))
728 text = g_strndup (p, end - p);
729 unescaped = swfdec_xml_unescape (swfdec_gc_object_get_context (xml), text);
730 g_free (text);
731 child = swfdec_xml_node_new_no_properties (
732 swfdec_gc_object_get_context (node), SWFDEC_XML_NODE_TEXT,
733 swfdec_as_context_give_string (swfdec_gc_object_get_context (xml),
734 unescaped));
735 if (child == NULL)
736 return strchr (p, '\0');
737 swfdec_xml_node_appendChild (node, child);
740 g_return_val_if_fail (end > p, strchr (p, '\0'));
742 return end;
745 static void
746 swfdec_xml_parseXML (SwfdecXml *xml, const char *value)
748 SwfdecAsObject *object;
749 SwfdecXmlNode *node;
750 const char *p;
751 gboolean ignore_white;
753 g_return_if_fail (SWFDEC_IS_XML (xml));
754 g_return_if_fail (value != NULL);
756 object = SWFDEC_AS_OBJECT (xml);
758 swfdec_xml_node_removeChildren (SWFDEC_XML_NODE (xml));
759 xml->xml_decl = NULL;
760 xml->doc_type_decl = NULL;
761 xml->status = XML_PARSE_STATUS_OK;
763 p = value;
764 node = SWFDEC_XML_NODE (xml);
766 // special case: we only use the ignoreWhite set at the start
767 ignore_white = xml->ignore_white;
769 while (xml->status == XML_PARSE_STATUS_OK && *p != '\0') {
770 if (*p == '<') {
771 if (g_ascii_strncasecmp (p + 1, "?xml", strlen ("?xml")) == 0) {
772 p = swfdec_xml_parse_xmlDecl (xml, node, p);
773 } else if (g_ascii_strncasecmp (p + 1, "!DOCTYPE", strlen ("!DOCTYPE")) == 0) {
774 p = swfdec_xml_parse_docTypeDecl (xml, node, p);
775 } else if (strncmp (p + 1, "!--", strlen ("!--")) == 0) {
776 p = swfdec_xml_parse_comment (xml, p);
777 } else if (g_ascii_strncasecmp (p + 1, "![CDATA", strlen ("![CDATA")) == 0) {
778 p = swfdec_xml_parse_cdata (xml, node, p);
779 } else {
780 p = swfdec_xml_parse_tag (xml, &node, p);
782 } else {
783 p = swfdec_xml_parse_text (xml, node, p, ignore_white);
785 g_assert (p != NULL);
788 if (xml->status == XML_PARSE_STATUS_OK && node != SWFDEC_XML_NODE (xml))
789 xml->status = XML_PARSE_STATUS_TAG_NOT_CLOSED;
792 // this is an old XML parsing function that is only available trough the
793 // ASnative code
794 SWFDEC_AS_NATIVE (300, 0, swfdec_xml_do_oldParseXML)
795 void
796 swfdec_xml_do_oldParseXML (SwfdecAsContext *cx, SwfdecAsObject *object,
797 guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
799 SWFDEC_STUB ("XML.oldParseXML (not-really-named)");
802 SWFDEC_AS_NATIVE (253, 12, swfdec_xml_do_parseXML)
803 void
804 swfdec_xml_do_parseXML (SwfdecAsContext *cx, SwfdecAsObject *object, guint argc,
805 SwfdecAsValue *argv, SwfdecAsValue *rval)
807 if (!SWFDEC_IS_XML (object))
808 return;
810 if (!SWFDEC_IS_VALID_XML_NODE (object))
811 return;
813 if (argc < 1)
814 return;
816 if (SWFDEC_AS_VALUE_IS_UNDEFINED (&argv[0]))
817 return;
819 swfdec_xml_parseXML (SWFDEC_XML (object),
820 swfdec_as_value_to_string (cx, &argv[0]));
823 SWFDEC_AS_NATIVE (253, 10, swfdec_xml_createElement)
824 void
825 swfdec_xml_createElement (SwfdecAsContext *cx, SwfdecAsObject *object,
826 guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
828 SwfdecXmlNode *node;
830 if (!SWFDEC_IS_XML (object))
831 return;
833 if (argc < 1)
834 return;
836 // special case
837 if (SWFDEC_AS_VALUE_IS_UNDEFINED (&argv[0]))
838 return;
840 node = swfdec_xml_node_new (cx, SWFDEC_XML_NODE_ELEMENT,
841 swfdec_as_value_to_string (cx, &argv[0]));
842 if (node == NULL)
843 return;
845 SWFDEC_AS_VALUE_SET_OBJECT (rval, SWFDEC_AS_OBJECT (node));
848 SWFDEC_AS_NATIVE (253, 11, swfdec_xml_createTextNode)
849 void
850 swfdec_xml_createTextNode (SwfdecAsContext *cx, SwfdecAsObject *object,
851 guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
853 SwfdecXmlNode *node;
855 if (!SWFDEC_IS_XML (object))
856 return;
858 if (argc < 1)
859 return;
861 // special case
862 if (SWFDEC_AS_VALUE_IS_UNDEFINED (&argv[0]))
863 return;
865 node = swfdec_xml_node_new (cx, SWFDEC_XML_NODE_TEXT,
866 swfdec_as_value_to_string (cx, &argv[0]));
867 if (node == NULL)
868 return;
870 SWFDEC_AS_VALUE_SET_OBJECT (rval, SWFDEC_AS_OBJECT (node));
873 static void
874 swfdec_xml_init_properties (SwfdecAsContext *cx)
876 SwfdecAsValue val;
877 SwfdecAsObject *xml, *proto;
879 // FIXME: We should only initialize if the prototype Object has not been
880 // initialized by any object's constructor with native properties
881 // (TextField, TextFormat, XML, XMLNode at least)
883 g_return_if_fail (SWFDEC_IS_AS_CONTEXT (cx));
885 swfdec_as_object_get_variable (cx->global, SWFDEC_AS_STR_XML, &val);
886 if (!SWFDEC_AS_VALUE_IS_OBJECT (&val))
887 return;
888 xml = SWFDEC_AS_VALUE_GET_OBJECT (&val);
890 swfdec_as_object_get_variable (xml, SWFDEC_AS_STR_prototype, &val);
891 if (!SWFDEC_AS_VALUE_IS_OBJECT (&val))
892 return;
893 proto = SWFDEC_AS_VALUE_GET_OBJECT (&val);
895 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_ignoreWhite,
896 swfdec_xml_get_ignoreWhite, swfdec_xml_set_ignoreWhite);
897 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_status,
898 swfdec_xml_get_status, swfdec_xml_set_status);
899 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_xmlDecl,
900 swfdec_xml_get_xmlDecl, swfdec_xml_set_xmlDecl);
901 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_docTypeDecl,
902 swfdec_xml_get_docTypeDecl, swfdec_xml_set_docTypeDecl);
904 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_contentType,
905 swfdec_xml_get_contentType, swfdec_xml_set_contentType);
906 swfdec_as_object_add_native_variable (proto, SWFDEC_AS_STR_loaded,
907 swfdec_xml_get_loaded, swfdec_xml_set_loaded);
910 SWFDEC_AS_CONSTRUCTOR (253, 9, swfdec_xml_construct, swfdec_xml_get_type)
911 void
912 swfdec_xml_construct (SwfdecAsContext *cx, SwfdecAsObject *object,
913 guint argc, SwfdecAsValue *argv, SwfdecAsValue *ret)
915 if (!swfdec_as_context_is_constructing (cx))
916 return;
918 g_assert (SWFDEC_IS_XML (object));
920 swfdec_xml_init_properties (cx);
922 swfdec_xml_node_init_values (SWFDEC_XML_NODE (object),
923 SWFDEC_XML_NODE_ELEMENT, SWFDEC_AS_STR_EMPTY);
925 SWFDEC_AS_VALUE_SET_STRING (&SWFDEC_XML (object)->content_type,
926 SWFDEC_AS_STR_application_x_www_form_urlencoded);
928 SWFDEC_XML_NODE (object)->name = NULL;
930 if (!SWFDEC_IS_VALID_XML_NODE (object))
931 return;
933 if (argc >= 1 && !SWFDEC_AS_VALUE_IS_UNDEFINED (&argv[0])) {
934 swfdec_xml_parseXML (SWFDEC_XML (object),
935 swfdec_as_value_to_string (cx, &argv[0]));
939 SwfdecXml *
940 swfdec_xml_new_no_properties (SwfdecAsContext *context, const char *str,
941 gboolean ignore_white)
943 SwfdecXml *xml;
945 g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (context), NULL);
947 xml = g_object_new (SWFDEC_TYPE_XML, "context", context, NULL);
949 swfdec_as_object_set_constructor_by_name (SWFDEC_AS_OBJECT (xml), SWFDEC_AS_STR_XML, NULL);
950 xml->ignore_white = ignore_white;
952 swfdec_xml_node_init_values (SWFDEC_XML_NODE (xml),
953 SWFDEC_XML_NODE_ELEMENT, SWFDEC_AS_STR_EMPTY);
955 SWFDEC_AS_VALUE_SET_STRING (&xml->content_type,
956 SWFDEC_AS_STR_application_x_www_form_urlencoded);
958 if (str != NULL)
959 swfdec_xml_parseXML (xml, str);
961 return xml;
964 SwfdecXml *
965 swfdec_xml_new (SwfdecAsContext *context, const char *str,
966 gboolean ignore_white)
968 g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (context), NULL);
970 swfdec_xml_init_properties (context);
972 return swfdec_xml_new_no_properties (context, str, ignore_white);