2009-10-09 Chris Toshok <toshok@ximian.com>
[moon.git] / src / xaml.cpp
blob0f0dbd929727d816fcfa095ade58c58268dbc76e
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * xaml.cpp: xaml parser
5 * Contact:
6 * Moonlight List (moonlight-list@lists.ximian.com)
8 * Copyright 2007 Novell, Inc. (http://www.novell.com)
10 * See the LICENSE file included with the distribution for details.
14 #include <config.h>
16 #include <glib.h>
17 #include <string.h>
18 #include <malloc.h>
19 #include <stdlib.h>
20 #include <stdarg.h>
21 #include <unistd.h>
22 #include <fcntl.h>
23 #include <errno.h>
25 #include <expat.h>
27 #include "xaml.h"
28 #include "error.h"
29 #include "shape.h"
30 #include "animation.h"
31 #include "bitmapimage.h"
32 #include "geometry.h"
33 #include "textblock.h"
34 #include "glyphs.h"
35 #include "media.h"
36 #include "list.h"
37 #include "rect.h"
38 #include "point.h"
39 #include "canvas.h"
40 #include "color.h"
41 #include "namescope.h"
42 #include "stylus.h"
43 #include "runtime.h"
44 #include "utils.h"
45 #include "control.h"
46 #include "template.h"
47 #include "style.h"
48 #include "application.h"
49 #include "thickness.h"
50 #include "cornerradius.h"
51 #include "deployment.h"
52 #include "grid.h"
53 #include "deepzoomimagetilesource.h"
56 class XamlElementInfo;
57 class XamlElementInstance;
58 class XamlParserInfo;
59 class XamlNamespace;
60 class DefaultNamespace;
61 class XNamespace;
62 class XmlNamespace;
63 class PrimitiveNamespace;
64 class MCIgnorableNamespace;
65 class XamlElementInfoNative;
66 class XamlElementInstanceNative;
67 class XamlElementInstanceValueType;
68 class XamlElementInfoEnum;
69 class XamlElementInstanceEnum;
70 class XamlElementInfoManaged;
71 class XamlElementInstanceManaged;
72 class XamlElementInfoImportedManaged;
73 class XamlElementInstanceTemplate;
75 #define INTERNAL_IGNORABLE_ELEMENT "MoonlightInternalIgnorableElement"
77 #define IS_NULL_OR_EMPTY(str) (!str || (*str == 0))
79 static DefaultNamespace *default_namespace = NULL;
80 static XNamespace *x_namespace = NULL;
81 static XmlNamespace *xml_namespace = NULL;
83 static const char* default_namespace_names [] = {
84 "http://schemas.microsoft.com/winfx/2006/xaml/presentation",
85 "http://schemas.microsoft.com/client/2007",
86 "http://schemas.microsoft.com/xps/2005/06",
87 "http://schemas.microsoft.com/client/2007/deployment",
88 NULL
91 #define X_NAMESPACE_URI "http://schemas.microsoft.com/winfx/2006/xaml"
92 #define XML_NAMESPACE_URI "http://www.w3.org/XML/1998/namespace"
93 #define PRIMITIVE_NAMESPACE_URI "clr-namespace:System;assembly=mscorlib"
94 #define MC_IGNORABLE_NAMESPACE_URI "http://schemas.openxmlformats.org/markup-compatibility/2006"
97 static bool value_from_str_with_parser (XamlParserInfo *p, Type::Kind type, const char *prop_name, const char *str, Value **v, bool *v_set);
98 static bool dependency_object_set_property (XamlParserInfo *p, XamlElementInstance *item, XamlElementInstance *property, XamlElementInstance *value, bool raise_errors);
99 static bool set_managed_attached_property (XamlParserInfo *p, XamlElementInstance *item, XamlElementInstance *property, XamlElementInstance *value);
100 static void dependency_object_add_child (XamlParserInfo *p, XamlElementInstance *parent, XamlElementInstance *child, bool fail_if_no_prop);
101 static void dependency_object_set_attributes (XamlParserInfo *p, XamlElementInstance *item, const char **attr);
102 static void value_type_set_attributes (XamlParserInfo *p, XamlElementInstance *item, const char **attr);
103 static bool element_begins_buffering (Type::Kind kind);
104 static bool is_managed_kind (Type::Kind kind);
105 static bool kind_requires_managed_load (Type::Kind kind);
106 static bool is_legal_top_level_kind (Type::Kind kind);
107 static Value *lookup_resource_dictionary (ResourceDictionary *rd, const char *name, bool *exists);
108 static void parser_error (XamlParserInfo *p, const char *el, const char *attr, int error_code, const char *format, ...);
109 static gboolean namespace_for_prefix (gpointer key, gpointer value, gpointer user_data);
111 static XamlElementInfo *create_element_info_from_imported_managed_type (XamlParserInfo *p, const char *name, const char **attr, bool create);
112 static void destroy_created_namespace (gpointer data, gpointer user_data);
114 enum BufferMode {
115 BUFFER_MODE_TEMPLATE,
116 BUFFER_MODE_IGNORE
120 class XamlNamespace {
121 public:
122 const char *name;
123 bool is_ignored;
125 XamlNamespace ()
127 name = NULL;
128 is_ignored = false;
131 virtual ~XamlNamespace () { }
132 virtual XamlElementInfo* FindElement (XamlParserInfo *p, const char *el, const char **attr, bool create) = 0;
133 virtual bool SetAttribute (XamlParserInfo *p, XamlElementInstance *item, const char *attr, const char *value) = 0;
135 virtual const char* GetUri () = 0;
136 virtual const char* GetPrefix () = 0;
139 void
140 add_namespace_data (gpointer key, gpointer value, gpointer user_data)
142 XamlNamespace *ns = (XamlNamespace *) value;
143 GHashTable *table = (GHashTable *) user_data;
145 if ((void *)ns != (void *)default_namespace)
146 g_hash_table_insert (table, g_strdup (ns->GetPrefix ()), g_strdup (ns->GetUri ()));
149 void
150 add_namespace_to_ignorable (gpointer key, gpointer value, gpointer user_data)
152 char *prefix = (char *) key;
153 char *uri = (char *) value;
154 GString *str = (GString *) user_data;
156 g_string_append_printf (str, "xmlns:%s=\"%s\" ", prefix, uri);
159 class XamlContextInternal {
161 public:
162 Value *top_element;
163 FrameworkTemplate *template_parent;
164 GHashTable *imported_namespaces;
165 Surface *surface;
166 XamlLoaderCallbacks callbacks;
167 GSList *resources;
168 XamlContextInternal *parent_context;
170 DependencyObject *source;
172 XamlContextInternal (XamlLoaderCallbacks callbacks, Value *top_element, FrameworkTemplate *template_parent, GHashTable *namespaces, GSList *resources, XamlContextInternal *parent_context)
174 this->callbacks = callbacks;
175 this->top_element = new Value (*top_element);
176 this->template_parent = template_parent;
177 this->surface = template_parent->GetSurface ();
178 this->resources = resources;
179 this->parent_context = parent_context;
181 if (this->callbacks.create_gchandle)
182 this->callbacks.create_gchandle ();
183 imported_namespaces = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
184 g_hash_table_foreach (namespaces, add_namespace_data, imported_namespaces);
188 ~XamlContextInternal ()
190 if (imported_namespaces)
191 g_hash_table_destroy (imported_namespaces);
192 if (resources)
193 g_slist_free (resources);
194 delete top_element;
197 char *CreateIgnorableTagOpen ()
199 GString *str = g_string_new ("<" INTERNAL_IGNORABLE_ELEMENT " ");
200 g_hash_table_foreach (imported_namespaces, add_namespace_to_ignorable, str);
202 str = g_string_append (str, ">");
204 char *res = str->str;
205 g_string_free (str, false);
207 return res;
210 char *CreateIgnorableTagClose ()
212 return g_strdup ("</" INTERNAL_IGNORABLE_ELEMENT ">");
215 bool LookupNamedItem (const char* name, Value **v)
217 if (!resources)
218 return NULL;
220 bool exists = false;
221 GSList *walk = resources;
222 while (walk) {
223 DependencyObject *dob = (DependencyObject*)walk->data;
224 if (dob->Is (Type::RESOURCE_DICTIONARY))
225 *v = lookup_resource_dictionary ((ResourceDictionary *) walk->data, name, &exists);
226 else /* dob->Is (Type::FRAMEWORKELEMENT) */ {
227 ResourceDictionary *rd = dob->GetValue (UIElement::ResourcesProperty)->AsResourceDictionary();
228 *v = lookup_resource_dictionary (rd, name, &exists);
231 if (exists)
232 break;
233 walk = walk->next;
236 if (exists)
237 return exists;
238 else if (!parent_context)
239 return false;
241 return parent_context->LookupNamedItem (name, v);
244 void SetTemplateBindingSource (DependencyObject *source)
246 this->source = source;
249 DependencyObject* GetTemplateBindingSource ()
251 return source;
256 XamlContext::XamlContext (XamlContextInternal *internal)
258 this->internal = internal;
261 XamlContext::~XamlContext ()
263 delete internal;
266 void
267 XamlContext::SetTemplateBindingSource (DependencyObject *source)
269 internal->SetTemplateBindingSource (source);
272 DependencyObject*
273 XamlContext::GetTemplateBindingSource ()
275 return internal->GetTemplateBindingSource ();
278 class XamlElementInfo {
279 protected:
280 Type::Kind kind;
281 Type::Kind property_owner_kind;
282 bool cdata_verbatim;
284 public:
285 XamlElementInfo *parent;
286 const char *name;
287 const char *xmlns;
289 XamlElementInfo (const char *xmlns, const char *name, Type::Kind kind)
291 this->parent = NULL;
292 this->kind = kind;
293 this->name = name;
294 this->xmlns = xmlns;
295 this->cdata_verbatim = false;
297 this->property_owner_kind = Type::INVALID;
300 ~XamlElementInfo ()
304 virtual Type::Kind GetKind () { return kind; }
306 virtual void SetPropertyOwnerKind (Type::Kind value) { property_owner_kind = value; }
307 virtual Type::Kind GetPropertyOwnerKind () { return property_owner_kind; }
309 virtual const char *GetContentProperty (XamlParserInfo *p)
311 Type *t = Type::Find (kind);
312 if (t)
313 return t->GetContentPropertyName ();
314 return NULL;
317 void SetIsCDataVerbatim (bool flag)
319 cdata_verbatim = flag;
322 bool IsCDataVerbatim ()
324 return cdata_verbatim;
327 virtual bool RequiresManagedSet () { return false; }
329 virtual XamlElementInstance *CreateElementInstance (XamlParserInfo *p) = 0;
330 virtual XamlElementInstance *CreateWrappedElementInstance (XamlParserInfo *p, Value *o) = 0;
331 virtual XamlElementInstance *CreatePropertyElementInstance (XamlParserInfo *p, const char *name) = 0;
335 struct DelayedProperty {
336 char *xmlns;
337 char *name;
338 Value *value;
340 DelayedProperty (const char *xmlns, const char *name, const Value *value)
342 this->xmlns = g_strdup (xmlns);
343 this->name = g_strdup (name);
344 this->value = new Value (*value);
347 ~DelayedProperty ()
349 g_free (xmlns);
350 g_free (name);
351 delete value;
355 static void
356 free_property_list (GSList *list)
358 GSList *walk = list;
360 while (walk) {
361 DelayedProperty *prop = (DelayedProperty *) walk->data;
363 delete prop;
364 walk = walk->next;
367 g_slist_free (list);
370 class XamlElementInstance : public List::Node {
372 protected:
373 DependencyObject *item;
374 Value *value;
375 bool cleanup_value;
376 GSList *delayed_properties;
378 public:
379 const char *element_name;
380 XamlElementInfo *info;
382 XamlElementInstance *parent;
383 List *children;
385 enum ElementType {
386 ELEMENT,
387 PROPERTY,
388 INVALID
391 int element_type;
392 bool requires_managed;
393 char *x_key;
394 char *x_name;
396 GHashTable *set_properties;
398 XamlElementInstance (XamlElementInfo *info, const char* element_name, ElementType type, bool requires_managed = false)
400 this->element_name = element_name;
401 this->set_properties = NULL;
402 this->element_type = type;
403 this->parent = NULL;
404 this->info = info;
405 this->item = NULL;
406 this->value = NULL;
407 this->x_key = NULL;
408 this->x_name = NULL;
409 this->cleanup_value = true;
410 this->requires_managed = requires_managed;
411 this->delayed_properties = NULL;
413 children = new List ();
416 virtual ~XamlElementInstance ()
418 children->Clear (true);
419 delete children;
420 delete info;
422 g_free (x_key);
423 g_free (x_name);
425 if (cleanup_value)
426 delete value;
428 if (set_properties)
429 g_hash_table_destroy (set_properties);
431 if (element_name && element_type == PROPERTY)
432 g_free ((void*) element_name);
434 free_property_list (delayed_properties);
437 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, XamlElementInstance *value) = 0;
438 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, const char* value) = 0;
439 virtual void AddChild (XamlParserInfo *p, XamlElementInstance *child) = 0;
440 virtual void SetAttributes (XamlParserInfo *p, const char **attr) = 0;
442 virtual bool TrySetContentProperty (XamlParserInfo *p, XamlElementInstance *value);
443 virtual bool TrySetContentProperty (XamlParserInfo *p, const char *value);
446 char *GetKey () { return x_key; }
447 char *GetName () { return x_name; }
449 void SetName (XamlParserInfo *p, const char *name)
451 this->x_name = g_strdup (name);
454 void SetKey (XamlParserInfo *p, const char *key)
456 this->x_key = g_strdup (key);
459 virtual bool IsDependencyObject ()
461 return true;
464 virtual bool SetUnknownAttribute (XamlParserInfo *p, const char* name, const char* value);
466 void SetValue (Value *v)
468 if (value && cleanup_value)
469 delete value;
470 value = v;
473 virtual Value *GetAsValue ()
475 if (!value) {
476 value = new Value (item);
478 return value;
481 virtual DependencyObject *GetAsDependencyObject ()
483 return item;
486 virtual void SetDependencyObject (DependencyObject *value)
488 item = value;
491 virtual void* GetManagedPointer ()
493 return item;
496 virtual Value* GetParentPointer ()
498 XamlElementInstance *walk = parent;
499 while (walk && walk->element_type != XamlElementInstance::ELEMENT)
500 walk = walk->parent;
502 if (!walk)
503 return NULL;
505 return walk->GetAsValue ();
508 virtual bool IsTemplate ()
510 return false;
513 virtual XamlElementInfo* FindPropertyElement (XamlParserInfo *p, const char *el, const char *dot);
515 void SetDelayedProperties (XamlParserInfo *p);
517 void DelaySetProperty (const char *xmlns, const char *name, const Value *value)
519 DelayedProperty *prop = new DelayedProperty (xmlns, name, value);
521 delayed_properties = g_slist_append (delayed_properties, prop);
524 bool IsPropertySet (const char *name)
526 if (!set_properties)
527 return false;
529 return g_hash_table_lookup (set_properties, name) != NULL;
532 void MarkPropertyAsSet (const char *name)
534 if (!set_properties)
535 set_properties = g_hash_table_new (g_str_hash, g_str_equal);
537 g_hash_table_insert (set_properties, (void *) name, GINT_TO_POINTER (TRUE));
541 void
542 unref_xaml_element (gpointer data, gpointer user_data)
544 DependencyObject* dob = (DependencyObject*) data;
545 //printf ("unref_xaml_element: %i\n", dob->id);
546 if (dob)
547 dob->unref ();
550 class XamlParserInfo {
551 public:
552 XML_Parser parser;
554 const char *file_name;
556 NameScope *namescope;
557 XamlElementInstance *top_element;
558 XamlNamespace *current_namespace;
559 XamlElementInstance *current_element;
560 const char *next_element;
562 GHashTable *namespace_map;
563 bool cdata_content;
564 GString *cdata;
566 bool implicit_default_namespace;
568 ParserErrorEventArgs *error_args;
570 XamlLoader *loader;
574 // If set, this is used to hydrate an existing object, not to create a new toplevel one
576 Value *hydrate_expecting;
577 bool hydrating;
579 char* buffer_until_element;
580 int buffer_depth;
581 BufferMode buffer_mode;
582 GString *buffer;
583 bool validate_templates;
585 private:
586 GList *created_elements;
587 GList *created_namespaces;
588 const char* xml_buffer;
589 int multi_buffer_offset;
590 int xml_buffer_start_index;
592 public:
593 XamlParserInfo (XML_Parser parser, const char *file_name)
595 this->parser = parser;
596 this->file_name = file_name;
597 this->namescope = new NameScope ();
599 top_element = NULL;
600 current_namespace = NULL;
601 current_element = NULL;
602 cdata_content = false;
603 cdata = NULL;
604 implicit_default_namespace = false;
605 error_args = NULL;
606 loader = NULL;
607 created_elements = NULL;
608 created_namespaces = NULL;
609 hydrate_expecting = NULL;
610 hydrating = false;
612 buffer_until_element = NULL;
613 buffer_depth = -1;
614 buffer = NULL;
615 xml_buffer = NULL;
616 multi_buffer_offset = 0;
617 validate_templates = false;
619 namespace_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
622 void AddCreatedElement (DependencyObject* element)
624 // if we have a loader, set the surface and base resource location
625 if (loader) {
626 element->SetSurface (loader->GetSurface());
627 element->SetResourceBase (loader->GetResourceBase());
630 // When instantiating a template, some elements are created which are not explicitly
631 // mentioned in the xaml. Therefore we need to keep walking up the tree until we find
632 // the last element which we set a value for Control::IsTemplateItem and propagate
633 // it from there.
634 XamlElementInstance *instance = current_element;
635 while (instance) {
636 if (!instance->IsDependencyObject () || !instance->GetAsDependencyObject ()) {
637 instance = instance->parent;
638 continue;
640 if (!instance->GetAsDependencyObject ()->ReadLocalValue (Control::IsTemplateItemProperty)) {
641 instance = instance->parent;
642 continue;
644 Control::SetIsTemplateItem (element, Control::GetIsTemplateItem (instance->GetAsDependencyObject ()));
645 break;
648 if (instance == NULL)
649 Control::SetIsTemplateItem (element, loader->GetExpandingTemplate ());
651 if (Control::GetIsTemplateItem (element))
652 NameScope::SetNameScope (element, namescope);
653 created_elements = g_list_prepend (created_elements, element);
656 void AddCreatedNamespace (XamlNamespace* ns)
658 created_namespaces = g_list_prepend (created_namespaces, ns);
661 void QueueBeginBuffering (char* buffer_until, BufferMode mode)
663 buffer_until_element = buffer_until;
664 buffer_depth = 1;
665 buffer_mode = mode;
667 xml_buffer_start_index = -1;
670 void BeginBuffering ()
672 xml_buffer_start_index = XML_GetCurrentByteIndex (parser) - multi_buffer_offset;
673 buffer = g_string_new (NULL);
676 bool ShouldBeginBuffering ()
678 return InBufferingMode () && xml_buffer_start_index == -1;
681 bool InBufferingMode ()
683 return buffer_until_element != NULL;
686 void AppendCurrentXml ()
688 if (!buffer)
689 return;
690 int pos = XML_GetCurrentByteIndex (parser) - multi_buffer_offset;
691 g_string_append_len (buffer, xml_buffer + xml_buffer_start_index, pos - xml_buffer_start_index);
694 char* ClearBuffer ()
696 AppendCurrentXml ();
698 buffer_depth = 0;
699 buffer_until_element = NULL;
701 if (!buffer)
702 return g_strdup ("");
704 char* res = buffer->str;
705 g_string_free (buffer, FALSE);
706 buffer = NULL;
707 return res;
710 void SetXmlBuffer (const char* xml_buffer)
712 if (InBufferingMode ())
713 AppendCurrentXml ();
715 if (this->xml_buffer)
716 multi_buffer_offset += strlen (this->xml_buffer);
718 this->xml_buffer = xml_buffer;
719 xml_buffer_start_index = 0;
722 void ValidateTemplate (const char* buffer, XamlContext* context, FrameworkTemplate *binding_source)
724 XamlLoader *loader = new XamlLoader (NULL, buffer, NULL, context);
725 Type::Kind dummy;
727 context->SetTemplateBindingSource (binding_source);
729 loader->SetImportDefaultXmlns (true);
731 MoonError error;
732 Value *result = loader->CreateFromStringWithError (buffer, true, &dummy, XamlLoader::IMPORT_DEFAULT_XMLNS | XamlLoader::VALIDATE_TEMPLATES, &error);
734 delete result;
735 delete loader;
737 if (error.number != MoonError::NO_ERROR) {
738 int line_number = error.line_number + XML_GetCurrentLineNumber (parser);
739 error_args = new ParserErrorEventArgs (error.message, file_name, line_number, error.char_position, error.code, NULL, NULL);
743 FrameworkTemplate *GetTemplateParent (XamlElementInstance *item)
745 XamlElementInstance *parent = item->parent;
747 while (parent && !parent->IsTemplate ())
748 parent = parent->parent;
750 if (parent)
751 return (FrameworkTemplate *) parent->GetManagedPointer ();
753 if (!loader)
754 return NULL;
756 XamlContext *context = loader->GetContext ();
757 if (!context)
758 return NULL;
760 return context->internal->template_parent;
763 Value *GetTopElementPtr ()
765 XamlContext *context = loader->GetContext ();
766 if (context)
767 return context->internal->top_element;
769 if (top_element)
770 return top_element->GetAsValue ();
772 return NULL;
775 ~XamlParserInfo ()
777 created_elements = g_list_reverse (created_elements);
778 g_list_foreach (created_elements, unref_xaml_element, NULL);
779 g_list_free (created_elements);
781 g_list_foreach (created_namespaces, destroy_created_namespace, NULL);
782 g_list_free (created_namespaces);
784 g_hash_table_destroy (namespace_map);
786 if (cdata)
787 g_string_free (cdata, TRUE);
788 if (top_element)
789 delete top_element;
790 namescope->unref ();
797 class XamlElementInfoNative : public XamlElementInfo {
798 Type *type;
800 public:
801 XamlElementInfoNative (Type *t) : XamlElementInfo (NULL, t->GetName (), t->GetKind ())
803 type = t;
806 Type* GetType ()
808 return type;
811 const char* GetName ()
813 return type->GetName ();
816 const char* GetContentProperty (XamlParserInfo *p);
818 XamlElementInstance* CreateElementInstance (XamlParserInfo *p);
819 XamlElementInstance* CreateWrappedElementInstance (XamlParserInfo *p, Value *o);
820 XamlElementInstance* CreatePropertyElementInstance (XamlParserInfo *p, const char *name);
824 class XamlElementInstanceNative : public XamlElementInstance {
825 XamlElementInfoNative *element_info;
826 XamlParserInfo *parser_info;
828 public:
829 XamlElementInstanceNative (XamlElementInfoNative *element_info, XamlParserInfo *parser_info, const char *name, ElementType type, bool create_item = true);
831 virtual DependencyObject *CreateItem ();
833 virtual XamlElementInfo* FindPropertyElement (XamlParserInfo *p, const char *el, const char *dot);
835 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, XamlElementInstance *value);
836 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, const char* value);
837 virtual void AddChild (XamlParserInfo *p, XamlElementInstance *child);
838 virtual void SetAttributes (XamlParserInfo *p, const char **attr);
842 class XamlElementInstanceValueType : public XamlElementInstance {
843 XamlElementInfoNative *element_info;
844 XamlParserInfo *parser_info;
846 public:
847 XamlElementInstanceValueType (XamlElementInfoNative *element_info, XamlParserInfo *parser_info, const char *name, ElementType type);
849 virtual bool IsDependencyObject ()
851 return false;
854 virtual Value *GetAsValue ()
856 if (value == NULL) {
857 // we are an empty element (e.g. <sys:String></sys:String>). do type specific magic here.
858 CreateValueItemFromString ("");
861 return value;
864 bool CreateValueItemFromString (const char* str);
866 // A Value type doesn't really support anything. It's just here so people can do <SolidColorBrush.Color><Color>#FF00FF</Color></SolidColorBrush.Color>
867 virtual DependencyObject *CreateItem () { return NULL; }
868 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, XamlElementInstance *value) { return false; }
869 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, const char *value) { return false; }
870 virtual void AddChild (XamlParserInfo *p, XamlElementInstance *child) { }
871 virtual void SetAttributes (XamlParserInfo *p, const char **attr);
873 virtual bool TrySetContentProperty (XamlParserInfo *p, XamlElementInstance *value) { return false; }
874 virtual bool TrySetContentProperty (XamlParserInfo *p, const char *value) { return CreateValueItemFromString (value); }
877 class XamlElementInfoEnum : public XamlElementInfo {
878 public:
879 XamlElementInfoEnum (const char *name) : XamlElementInfo (NULL, name, Type::INT32)
883 XamlElementInstance* CreateElementInstance (XamlParserInfo *p);
884 XamlElementInstance* CreateWrappedElementInstance (XamlParserInfo *p, Value *o);
885 XamlElementInstance* CreatePropertyElementInstance (XamlParserInfo *p, const char *name) { return NULL; }
888 class XamlElementInstanceEnum : public XamlElementInstance {
890 public:
891 XamlElementInstanceEnum (XamlElementInfoEnum *element_info, const char *name, ElementType type);
893 virtual bool IsDependencyObject ()
895 return false;
898 virtual Value *GetAsValue ()
900 return value;
903 bool CreateEnumFromString (const char* str);
905 // An enum type doesn't really support anything. It's just here so people can do <Visibility>Visible</Visibility>
906 virtual DependencyObject *CreateItem () { return NULL; }
907 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, XamlElementInstance *value) { return false; }
908 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, const char *value) { return false; }
909 virtual void AddChild (XamlParserInfo *p, XamlElementInstance *child) { }
910 virtual void SetAttributes (XamlParserInfo *p, const char **attr);
912 virtual bool TrySetContentProperty (XamlParserInfo *p, XamlElementInstance *value) { return false; }
913 virtual bool TrySetContentProperty (XamlParserInfo *p, const char *value) { return CreateEnumFromString (value); }
916 class XamlElementInstanceTemplate : public XamlElementInstanceNative {
917 public:
918 XamlElementInstanceTemplate (XamlElementInfoNative *element_info, XamlParserInfo *parser_info, const char *name, ElementType type, bool create_item = true)
919 : XamlElementInstanceNative (element_info, parser_info, name, type, create_item)
923 virtual bool IsTemplate ()
925 return true;
930 class DefaultNamespace : public XamlNamespace {
931 public:
932 DefaultNamespace () { }
934 virtual ~DefaultNamespace () { }
936 virtual XamlElementInfo* FindElement (XamlParserInfo *p, const char *el, const char **attr, bool create)
938 Type* t = Type::Find (el, false);
939 if (t && !kind_requires_managed_load (t->GetKind ()))
940 return new XamlElementInfoNative (t);
942 if (enums_is_enum_name (el))
943 return new XamlElementInfoEnum (g_strdup (el));
945 XamlElementInfo* managed_element = create_element_info_from_imported_managed_type (p, el, attr, create);
946 if (managed_element)
947 return managed_element;
949 return NULL;
953 virtual bool SetAttribute (XamlParserInfo *p, XamlElementInstance *item, const char *attr, const char *value)
955 return false;
958 virtual const char* GetUri () { return "http://schemas.microsoft.com/winfx/2006/xaml/presentation"; }
959 virtual const char* GetPrefix () { return ""; }
962 class XmlNamespace : public XamlNamespace {
963 public:
964 XmlNamespace () { }
966 virtual ~XmlNamespace () { }
968 virtual XamlElementInfo* FindElement (XamlParserInfo *p, const char *el, const char **attr, bool create)
970 return NULL;
973 virtual bool SetAttribute (XamlParserInfo *p, XamlElementInstance *item, const char *attr, const char *value)
975 if (!strcmp ("lang", attr)) {
976 if (item->IsDependencyObject ()) {
977 DependencyObject *dob = item->GetAsDependencyObject ();
978 if (dob->Is(Type::FRAMEWORKELEMENT)) {
979 ((FrameworkElement*)dob)->SetLanguage (value);
980 return true;
985 return false;
988 virtual const char* GetUri () { return "http://www.w3.org/XML/1998/namespace"; }
989 virtual const char* GetPrefix () { return "xml"; }
992 class XNamespace : public XamlNamespace {
993 public:
994 XNamespace () { }
996 virtual ~XNamespace () { }
998 virtual XamlElementInfo* FindElement (XamlParserInfo *p, const char *el, const char **attr, bool create)
1000 return NULL;
1003 virtual char *FindTypeName (const char **attr, char **xmlns)
1005 char *res = NULL;
1007 if (!attr)
1008 return NULL;
1010 for (int i = 0; attr [i]; i += 2) {
1011 const char *ns = strchr (attr [i], '|');
1012 if (!ns)
1013 continue;
1015 if (strncmp (GetUri (), attr [i], ns - attr [i]) || strcmp ("Class", ns + 1))
1016 continue;
1018 ns = strchr (attr [i + 1], ';');
1019 if (!ns) {
1020 *xmlns = g_strdup ("");
1021 res = g_strdup (attr [i + 1]);
1022 } else {
1023 *xmlns = g_strdup (ns + 1);
1024 res = g_strndup (attr [i + 1], attr [i + 1] - ns);
1026 return res;
1028 return NULL;
1031 bool IsParentResourceDictionary (XamlElementInstance *parent)
1033 if (parent == NULL)
1034 return false;
1036 return Type::IsSubclassOf (parent->info->GetKind (), Type::RESOURCE_DICTIONARY);
1039 virtual bool SetAttribute (XamlParserInfo *p, XamlElementInstance *item, const char *attr, const char *value)
1041 if (!strcmp ("Name", attr)) {
1043 // Causes breakage in airlines
1044 // Maybe x:Name overwrites but Name does not?
1046 // if (p->namescope->FindName (value)) {
1047 // parser_error (p, p->current_element->element_name, "x:Name", 2028, "The name already exists in the tree: %s.", value);
1048 // return false;
1049 // }
1052 if (IsParentResourceDictionary (p->current_element)) {
1053 if (item->GetKey ()) {
1054 // XXX don't know the proper values here...
1055 parser_error (p, item->element_name, NULL, 2028,
1056 "The name already exists in the tree: %s.", value);
1057 return false;
1061 if (item->GetName ()) {
1062 parser_error (p, item->element_name, NULL, 2016, "Cannot specify both Name and x:Name attributes.");
1063 return false;
1066 item->SetName (p, value);
1068 if (item->IsDependencyObject ()) {
1069 NameScope *scope = p->namescope;
1070 if (!item->GetAsDependencyObject ()->SetName (value, scope)) {
1071 if (IsParentResourceDictionary (p->current_element)) {
1072 // FIXME: inside of a resource dictionary this has an extremly
1073 // strange behavior. this isn't exactly right, since not only
1074 // does the exception get swallowed, but the name seems to also
1075 // be unregistered.
1077 else {
1078 parser_error (p, item->element_name, NULL, 2028,
1079 "The name already exists in the tree: %s.", value);
1080 return false;
1083 return true;
1086 return false;
1089 if (!strcmp ("Key", attr)) {
1090 if (item->GetKey () && IsParentResourceDictionary (p->current_element) && !Type::IsSubclassOf (item->info->GetKind (), Type::STORYBOARD)) {
1091 // XXX don't know the proper values here...
1092 parser_error (p, item->element_name, NULL, 2028,
1093 "The name already exists in the tree: %s.", value);
1094 return false;
1096 item->SetKey (p, value);
1097 return true;
1100 if (!strcmp ("Class", attr)) {
1101 if (!is_legal_top_level_kind (item->info->GetKind ())) {
1102 // XXX don't know the proper values here...
1103 parser_error (p, item->element_name, attr, -1,
1104 "Cannot specify x:Class type '%s' on value type element (%s).", value, item->element_name);
1105 return false;
1108 if (p->top_element != item) {
1109 // HAH: what a useless error message
1110 parser_error (p, item->element_name, attr, 2012,
1111 "Unknown attribute %s on element %s.", attr, item->element_name);
1112 return false;
1115 // While hydrating, we do not need to create the toplevel class, its created already
1116 if (p->hydrating)
1117 return true;
1118 else {
1119 parser_error (p, item->element_name, attr, 4005,
1120 "Cannot specify x:Class in xaml files outside of a xap.");
1121 return false;
1125 return false;
1128 virtual const char* GetUri () { return X_NAMESPACE_URI; }
1129 virtual const char* GetPrefix () { return "x"; }
1133 class PrimitiveNamespace : public XamlNamespace {
1135 private:
1136 char *prefix;
1139 public:
1140 PrimitiveNamespace (char *prefix)
1142 this->prefix = prefix;
1145 virtual ~PrimitiveNamespace ()
1147 if (prefix)
1148 g_free (prefix);
1151 virtual XamlElementInfo* FindElement (XamlParserInfo *p, const char *el, const char **attr, bool create)
1153 if (!strcmp ("String", el)) {
1154 Type* t = Type::Find (Type::STRING);
1155 // it's not as easy in this case, because primitive clr strings require that the
1156 // character data be read in verbatim, including all whitespace.
1157 XamlElementInfo *info = new XamlElementInfoNative (t);
1158 info->SetIsCDataVerbatim (true);
1159 return info;
1160 } else if (!strcmp ("Int32", el)) {
1161 Type* t = Type::Find (Type::INT32);
1162 return new XamlElementInfoNative (t);
1163 } else if (!strcmp ("Double", el)) {
1164 Type* t = Type::Find (Type::DOUBLE);
1165 return new XamlElementInfoNative (t);
1166 } else if (!strcmp ("Boolean", el)) {
1167 Type* t = Type::Find (Type::BOOL);
1168 return new XamlElementInfoNative (t);
1169 } else if (!strcmp ("TimeSpan", el)) {
1170 Type* t = Type::Find (Type::TIMESPAN);
1171 return new XamlElementInfoNative (t);
1174 return NULL;
1177 virtual bool SetAttribute (XamlParserInfo *p, XamlElementInstance *item, const char *attr, const char *value)
1179 return false;
1182 virtual const char* GetUri () { return PRIMITIVE_NAMESPACE_URI; }
1183 virtual const char* GetPrefix () { return prefix; }
1187 class MCIgnorableNamespace : public XamlNamespace {
1189 private:
1190 char *prefix;
1192 public:
1193 MCIgnorableNamespace (char *prefix)
1195 this->prefix = prefix;
1198 virtual ~MCIgnorableNamespace ()
1200 if (prefix)
1201 g_free (prefix);
1204 virtual XamlElementInfo* FindElement (XamlParserInfo *p, const char *el, const char **attr, bool create)
1206 return NULL;
1209 virtual bool SetAttribute (XamlParserInfo *p, XamlElementInstance *item, const char *attr, const char *value)
1211 if (!strcmp ("Ignorable", attr)) {
1212 const char *start = value;
1213 do {
1214 const char *space = strchr (start, ' ');
1215 char *prefix;
1216 if (space) {
1217 prefix = g_strndup (start, space - start);
1218 start = space + 1;
1219 } else {
1220 prefix = g_strdup (start);
1221 start = NULL;
1224 XamlNamespace *ns = (XamlNamespace *) g_hash_table_find (p->namespace_map, namespace_for_prefix, prefix);
1225 if (ns)
1226 ns->is_ignored = true;
1228 } while (start);
1230 return true;
1233 return false;
1236 virtual const char* GetUri () { return MC_IGNORABLE_NAMESPACE_URI; }
1237 virtual const char* GetPrefix () { return prefix; }
1241 static void
1242 destroy_created_namespace (gpointer data, gpointer user_data)
1244 XamlNamespace* ns = (XamlNamespace *) data;
1245 delete ns;
1249 class XamlElementInfoManaged : public XamlElementInfo {
1250 public:
1251 XamlElementInfoManaged (const char *xmlns, const char *name, XamlElementInfo *parent, Type::Kind dependency_type, Value *obj) : XamlElementInfo (xmlns, name, dependency_type)
1253 this->obj = obj;
1256 Value *obj;
1258 const char* GetName () { return name; }
1260 const char* GetContentProperty (XamlParserInfo *p);
1262 virtual bool RequiresManagedSet () { return true; }
1264 XamlElementInstance* CreateElementInstance (XamlParserInfo *p);
1265 XamlElementInstance* CreateWrappedElementInstance (XamlParserInfo *p, Value *o);
1266 XamlElementInstance* CreatePropertyElementInstance (XamlParserInfo *p, const char *name);
1270 class XamlElementInstanceManaged : public XamlElementInstance {
1271 public:
1272 XamlElementInstanceManaged (XamlElementInfo *info, const char *name, ElementType type, Value *obj);
1274 virtual bool IsDependencyObject ()
1276 return is_dependency_object;
1279 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, XamlElementInstance *value);
1280 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, const char* value);
1281 virtual void AddChild (XamlParserInfo *p, XamlElementInstance *child);
1282 virtual void SetAttributes (XamlParserInfo *p, const char **attr);
1284 virtual bool TrySetContentProperty (XamlParserInfo *p, XamlElementInstance *value);
1285 virtual bool TrySetContentProperty (XamlParserInfo *p, const char *value);
1287 virtual void* GetManagedPointer ();
1288 virtual Value* GetParentPointer ();
1289 private:
1290 bool is_dependency_object;
1294 class XamlElementInfoImportedManaged : public XamlElementInfoManaged {
1295 public:
1296 XamlElementInfoImportedManaged (const char *name, XamlElementInfo *parent, Value *obj) : XamlElementInfoManaged (NULL, name, parent, obj->GetKind (), obj)
1300 const char* GetContentProperty (XamlParserInfo *p);
1302 XamlElementInstance* CreateElementInstance (XamlParserInfo *p);
1303 XamlElementInstance* CreateWrappedElementInstance (XamlParserInfo *p, Value *o);
1304 XamlElementInstance* CreatePropertyElementInstance (XamlParserInfo *p, const char *name);
1309 class ManagedNamespace : public XamlNamespace {
1310 public:
1311 char *xmlns;
1312 char *prefix;
1314 ManagedNamespace (char *xmlns, char *prefix)
1316 this->xmlns = xmlns;
1317 this->prefix = prefix;
1320 virtual ~ManagedNamespace ()
1322 g_free (xmlns);
1323 g_free (prefix);
1326 virtual XamlElementInfo* FindElement (XamlParserInfo *p, const char *el, const char **attr, bool create)
1328 char* type_name = NULL;
1329 char* type_xmlns = NULL;
1330 const char* use_xmlns = xmlns;
1332 if (!p->loader)
1333 return NULL;
1335 if (x_namespace) {
1336 // We might have an x:Class attribute specified, so we need to use that for the
1337 // type_name that we pass to LookupObject
1338 if (strcmp ("Application", el)) {
1339 type_name = x_namespace->FindTypeName (attr, &type_xmlns);
1340 if (type_name) {
1341 el = type_name;
1342 use_xmlns = type_xmlns;
1344 if (!p->hydrating) {
1345 parser_error (p, el, "x:Class", 4005, "Cannot specify x:Class in xaml files outside of a xap.");
1346 return NULL;
1352 Value *value = new Value ();
1353 if (!p->loader->LookupObject (p, p->GetTopElementPtr (), p->current_element ? p->current_element->GetAsValue () : NULL, use_xmlns, el, create, false, value)) {
1354 parser_error (p, el, NULL, 2007, "Unable to resolve managed type %s.", el);
1355 delete value;
1356 if (type_name)
1357 g_free (type_name);
1358 if (type_xmlns)
1359 g_free (type_xmlns);
1360 return NULL;
1363 if (p->hydrate_expecting) {
1365 // If we are hydrating a top level managed object, use the Value* passed
1366 // to Hydrate as our value
1368 Value *v = value;
1369 value = p->hydrate_expecting;
1370 delete v;
1373 XamlElementInfoManaged *info = new XamlElementInfoManaged (xmlns, g_strdup (el), NULL, value->GetKind (), value);
1374 if (type_name)
1375 g_free (type_name);
1376 if (type_xmlns)
1377 g_free (type_xmlns);
1378 return info;
1381 virtual bool SetAttribute (XamlParserInfo *p, XamlElementInstance *item, const char *attr, const char *value)
1383 if (is_ignored)
1384 return true;
1386 if (p->loader) {
1387 Value v = Value (value);
1388 return p->loader->SetProperty (p, p->GetTopElementPtr (), item->info->xmlns, item->GetAsValue (), item, item->GetParentPointer (), xmlns, attr, &v, NULL);
1390 return false;
1394 virtual const char* GetUri () { return xmlns; }
1395 virtual const char* GetPrefix () { return prefix; }
1398 bool
1399 XamlLoader::LookupObject (void *p, Value *top_level, Value *parent, const char* xmlns, const char* type_name, bool create, bool is_property, Value *value)
1401 if (callbacks.lookup_object) {
1402 if (!vm_loaded && !LoadVM ())
1403 return false;
1404 MoonError error;
1405 XamlCallbackData data = XamlCallbackData (this, p, top_level);
1406 bool res = callbacks.lookup_object (&data, parent, xmlns, type_name, create, is_property, value, &error);
1407 return res;
1410 return false;
1413 const char *
1414 XamlLoader::GetContentPropertyName (void *p, Value *top_level, Value *object)
1416 if (callbacks.get_content_property_name) {
1417 MoonError error;
1418 XamlCallbackData data = XamlCallbackData (this, p, top_level);
1419 return callbacks.get_content_property_name (&data, object, &error);
1421 return NULL;
1424 bool
1425 XamlLoader::SetProperty (void *p, Value *top_level, const char* xmlns, Value *target, void *target_data, Value *target_parent, const char* prop_xmlns, const char *name, Value *value, void* value_data, int flags)
1427 if (callbacks.set_property) {
1428 MoonError error;
1429 XamlCallbackData data = XamlCallbackData (this, p, top_level, flags);
1430 bool res = callbacks.set_property (&data, xmlns, target, target_data, target_parent, prop_xmlns, name, value, value_data, &error);
1432 if (error.number != MoonError::NO_ERROR) {
1433 parser_error ((XamlParserInfo *) p, ((XamlElementInstance *) target_data)->element_name, NULL, error.code, error.message);
1434 return false;
1437 return res;
1440 return false;
1443 bool
1444 XamlLoader::AddChild (void *p, Value *top_level, Value *parent_parent, bool parent_is_property, const char* parent_xmlns, Value *parent, void *parent_data, Value *child, void *child_data)
1446 if (callbacks.add_child) {
1447 MoonError error;
1448 XamlCallbackData data = XamlCallbackData (this, p, top_level);
1449 bool res = callbacks.add_child (&data, parent_parent, parent_is_property, parent_xmlns, parent, parent_data, child, child_data, &error);
1451 if (error.number != MoonError::NO_ERROR) {
1452 parser_error ((XamlParserInfo *) p, ((XamlElementInstance *) child_data)->element_name, NULL, error.code, error.message);
1453 return false;
1456 return res;
1458 return false;
1461 XamlLoader::XamlLoader (const char *resourceBase, const char* filename, const char* str, Surface* surface, XamlContext *context)
1463 Initialize (resourceBase, filename, str, surface, context);
1466 XamlLoader::XamlLoader (const char* filename, const char* str, Surface* surface, XamlContext *context)
1468 Initialize (NULL, filename, str, surface, context);
1471 void
1472 XamlLoader::Initialize (const char *resourceBase, const char* filename, const char* str, Surface* surface, XamlContext *context)
1474 this->filename = g_strdup (filename);
1475 this->resource_base = g_strdup (resourceBase);
1476 this->str = g_strdup (str);
1477 this->surface = surface;
1478 if (surface)
1479 surface->ref ();
1480 this->context = context;
1481 this->vm_loaded = false;
1482 this->error_args = NULL;
1483 this->expanding_template = false;
1484 this->import_default_xmlns = false;
1486 if (context) {
1487 callbacks = context->internal->callbacks;
1488 this->vm_loaded = true;
1490 if (!surface && context->internal->surface) {
1491 this->surface = context->internal->surface;
1492 this->surface->ref ();
1495 #if DEBUG
1496 if (!surface && debug_flags & RUNTIME_DEBUG_XAML) {
1497 printf ("XamlLoader::XamlLoader ('%s', '%s', %p): Initializing XamlLoader without a surface.\n",
1498 filename, str, surface);
1500 #endif
1503 XamlLoader::~XamlLoader ()
1505 g_free (filename);
1506 g_free (resource_base);
1507 g_free (str);
1508 if (surface)
1509 surface->unref ();
1510 surface = NULL;
1511 filename = NULL;
1512 str = NULL;
1513 if (error_args)
1514 error_args->unref();
1517 bool
1518 XamlLoader::LoadVM ()
1520 return false;
1523 XamlLoader*
1524 xaml_loader_new (const char *resourceBase, const char* filename, const char* str, Surface* surface)
1526 return new XamlLoader (resourceBase, filename, str, surface);
1529 void
1530 xaml_loader_free (XamlLoader* loader)
1532 delete loader;
1535 void
1536 xaml_loader_set_callbacks (XamlLoader* loader, XamlLoaderCallbacks callbacks)
1538 if (!loader) {
1539 LOG_XAML ("Trying to set callbacks for a null object\n");
1540 return;
1543 loader->callbacks = callbacks;
1544 loader->vm_loaded = true;
1547 static gboolean
1548 namespace_for_prefix (gpointer key, gpointer value, gpointer user_data)
1550 XamlNamespace *ns = (XamlNamespace *) value;
1551 const char *prefix = (const char *) user_data;
1553 if (!strcmp (prefix, ns->GetPrefix ()))
1554 return TRUE;
1555 return FALSE;
1558 char*
1559 xaml_uri_for_prefix (void *parser, char* prefix)
1561 XamlParserInfo *p = (XamlParserInfo *) parser;
1563 XamlNamespace *ns = (XamlNamespace *) g_hash_table_find (p->namespace_map, namespace_for_prefix, prefix);
1564 if (!ns)
1565 return NULL;
1567 return g_strdup (ns->GetUri ());
1571 // Called when we encounter an error. Note that memory ownership is taken for everything
1572 // except the message, this allows you to use g_strdup_printf when creating the error message
1574 static void
1575 parser_error (XamlParserInfo *p, const char *el, const char *attr, int error_code, const char *format, ...)
1577 char *message;
1578 va_list args;
1580 // Already failed
1581 if (p->error_args)
1582 return;
1584 // if parsing fails too early it's not safe (i.e. sigsegv) to call some functions, e.g. XML_GetCurrentLineNumber
1585 bool report_line_col = (error_code != XML_ERROR_XML_DECL);
1586 int line_number = report_line_col ? XML_GetCurrentLineNumber (p->parser) : 0;
1587 int char_position = report_line_col ? XML_GetCurrentColumnNumber (p->parser) : 0;
1589 va_start (args, format);
1590 message = g_strdup_vprintf (format, args);
1591 va_end (args);
1593 p->error_args = new ParserErrorEventArgs (message, p->file_name, line_number, char_position, error_code, el, attr);
1595 g_free (message);
1597 LOG_XAML ("PARSER ERROR, STOPPING PARSING: (%d) %s line: %d char: %d\n", error_code, message,
1598 line_number, char_position);
1600 XML_StopParser (p->parser, FALSE);
1603 void
1604 expat_parser_error (XamlParserInfo *p, XML_Error expat_error)
1606 // Already had an error
1607 if (p->error_args)
1608 return;
1610 LOG_XAML ("expat error is: %d\n", expat_error);
1612 switch (expat_error) {
1613 case XML_ERROR_DUPLICATE_ATTRIBUTE:
1614 parser_error (p, NULL, NULL, 7031, "wfc: unique attribute spec");
1615 break;
1616 case XML_ERROR_UNBOUND_PREFIX:
1617 parser_error (p, NULL, NULL, 7055, "undeclared prefix");
1618 break;
1619 case XML_ERROR_NO_ELEMENTS:
1620 parser_error (p, NULL, NULL, 7000, "unexpected end of input");
1621 break;
1622 case XML_ERROR_SYNTAX:
1623 parser_error (p, NULL, NULL, 2103, "syntax error");
1624 break;
1625 default:
1626 parser_error (p, NULL, NULL, expat_error, "Unhandled XML error %s", XML_ErrorString (expat_error));
1627 break;
1631 static void
1632 start_element (void *data, const char *el, const char **attr)
1634 XamlParserInfo *p = (XamlParserInfo *) data;
1635 XamlElementInfo *elem = NULL;
1636 XamlElementInstance *inst;
1637 Types *types = Deployment::GetCurrent ()->GetTypes ();
1639 if (!strcmp (el, INTERNAL_IGNORABLE_ELEMENT))
1640 return;
1642 if (p->ShouldBeginBuffering ()) {
1643 p->BeginBuffering ();
1644 return;
1647 if (p->InBufferingMode ()) {
1648 if (!strcmp (p->buffer_until_element, el))
1649 p->buffer_depth++;
1650 return;
1653 const char *dot = strchr (el, '.');
1654 if (!dot)
1655 elem = p->current_namespace->FindElement (p, el, attr, p->hydrate_expecting == NULL);
1657 if (p->error_args)
1658 return;
1661 if (elem) {
1662 if (p->hydrate_expecting){
1664 Type::Kind expecting_type = p->hydrate_expecting->GetObjectType ();
1666 if (!types->IsSubclassOf (expecting_type, elem->GetKind ())) {
1667 parser_error (p, el, NULL, -1, "Invalid top-level element found %s, expecting %s", el,
1668 types->Find (expecting_type)->GetName ());
1669 return;
1673 inst = elem->CreateWrappedElementInstance (p, p->hydrate_expecting);
1674 p->hydrate_expecting = NULL;
1675 } else
1676 inst = elem->CreateElementInstance (p);
1678 if (!inst)
1679 return;
1681 inst->parent = p->current_element;
1683 if (!p->top_element) {
1684 p->top_element = inst;
1685 if (inst->GetAsDependencyObject ())
1686 NameScope::SetNameScope (inst->GetAsDependencyObject (), p->namescope);
1689 inst->SetAttributes (p, attr);
1690 if (p->error_args)
1691 return;
1693 if (inst->IsDependencyObject ()) {
1694 if (p->current_element){
1695 if (p->current_element->info) {
1696 p->current_element->AddChild (p, inst);
1697 if (p->error_args)
1698 return;
1702 } else {
1703 // it's actually valid (from SL point of view) to have <Ellipse.Triggers> inside a <Rectangle>
1704 // however we can't add properties to something bad, like a <Recta.gle> element
1705 XamlElementInfo *prop_info = NULL;
1706 if (dot) {
1707 gchar *prop_elem = g_strndup (el, dot - el);
1708 prop_info = p->current_element->FindPropertyElement (p, el, dot);
1709 g_free (prop_elem);
1712 if (prop_info != NULL) {
1713 inst = prop_info->CreatePropertyElementInstance (p, g_strdup (el));
1714 inst->parent = p->current_element;
1716 if (attr [0] != NULL) {
1717 // It appears there is a bug in the error string but it matches the MS runtime
1718 parser_error (p, el, NULL, 2018, "The element %s does not support attributes.", attr[0]);
1719 return;
1722 if (prop_info && !strcmp (el, "TextBox.Text"))
1723 prop_info->SetIsCDataVerbatim (true);
1725 if (!p->top_element) {
1726 if (types->IsSubclassOf (prop_info->GetKind (), Type::COLLECTION)) {
1727 XamlElementInstance *wrap = prop_info->CreateElementInstance (p);
1728 NameScope::SetNameScope (wrap->GetAsDependencyObject (), p->namescope);
1729 p->top_element = wrap;
1730 p->current_element = wrap;
1731 return;
1734 } else {
1735 g_warning ("Unknown element: %s.", el);
1736 parser_error (p, el, NULL, 2007, "Unknown element: %s.", el);
1737 return;
1741 if (p->current_element) {
1742 p->current_element->children->Append (inst);
1744 p->current_element = inst;
1746 if (elem && element_begins_buffering (elem->GetKind ())) {
1747 p->QueueBeginBuffering (g_strdup (el), BUFFER_MODE_TEMPLATE);
1751 static bool
1752 allow_value_from_str_in_flush (XamlParserInfo *p, XamlElementInstance *parent)
1754 if (parent == NULL || parent->element_type != XamlElementInstance::PROPERTY || parent->parent == NULL || !parent->parent->IsDependencyObject ())
1755 return false;
1757 if (parent->info->GetKind () == Type::OBJECT)
1758 return true;
1760 return false;
1763 static void
1764 flush_char_data (XamlParserInfo *p)
1766 if (p->InBufferingMode ())
1767 return;
1769 if (!p->cdata || !p->current_element)
1770 return;
1772 if (p->current_element->info->IsCDataVerbatim()) {
1773 p->cdata->str = g_strstrip (p->cdata->str);
1776 if (p->current_element->element_type == XamlElementInstance::ELEMENT) {
1777 if (!p->current_element->TrySetContentProperty (p, p->cdata->str) && p->cdata_content) {
1778 if (allow_value_from_str_in_flush (p, p->current_element->parent)) {
1779 Value *v;
1780 if (value_from_str (p->current_element->info->GetKind (), NULL, p->cdata->str, &v)) {
1781 p->current_element->SetValue (v);
1782 goto cleanup;
1785 parser_error (p, p->current_element->element_name, NULL, 2011,
1786 "%s does not support text content.", p->current_element->element_name);
1788 } else if (p->current_element->element_type == XamlElementInstance::PROPERTY) {
1789 if (p->cdata_content && p->current_element->parent && !p->current_element->parent->SetProperty (p, p->current_element, p->cdata->str)) {
1790 parser_error (p, p->current_element->element_name, NULL, 2011,
1791 "%s does not support text content.", p->current_element->element_name);
1795 cleanup:
1796 if (p->cdata) {
1797 g_string_free (p->cdata, TRUE);
1798 p->cdata_content = false;
1799 p->cdata = NULL;
1803 static bool
1804 element_begins_buffering (Type::Kind kind)
1806 return Type::IsSubclassOf (kind, Type::FRAMEWORKTEMPLATE);
1809 static gboolean
1810 is_default_namespace (gpointer key, gpointer value, gpointer user_data)
1812 return value == default_namespace;
1815 static void
1816 start_element_handler (void *data, const char *el, const char **attr)
1818 XamlParserInfo *p = (XamlParserInfo *) data;
1820 if (p->error_args)
1821 return;
1823 char **name = g_strsplit (el, "|", -1);
1824 XamlNamespace *next_namespace = NULL;
1825 char *element = NULL;
1827 if (g_strv_length (name) == 2) {
1828 // Find the proper namespace for our next element
1829 next_namespace = (XamlNamespace *) g_hash_table_lookup (p->namespace_map, name [0]);
1830 element = name [1];
1833 if (!next_namespace && p->implicit_default_namespace) {
1834 // Use the default namespace for the next element
1835 next_namespace = default_namespace;
1836 element = name [0];
1837 } else if (!next_namespace) {
1838 if (!g_hash_table_find (p->namespace_map, is_default_namespace, NULL))
1839 return parser_error (p, el, NULL, 2263, "AG_E_PARSER_MISSING_DEFAULT_NAMESPACE");
1842 if (next_namespace && next_namespace->is_ignored) {
1843 p->current_namespace = next_namespace;
1844 if (!p->InBufferingMode ())
1845 p->QueueBeginBuffering (g_strdup (element), BUFFER_MODE_IGNORE);
1847 start_element (data, element, attr); // This will force the buffering to start/build depth if needed
1848 return;
1851 p->next_element = element;
1853 flush_char_data (p);
1855 // Now update our namespace
1856 p->current_namespace = next_namespace;
1858 if (!p->current_namespace && !p->InBufferingMode ()) {
1859 if (name[1])
1860 parser_error (p, name[1], NULL, -1, "No handlers available for namespace: '%s' (%s)\n", name[0], el);
1861 else
1862 parser_error (p, name[1], NULL, -1, "No namespace mapping available for element: '%s'\n", el);
1864 g_strfreev (name);
1865 return;
1868 p->next_element = NULL;
1869 start_element (data, element, attr);
1871 g_strfreev (name);
1874 static char*
1875 get_element_name (XamlParserInfo* p, const char *el)
1877 char **names = g_strsplit (el, "|", -1);
1878 char *name = g_strdup (names [g_strv_length (names) - 1]);
1880 g_strfreev (names);
1882 return name;
1885 static GSList *
1886 create_resource_list (XamlParserInfo *p)
1888 GSList *list = NULL;
1889 XamlElementInstance *walk = p->current_element;
1891 Types * types = Deployment::GetCurrent ()->GetTypes ();
1892 while (walk) {
1893 if (walk->element_type == XamlElementInstance::ELEMENT && types->IsSubclassOf (walk->info->GetKind (), Type::FRAMEWORKELEMENT)) {
1894 FrameworkElement *fwe = (FrameworkElement *)walk->GetAsDependencyObject ();
1895 if (g_slist_index (list, fwe) == -1)
1896 list = g_slist_prepend (list, fwe);
1898 if (walk->element_type == XamlElementInstance::ELEMENT && types->IsSubclassOf (walk->info->GetKind (), Type::RESOURCE_DICTIONARY)) {
1899 ResourceDictionary *rd = (ResourceDictionary *) walk->GetAsDependencyObject ();
1900 if (g_slist_index (list, rd) == -1)
1901 list = g_slist_prepend (list, walk->GetAsDependencyObject ());
1903 walk = walk->parent;
1906 list = g_slist_reverse (list);
1907 return list;
1910 static XamlContext *
1911 create_xaml_context (XamlParserInfo *p, FrameworkTemplate *template_, XamlContext *parent_context)
1913 GSList *resources = create_resource_list (p);
1914 XamlContextInternal *ic = new XamlContextInternal (p->loader->callbacks, p->GetTopElementPtr (), template_, p->namespace_map, resources, parent_context ? parent_context->internal : NULL);
1915 return new XamlContext (ic);
1918 static void
1919 end_element_handler (void *data, const char *el)
1921 XamlParserInfo *p = (XamlParserInfo *) data;
1923 if (!strcmp (el, INTERNAL_IGNORABLE_ELEMENT))
1924 return;
1926 if (p->error_args)
1927 return;
1929 if (!p->current_element) {
1930 g_warning ("p->current_element == NULL, current_element = %p (%s)\n",
1931 p->current_element, p->current_element ? p->current_element->element_name : "<NULL>");
1932 return;
1935 if (p->InBufferingMode ()) {
1936 char* name = get_element_name (p, el);
1937 if (!strcmp (p->buffer_until_element, name)) {
1938 p->buffer_depth--;
1940 if (p->buffer_depth == 0) {
1941 if (p->buffer_mode == BUFFER_MODE_TEMPLATE) {
1942 // OK we are done buffering, the element we are buffering for
1943 FrameworkTemplate* template_ = (FrameworkTemplate *) p->current_element->GetAsDependencyObject ();
1945 char* buffer = p->ClearBuffer ();
1947 XamlContext *context = create_xaml_context (p, template_, p->loader->GetContext());
1949 if (p->validate_templates) {
1950 p->ValidateTemplate (buffer, context, template_);
1952 if (p->error_args)
1953 return;
1956 template_->SetXamlBuffer (context, buffer);
1957 p->current_element = p->current_element->parent;
1958 } else if (p->buffer_mode == BUFFER_MODE_IGNORE) {
1959 // For now we'll actually keep/clear this buffer because it makes testing easier
1960 char *buffer = p->ClearBuffer ();
1961 g_free (buffer);
1966 g_free (name);
1967 return;
1970 switch (p->current_element->element_type) {
1971 case XamlElementInstance::ELEMENT:
1973 p->current_element->SetDelayedProperties (p);
1974 flush_char_data (p);
1976 // according to http://blogs.msdn.com/devdave/archive/2008/10/11/control-lifecycle.aspx
1977 // default styles are apply when the end tag is read.
1979 if (p->current_element->IsDependencyObject () &&
1980 p->current_element->GetAsDependencyObject() &&
1981 p->current_element->GetAsDependencyObject()->Is(Type::CONTROL)) {
1983 Control *control = (Control*)p->current_element->GetAsDependencyObject();
1984 ManagedTypeInfo *key = control->GetDefaultStyleKey ();
1986 if (key) {
1987 if (Application::GetCurrent () == NULL)
1988 g_warning ("attempting to use a null application applying default style while parsing.");
1989 else
1990 Application::GetCurrent()->ApplyDefaultStyle (control, key);
1993 else if (!p->current_element->IsDependencyObject ()) {
1995 if (p->current_element->parent)
1996 p->current_element->parent->AddChild (p, p->current_element);
1998 break;
1999 case XamlElementInstance::PROPERTY: {
2000 List::Node *walk = p->current_element->children->First ();
2001 while (walk) {
2002 XamlElementInstance *child = (XamlElementInstance *) walk;
2003 if (p->current_element->parent) {
2004 p->current_element->parent->SetProperty (p, p->current_element, child);
2006 walk = walk->next;
2008 flush_char_data (p);
2009 break;
2013 p->current_element = p->current_element->parent;
2016 static void
2017 char_data_handler (void *data, const char *in, int inlen)
2019 XamlParserInfo *p = (XamlParserInfo *) data;
2020 register const char *inptr = in;
2021 const char *inend = in + inlen;
2022 const char *start;
2024 if (p->InBufferingMode ())
2025 return;
2027 if (p->error_args)
2028 return;
2030 if (p->current_element && p->current_element->info->IsCDataVerbatim()) {
2031 if (!p->cdata)
2032 p->cdata = g_string_new ("");
2034 g_string_append_len (p->cdata, inptr, inlen);
2035 p->cdata_content = true;
2036 return;
2039 if (!p->cdata) {
2040 p->cdata = g_string_new ("");
2042 if (g_ascii_isspace (*inptr)) {
2043 g_string_append_c (p->cdata, ' ');
2044 inptr++;
2046 while (inptr < inend && g_ascii_isspace (*inptr))
2047 inptr++;
2050 if (inptr == inend)
2051 return;
2052 } else if (g_ascii_isspace (p->cdata->str[p->cdata->len - 1])) {
2053 // previous cdata chunk ended with lwsp, skip over leading lwsp for this chunk
2054 while (inptr < inend && g_ascii_isspace (*inptr))
2055 inptr++;
2058 while (inptr < inend) {
2059 start = inptr;
2060 while (inptr < inend && !g_ascii_isspace (*inptr))
2061 inptr++;
2063 if (inptr > start) {
2064 g_string_append_len (p->cdata, start, inptr - start);
2065 p->cdata_content = true;
2068 if (inptr < inend) {
2069 g_string_append_c (p->cdata, ' ');
2070 inptr++;
2072 while (inptr < inend && g_ascii_isspace (*inptr))
2073 inptr++;
2078 static void
2079 start_namespace_handler (void *data, const char *prefix, const char *uri)
2081 XamlParserInfo *p = (XamlParserInfo *) data;
2083 if (p->InBufferingMode ())
2084 return;
2086 if (p->error_args)
2087 return;
2089 if (p->loader != NULL && p->loader->callbacks.import_xaml_xmlns != NULL) {
2090 MoonError error;
2091 XamlCallbackData data = XamlCallbackData (p->loader, p, p->GetTopElementPtr ());
2092 if (!p->loader->callbacks.import_xaml_xmlns (&data, uri, &error))
2093 return parser_error (p, p->current_element ? p->current_element->element_name : NULL, prefix, 2005, "Unknown namespace %s", uri);
2096 for (int i = 0; default_namespace_names [i]; i++) {
2097 if (!strcmp (default_namespace_names [i], uri)) {
2098 g_hash_table_insert (p->namespace_map, g_strdup (uri), default_namespace);
2099 return;
2103 if (!strcmp (X_NAMESPACE_URI, uri)){
2104 g_hash_table_insert (p->namespace_map, g_strdup (uri), x_namespace);
2105 } else if (!strcmp (PRIMITIVE_NAMESPACE_URI, uri)) {
2106 PrimitiveNamespace *pn = new PrimitiveNamespace (g_strdup (prefix));
2107 g_hash_table_insert (p->namespace_map, g_strdup (uri), pn);
2108 p->AddCreatedNamespace (pn);
2109 } else if (!strcmp (MC_IGNORABLE_NAMESPACE_URI, uri)) {
2110 MCIgnorableNamespace *mc = new MCIgnorableNamespace (g_strdup (prefix));
2111 g_hash_table_insert (p->namespace_map, g_strdup (uri), mc);
2112 p->AddCreatedNamespace (mc);
2113 } else {
2114 if (!p->loader) {
2115 return parser_error (p, (p->current_element ? p->current_element->element_name : NULL), prefix, -1,
2116 "No managed element callback installed to handle %s", uri);
2119 if (!prefix) {
2120 parser_error (p, (p->current_element ? p->current_element->element_name : NULL), NULL, 2262,
2121 "AG_E_PARSER_NAMESPACE_NOT_SUPPORTED");
2122 return;
2125 ManagedNamespace *c = new ManagedNamespace (g_strdup (uri), g_strdup (prefix));
2126 g_hash_table_insert (p->namespace_map, g_strdup (c->xmlns), c);
2127 p->AddCreatedNamespace (c);
2131 static void
2132 start_doctype_handler (void *data,
2133 const XML_Char *doctype_name,
2134 const XML_Char *sysid,
2135 const XML_Char *pubid,
2136 int has_internal_subset)
2138 XamlParserInfo *p = (XamlParserInfo *) data;
2140 if (p->InBufferingMode ())
2141 return;
2143 if (sysid)
2144 return parser_error (p, NULL, NULL, 7050, "DTD was found but is prohibited");
2146 if (doctype_name)
2147 return parser_error (p, NULL, NULL, 7016, "incorrect document syntax.");
2150 static void
2151 add_default_namespaces (XamlParserInfo *p, bool sl_xmlns)
2153 if (sl_xmlns) {
2154 p->implicit_default_namespace = true;
2155 g_hash_table_insert (p->namespace_map, g_strdup ("http://schemas.microsoft.com/winfx/2006/xaml/presentation"), default_namespace);
2156 g_hash_table_insert (p->namespace_map, g_strdup (X_NAMESPACE_URI), x_namespace);
2158 g_hash_table_insert (p->namespace_map, g_strdup (XML_NAMESPACE_URI), xml_namespace);
2161 static void
2162 print_tree (XamlElementInstance *el, int depth)
2164 #if DEBUG
2165 if (debug_flags & RUNTIME_DEBUG_XAML) {
2166 for (int i = 0; i < depth; i++)
2167 printf ("\t");
2169 const char *name = NULL;
2171 if (!el) {
2172 printf (" -null- \n");
2173 return;
2176 if (el->element_type == XamlElementInstance::ELEMENT && el->IsDependencyObject ())
2177 name = el->GetAsDependencyObject ()->GetName ();
2178 printf ("%s (%s) (%p) (%s)\n", el->element_name, name ? name : "-no name-", el->parent, el->element_type == XamlElementInstance::PROPERTY ? "PROPERTY" : "ELEMENT");
2180 for (List::Node *walk = el->children->First (); walk != NULL; walk = walk->next) {
2181 XamlElementInstance *el = (XamlElementInstance *) walk;
2182 print_tree (el, depth + 1);
2185 #endif
2188 void
2189 xaml_parse_xmlns (const char* xmlns, char** type_name, char** ns, char** assembly)
2191 const char delimiters[] = ";";
2192 char* decl;
2193 char* buffer = g_strdup (xmlns);
2195 *type_name = NULL;
2196 *ns = NULL;
2197 *assembly = NULL;
2199 decl = strtok (buffer, delimiters);
2200 while (decl != NULL) {
2201 if (strstr (decl, "clr-namespace:") == decl) {
2202 if (*ns)
2203 g_free (*ns);
2204 *ns = g_strdup (decl + 14);
2205 } else if (strstr (decl, "assembly=") == decl) {
2206 if (*assembly)
2207 g_free (*assembly);
2208 *assembly = g_strdup (decl + 9);
2209 } else {
2210 if (*type_name)
2211 g_free (*type_name);
2212 *type_name = g_strdup (decl);
2215 decl = strtok (NULL, delimiters);
2217 g_free (buffer);
2220 Value *
2221 XamlLoader::CreateFromFile (const char *xaml_file, bool create_namescope,
2222 Type::Kind *element_type)
2224 Value *res = NULL;
2225 XamlParserInfo *parser_info = NULL;
2226 XML_Parser p = NULL;
2227 bool first_read = true;
2228 const char *inptr, *inend;
2229 TextStream *stream;
2230 char buffer[4096];
2231 ssize_t nread, n;
2233 LOG_XAML ("attemtping to load xaml file: %s\n", xaml_file);
2235 stream = new TextStream ();
2236 if (!stream->OpenFile (xaml_file, false)) {
2237 LOG_XAML ("can not open file\n");
2238 goto cleanup_and_return;
2241 if (!(p = XML_ParserCreateNS ("UTF-8", '|'))) {
2242 LOG_XAML ("can not create parser\n");
2243 goto cleanup_and_return;
2246 parser_info = new XamlParserInfo (p, xaml_file);
2248 parser_info->namescope->SetTemporary (!create_namescope);
2250 parser_info->loader = this;
2252 // TODO: This is just in here temporarily, to make life less difficult for everyone
2253 // while we are developing.
2254 add_default_namespaces (parser_info, false);
2256 XML_SetUserData (p, parser_info);
2258 XML_SetElementHandler (p, start_element_handler, end_element_handler);
2259 XML_SetCharacterDataHandler (p, char_data_handler);
2260 XML_SetNamespaceDeclHandler(p, start_namespace_handler, NULL);
2261 XML_SetDoctypeDeclHandler(p, start_doctype_handler, NULL);
2264 XML_SetProcessingInstructionHandler (p, proc_handler);
2267 while ((nread = stream->Read (buffer, sizeof (buffer))) >= 0) {
2268 inptr = buffer;
2269 n = nread;
2271 if (first_read && nread > 0) {
2272 // Remove preceding white space
2273 inend = buffer + nread;
2275 while (inptr < inend && g_ascii_isspace (*inptr))
2276 inptr++;
2278 if (inptr == inend)
2279 continue;
2281 n = (inend - inptr);
2282 first_read = false;
2285 parser_info->SetXmlBuffer (inptr);
2286 if (!XML_Parse (p, inptr, n, nread == 0)) {
2287 expat_parser_error (parser_info, XML_GetErrorCode (p));
2288 goto cleanup_and_return;
2291 if (nread == 0)
2292 break;
2295 print_tree (parser_info->top_element, 0);
2297 if (parser_info->top_element) {
2298 res = parser_info->top_element->GetAsValue ();
2299 // We want a copy because the old one is going to be deleted
2300 res = new Value (*res);
2302 if (element_type)
2303 *element_type = parser_info->top_element->info->GetKind ();
2305 if (parser_info->error_args) {
2306 *element_type = Type::INVALID;
2307 goto cleanup_and_return;
2311 cleanup_and_return:
2313 if (!parser_info)
2314 error_args = new ParserErrorEventArgs ("Error opening xaml file", xaml_file, 0, 0, 1, "", "");
2315 else if (parser_info->error_args) {
2316 error_args = parser_info->error_args;
2317 error_args->ref ();
2320 delete stream;
2322 if (p)
2323 XML_ParserFree (p);
2325 if (parser_info)
2326 delete parser_info;
2328 return res;
2331 Value *
2332 XamlLoader::CreateFromString (const char *xaml, bool create_namescope, Type::Kind *element_type, int flags)
2334 return HydrateFromString (xaml, NULL, create_namescope, element_type, flags);
2337 DependencyObject *
2338 value_to_dependency_object (Value *value)
2340 if (!value || !value->Is (Type::DEPENDENCY_OBJECT))
2341 return NULL;
2342 return value->AsDependencyObject ();
2345 DependencyObject *
2346 XamlLoader::CreateDependencyObjectFromFile (const char *xaml, bool create_namescope, Type::Kind *element_type)
2348 return value_to_dependency_object (CreateFromFile (xaml, create_namescope, element_type));
2351 DependencyObject *
2352 XamlLoader::CreateDependencyObjectFromString (const char *xaml, bool create_namescope, Type::Kind *element_type)
2354 return value_to_dependency_object (CreateFromString (xaml, create_namescope, element_type, IMPORT_DEFAULT_XMLNS));
2358 * Hydrates an existing DependencyObject (@object) with the contents from the @xaml
2359 * data
2361 Value *
2362 XamlLoader::HydrateFromString (const char *xaml, Value *object, bool create_namescope, Type::Kind *element_type, int flags)
2364 XML_Parser p = XML_ParserCreateNS ("utf-8", '|');
2365 XamlParserInfo *parser_info = NULL;
2366 Value *res = NULL;
2367 char *start = (char*)xaml;
2368 char *prepend = NULL;
2369 char *append = NULL;
2370 char * inputs [4] = {NULL, NULL, NULL, NULL};
2372 inputs [0] = start;
2374 if (!p) {
2375 LOG_XAML ("can not create parser\n");
2376 goto cleanup_and_return;
2379 #if 0
2380 if (true) {
2381 static int id = 0;
2382 char filename[64];
2383 FILE *fp;
2385 sprintf (filename, "createFromXaml.%d.xaml", id++);
2386 if ((fp = fopen (filename, "wt")) != NULL) {
2387 fwrite (xaml, strlen (xaml), 1, fp);
2388 fclose (fp);
2391 #endif
2393 parser_info = new XamlParserInfo (p, NULL);
2395 parser_info->namescope->SetTemporary (!create_namescope);
2397 parser_info->loader = this;
2398 parser_info->validate_templates = (flags & VALIDATE_TEMPLATES) == VALIDATE_TEMPLATES;
2401 // If we are hydrating, we are not null
2403 if (object != NULL) {
2404 parser_info->hydrate_expecting = object;
2405 parser_info->hydrating = true;
2406 if (Type::IsSubclassOf (object->GetKind (), Type::DEPENDENCY_OBJECT)) {
2407 DependencyObject *dob = object->AsDependencyObject ();
2408 dob->SetSurface (GetSurface());
2409 dob->SetResourceBase (GetResourceBase());
2411 } else {
2412 parser_info->hydrate_expecting = NULL;
2413 parser_info->hydrating = false;
2416 // from_str gets the default namespaces implictly added
2417 add_default_namespaces (parser_info, (flags & IMPORT_DEFAULT_XMLNS) == IMPORT_DEFAULT_XMLNS);
2419 XML_SetUserData (p, parser_info);
2421 XML_SetElementHandler (p, start_element_handler, end_element_handler);
2422 XML_SetCharacterDataHandler (p, char_data_handler);
2423 XML_SetNamespaceDeclHandler(p, start_namespace_handler, NULL);
2424 XML_SetDoctypeDeclHandler(p, start_doctype_handler, NULL);
2427 XML_SetProcessingInstructionHandler (p, proc_handler);
2430 if (context) {
2431 prepend = context->internal->CreateIgnorableTagOpen ();
2432 append = context->internal->CreateIgnorableTagClose ();
2434 inputs [0] = prepend;
2435 inputs [1] = start;
2436 inputs [2] = append;
2439 for (int i = 0; inputs [i]; i++) {
2440 char *start = inputs [i];
2442 // don't freak out if the <?xml ... ?> isn't on the first line (see #328907)
2443 while (g_ascii_isspace (*start))
2444 start++;
2446 parser_info->SetXmlBuffer (start);
2447 if (!XML_Parse (p, start, strlen (start), inputs [i + 1] == NULL)) {
2448 expat_parser_error (parser_info, XML_GetErrorCode (p));
2449 LOG_XAML ("error parsing: %s\n\n", xaml);
2450 goto cleanup_and_return;
2454 print_tree (parser_info->top_element, 0);
2456 if (parser_info->top_element) {
2457 if (is_legal_top_level_kind (parser_info->top_element->info->GetKind ())) {
2458 res = parser_info->top_element->GetAsValue ();
2459 res = new Value (*res);
2460 if (res->Is (Type::DEPENDENCY_OBJECT) && object) {
2461 DependencyObject *dob = res->AsDependencyObject ();
2462 dob->unref ();
2463 dob->SetIsHydratedFromXaml (parser_info->hydrating);
2467 if (element_type)
2468 *element_type = parser_info->top_element->info->GetKind ();
2470 if (!res && !parser_info->error_args)
2471 parser_info->error_args = new ParserErrorEventArgs ("No DependencyObject found", "", 0, 0, 1, "", "");
2473 if (parser_info->error_args) {
2474 delete res;
2475 res = NULL;
2476 if (element_type)
2477 *element_type = Type::INVALID;
2478 goto cleanup_and_return;
2482 cleanup_and_return:
2484 if (parser_info->error_args) {
2485 error_args = parser_info->error_args;
2486 printf ("Could not parse element %s, attribute %s, error: %s\n",
2487 error_args->xml_element,
2488 error_args->xml_attribute,
2489 error_args->GetErrorMessage());
2492 if (p)
2493 XML_ParserFree (p);
2494 if (parser_info)
2495 delete parser_info;
2496 if (prepend)
2497 g_free (prepend);
2498 if (append)
2499 g_free (append);
2501 return res;
2504 Value *
2505 XamlLoader::CreateFromFileWithError (const char *xaml_file, bool create_namescope, Type::Kind *element_type, MoonError *error)
2507 Value *res = CreateFromFile (xaml_file, create_namescope, element_type);
2508 if (error_args && error_args->GetErrorCode () != -1)
2509 MoonError::FillIn (error, error_args);
2510 return res;
2513 Value *
2514 XamlLoader::CreateFromStringWithError (const char *xaml, bool create_namescope, Type::Kind *element_type, int flags, MoonError *error)
2516 Value *res = CreateFromString (xaml, create_namescope, element_type, flags);
2517 if (error_args && error_args->GetErrorCode () != -1)
2518 MoonError::FillIn (error, error_args);
2519 return res;
2522 Value *
2523 XamlLoader::HydrateFromStringWithError (const char *xaml, Value *object, bool create_namescope, Type::Kind *element_type, int flags, MoonError *error)
2525 Value *res = HydrateFromString (xaml, object, create_namescope, element_type, flags);
2526 if (error_args && error_args->GetErrorCode () != -1)
2527 MoonError::FillIn (error, error_args);
2528 return res;
2531 static int
2532 parse_int (const char **pp, const char *end)
2534 const char *p = *pp;
2535 #if 0
2536 if (optional && AtEnd)
2537 return 0;
2538 #endif
2540 int res = 0;
2541 int count = 0;
2543 while (p <= end && g_ascii_isdigit (*p)) {
2544 res = res * 10 + *p - '0';
2545 p++;
2546 count++;
2549 #if 0
2550 if (count == 0)
2551 formatError = true;
2552 #endif
2554 *pp = p;
2555 return res;
2558 static gint64
2559 parse_ticks (const char **pp, const char *end)
2561 gint64 mag = 1000000;
2562 gint64 res = 0;
2563 bool digitseen = false;
2565 const char *p = *pp;
2567 while (mag > 0 && p <= end && g_ascii_isdigit (*p)) {
2568 res = res + (*p - '0') * mag;
2569 p++;
2570 mag = mag / 10;
2571 digitseen = true;
2574 #if 0
2575 if (!digitseen)
2576 formatError = true;
2577 #endif
2579 *pp = p;
2580 return res;
2583 bool
2584 time_span_from_str (const char *str, TimeSpan *res)
2586 const char *end = str + strlen (str);
2587 const char *p;
2589 bool negative = false;
2590 int days;
2591 int hours;
2592 int minutes;
2593 int seconds;
2594 gint64 ticks;
2596 p = str;
2598 if (*p == '-') {
2599 p++;
2600 negative = true;
2603 days = parse_int (&p, end);
2605 if (*p == '.') {
2606 p++;
2607 hours = parse_int (&p, end);
2609 else {
2610 hours = days;
2611 days = 0;
2614 if (*p == ':') p++;
2615 minutes = parse_int (&p, end);
2616 if (*p == ':') p++;
2617 seconds = parse_int (&p, end);
2618 if (*p == '.') {
2619 p++;
2620 ticks = parse_ticks (&p, end);
2622 else {
2623 ticks = 0;
2626 gint64 t = (days * 86400) + (hours * 3600) + (minutes * 60) + seconds;
2627 t *= 10000000L;
2629 *res = negative ? (-t - ticks) : (t + ticks);
2631 return true;
2634 bool
2635 repeat_behavior_from_str (const char *str, RepeatBehavior *res)
2637 if (!g_ascii_strcasecmp ("Forever", str)) {
2638 *res = RepeatBehavior::Forever;
2639 return true;
2642 // check for "<float>x".
2644 // XXX more validation work is needed here.. but how do we
2645 // report an error?
2646 const char *x = strchr (str, 'x');
2647 if (x) {
2648 if (*(x + 1) != '\0') {
2649 return false;
2651 else {
2652 char *endptr;
2653 errno = 0;
2654 double d = g_ascii_strtod (str, &endptr);
2656 if (errno || endptr == str)
2657 return false;
2659 *res = RepeatBehavior (d);
2660 return true;
2664 /* XXX RepeatBehavior='XX:XX:XX' syntax is NOT correctly supported by
2665 Silverlight 1.0 (most likely a bug). It works fine in Silverlight 2.0
2666 though. We currently stick to the 2.0 behavior, not replicating the bug
2667 from 1.0.
2669 TimeSpan t;
2670 if (!time_span_from_str (str, &t))
2671 return false;
2673 *res = RepeatBehavior (t);
2675 return true;
2678 bool
2679 duration_from_str (const char *str, Duration *res)
2681 if (!g_ascii_strcasecmp ("Automatic", str)) {
2682 *res = Duration::Automatic;
2683 return true;
2686 if (!g_ascii_strcasecmp ("Forever", str)) {
2687 *res = Duration::Forever;
2688 return true;
2691 TimeSpan ts;
2692 if (!time_span_from_str (str, &ts))
2693 return false;
2695 *res = Duration (ts);
2696 return true;
2699 bool
2700 keytime_from_str (const char *str, KeyTime *res)
2702 if (!g_ascii_strcasecmp ("Uniform", str)) {
2703 *res = KeyTime::Uniform;
2704 return true;
2707 if (!g_ascii_strcasecmp ("Paced", str)) {
2708 *res = KeyTime::Paced;
2709 return true;
2712 /* check for a percentage first */
2713 const char *last = str + strlen(str) - 1;
2714 if (*last == '%') {
2715 char *ep;
2716 double pct = g_ascii_strtod (str, &ep);
2717 if (ep == last) {
2718 *res = KeyTime (pct);
2719 return true;
2723 TimeSpan ts;
2724 if (!time_span_from_str (str, &ts))
2725 return false;
2727 *res = KeyTime (ts);
2728 return true;
2731 bool
2732 key_spline_from_str (const char *str, KeySpline **res)
2734 PointCollection *pts = PointCollection::FromStr (str);
2736 if (!pts)
2737 return false;
2739 if (pts->GetCount () != 2) {
2740 pts->unref ();
2741 return false;
2744 *res = new KeySpline (*pts->GetValueAt (0)->AsPoint (), *pts->GetValueAt (1)->AsPoint ());
2746 pts->unref ();
2748 return true;
2751 Matrix *
2752 matrix_from_str (const char *str)
2754 if (!g_ascii_strcasecmp ("Identity", str)) {
2755 return new Matrix ();
2758 DoubleCollection *values = DoubleCollection::FromStr (str);
2759 Matrix *matrix;
2761 if (!values)
2762 return new Matrix ();
2764 if (values->GetCount () < 6) {
2765 values->unref ();
2766 return NULL;
2769 matrix = new Matrix ();
2770 matrix->SetM11 (values->GetValueAt (0)->AsDouble ());
2771 matrix->SetM12 (values->GetValueAt (1)->AsDouble ());
2772 matrix->SetM21 (values->GetValueAt (2)->AsDouble ());
2773 matrix->SetM22 (values->GetValueAt (3)->AsDouble ());
2774 matrix->SetOffsetX (values->GetValueAt (4)->AsDouble ());
2775 matrix->SetOffsetY (values->GetValueAt (5)->AsDouble ());
2777 values->unref ();
2779 return matrix;
2782 bool
2783 grid_length_from_str (const char *str, GridLength *grid_length)
2785 if (IS_NULL_OR_EMPTY (str)) {
2786 *grid_length = GridLength (0.0, GridUnitTypePixel);
2787 return true;
2790 if (str [0] == '*') {
2791 *grid_length = GridLength (1.0, GridUnitTypeStar);
2792 return true;
2795 // unit tests shows that "Auto", "auto", "aUtO"... all works
2796 if (!g_ascii_strcasecmp (str, "Auto")) {
2797 *grid_length = GridLength ();
2798 return true;
2801 char *endptr;
2802 errno = 0;
2803 double d = g_ascii_strtod (str, &endptr);
2805 if (errno || endptr == str)
2806 return false;
2808 *grid_length = GridLength (d, *endptr == '*' ? GridUnitTypeStar : GridUnitTypePixel);
2809 return true;
2812 static void
2813 advance (char **in)
2815 char *inptr = *in;
2817 while (*inptr && !g_ascii_isalnum (*inptr) && *inptr != '.' && *inptr != '-' && *inptr != '+')
2818 inptr = g_utf8_next_char (inptr);
2820 *in = inptr;
2823 static bool
2824 get_point (Point *p, char **in)
2826 char *end, *inptr = *in;
2827 double x, y;
2829 x = g_ascii_strtod (inptr, &end);
2830 if (end == inptr)
2831 return false;
2833 inptr = end;
2834 while (g_ascii_isspace (*inptr))
2835 inptr++;
2837 if (*inptr == ',')
2838 inptr++;
2840 while (g_ascii_isspace (*inptr))
2841 inptr++;
2843 y = g_ascii_strtod (inptr, &end);
2844 if (end == inptr)
2845 return false;
2847 p->x = x;
2848 p->y = y;
2850 *in = end;
2852 return true;
2855 static void
2856 make_relative (const Point *cp, Point *mv)
2858 mv->x += cp->x;
2859 mv->y += cp->y;
2862 static bool
2863 more_points_available (char **in)
2865 char *inptr = *in;
2867 while (g_ascii_isspace (*inptr) || *inptr == ',')
2868 inptr++;
2870 *in = inptr;
2872 return (g_ascii_isdigit (*inptr) || *inptr == '.' || *inptr == '-' || *inptr == '+');
2875 Geometry *
2876 geometry_from_str (const char *str)
2878 char *inptr = (char *) str;
2879 Point cp = Point (0, 0);
2880 Point cp1, cp2, cp3;
2881 Point start;
2882 char *end;
2883 PathGeometry *pg = NULL;
2884 FillRule fill_rule = FillRuleEvenOdd;
2885 bool cbz = false; // last figure is a cubic bezier curve
2886 bool qbz = false; // last figure is a quadratic bezier curve
2887 Point cbzp, qbzp; // points needed to create "smooth" beziers
2889 moon_path *path = moon_path_new (10);
2891 while (*inptr) {
2892 if (g_ascii_isspace (*inptr))
2893 inptr++;
2895 if (!inptr[0])
2896 break;
2898 bool relative = false;
2900 char c = *inptr;
2901 inptr = g_utf8_next_char (inptr);
2903 switch (c) {
2904 case 'f':
2905 case 'F':
2906 advance (&inptr);
2908 if (*inptr == '0')
2909 fill_rule = FillRuleEvenOdd;
2910 else if (*inptr == '1')
2911 fill_rule = FillRuleNonzero;
2912 else
2913 // FIXME: else it's a bad value and nothing should be rendered
2914 goto bad_pml; // partial: only this Path won't be rendered
2916 inptr = g_utf8_next_char (inptr);
2917 break;
2918 case 'm':
2919 relative = true;
2920 case 'M':
2921 if (!get_point (&cp1, &inptr))
2922 break;
2924 if (relative)
2925 make_relative (&cp, &cp1);
2927 // start point
2928 moon_move_to (path, cp1.x, cp1.y);
2930 start.x = cp.x = cp1.x;
2931 start.y = cp.y = cp1.y;
2933 advance (&inptr);
2934 while (more_points_available (&inptr)) {
2935 if (!get_point (&cp1, &inptr))
2936 break;
2938 if (relative)
2939 make_relative (&cp, &cp1);
2941 moon_line_to (path, cp1.x, cp1.y);
2944 cp.x = cp1.x;
2945 cp.y = cp1.y;
2946 cbz = qbz = false;
2947 break;
2949 case 'l':
2950 relative = true;
2951 case 'L':
2953 while (more_points_available (&inptr)) {
2954 if (!get_point (&cp1, &inptr))
2955 break;
2957 if (relative)
2958 make_relative (&cp, &cp1);
2960 moon_line_to (path, cp1.x, cp1.y);
2962 cp.x = cp1.x;
2963 cp.y = cp1.y;
2965 advance (&inptr);
2967 cbz = qbz = false;
2968 break;
2971 case 'h':
2972 relative = true;
2973 case 'H':
2975 double x = g_ascii_strtod (inptr, &end);
2976 if (end == inptr)
2977 break;
2979 inptr = end;
2981 if (relative)
2982 x += cp.x;
2983 cp = Point (x, cp.y);
2985 moon_line_to (path, cp.x, cp.y);
2986 cbz = qbz = false;
2987 break;
2990 case 'v':
2991 relative = true;
2992 case 'V':
2994 double y = g_ascii_strtod (inptr, &end);
2995 if (end == inptr)
2996 break;
2998 inptr = end;
3000 if (relative)
3001 y += cp.y;
3002 cp = Point (cp.x, y);
3004 moon_line_to (path, cp.x, cp.y);
3005 cbz = qbz = false;
3006 break;
3009 case 'c':
3010 relative = true;
3011 case 'C':
3013 while (more_points_available (&inptr)) {
3014 if (!get_point (&cp1, &inptr))
3015 break;
3017 if (relative)
3018 make_relative (&cp, &cp1);
3020 advance (&inptr);
3022 if (!get_point (&cp2, &inptr))
3023 break;
3025 if (relative)
3026 make_relative (&cp, &cp2);
3028 advance (&inptr);
3030 if (!get_point (&cp3, &inptr))
3031 break;
3033 if (relative)
3034 make_relative (&cp, &cp3);
3036 advance (&inptr);
3038 moon_curve_to (path, cp1.x, cp1.y, cp2.x, cp2.y, cp3.x, cp3.y);
3040 cp1.x = cp3.x;
3041 cp1.y = cp3.y;
3043 cp.x = cp3.x;
3044 cp.y = cp3.y;
3045 cbz = true;
3046 cbzp.x = cp2.x;
3047 cbzp.y = cp2.y;
3048 qbz = false;
3049 break;
3051 case 's':
3052 relative = true;
3053 case 'S':
3055 while (more_points_available (&inptr)) {
3056 if (!get_point (&cp2, &inptr))
3057 break;
3059 if (relative)
3060 make_relative (&cp, &cp2);
3062 advance (&inptr);
3064 if (!get_point (&cp3, &inptr))
3065 break;
3067 if (relative)
3068 make_relative (&cp, &cp3);
3070 if (cbz) {
3071 cp1.x = 2 * cp.x - cbzp.x;
3072 cp1.y = 2 * cp.y - cbzp.y;
3073 } else
3074 cp1 = cp;
3076 moon_curve_to (path, cp1.x, cp1.y, cp2.x, cp2.y, cp3.x, cp3.y);
3077 cbz = true;
3078 cbzp.x = cp2.x;
3079 cbzp.y = cp2.y;
3081 cp.x = cp3.x;
3082 cp.y = cp3.y;
3084 advance (&inptr);
3086 qbz = false;
3087 break;
3089 case 'q':
3090 relative = true;
3091 case 'Q':
3093 while (more_points_available (&inptr)) {
3094 if (!get_point (&cp1, &inptr))
3095 break;
3097 if (relative)
3098 make_relative (&cp, &cp1);
3100 advance (&inptr);
3102 if (!get_point (&cp2, &inptr))
3103 break;
3105 if (relative)
3106 make_relative (&cp, &cp2);
3108 advance (&inptr);
3110 moon_quad_curve_to (path, cp1.x, cp1.y, cp2.x, cp2.y);
3112 cp.x = cp2.x;
3113 cp.y = cp2.y;
3115 qbz = true;
3116 qbzp.x = cp1.x;
3117 qbzp.y = cp1.y;
3118 cbz = false;
3119 break;
3121 case 't':
3122 relative = true;
3123 case 'T':
3125 while (more_points_available (&inptr)) {
3126 if (!get_point (&cp2, &inptr))
3127 break;
3129 if (relative)
3130 make_relative (&cp, &cp2);
3132 if (qbz) {
3133 cp1.x = 2 * cp.x - qbzp.x;
3134 cp1.y = 2 * cp.y - qbzp.y;
3135 } else
3136 cp1 = cp;
3138 moon_quad_curve_to (path, cp1.x, cp1.y, cp2.x, cp2.y);
3139 qbz = true;
3140 qbzp.x = cp1.x;
3141 qbzp.y = cp1.y;
3143 cp.x = cp2.x;
3144 cp.y = cp2.y;
3146 advance (&inptr);
3148 cbz = false;
3149 break;
3151 case 'a':
3152 relative = true;
3153 case 'A':
3155 while (more_points_available (&inptr)) {
3156 if (!get_point (&cp1, &inptr))
3157 break;
3159 advance (&inptr);
3161 double angle = g_ascii_strtod (inptr, &end);
3162 if (end == inptr)
3163 break;
3165 inptr = end;
3166 advance (&inptr);
3168 int is_large = strtol (inptr, &end, 10);
3169 if (end == inptr)
3170 break;
3172 inptr = end;
3173 advance (&inptr);
3175 int sweep = strtol (inptr, &end, 10);
3176 if (end == inptr)
3177 break;
3179 inptr = end;
3180 advance (&inptr);
3182 if (!get_point (&cp2, &inptr))
3183 break;
3185 if (relative)
3186 make_relative (&cp, &cp2);
3188 moon_arc_to (path, cp1.x, cp1.y, angle, is_large, sweep, cp2.x, cp2.y);
3190 cp.x = cp2.x;
3191 cp.y = cp2.y;
3193 advance (&inptr);
3195 cbz = qbz = false;
3196 break;
3198 case 'z':
3199 case 'Z':
3200 moon_line_to (path, start.x, start.y);
3201 moon_close_path (path);
3202 moon_move_to (path, start.x, start.y);
3204 cp.x = start.x;
3205 cp.y = start.y;
3206 cbz = qbz = false;
3207 break;
3208 default:
3209 break;
3213 pg = new PathGeometry (path);
3214 pg->SetFillRule (fill_rule);
3215 return pg;
3217 bad_pml:
3218 moon_path_destroy (path);
3219 return NULL;
3222 static bool
3223 value_is_explicit_null (const char *str)
3225 return !strcmp ("{x:Null}", str);
3228 static bool
3229 is_managed_kind (Type::Kind kind)
3232 if (kind == Type::MANAGED ||
3233 kind == Type::OBJECT ||
3234 kind == Type::URI ||
3235 kind == Type::MANAGEDTYPEINFO ||
3236 kind == Type::DEPENDENCYPROPERTY)
3237 return true;
3239 return false;
3242 static bool
3243 kind_requires_managed_load (Type::Kind kind)
3245 if (kind == Type::USERCONTROL) {
3246 return true;
3249 return false;
3252 static bool
3253 is_legal_top_level_kind (Type::Kind kind)
3255 if (kind == Type::MANAGED || kind == Type::OBJECT || Type::IsSubclassOf (kind, Type::DEPENDENCY_OBJECT))
3256 return true;
3257 return false;
3260 // NOTE: Keep definition in sync with class/System.Windows/Mono/NativeMethods.cs
3261 bool
3262 value_from_str_with_typename (const char *type_name, const char *prop_name, const char *str, Value **v)
3264 Type *t = Type::Find (type_name);
3265 if (!t)
3266 return false;
3268 return value_from_str (t->GetKind (), prop_name, str, v);
3271 char *
3272 expand_property_path (XamlParserInfo *p, PropertyPath *path)
3274 if (!path->path)
3275 return NULL;
3277 bool expanded = false;
3278 GString *res = g_string_new (path->path);
3280 int len = strlen (res->str);
3281 for (int i = 0; i < len; i++) {
3282 if (res->str [i] == ':') {
3283 int e = i;
3284 int s = i - 1;
3285 int te = i + 1;
3286 for ( ; s > 0; s--) {
3287 if (!g_ascii_isalnum (res->str [s]))
3288 break;
3291 for ( ; te < len; te++) {
3292 if (!g_ascii_isalpha (res->str [te]) || res->str [te] == '_')
3293 break;
3296 char *prefix = g_strndup (res->str + s + 1, e - s - 1);
3297 char *type = g_strndup (res->str + e + 1, te - e - 1);
3299 res = g_string_erase (res, s + 1, te - s - 1);
3301 XamlNamespace *ns = (XamlNamespace *) g_hash_table_find (p->namespace_map, namespace_for_prefix, prefix);
3302 if (!ns) {
3303 g_free (prefix);
3304 g_free (type);
3305 g_string_free (res, true);
3306 return NULL;
3309 XamlElementInfo *info = ns->FindElement (p, type, NULL, false);
3311 if (!info) {
3312 g_free (prefix);
3313 g_free (type);
3314 g_string_free (res, true);
3315 return NULL;
3318 char *uri = g_strdup_printf ("'%s'", Type::Find (info->GetKind ())->GetName ());
3320 res = g_string_insert (res, s + 1, uri);
3321 i = s + 1 + strlen (uri);
3322 len = strlen (res->str);
3324 delete info;
3325 g_free (uri);
3326 g_free (prefix);
3327 g_free (type);
3329 expanded = true;
3333 if (!expanded) {
3334 g_string_free (res, true);
3335 return NULL;
3338 char *expanded_str = res->str;
3339 g_string_free (res, false);
3341 return expanded_str;
3344 bool
3345 value_from_str (Type::Kind type, const char *prop_name, const char *str, Value **v)
3347 bool v_set = false;
3349 value_from_str_with_parser (NULL, type, prop_name, str, v, &v_set);
3351 return v_set;
3354 bool
3355 xaml_bool_from_str (const char *s, bool *res)
3357 bool b;
3358 char *endptr;
3360 if (!g_ascii_strcasecmp ("true", s))
3361 b = true;
3362 else if (!g_ascii_strcasecmp ("false", s))
3363 b = false;
3364 else {
3365 // Check if it's a string representing a decimal value
3366 gint64 l;
3368 errno = 0;
3369 l = strtol (s, &endptr, 10);
3371 if (errno || endptr == s || *endptr || l > G_MAXINT32 || l < G_MININT32)
3372 return false;;
3374 if (l == 0)
3375 b = false;
3376 else
3377 b = true;
3380 *res = b;
3381 return true;
3384 static bool
3385 value_from_str_with_parser (XamlParserInfo *p, Type::Kind type, const char *prop_name, const char *str, Value **v, bool *v_set)
3387 char *endptr;
3388 *v = NULL;
3390 if (value_is_explicit_null (str)) {
3391 *v = NULL;
3392 *v_set = true;
3393 return true;
3396 char *s = g_strdup (str);
3398 if (type == Type::OBJECT || type == Type::STRING) {
3399 // object and string use the literal string
3401 else {
3402 // everything else depends on the string being stripped
3403 s = g_strstrip (s);
3406 switch (type) {
3407 case Type::OBJECT: {
3408 // not much more can do here, unless we want to try to
3409 // probe str to see if it's actually meant to be a
3410 // specific type. just assume it's a string.
3411 *v = new Value (s);
3412 *v_set = true;
3413 break;
3416 case Type::BOOL: {
3417 bool b;
3419 if (!xaml_bool_from_str (s, &b))
3420 break;
3422 *v = new Value (b);
3423 *v_set = true;
3424 break;
3426 case Type::DOUBLE: {
3427 double d;
3429 // empty string should not reset default values with 0
3431 // FIXME: this causes a 2.0 unit test to fail (PrimitiveTest.ParseEmptyDouble)
3432 if (IS_NULL_OR_EMPTY(s)) {
3433 g_free (s);
3434 return false;
3437 bool is_nan = false;
3438 if (!g_ascii_strcasecmp (s, "NAN"))
3439 is_nan = true;
3440 else {
3441 errno = 0;
3442 d = g_ascii_strtod (s, &endptr);
3445 if (is_nan || errno || endptr == s || *endptr) {
3446 if (prop_name
3447 && (!strcmp (prop_name, "Width") || !strcmp (prop_name, "Height"))
3448 && (!g_ascii_strcasecmp (s, "Auto") || is_nan))
3449 d = NAN;
3450 else
3451 break;
3454 *v = new Value (d);
3455 *v_set = true;
3456 break;
3458 case Type::INT64: {
3459 gint64 l;
3461 errno = 0;
3462 l = strtol (s, &endptr, 10);
3464 if (errno || endptr == s)
3465 break;
3467 *v = new Value (l, Type::INT64);
3468 *v_set = true;
3469 break;
3471 case Type::TIMESPAN: {
3472 TimeSpan ts;
3474 if (!time_span_from_str (s, &ts))
3475 break;
3477 *v = new Value (ts, Type::TIMESPAN);
3478 *v_set = true;
3479 break;
3481 case Type::INT32: {
3482 int i;
3484 if (IS_NULL_OR_EMPTY(s))
3485 i = 0;
3486 else if (g_ascii_isalpha (s[0]) && prop_name) {
3487 i = enums_str_to_int (prop_name, s);
3488 if (i == -1) {
3489 // g_warning ("'%s' enum is not valid on '%s' property", str, prop_name);
3490 break;
3492 } else {
3493 errno = 0;
3494 long l = strtol (s, &endptr, 10);
3496 if (errno || endptr == s)
3497 break;
3499 i = (int) l;
3502 *v = new Value (i);
3503 *v_set = true;
3504 break;
3506 case Type::CHAR: {
3507 gunichar unichar = g_utf8_get_char_validated (str, -1);
3508 const char *next;
3510 if ((int) unichar < 0)
3511 break;
3513 if (!(next = g_utf8_next_char (str)) || *next != '\0')
3514 break;
3516 *v = new Value (unichar, Type::CHAR);
3517 *v_set = true;
3518 break;
3520 case Type::STRING: {
3521 *v = new Value (str);
3522 *v_set = true;
3523 break;
3525 case Type::COLOR: {
3526 Color *c = color_from_str (s);
3527 if (c == NULL)
3528 break;
3529 *v = new Value (*c);
3530 *v_set = true;
3531 delete c;
3532 break;
3534 case Type::REPEATBEHAVIOR: {
3535 RepeatBehavior rb = RepeatBehavior::Forever;
3537 if (!repeat_behavior_from_str (s, &rb))
3538 break;
3540 *v = new Value (rb);
3541 *v_set = true;
3542 break;
3544 case Type::DURATION: {
3545 Duration d = Duration::Forever;
3547 if (!duration_from_str (s, &d))
3548 break;
3550 *v = new Value (d);
3551 *v_set = true;
3552 break;
3554 case Type::KEYTIME: {
3555 KeyTime kt = KeyTime::Paced;
3557 if (!keytime_from_str (s, &kt))
3558 break;
3560 *v = new Value (kt);
3561 *v_set = true;
3562 break;
3564 case Type::KEYSPLINE: {
3565 KeySpline *ks;
3567 if (!key_spline_from_str (s, &ks))
3568 break;
3570 *v = Value::CreateUnrefPtr (ks);
3571 *v_set = true;
3572 break;
3574 case Type::BRUSH:
3575 case Type::SOLIDCOLORBRUSH: {
3576 // Only solid color brushes can be specified using attribute syntax
3577 Color *c = color_from_str (s);
3579 if (c == NULL)
3580 break;
3582 SolidColorBrush *scb = new SolidColorBrush ();
3584 scb->SetColor (c);
3585 delete c;
3587 *v = Value::CreateUnrefPtr (scb);
3588 *v_set = true;
3589 break;
3591 case Type::POINT: {
3592 Point p;
3594 if (!Point::FromStr (s, &p))
3595 break;
3597 *v = new Value (p);
3598 *v_set = true;
3599 break;
3601 case Type::SIZE: {
3602 Size size;
3604 if (!Size::FromStr (s, &size))
3605 break;
3607 *v = new Value (size);
3608 *v_set = true;
3609 break;
3611 case Type::RECT: {
3612 Rect rect;
3614 if (!Rect::FromStr (s, &rect))
3615 break;
3617 *v = new Value (rect);
3618 *v_set = true;
3619 break;
3621 case Type::URI: {
3622 Uri uri;
3624 if (!uri.Parse (s)) {
3625 break;
3628 *v = new Value (uri);
3629 *v_set = true;
3630 break;
3632 case Type::DOUBLE_COLLECTION: {
3633 DoubleCollection *doubles = DoubleCollection::FromStr (s);
3634 if (!doubles) {
3635 *v = Value::CreateUnrefPtr (new DoubleCollection ());
3636 *v_set = true;
3637 break;
3640 *v = Value::CreateUnrefPtr (doubles);
3641 *v_set = true;
3642 break;
3644 case Type::POINT_COLLECTION: {
3645 PointCollection *points = PointCollection::FromStr (s);
3646 if (!points) {
3647 *v = Value::CreateUnrefPtr (new PointCollection ());
3648 *v_set = true;
3649 break;
3652 *v = Value::CreateUnrefPtr (points);
3653 *v_set = true;
3654 break;
3656 case Type::TRANSFORMGROUP: {
3657 if (IS_NULL_OR_EMPTY(s))
3658 break;
3660 Matrix *mv = matrix_from_str (s);
3661 if (!mv)
3662 break;
3664 TransformGroup *tg = new TransformGroup ();
3665 MatrixTransform *t = new MatrixTransform ();
3666 t->SetValue (MatrixTransform::MatrixProperty, Value (mv));
3668 tg->GetChildren()->Add (t);
3669 t->unref ();
3671 *v = new Value (tg);
3672 *v_set = true;
3673 tg->unref ();
3674 mv->unref ();
3675 break;
3677 case Type::TRANSFORM:
3679 if (!g_ascii_strcasecmp ("Identity", str)) {
3680 *v = NULL;
3681 *v_set = true;
3682 break;
3685 // Intentional fall through, you can create a matrix from a TRANSFORM property, but not using Identity
3686 case Type::MATRIXTRANSFORM:
3688 if (IS_NULL_OR_EMPTY(s))
3689 break;
3691 Matrix *mv = matrix_from_str (s);
3692 if (!mv)
3693 break;
3695 MatrixTransform *t = new MatrixTransform ();
3696 t->SetValue (MatrixTransform::MatrixProperty, Value (mv));
3698 *v = new Value (t);
3699 *v_set = true;
3700 t->unref ();
3701 mv->unref ();
3702 break;
3704 case Type::UNMANAGEDMATRIX:
3705 case Type::MATRIX: {
3706 // note: unlike TRANSFORM this creates an empty, identity, matrix for an empty string
3707 Matrix *matrix = matrix_from_str (s);
3708 if (!matrix)
3709 break;
3711 *v = new Value (matrix);
3712 *v_set = true;
3713 matrix->unref ();
3714 break;
3716 case Type::PATHGEOMETRY:
3717 case Type::GEOMETRY: {
3718 Geometry *geometry = geometry_from_str (s);
3720 if (!geometry)
3721 break;
3723 *v = new Value (geometry);
3724 *v_set = true;
3725 geometry->unref ();
3726 break;
3728 case Type::THICKNESS: {
3729 Thickness t;
3731 if (!Thickness::FromStr (s, &t))
3732 break;
3734 *v = new Value (t);
3735 *v_set = true;
3736 break;
3738 case Type::CORNERRADIUS: {
3739 CornerRadius c;
3741 if (!CornerRadius::FromStr (s, &c))
3742 break;
3744 *v = new Value (c);
3745 *v_set = true;
3746 break;
3748 case Type::GRIDLENGTH: {
3749 GridLength grid_length;
3751 if (!grid_length_from_str (s, &grid_length))
3752 break;
3754 *v = new Value (grid_length);
3755 *v_set = true;
3756 break;
3758 case Type::IMAGESOURCE:
3759 case Type::BITMAPIMAGE: {
3760 Uri uri;
3762 if (!uri.Parse (s))
3763 break;
3765 BitmapImage *bi = new BitmapImage ();
3767 bi->SetUriSource (&uri);
3769 *v = Value::CreateUnrefPtr (bi);
3770 *v_set = true;
3772 break;
3774 case Type::MULTISCALETILESOURCE:
3775 case Type::DEEPZOOMIMAGETILESOURCE: {
3776 // As far as I know the only thing you can create here is a URI based DeepZoomImageTileSource
3777 Uri uri;
3778 if (!uri.Parse (s))
3779 break;
3780 *v = Value::CreateUnrefPtr (new DeepZoomImageTileSource (&uri));
3781 *v_set = true;
3783 break;
3785 case Type::FONTFAMILY: {
3786 *v = new Value (FontFamily (s));
3787 *v_set = true;
3788 break;
3790 case Type::FONTWEIGHT: {
3791 int fw = enums_str_to_int ("FontWeight", s);
3792 if (fw != -1) {
3793 *v = new Value (FontWeight ((FontWeights)fw));
3794 *v_set = true;
3796 break;
3798 case Type::FONTSTYLE: {
3799 int fs = enums_str_to_int ("FontStyle", s);
3800 if (fs != -1) {
3801 *v = new Value (FontStyle ((FontStyles)fs));
3802 *v_set = true;
3804 break;
3806 case Type::FONTSTRETCH: {
3807 int fs = enums_str_to_int ("FontStretch", s);
3808 if (fs != -1) {
3809 *v = new Value (FontStretch ((FontStretches)fs));
3810 *v_set = true;
3812 break;
3814 case Type::PROPERTYPATH: {
3815 PropertyPath path (s);
3816 path.expanded_path = expand_property_path (p, &path);
3817 *v = new Value (path);
3818 *v_set = true;
3819 break;
3821 default:
3822 // we don't care about NULL or empty values
3823 if (!IS_NULL_OR_EMPTY (s)) {
3824 g_free (s);
3825 return true;
3829 g_free (s);
3830 return true;
3833 bool
3834 XamlElementInstance::TrySetContentProperty (XamlParserInfo *p, XamlElementInstance *value)
3836 const char* prop_name = info->GetContentProperty (p);
3838 if (!prop_name)
3839 return false;
3841 DependencyProperty *dep = DependencyProperty::GetDependencyProperty (info->GetKind (), prop_name);
3842 if (!dep)
3843 return false;
3845 bool is_collection = Type::IsSubclassOf (dep->GetPropertyType(), Type::DEPENDENCY_OBJECT_COLLECTION);
3847 if (!is_collection && Type::IsSubclassOf (value->info->GetKind (), dep->GetPropertyType())) {
3848 MoonError err;
3849 if (!item->SetValueWithError (dep, value->GetAsValue (), &err)) {
3850 parser_error (p, value->element_name, NULL, err.code, err.message);
3851 return false;
3853 return true;
3856 // We only want to enter this if statement if we are NOT dealing with the content property element,
3857 // otherwise, attempting to use explicit property setting, would add the content property element
3858 // to the content property element collection
3859 if (is_collection && dep->GetPropertyType() != value->info->GetKind ()) {
3860 Value *col_v = item->GetValue (dep);
3861 Collection *col;
3863 if (!col_v) {
3864 col = collection_new (dep->GetPropertyType ());
3865 item->SetValue (dep, Value (col));
3866 col->unref ();
3867 } else {
3868 col = (Collection *) col_v->AsCollection ();
3871 MoonError err;
3872 if (-1 == col->AddWithError (value->GetAsValue (), &err)) {
3873 parser_error (p, value->element_name, NULL, err.code, err.message);
3874 return false;
3877 return true;
3880 return false;
3883 bool
3884 XamlElementInstance::TrySetContentProperty (XamlParserInfo *p, const char *value)
3886 const char* prop_name = info->GetContentProperty (p);
3887 if (!prop_name)
3888 return false;
3890 Type::Kind prop_type = p->current_element->info->GetKind ();
3891 DependencyProperty *content = DependencyProperty::GetDependencyProperty (prop_type, prop_name);
3893 // TODO: There might be other types that can be specified here,
3894 // but string is all i have found so far. If you can specify other
3895 // types, i should pull the property setting out of set_attributes
3896 // and use that code
3898 if (content && (content->GetPropertyType ()) == Type::STRING && value) {
3899 item->SetValue (content, Value (g_strstrip (p->cdata->str)));
3900 return true;
3901 } else if (Type::IsSubclassOf (info->GetKind (), Type::TEXTBLOCK)) {
3902 TextBlock *textblock = (TextBlock *) item;
3903 InlineCollection *inlines = textblock->GetInlines ();
3904 Inline *last = NULL;
3906 if (inlines && inlines->GetCount () > 0)
3907 last = inlines->GetValueAt (inlines->GetCount () - 1)->AsInline ();
3909 if (!p->cdata_content) {
3910 if (p->next_element && !strcmp (p->next_element, "Run") && last && last->GetObjectType () == Type::RUN &&
3911 !last->GetAutogenerated ()) {
3912 // LWSP between <Run> elements is to be treated as a single-SPACE <Run> element
3913 // Note: p->cdata is already canonicalized
3914 } else {
3915 // This is one of the following cases:
3917 // 1. LWSP before the first <Run> element
3918 // 2. LWSP after the last <Run> element
3919 // 3. LWSP between <Run> and <LineBreak> elements
3920 return true;
3922 } else {
3923 if (!p->next_element || !strcmp (p->next_element, "LineBreak"))
3924 g_strchomp (p->cdata->str);
3926 if (!last || last->GetObjectType () != Type::RUN || last->GetAutogenerated ())
3927 g_strchug (p->cdata->str);
3930 Run *run = new Run ();
3931 run->SetText (p->cdata->str);
3933 if (!inlines) {
3934 inlines = new InlineCollection ();
3935 textblock->SetInlines (inlines);
3936 inlines->unref ();
3939 inlines->Add (run);
3940 run->unref ();
3941 return true;
3944 return false;
3947 bool
3948 XamlElementInstance::SetUnknownAttribute (XamlParserInfo *p, const char *name, const char *value)
3950 if (!p->loader)
3951 return false;
3953 Value v = Value (value);
3954 if (!p->loader->SetProperty (p, p->GetTopElementPtr (), info->xmlns, GetAsValue (), this, GetParentPointer (), NULL, name, &v, NULL)) {
3955 return false;
3957 return true;
3960 void
3961 XamlElementInstance::SetDelayedProperties (XamlParserInfo *p)
3963 GSList *walk = delayed_properties;
3965 while (walk) {
3966 DelayedProperty *prop = (DelayedProperty *) walk->data;
3968 if (!p->loader->SetProperty (p, p->GetTopElementPtr (), info->xmlns, GetAsValue (), this, GetParentPointer (), prop->xmlns, prop->name, prop->value, NULL, XamlCallbackData::SETTING_DELAYED_PROPERTY)) {
3969 parser_error (p, element_name, prop->name, 2012,
3970 "Unknown property %s on element %s.",
3971 prop->name, element_name);
3972 return;
3975 walk = walk->next;
3980 XamlElementInfo *
3981 XamlElementInstance::FindPropertyElement (XamlParserInfo *p, const char *el, const char *dot)
3983 // We didn't find anything so try looking up in managed
3984 if (!p->loader)
3985 return NULL;
3987 Value *v = new Value ();
3988 if (p->loader->LookupObject (p, p->GetTopElementPtr (), GetAsValue (), p->current_namespace->GetUri (), el, false, true, v)) {
3989 char *type_name = g_strndup (el, dot - el);
3991 XamlElementInfoManaged *res = new XamlElementInfoManaged (g_strdup (p->current_namespace->GetUri ()), el, info, v->GetKind (), v);
3992 XamlElementInfo *container = p->current_namespace->FindElement (p, type_name, NULL, false);
3993 info->SetPropertyOwnerKind (container->GetKind ());
3994 g_free (type_name);
3995 return res;
3998 delete v;
3999 return NULL;
4002 static XamlElementInfo *
4003 create_element_info_from_imported_managed_type (XamlParserInfo *p, const char *name, const char **attr, bool create)
4005 if (!p->loader)
4006 return NULL;
4008 char* type_name = NULL;
4009 char* type_xmlns = NULL;
4010 const char* use_xmlns = NULL;
4012 if (x_namespace) {
4013 // We might have an x:Class attribute specified, so we need to use that for the
4014 // type_name that we pass to LookupObject
4015 if (strcmp ("Application", name)) {
4016 type_name = x_namespace->FindTypeName (attr, &type_xmlns);
4017 if (type_name) {
4018 name = type_name;
4019 use_xmlns = type_xmlns;
4021 if (!p->hydrating) {
4022 parser_error (p, name, "x:Class", 4005, "Cannot specify x:Class in xaml files outside of a xap.");
4023 return NULL;
4029 Value *v = new Value ();
4030 if (!p->loader->LookupObject (p, use_xmlns ? p->GetTopElementPtr () : NULL, NULL, use_xmlns, name, create, false, v)) {
4031 delete v;
4032 if (type_name)
4033 g_free (type_name);
4034 if (type_xmlns)
4035 g_free (type_xmlns);
4036 return NULL;
4039 XamlElementInfoImportedManaged *info = new XamlElementInfoImportedManaged (g_strdup (name), NULL, v);
4041 if (create) {
4042 if (v->Is (Type::DEPENDENCY_OBJECT))
4043 p->AddCreatedElement (v->AsDependencyObject());
4046 return info;
4050 const char *
4051 XamlElementInfoNative::GetContentProperty (XamlParserInfo *p)
4053 return type->GetContentPropertyName ();
4056 XamlElementInstance *
4057 XamlElementInfoNative::CreateElementInstance (XamlParserInfo *p)
4059 if (type->IsValueType ())
4060 return new XamlElementInstanceValueType (this, p, GetName (), XamlElementInstance::ELEMENT);
4061 else if (type->IsSubclassOf (Type::FRAMEWORKTEMPLATE))
4062 return new XamlElementInstanceTemplate (this, p, GetName (), XamlElementInstance::ELEMENT);
4063 else
4064 return new XamlElementInstanceNative (this, p, GetName (), XamlElementInstance::ELEMENT);
4067 XamlElementInstance *
4068 XamlElementInfoNative::CreateWrappedElementInstance (XamlParserInfo *p, Value *o)
4070 XamlElementInstance *res = new XamlElementInstanceNative (this, p, GetName (), XamlElementInstance::ELEMENT, false);
4071 res->SetDependencyObject (o->AsDependencyObject ());
4073 return res;
4076 XamlElementInfo *
4077 XamlElementInstanceNative::FindPropertyElement (XamlParserInfo *p, const char *el, const char *dot)
4079 if (IsDependencyObject ()) {
4080 const char *prop_name = dot + 1;
4081 DependencyProperty *prop = DependencyProperty::GetDependencyProperty (info->GetKind (), prop_name);
4082 if (prop) {
4083 XamlElementInfoNative *info = new XamlElementInfoNative (Type::Find (prop->GetPropertyType ()));
4084 info->SetPropertyOwnerKind (prop->GetOwnerType ());
4085 return info;
4089 return XamlElementInstance::FindPropertyElement (p, el, dot);
4092 XamlElementInstance *
4093 XamlElementInfoNative::CreatePropertyElementInstance (XamlParserInfo *p, const char *name)
4095 return new XamlElementInstanceNative (this, p, name, XamlElementInstance::PROPERTY, false);
4098 XamlElementInstanceNative::XamlElementInstanceNative (XamlElementInfoNative *element_info, XamlParserInfo *parser_info, const char *name, ElementType type, bool create_item) :
4099 XamlElementInstance (element_info, name, type)
4101 this->element_info = element_info;
4102 this->parser_info = parser_info;
4103 if (create_item)
4104 SetDependencyObject (CreateItem ());
4109 DependencyObject *
4110 XamlElementInstanceNative::CreateItem ()
4112 XamlElementInstance *walk = parser_info->current_element;
4113 Type *type = element_info->GetType ();
4115 DependencyObject *item = NULL;
4116 DependencyProperty *dep = NULL;
4118 if (type->IsSubclassOf (Type::COLLECTION) || type->IsSubclassOf (Type::RESOURCE_DICTIONARY)) {
4119 // If we are creating a collection, try walking up the element tree,
4120 // to find the parent that we belong to and using that instance for
4121 // our collection, instead of creating a new one
4123 // We attempt to advance past the property setter, because we might be dealing with a
4124 // content element
4126 if (walk && walk->element_type == XamlElementInstance::PROPERTY) {
4127 char **prop_name = g_strsplit (walk->element_name, ".", -1);
4129 walk = walk->parent;
4130 dep = DependencyProperty::GetDependencyProperty (walk->info->GetKind (), prop_name [1]);
4132 g_strfreev (prop_name);
4133 } else if (walk && walk->info->GetContentProperty (parser_info)) {
4134 dep = DependencyProperty::GetDependencyProperty (walk->info->GetKind (),
4135 (char *) walk->info->GetContentProperty (parser_info));
4138 if (dep && Type::IsSubclassOf (dep->GetPropertyType(), type->GetKind ())) {
4139 Value *v = ((DependencyObject * ) walk->GetAsDependencyObject ())->GetValue (dep);
4140 if (v) {
4141 item = v->AsDependencyObject ();
4142 dep = NULL;
4144 // note: if !v then the default collection is NULL (e.g. PathFigureCollection)
4148 if (!item) {
4149 item = element_info->GetType()->IsCtorVisible() ? element_info->GetType ()->CreateInstance () : NULL;
4151 if (item) {
4152 parser_info->AddCreatedElement (item);
4154 // in case we must store the collection into the parent
4155 if (dep && dep->GetPropertyType() == type->GetKind ()) {
4156 MoonError err;
4157 Value item_value (item);
4158 if (!((DependencyObject * ) walk->GetAsDependencyObject ())->SetValueWithError (dep, &item_value, &err))
4159 parser_error (parser_info, element_name, NULL, err.code, err.message);
4161 } else {
4162 parser_error (parser_info, element_name, NULL, 2007, "Unknown element: %s.", element_name);
4166 return item;
4169 bool
4170 XamlElementInstanceNative::SetProperty (XamlParserInfo *p, XamlElementInstance *property, XamlElementInstance *value)
4172 if (property->info->RequiresManagedSet () || value->info->RequiresManagedSet ())
4173 return p->loader->SetProperty (p, p->GetTopElementPtr (), NULL, GetAsValue (), this, GetParentPointer (), property->info->xmlns, property->element_name, value->GetAsValue (), NULL);
4175 return dependency_object_set_property (p, this, property, value, true);
4178 bool
4179 XamlElementInstanceNative::SetProperty (XamlParserInfo *p, XamlElementInstance *property, const char *value)
4181 char **prop_name = g_strsplit (property->element_name, ".", -1);
4182 Type *owner = Type::Find (prop_name [0]);
4183 DependencyProperty *dep;
4185 if (!owner)
4186 return false;
4188 dep = DependencyProperty::GetDependencyProperty (owner->GetKind (), prop_name [1]);
4189 if (!dep)
4190 return false;
4192 return xaml_set_property_from_str (item, dep, value, NULL/*XXX*/);
4195 void
4196 XamlElementInstanceNative::AddChild (XamlParserInfo *p, XamlElementInstance *child)
4198 dependency_object_add_child (p, this, child, true);
4201 void
4202 XamlElementInstanceNative::SetAttributes (XamlParserInfo *p, const char **attr)
4204 dependency_object_set_attributes (p, this, attr);
4208 XamlElementInstanceValueType::XamlElementInstanceValueType (XamlElementInfoNative *element_info, XamlParserInfo *parser_info, const char *name, ElementType type) :
4209 XamlElementInstance (element_info, name, type)
4211 this->element_info = element_info;
4212 this->parser_info = parser_info;
4215 bool
4216 XamlElementInstanceValueType::CreateValueItemFromString (const char* str)
4219 bool res = value_from_str (element_info->GetType ()->GetKind (), NULL, str, &value);
4220 return res;
4223 void
4224 XamlElementInstanceValueType::SetAttributes (XamlParserInfo *p, const char **attr)
4226 value_type_set_attributes (p, this, attr);
4229 XamlElementInstanceEnum::XamlElementInstanceEnum (XamlElementInfoEnum *element_info, const char *name, ElementType type) :
4230 XamlElementInstance (element_info, name, type)
4234 bool
4235 XamlElementInstanceEnum::CreateEnumFromString (const char* str)
4237 int i = enums_str_to_int (element_name, str);
4238 if (i == -1)
4239 return false;
4241 value = new Value (i);
4242 return true;
4245 void
4246 XamlElementInstanceEnum::SetAttributes (XamlParserInfo *p, const char **attr)
4248 value_type_set_attributes (p, this, attr);
4251 XamlElementInstance *
4252 XamlElementInfoEnum::CreateElementInstance (XamlParserInfo *p)
4254 return new XamlElementInstanceEnum (this, name, XamlElementInstance::ELEMENT);
4257 XamlElementInstance *
4258 XamlElementInfoEnum::CreateWrappedElementInstance (XamlParserInfo *p, Value *o)
4260 XamlElementInstance *res = new XamlElementInstanceEnum (this, name, XamlElementInstance::ELEMENT);
4261 return res;
4264 const char *
4265 XamlElementInfoManaged::GetContentProperty (XamlParserInfo *p)
4267 if (!p->loader)
4268 return NULL;
4270 // TODO: We could cache this, but for now lets keep things as simple as possible.
4271 const char *res = p->loader->GetContentPropertyName (p, p->GetTopElementPtr (), obj);
4272 if (res)
4273 return res;
4274 return XamlElementInfo::GetContentProperty (p);
4277 XamlElementInstance *
4278 XamlElementInfoManaged::CreateElementInstance (XamlParserInfo *p)
4280 XamlElementInstanceManaged *inst = new XamlElementInstanceManaged (this, GetName (), XamlElementInstance::ELEMENT, obj);
4282 if (obj->Is (Type::DEPENDENCY_OBJECT))
4283 p->AddCreatedElement (inst->GetAsDependencyObject ());
4285 return inst;
4288 XamlElementInstance *
4289 XamlElementInfoManaged::CreateWrappedElementInstance (XamlParserInfo *p, Value *o)
4291 XamlElementInstanceManaged *inst = new XamlElementInstanceManaged (this, GetName (), XamlElementInstance::ELEMENT, o);
4293 return inst;
4296 XamlElementInstance *
4297 XamlElementInfoManaged::CreatePropertyElementInstance (XamlParserInfo *p, const char *name)
4299 XamlElementInstanceManaged *inst = new XamlElementInstanceManaged (this, name, XamlElementInstance::PROPERTY, obj);
4301 return inst;
4304 XamlElementInstanceManaged::XamlElementInstanceManaged (XamlElementInfo *info, const char *name, ElementType type, Value *obj) :
4305 XamlElementInstance (info, name, type)
4307 // The managed code owns our Value objects
4308 cleanup_value = false;
4310 this->value = obj;
4312 if (obj->Is (Type::DEPENDENCY_OBJECT)) {
4313 this->is_dependency_object = true;
4314 this->SetDependencyObject (obj->AsDependencyObject ());
4316 else
4317 this->is_dependency_object = false;
4320 void *
4321 XamlElementInstanceManaged::GetManagedPointer ()
4323 if (value->Is (Type::DEPENDENCY_OBJECT))
4324 return value->AsDependencyObject ();
4325 return value->AsManagedObject ();
4328 Value *
4329 XamlElementInstanceManaged::GetParentPointer ()
4331 XamlElementInstance *walk = parent;
4332 while (walk && walk->element_type != XamlElementInstance::ELEMENT)
4333 walk = walk->parent;
4335 if (!walk) {
4336 return NULL;
4339 return walk->GetAsValue ();
4342 bool
4343 XamlElementInstanceManaged::SetProperty (XamlParserInfo *p, XamlElementInstance *property, XamlElementInstance *value)
4345 if (GetAsDependencyObject () != NULL && dependency_object_set_property (p, this, property, value, false))
4346 return true;
4347 return p->loader->SetProperty (p, p->GetTopElementPtr (), info->xmlns, GetAsValue (), this, GetParentPointer (), property->info->xmlns, property->element_name, value->GetAsValue (), value);
4350 bool
4351 XamlElementInstanceManaged::SetProperty (XamlParserInfo *p, XamlElementInstance *property, const char *value)
4353 Value v = Value (value);
4354 return p->loader->SetProperty (p, p->GetTopElementPtr (), info->xmlns, GetAsValue (), this, GetParentPointer (), property->info->xmlns, property->element_name, &v, NULL);
4357 void
4358 XamlElementInstanceManaged::AddChild (XamlParserInfo *p, XamlElementInstance *child)
4360 if (element_type == XamlElementInstance::PROPERTY) {
4361 Value *prop = new Value (element_name);
4362 p->loader->AddChild (p, p->GetTopElementPtr (), GetParentPointer (), true, info->xmlns, prop, this, child->GetAsValue (), child);
4363 delete prop;
4364 return;
4367 p->loader->AddChild (p, p->GetTopElementPtr (), GetParentPointer (), false, info->xmlns, GetAsValue (), this, child->GetAsValue (), child);
4370 void
4371 XamlElementInstanceManaged::SetAttributes (XamlParserInfo *p, const char **attr)
4373 dependency_object_set_attributes (p, this, attr);
4376 bool
4377 XamlElementInstanceManaged::TrySetContentProperty (XamlParserInfo *p, XamlElementInstance *value)
4379 Value *v = value->GetAsValue ();
4380 const char* prop_name = info->GetContentProperty (p);
4382 return p->loader->SetProperty (p, p->GetTopElementPtr (), info->xmlns, GetAsValue (), this, GetParentPointer (), NULL, prop_name, v, value);
4385 bool
4386 XamlElementInstanceManaged::TrySetContentProperty (XamlParserInfo *p, const char *value)
4388 if (Type::IsSubclassOf (info->GetKind (), Type::CONTENTCONTROL)) {
4389 // Content controls are not allowed to have their content set as text, they need to have a child element
4390 // if you want to set the content of a contentcontrol to text you need to use attribute syntax
4391 return false;
4394 if (!XamlElementInstance::TrySetContentProperty (p, value)) {
4395 const char* prop_name = info->GetContentProperty (p);
4396 if (!p->cdata_content)
4397 return false;
4398 Value v = Value (value);
4399 bool res = p->loader->SetProperty (p, p->GetTopElementPtr (), info->xmlns, GetAsValue (), this, GetParentPointer (), NULL, prop_name, &v, NULL);
4400 return res;
4403 return false;
4406 XamlElementInstance *
4407 XamlElementInfoImportedManaged::CreateElementInstance (XamlParserInfo *p)
4409 XamlElementInstanceManaged *inst = new XamlElementInstanceManaged (this, name, XamlElementInstance::ELEMENT, obj);
4411 return inst;
4414 const char *
4415 XamlElementInfoImportedManaged::GetContentProperty (XamlParserInfo *p)
4417 if (!p->loader)
4418 return NULL;
4420 // TODO: Test, it's possible that managed objects that aren't DOs are allowed to have content properties.
4421 if (!obj->Is (Type::DEPENDENCY_OBJECT))
4422 return XamlElementInfo::GetContentProperty (p);
4425 // TODO: We could cache this, but for now lets keep things as simple as possible.
4426 const char *res = p->loader->GetContentPropertyName (p, p->GetTopElementPtr (), obj);
4427 if (res)
4428 return res;
4430 return XamlElementInfo::GetContentProperty (p);
4433 XamlElementInstance *
4434 XamlElementInfoImportedManaged::CreateWrappedElementInstance (XamlParserInfo *p, Value *o)
4436 XamlElementInstanceManaged *inst = new XamlElementInstanceManaged (this, Type::Find (o->GetKind ())->GetName (), XamlElementInstance::ELEMENT, o);
4438 return inst;
4441 XamlElementInstance *
4442 XamlElementInfoImportedManaged::CreatePropertyElementInstance (XamlParserInfo *p, const char *name)
4444 XamlElementInstanceManaged *inst = new XamlElementInstanceManaged (this, name, XamlElementInstance::PROPERTY, obj);
4446 return inst;
4451 /// Add Child funcs
4454 static const char*
4455 get_key_from_child (XamlElementInstance *child)
4457 const char *key = child->GetKey ();
4458 if (key)
4459 return key;
4461 key = child->GetName ();
4462 if (key)
4463 return key;
4465 if (child->IsDependencyObject ()) {
4466 DependencyObject *c = child->GetAsDependencyObject();
4468 if (Type::IsSubclassOf (Type::STYLE, child->info->GetKind ())) {
4469 Value *v = c->GetValue (Style::TargetTypeProperty);
4470 if (v && v->GetKind () == Type::MANAGEDTYPEINFO)
4471 key = v->AsManagedTypeInfo ()->full_name;
4473 if (key)
4474 return key;
4478 return NULL;
4481 static void
4482 dependency_object_add_child (XamlParserInfo *p, XamlElementInstance *parent, XamlElementInstance *child, bool fail_if_no_prop)
4484 Types *types = Deployment::GetCurrent ()->GetTypes ();
4485 if (parent->element_type == XamlElementInstance::PROPERTY) {
4487 if (parent->info->RequiresManagedSet ())
4488 return;
4490 char **prop_name = g_strsplit (parent->element_name, ".", -1);
4491 Type *owner = types->Find (prop_name [0]);
4493 if (owner) {
4494 DependencyProperty *dep = DependencyProperty::GetDependencyProperty (owner->GetKind (), prop_name [1]);
4496 g_strfreev (prop_name);
4498 if (!dep) {
4499 g_warning ("Unknown element: %s.", parent->element_name);
4500 if (fail_if_no_prop)
4501 parser_error (p, parent->element_name, NULL, 2007, "Unknown element: %s.", parent->element_name);
4502 return;
4505 // XamlElementInfoEnum has Type::INVALID as
4506 // its kind, which is why that first check is
4507 // here.
4508 if (child->info->GetKind() != Type::MANAGED &&
4509 !types->Find (child->info->GetKind())->IsCtorVisible()) {
4510 // we can't instantiate this type
4511 return parser_error (p, child->element_name, NULL, 2007,
4512 "Unknown element: %s.", child->element_name);
4515 // Don't add the child element, if it is the entire collection
4516 if (dep->GetPropertyType() == child->info->GetKind ())
4517 return;
4519 Type::Kind prop_type = dep->GetPropertyType ();
4520 if (!types->IsSubclassOf (prop_type, Type::DEPENDENCY_OBJECT_COLLECTION)
4521 && !types->IsSubclassOf (prop_type, Type::RESOURCE_DICTIONARY))
4522 return;
4524 // Most common case, we will have a parent that we can snag the collection from
4525 DependencyObject *obj = (DependencyObject *) parent->parent->GetAsDependencyObject ();
4526 if (!obj)
4527 return;
4529 Value *col_v = obj->GetValue (dep);
4530 if (!col_v) {
4531 Type *col_type = types->Find (prop_type);
4532 DependencyObject *c_obj = col_type->CreateInstance ();
4533 obj->SetValue (dep, Value::CreateUnrefPtr (c_obj));
4534 col_v = obj->GetValue (dep);
4535 c_obj->unref ();
4537 Collection *col = col_v->AsCollection ();
4538 MoonError err;
4540 if (types->IsSubclassOf (prop_type, Type::DEPENDENCY_OBJECT_COLLECTION)) {
4541 Value child_val (child->GetAsDependencyObject ());
4542 if (-1 == col->AddWithError (&child_val, &err))
4543 return parser_error (p, child->element_name, NULL, err.code, err.message);
4545 else if (types->IsSubclassOf (prop_type, Type::RESOURCE_DICTIONARY)) {
4546 ResourceDictionary *dict = (ResourceDictionary *)col;
4548 const char *key = get_key_from_child (child);
4550 if (key == NULL) {
4551 // XXX don't know the proper values here...
4552 return parser_error (p, child->element_name, NULL, 2007,
4553 "You must specify an x:Key or x:Name for elements in a ResourceDictionary");
4556 Value *child_as_value = child->GetAsValue ();
4558 if (!child_as_value) {
4559 // XXX don't know the proper values here...
4560 return parser_error (p, child->element_name, NULL, 2007,
4561 "Error adding child to ResourceDictionary");
4564 bool added = dict->AddWithError (key, child_as_value, &err);
4565 if (!added)
4566 return parser_error (p, child->element_name, NULL, err.code, err.message);
4569 return;
4572 return;
4575 if (types->IsSubclassOf (parent->info->GetKind (), Type::DEPENDENCY_OBJECT_COLLECTION)) {
4576 Collection *col = (Collection *) parent->GetAsDependencyObject ();
4577 MoonError err;
4578 Value child_val ((DependencyObject*)child->GetAsDependencyObject ());
4580 if (-1 == col->AddWithError (&child_val, &err))
4581 return parser_error (p, child->element_name, NULL, err.code, err.message);
4582 return;
4584 else if (types->IsSubclassOf (parent->info->GetKind (), Type::RESOURCE_DICTIONARY)) {
4585 ResourceDictionary *dict = (ResourceDictionary *) parent->GetAsDependencyObject ();
4587 MoonError err;
4588 const char *key = get_key_from_child (child);
4590 if (key == NULL) {
4591 // XXX don't know the proper values here...
4592 return parser_error (p, child->element_name, NULL, 2007,
4593 "You must specify an x:Key or x:Name for elements in a ResourceDictionary");
4596 Value *child_as_value = child->GetAsValue ();
4597 bool added = dict->AddWithError (key, child_as_value, &err);
4598 if (!added)
4599 return parser_error (p, child->element_name, NULL, err.code, err.message);
4603 if (parent->element_type != XamlElementInstance::PROPERTY) {
4604 parent->TrySetContentProperty (p, child);
4607 // Do nothing if we aren't adding to a collection, or a content property collection
4612 /// set property funcs
4615 // these are just a bunch of special cases
4616 static void
4617 dependency_object_missed_property (XamlElementInstance *item, XamlElementInstance *prop, XamlElementInstance *value, char **prop_name)
4622 static bool
4623 set_managed_attached_property (XamlParserInfo *p, XamlElementInstance *item, XamlElementInstance *prop, XamlElementInstance *value)
4625 if (!p->loader)
4626 return false;
4628 return p->loader->SetProperty (p, p->GetTopElementPtr (), item->info->xmlns, item->GetAsValue (), item, item->GetParentPointer (), prop->info->xmlns, prop->element_name, value->GetAsValue (), value);
4631 static bool
4632 dependency_object_set_property (XamlParserInfo *p, XamlElementInstance *item, XamlElementInstance *property, XamlElementInstance *value, bool raise_errors)
4634 char **prop_name = g_strsplit (property->element_name, ".", -1);
4635 DependencyObject *dep = item->GetAsDependencyObject ();
4636 DependencyProperty *prop = NULL;
4637 bool res;
4638 Types *types = Deployment::GetCurrent ()->GetTypes ();
4640 if (types->Find (item->info->GetKind ())->IsValueType ()) {
4641 if (raise_errors) parser_error (p, item->element_name, NULL, -1, "Value types (%s) do not have properties.", property->element_name);
4642 g_strfreev (prop_name);
4643 return false;
4646 if (types->Find (property->info->GetPropertyOwnerKind ())->IsCustomType ()) {
4647 g_strfreev (prop_name);
4648 return set_managed_attached_property (p, item, property, value);
4651 if (!dep) {
4652 // FIXME is this really where this check should live
4653 if (raise_errors)
4654 parser_error (p, item->element_name, NULL, 2030,
4655 "Property element %s cannot be used inside another property element.",
4656 property->element_name);
4658 g_strfreev (prop_name);
4659 return false;
4662 prop = DependencyProperty::GetDependencyProperty (item->info->GetKind (), prop_name [1]);
4664 if (prop) {
4665 if (prop->IsReadOnly ()) {
4666 if (raise_errors)
4667 parser_error (p, item->element_name, NULL, 2014,
4668 "The attribute %s is read only and cannot be set.", prop->GetName ());
4669 res = false;
4670 } else if (types->IsSubclassOf (value->info->GetKind (), prop->GetPropertyType())) {
4671 // an empty collection can be NULL and valid
4672 if (item->IsPropertySet (prop->GetName())) {
4673 if (raise_errors)
4674 parser_error (p, item->element_name, NULL, 2033,
4675 "Cannot specify the value multiple times for property: %s.",
4676 property->element_name);
4677 res = false;
4678 } else {
4679 MoonError err;
4681 // HACK - since the Setter is added to the collection *before* its properties are set
4682 // we find ourselves with a sealed Setter - which should not be possible at the parse time
4683 SetterBase *sb = NULL;
4684 if (types->IsSubclassOf (dep->GetObjectType (), Type::SETTERBASE)) {
4685 sb = (SetterBase*) dep;
4686 sb->SetIsSealed (false);
4689 if (!is_managed_kind (value->info->GetKind ()) && !value->info->RequiresManagedSet()) {
4690 if (!dep->SetValueWithError (prop, value->GetAsValue (), &err)) {
4691 if (raise_errors)
4692 parser_error (p, item->element_name, NULL, err.code, err.message);
4693 res = false;
4694 goto cleanup;
4697 } else {
4698 if (!p->loader->SetProperty (p, p->GetTopElementPtr (), NULL, item->GetAsValue (), item, item->GetParentPointer (), NULL, prop_name [1], value->GetAsValue (), NULL)) {
4699 if (raise_errors)
4700 parser_error (p, item->element_name, NULL, err.code, err.message);
4701 res = false;
4702 goto cleanup;
4707 // re-seal the Setter (end-HACK)
4708 if (sb)
4709 sb->SetIsSealed (true);
4711 item->MarkPropertyAsSet (prop->GetName());
4712 res = true;
4714 } else if (types->IsSubclassOf (prop->GetPropertyType (), Type::COLLECTION) || types->IsSubclassOf (prop->GetPropertyType (), Type::RESOURCE_DICTIONARY)) {
4715 // The items were added in add_child
4716 return true;
4717 } else {
4718 if (raise_errors)
4719 parser_error (p, item->element_name, NULL, 2010, "does not support %s as content.", value->element_name);
4720 res = false;
4722 } else {
4723 dependency_object_missed_property (item, property, value, prop_name);
4724 res = false;
4727 cleanup:
4728 g_strfreev (prop_name);
4729 return res;
4732 bool
4733 xaml_set_property_from_str (DependencyObject *obj, DependencyProperty *prop, const char *value, MoonError *error)
4735 Value *v = NULL;
4736 bool rv = true;
4738 if (!value_from_str (prop->GetPropertyType(), prop->GetName(), value, &v))
4739 return false;
4741 // it's possible for (a valid) value to be NULL (and we must keep the default value)
4742 if (v) {
4743 rv = obj->SetValueWithError (prop, v, error);
4744 delete v;
4747 return rv;
4750 bool
4751 xaml_is_valid_event_name (Type::Kind kind, const char *name, bool allow_desktop_events)
4753 Type *type = Type::Find (kind);
4754 if (!type)
4755 return false;
4757 int event_id = type->LookupEvent (name);
4758 if (event_id == -1)
4759 return false;
4761 if (!allow_desktop_events || (moonlight_flags & RUNTIME_INIT_DESKTOP_EXTENSIONS) == 0) {
4762 // if we're not allowing desktop-only events, or if the user hasn't allowed them,
4763 // return false if the name corresponds to one of them.
4764 if (!strcmp (name, "MouseRightButtonDown") ||
4765 !strcmp (name, "MouseRightButtonUp") ||
4766 !strcmp (name, "MouseWheel"))
4767 return false;
4770 return true;
4773 static void
4774 value_type_set_attributes (XamlParserInfo *p, XamlElementInstance *item, const char **attr)
4776 // the only attributes value on value types seem to be x:Key
4777 // and x:Name, but reuse the generic namespace attribute stuff
4778 // anyway.
4780 for (int i = 0; attr [i]; i += 2) {
4781 // Skip empty attrs
4782 if (attr[i + 1] == NULL || attr[i + 1][0] == '\0')
4783 continue;
4785 char **attr_name = g_strsplit (attr [i], "|", -1);
4787 if (attr_name [1]) {
4789 XamlNamespace *ns = (XamlNamespace *) g_hash_table_lookup (p->namespace_map, attr_name [0]);
4791 if (!ns)
4792 return parser_error (p, item->element_name, attr[i], 7055, "undeclared prefix");
4794 ns->SetAttribute (p, item, attr_name [1], attr [i + 1]);
4796 g_strfreev (attr_name);
4798 // Setting managed attributes can cause errors galore
4799 if (p->error_args)
4800 return;
4802 continue;
4805 g_strfreev (attr_name);
4809 static void
4810 dependency_object_set_attributes (XamlParserInfo *p, XamlElementInstance *item, const char **attr)
4812 Types *types = Deployment::GetCurrent ()->GetTypes ();
4813 GList *delay_att = NULL;
4815 for (int i = 0; attr [i]; i += 2) {
4817 if (p->error_args)
4818 return;
4820 // Setting attributes like x:Class can change item->item, so we
4821 // need to make sure we have an up to date pointer
4822 DependencyObject *dep = item->GetAsDependencyObject ();
4823 char **attr_name = g_strsplit (attr [i], "|", -1);
4825 if (attr_name [1]) {
4826 XamlNamespace *ns = (XamlNamespace *) g_hash_table_lookup (p->namespace_map, attr_name [0]);
4828 if (ns != x_namespace) {
4829 delay_att = g_list_append (delay_att, GINT_TO_POINTER (i));
4830 g_strfreev (attr_name);
4831 continue;
4834 if (!ns) {
4835 g_strfreev (attr_name);
4836 return parser_error (p, item->element_name, attr[i], 5055, "undeclared prefix");
4839 ns->SetAttribute (p, item, attr_name [1], attr [i + 1]);
4841 g_strfreev (attr_name);
4843 // Setting managed attributes can cause errors galore
4844 if (p->error_args)
4845 return;
4847 continue;
4850 g_strfreev (attr_name);
4852 const char *pname = attr [i];
4853 char *atchname = NULL;
4854 for (int a = 0; attr [i][a]; a++) {
4855 if (attr [i][a] != '.')
4856 continue;
4857 atchname = g_strndup (attr [i], a);
4858 pname = attr [i] + a + 1;
4859 break;
4862 DependencyProperty *prop = NULL;
4863 if (atchname) {
4864 Type *attached_type = types->Find (atchname);
4865 if (attached_type)
4866 prop = DependencyProperty::GetDependencyProperty (attached_type->GetKind (), pname);
4867 } else {
4868 prop = DependencyProperty::GetDependencyProperty (item->info->GetKind (), pname);
4871 if (prop) {
4872 if (prop->GetId () == DependencyObject::NameProperty) {
4874 if (item->GetName ()) {
4875 parser_error (p, item->element_name, NULL, 2016, "Cannot specify both Name and x:Name attributes.");
4876 return;
4879 // XXX toshok - I don't like doing this here... but it fixes airlines.
4880 item->SetKey (p, attr[i+1]);
4882 NameScope *scope = p->namescope;
4883 if (!item->GetAsDependencyObject ()->SetName (attr [i+1], scope)) {
4884 parser_error (p, item->element_name, NULL, 2028,
4885 "The name already exists in the tree: %s.", attr [i+1]);
4886 g_free (atchname);
4887 g_list_free (delay_att);
4888 return;
4890 continue;
4893 if (prop->IsReadOnly ()) {
4894 parser_error (p, item->element_name, NULL, 2014,
4895 "The attribute %s is read only and cannot be set.", prop->GetName ());
4896 g_free (atchname);
4897 g_list_free (delay_att);
4898 return;
4901 if (item->IsPropertySet (prop->GetName())) {
4902 parser_error (p, item->element_name, attr [i], 2033,
4903 "Cannot specify the value multiple times for property: %s.", prop->GetName ());
4904 g_free (atchname);
4905 g_list_free (delay_att);
4906 return;
4909 Value *v = NULL;
4910 bool v_set = false;
4911 char *attr_value = g_strdup (attr [i+1]);
4913 bool need_managed = false;
4914 if (attr[i+1][0] == '{') {
4915 if (attr[i+1][1] == '}') {
4916 // {} is an escape sequence so you can have strings like {StaticResource}
4917 char *nv = attr_value;
4918 attr_value = g_strdup (attr_value + 2);
4919 g_free (nv);
4921 else if (attr[i+1][strlen(attr[i+1]) - 1] == '}') {
4922 need_managed = true;
4926 if (!need_managed) {
4927 if (!value_from_str_with_parser (p, prop->GetPropertyType(), prop->GetName(), attr_value, &v, &v_set)) {
4928 delete v;
4929 g_free (attr_value);
4930 continue;
4934 Type::Kind propKind = prop->GetPropertyType ();
4935 Type::Kind itemKind = item->info->GetKind();
4937 if (need_managed || is_managed_kind (propKind) || types->Find (itemKind)->IsCustomType () || (v && is_managed_kind (v->GetKind ()))) {
4938 bool str_value = false;
4939 if (!v_set) {
4940 v = new Value (attr [i + 1]); // Note that we passed the non escaped value, not attr_value
4941 v_set = true;
4942 str_value = true;
4945 // printf ("setting managed property: %s::%s to %s=%s\n", dep->GetType ()->GetName (), prop->GetName (), attr [i], attr [i + 1]);
4946 if (p->loader->SetProperty (p, p->GetTopElementPtr (), NULL, item->GetAsValue (), item, item->GetParentPointer (), NULL, g_strdup (attr [i]), v, NULL)) {
4947 delete v;
4948 g_free (attr_value);
4949 continue;
4950 } else {
4951 if (str_value) {
4952 delete v;
4953 v = NULL;
4955 if (!value_from_str_with_parser (p, prop->GetPropertyType(), prop->GetName(), attr_value, &v, &v_set)) {
4956 delete v;
4957 g_free (attr_value);
4958 continue;
4964 if (!v_set && !value_is_explicit_null (attr [i + 1])) { // Check the non escaped value
4965 parser_error (p, item->element_name, attr [i], 2024, "Invalid attribute value %s for property %s.", attr [i+1], attr [i]);
4967 g_free (attr_value);
4968 g_free (atchname);
4969 g_list_free (delay_att);
4970 return;
4973 MoonError err;
4974 // printf ("settng: %s %s value type: %s prop type: %s\n", attr [i], attr [i+1], v ? Type::Find (v->GetKind ())->GetName () : "--null--", Type::Find (prop->GetPropertyType ())->GetName ());
4975 if (!dep->SetValueWithError (prop, v, &err))
4976 parser_error (p, item->element_name, attr [i], err.code, err.message);
4977 else
4978 item->MarkPropertyAsSet (prop->GetName());
4980 delete v;
4981 g_free (attr_value);
4982 } else {
4983 delay_att = g_list_append (delay_att, GINT_TO_POINTER (i));
4986 if (atchname)
4987 g_free (atchname);
4990 GList *walk = g_list_first (delay_att);
4991 while (walk) {
4992 int i = GPOINTER_TO_INT (walk->data);
4994 if (p->error_args)
4995 return;
4997 char **attr_name = g_strsplit (attr [i], "|", -1);
4999 if (attr_name [1]) {
5000 XamlNamespace *ns = (XamlNamespace *) g_hash_table_lookup (p->namespace_map, attr_name [0]);
5002 if (ns == x_namespace) {
5003 // Skip these, they are handled earlier
5004 g_strfreev (attr_name);
5005 walk = walk->prev;
5008 if (!ns) {
5009 g_strfreev (attr_name);
5010 parser_error (p, item->element_name, attr[i], 5055, "undeclared prefix");
5011 break;
5014 ns->SetAttribute (p, item, attr_name [1], attr [i + 1]);
5016 g_strfreev (attr_name);
5018 // Setting managed attributes can cause errors galore
5019 if (p->error_args)
5020 break;
5021 } else {
5022 if (!item->SetUnknownAttribute (p, attr [i], attr [i + 1])) {
5023 parser_error (p, item->element_name, attr [i], 2012,
5024 "Unknown attribute %s on element %s.",
5025 attr [i], item->element_name);
5026 break;
5030 walk = walk->next;
5033 g_list_free (delay_att);
5037 static Value *
5038 lookup_named_item (XamlElementInstance *top, const char *name)
5040 Types *types = Deployment::GetCurrent ()->GetTypes ();
5041 XamlElementInstance *inst = top;
5043 while (inst) {
5044 if (inst->element_type == XamlElementInstance::ELEMENT) {
5045 ResourceDictionary *rd = NULL;
5046 Type::Kind kind = inst->info->GetKind ();
5048 if (types->IsSubclassOf (kind, Type::FRAMEWORKELEMENT)) {
5049 rd = inst->GetAsDependencyObject ()->GetValue (UIElement::ResourcesProperty)->AsResourceDictionary ();
5050 } else if (types->IsSubclassOf (kind, Type::RESOURCE_DICTIONARY)) {
5051 rd = (ResourceDictionary*) inst->GetAsDependencyObject ();
5054 if (rd) {
5055 bool exists;
5056 Value *res = lookup_resource_dictionary (rd, name, &exists);
5057 if (exists)
5058 return res;
5062 inst = inst->parent;
5065 return NULL;
5068 static Value *
5069 lookup_resource_dictionary (ResourceDictionary *rd, const char *name, bool *exists)
5071 *exists = false;
5072 Value *resource_value = rd->Get (name, exists);
5073 return *exists ? new Value (*resource_value) : NULL;
5076 Value *
5077 xaml_lookup_named_item (void *parser, void *instance, const char* name)
5079 XamlParserInfo *p = (XamlParserInfo *) parser;
5080 XamlElementInstance *inst = (XamlElementInstance *) instance;
5081 Value *res = NULL;
5083 if (inst)
5084 res = lookup_named_item (inst, name);
5086 XamlContext *context = p->loader->GetContext ();
5087 if (!res && context)
5088 context->internal->LookupNamedItem (name, &res);
5090 if (!res) {
5091 Application *app = Application::GetCurrent ();
5092 if (app) {
5093 ResourceDictionary *rd = app->GetResources ();
5095 bool exists = false;
5096 res = lookup_resource_dictionary (rd, name, &exists);
5098 if (res && Type::IsSubclassOf (res->GetKind (), Type::DEPENDENCY_OBJECT)) {
5099 DependencyObject *dob = res->AsDependencyObject ();
5100 NameScope::SetNameScope (dob, dob->FindNameScope ());
5105 return res;
5108 void *
5109 xaml_get_template_parent (void *parser, void *element_instance)
5111 XamlParserInfo *p = (XamlParserInfo *) parser;
5112 XamlElementInstance *item = (XamlElementInstance *) element_instance;
5114 return p->GetTemplateParent (item);
5117 char *
5118 xaml_get_element_key (void *parser, void *element_instance)
5120 XamlElementInstance *item = (XamlElementInstance *) element_instance;
5121 const char *key = item->GetKey ();
5122 if (!key)
5123 key = item->GetName ();
5124 return g_strdup (key);
5127 char *
5128 xaml_get_element_name (void *parser, void *element_instance)
5130 XamlElementInstance *item = (XamlElementInstance *) element_instance;
5131 return g_strdup (item->element_name);
5134 bool
5135 xaml_is_property_set (void *parser, void *element_instance, char *name)
5137 XamlElementInstance *item = (XamlElementInstance *) element_instance;
5138 return item->IsPropertySet (name);
5141 void
5142 xaml_mark_property_as_set (void *parser, void *element_instance, char *name)
5144 XamlElementInstance *item = (XamlElementInstance *) element_instance;
5145 item->MarkPropertyAsSet (g_strdup (name));
5148 void
5149 xaml_delay_set_property (void *parser, void *element_instance, const char *xmlns, const char *name, const Value *value)
5151 XamlElementInstance *item = (XamlElementInstance *) element_instance;
5152 item->DelaySetProperty (xmlns, name, value);
5155 void
5156 xaml_init (void)
5158 default_namespace = new DefaultNamespace ();
5159 x_namespace = new XNamespace ();
5160 xml_namespace = new XmlNamespace ();