stub out things to get the beatles xbox site up and running
[moon.git] / src / xaml.cpp
blob9abde85fe5f7ca6a1e6fa410c9e07911985ef165
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"
54 #include "managedtypeinfo.h"
57 class XamlElementInfo;
58 class XamlElementInstance;
59 class XamlParserInfo;
60 class XamlNamespace;
61 class DefaultNamespace;
62 class XNamespace;
63 class XmlNamespace;
64 class PrimitiveNamespace;
65 class MCIgnorableNamespace;
66 class XamlElementInfoNative;
67 class XamlElementInstanceNative;
68 class XamlElementInstanceValueType;
69 class XamlElementInfoEnum;
70 class XamlElementInstanceEnum;
71 class XamlElementInfoManaged;
72 class XamlElementInstanceManaged;
73 class XamlElementInfoImportedManaged;
74 class XamlElementInstanceTemplate;
76 #define INTERNAL_IGNORABLE_ELEMENT "MoonlightInternalIgnorableElement"
78 #define IS_NULL_OR_EMPTY(str) (!str || (*str == 0))
80 static DefaultNamespace *default_namespace = NULL;
81 static XNamespace *x_namespace = NULL;
82 static XmlNamespace *xml_namespace = NULL;
84 static const char* default_namespace_names [] = {
85 "http://schemas.microsoft.com/winfx/2006/xaml/presentation",
86 "http://schemas.microsoft.com/client/2007",
87 "http://schemas.microsoft.com/xps/2005/06",
88 "http://schemas.microsoft.com/client/2007/deployment",
89 NULL
92 #define X_NAMESPACE_URI "http://schemas.microsoft.com/winfx/2006/xaml"
93 #define XML_NAMESPACE_URI "http://www.w3.org/XML/1998/namespace"
94 #define PRIMITIVE_NAMESPACE_URI "clr-namespace:System;assembly=mscorlib"
95 #define MC_IGNORABLE_NAMESPACE_URI "http://schemas.openxmlformats.org/markup-compatibility/2006"
98 static bool value_from_str_with_parser (XamlParserInfo *p, Type::Kind type, const char *prop_name, const char *str, Value **v, bool *v_set);
99 static bool dependency_object_set_property (XamlParserInfo *p, XamlElementInstance *item, XamlElementInstance *property, XamlElementInstance *value, bool raise_errors);
100 static bool set_managed_attached_property (XamlParserInfo *p, XamlElementInstance *item, XamlElementInstance *property, XamlElementInstance *value);
101 static void dependency_object_add_child (XamlParserInfo *p, XamlElementInstance *parent, XamlElementInstance *child, bool fail_if_no_prop);
102 static void dependency_object_set_attributes (XamlParserInfo *p, XamlElementInstance *item, const char **attr);
103 static void value_type_set_attributes (XamlParserInfo *p, XamlElementInstance *item, const char **attr);
104 static bool element_begins_buffering (Type::Kind kind);
105 static bool is_managed_kind (Type::Kind kind);
106 static bool kind_requires_managed_load (Type::Kind kind);
107 static bool is_legal_top_level_kind (Type::Kind kind);
108 static Value *lookup_resource_dictionary (ResourceDictionary *rd, const char *name, bool *exists);
109 static void parser_error (XamlParserInfo *p, const char *el, const char *attr, int error_code, const char *format, ...);
110 static gboolean namespace_for_prefix (gpointer key, gpointer value, gpointer user_data);
112 static XamlElementInfo *create_element_info_from_imported_managed_type (XamlParserInfo *p, const char *name, const char **attr, bool create);
113 static void destroy_created_namespace (gpointer data, gpointer user_data);
115 enum BufferMode {
116 BUFFER_MODE_TEMPLATE,
117 BUFFER_MODE_IGNORE
121 class XamlNamespace {
122 public:
123 const char *name;
124 bool is_ignored;
126 XamlNamespace ()
128 name = NULL;
129 is_ignored = false;
132 virtual ~XamlNamespace () { }
133 virtual XamlElementInfo* FindElement (XamlParserInfo *p, const char *el, const char **attr, bool create) = 0;
134 virtual bool SetAttribute (XamlParserInfo *p, XamlElementInstance *item, const char *attr, const char *value) = 0;
136 virtual const char* GetUri () = 0;
137 virtual const char* GetPrefix () = 0;
140 void
141 add_namespace_data (gpointer key, gpointer value, gpointer user_data)
143 XamlNamespace *ns = (XamlNamespace *) value;
144 GHashTable *table = (GHashTable *) user_data;
146 if ((void *)ns != (void *)default_namespace)
147 g_hash_table_insert (table, g_strdup (ns->GetPrefix ()), g_strdup (ns->GetUri ()));
150 void
151 add_namespace_to_ignorable (gpointer key, gpointer value, gpointer user_data)
153 char *prefix = (char *) key;
154 char *uri = (char *) value;
155 GString *str = (GString *) user_data;
157 g_string_append_printf (str, "xmlns:%s=\"%s\" ", prefix, uri);
160 class XamlContextInternal {
162 public:
163 Value *top_element;
164 FrameworkTemplate *template_parent;
165 GHashTable *imported_namespaces;
166 Surface *surface;
167 XamlLoaderCallbacks callbacks;
168 GSList *resources;
169 XamlContextInternal *parent_context;
171 DependencyObject *source;
173 XamlContextInternal (XamlLoaderCallbacks callbacks, Value *top_element, FrameworkTemplate *template_parent, GHashTable *namespaces, GSList *resources, XamlContextInternal *parent_context)
175 this->callbacks = callbacks;
176 this->top_element = new Value (*top_element);
177 this->template_parent = template_parent;
178 this->surface = template_parent->GetSurface ();
179 this->resources = resources;
180 this->parent_context = parent_context;
182 if (this->callbacks.create_gchandle)
183 this->callbacks.create_gchandle ();
184 imported_namespaces = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
185 g_hash_table_foreach (namespaces, add_namespace_data, imported_namespaces);
189 ~XamlContextInternal ()
191 if (imported_namespaces)
192 g_hash_table_destroy (imported_namespaces);
193 if (resources)
194 g_slist_free (resources);
195 delete top_element;
198 char *CreateIgnorableTagOpen ()
200 GString *str = g_string_new ("<" INTERNAL_IGNORABLE_ELEMENT " ");
201 g_hash_table_foreach (imported_namespaces, add_namespace_to_ignorable, str);
203 str = g_string_append (str, ">");
205 char *res = str->str;
206 g_string_free (str, false);
208 return res;
211 char *CreateIgnorableTagClose ()
213 return g_strdup ("</" INTERNAL_IGNORABLE_ELEMENT ">");
216 bool LookupNamedItem (const char* name, Value **v)
218 if (!resources)
219 return NULL;
221 bool exists = false;
222 GSList *walk = resources;
223 while (walk) {
224 DependencyObject *dob = (DependencyObject*)walk->data;
225 if (dob->Is (Type::RESOURCE_DICTIONARY))
226 *v = lookup_resource_dictionary ((ResourceDictionary *) walk->data, name, &exists);
227 else /* dob->Is (Type::FRAMEWORKELEMENT) */ {
228 ResourceDictionary *rd = dob->GetValue (UIElement::ResourcesProperty)->AsResourceDictionary();
229 *v = lookup_resource_dictionary (rd, name, &exists);
232 if (exists)
233 break;
234 walk = walk->next;
237 if (exists)
238 return exists;
239 else if (!parent_context)
240 return false;
242 return parent_context->LookupNamedItem (name, v);
245 void SetTemplateBindingSource (DependencyObject *source)
247 this->source = source;
250 DependencyObject* GetTemplateBindingSource ()
252 return source;
257 XamlContext::XamlContext (XamlContextInternal *internal)
259 this->internal = internal;
262 XamlContext::~XamlContext ()
264 delete internal;
267 void
268 XamlContext::SetTemplateBindingSource (DependencyObject *source)
270 internal->SetTemplateBindingSource (source);
273 DependencyObject*
274 XamlContext::GetTemplateBindingSource ()
276 return internal->GetTemplateBindingSource ();
279 class XamlElementInfo {
280 protected:
281 Type::Kind kind;
282 Type::Kind property_owner_kind;
283 bool cdata_verbatim;
285 public:
286 XamlElementInfo *parent;
287 const char *name;
288 const char *xmlns;
290 XamlElementInfo (const char *xmlns, const char *name, Type::Kind kind)
292 this->parent = NULL;
293 this->kind = kind;
294 this->name = name;
295 this->xmlns = xmlns;
296 this->cdata_verbatim = false;
298 this->property_owner_kind = Type::INVALID;
301 ~XamlElementInfo ()
305 virtual Type::Kind GetKind () { return kind; }
307 virtual void SetPropertyOwnerKind (Type::Kind value) { property_owner_kind = value; }
308 virtual Type::Kind GetPropertyOwnerKind () { return property_owner_kind; }
310 virtual const char *GetContentProperty (XamlParserInfo *p)
312 Type *t = Type::Find (Deployment::GetCurrent (), kind);
313 if (t)
314 return t->GetContentPropertyName ();
315 return NULL;
318 void SetIsCDataVerbatim (bool flag)
320 cdata_verbatim = flag;
323 bool IsCDataVerbatim ()
325 return cdata_verbatim;
328 virtual bool RequiresManagedSet () { return false; }
330 virtual XamlElementInstance *CreateElementInstance (XamlParserInfo *p) = 0;
331 virtual XamlElementInstance *CreateWrappedElementInstance (XamlParserInfo *p, Value *o) = 0;
332 virtual XamlElementInstance *CreatePropertyElementInstance (XamlParserInfo *p, const char *name) = 0;
336 struct DelayedProperty {
337 char *xmlns;
338 char *name;
339 Value *value;
341 DelayedProperty (const char *xmlns, const char *name, const Value *value)
343 this->xmlns = g_strdup (xmlns);
344 this->name = g_strdup (name);
345 this->value = new Value (*value);
348 ~DelayedProperty ()
350 g_free (xmlns);
351 g_free (name);
352 delete value;
356 static void
357 free_property_list (GSList *list)
359 GSList *walk = list;
361 while (walk) {
362 DelayedProperty *prop = (DelayedProperty *) walk->data;
364 delete prop;
365 walk = walk->next;
368 g_slist_free (list);
371 class XamlElementInstance : public List::Node {
373 protected:
374 DependencyObject *item;
375 Value *value;
376 bool cleanup_value;
377 GSList *delayed_properties;
379 public:
380 const char *element_name;
381 XamlElementInfo *info;
383 XamlElementInstance *parent;
384 List *children;
386 enum ElementType {
387 ELEMENT,
388 PROPERTY,
389 INVALID
392 int element_type;
393 bool requires_managed;
394 char *x_key;
395 char *x_name;
397 GHashTable *set_properties;
399 XamlElementInstance (XamlElementInfo *info, const char* element_name, ElementType type, bool requires_managed = false)
401 this->element_name = element_name;
402 this->set_properties = NULL;
403 this->element_type = type;
404 this->parent = NULL;
405 this->info = info;
406 this->item = NULL;
407 this->value = NULL;
408 this->x_key = NULL;
409 this->x_name = NULL;
410 this->cleanup_value = true;
411 this->requires_managed = requires_managed;
412 this->delayed_properties = NULL;
414 children = new List ();
417 virtual ~XamlElementInstance ()
419 children->Clear (true);
420 delete children;
421 delete info;
423 g_free (x_key);
424 g_free (x_name);
426 if (cleanup_value)
427 delete value;
429 if (set_properties)
430 g_hash_table_destroy (set_properties);
432 if (element_name && element_type == PROPERTY)
433 g_free ((void*) element_name);
435 free_property_list (delayed_properties);
438 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, XamlElementInstance *value) = 0;
439 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, const char* value) = 0;
440 virtual void AddChild (XamlParserInfo *p, XamlElementInstance *child) = 0;
441 virtual void SetAttributes (XamlParserInfo *p, const char **attr) = 0;
443 virtual bool TrySetContentProperty (XamlParserInfo *p, XamlElementInstance *value);
444 virtual bool TrySetContentProperty (XamlParserInfo *p, const char *value);
447 char *GetKey () { return x_key; }
448 char *GetName () { return x_name; }
450 void SetName (XamlParserInfo *p, const char *name)
452 this->x_name = g_strdup (name);
455 void SetKey (XamlParserInfo *p, const char *key)
457 this->x_key = g_strdup (key);
460 virtual bool IsDependencyObject ()
462 return true;
465 virtual bool SetUnknownAttribute (XamlParserInfo *p, const char* name, const char* value);
467 void SetValue (Value *v)
469 if (value && cleanup_value)
470 delete value;
471 value = v;
474 virtual Value *GetAsValue ()
476 if (!value) {
477 value = new Value (item);
479 return value;
482 virtual DependencyObject *GetAsDependencyObject ()
484 return item;
487 virtual void SetDependencyObject (DependencyObject *value)
489 item = value;
492 virtual void* GetManagedPointer ()
494 return item;
497 virtual Value* GetParentPointer ()
499 XamlElementInstance *walk = parent;
500 while (walk && walk->element_type != XamlElementInstance::ELEMENT)
501 walk = walk->parent;
503 if (!walk)
504 return NULL;
506 return walk->GetAsValue ();
509 virtual bool IsTemplate ()
511 return false;
514 virtual XamlElementInfo* FindPropertyElement (XamlParserInfo *p, const char *el, const char *dot);
516 void SetDelayedProperties (XamlParserInfo *p);
518 void DelaySetProperty (const char *xmlns, const char *name, const Value *value)
520 DelayedProperty *prop = new DelayedProperty (xmlns, name, value);
522 delayed_properties = g_slist_append (delayed_properties, prop);
525 bool IsPropertySet (const char *name)
527 if (!set_properties)
528 return false;
530 return g_hash_table_lookup (set_properties, name) != NULL;
533 void MarkPropertyAsSet (const char *name)
535 if (!set_properties)
536 set_properties = g_hash_table_new (g_str_hash, g_str_equal);
538 g_hash_table_insert (set_properties, (void *) name, GINT_TO_POINTER (TRUE));
542 void
543 unref_xaml_element (gpointer data, gpointer user_data)
545 DependencyObject* dob = (DependencyObject*) data;
546 //printf ("unref_xaml_element: %i\n", dob->id);
547 if (dob)
548 dob->unref ();
551 class XamlParserInfo {
552 public:
553 XML_Parser parser;
555 const char *file_name;
557 NameScope *namescope;
558 XamlElementInstance *top_element;
559 XamlNamespace *current_namespace;
560 XamlElementInstance *current_element;
561 const char *next_element;
562 Deployment *deployment;
564 GHashTable *namespace_map;
565 bool cdata_content;
566 GString *cdata;
568 bool implicit_default_namespace;
570 ParserErrorEventArgs *error_args;
572 XamlLoader *loader;
576 // If set, this is used to hydrate an existing object, not to create a new toplevel one
578 Value *hydrate_expecting;
579 bool hydrating;
581 char* buffer_until_element;
582 int buffer_depth;
583 BufferMode buffer_mode;
584 GString *buffer;
585 bool validate_templates;
587 private:
588 GList *created_elements;
589 GList *created_namespaces;
590 const char* xml_buffer;
591 int multi_buffer_offset;
592 int xml_buffer_start_index;
594 public:
595 XamlParserInfo (XML_Parser parser, const char *file_name)
597 this->deployment = Deployment::GetCurrent ();
598 this->parser = parser;
599 this->file_name = file_name;
600 this->namescope = new NameScope ();
602 top_element = NULL;
603 current_namespace = NULL;
604 current_element = NULL;
605 cdata_content = false;
606 cdata = NULL;
607 implicit_default_namespace = false;
608 error_args = NULL;
609 loader = NULL;
610 created_elements = NULL;
611 created_namespaces = NULL;
612 hydrate_expecting = NULL;
613 hydrating = false;
615 buffer_until_element = NULL;
616 buffer_depth = -1;
617 buffer = NULL;
618 xml_buffer = NULL;
619 multi_buffer_offset = 0;
620 validate_templates = false;
622 namespace_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
625 void AddCreatedElement (DependencyObject* element)
627 // if we have a loader, set the surface and base resource location
628 if (loader) {
629 element->SetSurface (loader->GetSurface());
630 element->SetResourceBase (loader->GetResourceBase());
633 // When instantiating a template, some elements are created which are not explicitly
634 // mentioned in the xaml. Therefore we need to keep walking up the tree until we find
635 // the last element which we set a value for Control::IsTemplateItem and propagate
636 // it from there.
637 XamlElementInstance *instance = current_element;
638 while (instance) {
639 if (!instance->IsDependencyObject () || !instance->GetAsDependencyObject ()) {
640 instance = instance->parent;
641 continue;
643 if (!instance->GetAsDependencyObject ()->ReadLocalValue (Control::IsTemplateItemProperty)) {
644 instance = instance->parent;
645 continue;
647 Control::SetIsTemplateItem (element, Control::GetIsTemplateItem (instance->GetAsDependencyObject ()));
648 break;
651 if (instance == NULL)
652 Control::SetIsTemplateItem (element, loader->GetExpandingTemplate ());
654 if (Control::GetIsTemplateItem (element))
655 NameScope::SetNameScope (element, namescope);
656 created_elements = g_list_prepend (created_elements, element);
659 void AddCreatedNamespace (XamlNamespace* ns)
661 created_namespaces = g_list_prepend (created_namespaces, ns);
664 void QueueBeginBuffering (char* buffer_until, BufferMode mode)
666 buffer_until_element = buffer_until;
667 buffer_depth = 1;
668 buffer_mode = mode;
670 xml_buffer_start_index = -1;
673 void BeginBuffering ()
675 xml_buffer_start_index = XML_GetCurrentByteIndex (parser) - multi_buffer_offset;
676 buffer = g_string_new (NULL);
679 bool ShouldBeginBuffering ()
681 return InBufferingMode () && xml_buffer_start_index == -1;
684 bool InBufferingMode ()
686 return buffer_until_element != NULL;
689 void AppendCurrentXml ()
691 if (!buffer)
692 return;
693 int pos = XML_GetCurrentByteIndex (parser) - multi_buffer_offset;
694 g_string_append_len (buffer, xml_buffer + xml_buffer_start_index, pos - xml_buffer_start_index);
697 char* ClearBuffer ()
699 AppendCurrentXml ();
701 buffer_depth = 0;
702 buffer_until_element = NULL;
704 if (!buffer)
705 return g_strdup ("");
707 char* res = buffer->str;
708 g_string_free (buffer, FALSE);
709 buffer = NULL;
710 return res;
713 void SetXmlBuffer (const char* xml_buffer)
715 if (InBufferingMode ())
716 AppendCurrentXml ();
718 if (this->xml_buffer)
719 multi_buffer_offset += strlen (this->xml_buffer);
721 this->xml_buffer = xml_buffer;
722 xml_buffer_start_index = 0;
725 void ValidateTemplate (const char* buffer, XamlContext* context, FrameworkTemplate *binding_source)
727 XamlLoader *loader = new XamlLoader (NULL, buffer, NULL, context);
728 Type::Kind dummy;
730 context->SetTemplateBindingSource (binding_source);
732 loader->SetImportDefaultXmlns (true);
734 MoonError error;
735 Value *result = loader->CreateFromStringWithError (buffer, true, &dummy, XamlLoader::IMPORT_DEFAULT_XMLNS | XamlLoader::VALIDATE_TEMPLATES, &error);
737 delete result;
738 delete loader;
740 if (error.number != MoonError::NO_ERROR) {
741 int line_number = error.line_number + XML_GetCurrentLineNumber (parser);
742 error_args = new ParserErrorEventArgs (error.message, file_name, line_number, error.char_position, error.code, NULL, NULL);
746 FrameworkTemplate *GetTemplateParent (XamlElementInstance *item)
748 XamlElementInstance *parent = item->parent;
750 while (parent && !parent->IsTemplate ())
751 parent = parent->parent;
753 if (parent)
754 return (FrameworkTemplate *) parent->GetManagedPointer ();
756 if (!loader)
757 return NULL;
759 XamlContext *context = loader->GetContext ();
760 if (!context)
761 return NULL;
763 return context->internal->template_parent;
766 Value *GetTopElementPtr ()
768 XamlContext *context = loader->GetContext ();
769 if (context)
770 return context->internal->top_element;
772 if (top_element)
773 return top_element->GetAsValue ();
775 return NULL;
778 ~XamlParserInfo ()
780 created_elements = g_list_reverse (created_elements);
781 g_list_foreach (created_elements, unref_xaml_element, NULL);
782 g_list_free (created_elements);
784 g_list_foreach (created_namespaces, destroy_created_namespace, NULL);
785 g_list_free (created_namespaces);
787 g_hash_table_destroy (namespace_map);
789 if (cdata)
790 g_string_free (cdata, TRUE);
791 if (top_element)
792 delete top_element;
793 namescope->unref ();
800 class XamlElementInfoNative : public XamlElementInfo {
801 Type *type;
803 public:
804 XamlElementInfoNative (Type *t) : XamlElementInfo (NULL, t->GetName (), t->GetKind ())
806 type = t;
809 Type* GetType ()
811 return type;
814 const char* GetName ()
816 return type->GetName ();
819 const char* GetContentProperty (XamlParserInfo *p);
821 XamlElementInstance* CreateElementInstance (XamlParserInfo *p);
822 XamlElementInstance* CreateWrappedElementInstance (XamlParserInfo *p, Value *o);
823 XamlElementInstance* CreatePropertyElementInstance (XamlParserInfo *p, const char *name);
827 class XamlElementInstanceNative : public XamlElementInstance {
828 XamlElementInfoNative *element_info;
829 XamlParserInfo *parser_info;
831 public:
832 XamlElementInstanceNative (XamlElementInfoNative *element_info, XamlParserInfo *parser_info, const char *name, ElementType type, bool create_item = true);
834 virtual DependencyObject *CreateItem ();
836 virtual XamlElementInfo* FindPropertyElement (XamlParserInfo *p, const char *el, const char *dot);
838 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, XamlElementInstance *value);
839 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, const char* value);
840 virtual void AddChild (XamlParserInfo *p, XamlElementInstance *child);
841 virtual void SetAttributes (XamlParserInfo *p, const char **attr);
845 class XamlElementInstanceValueType : public XamlElementInstance {
846 XamlElementInfoNative *element_info;
847 XamlParserInfo *parser_info;
849 public:
850 XamlElementInstanceValueType (XamlElementInfoNative *element_info, XamlParserInfo *parser_info, const char *name, ElementType type);
852 virtual bool IsDependencyObject ()
854 return false;
857 virtual Value *GetAsValue ()
859 if (value == NULL) {
860 // we are an empty element (e.g. <sys:String></sys:String>). do type specific magic here.
861 CreateValueItemFromString ("");
864 return value;
867 bool CreateValueItemFromString (const char* str);
869 // A Value type doesn't really support anything. It's just here so people can do <SolidColorBrush.Color><Color>#FF00FF</Color></SolidColorBrush.Color>
870 virtual DependencyObject *CreateItem () { return NULL; }
871 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, XamlElementInstance *value) { return false; }
872 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, const char *value) { return false; }
873 virtual void AddChild (XamlParserInfo *p, XamlElementInstance *child) { }
874 virtual void SetAttributes (XamlParserInfo *p, const char **attr);
876 virtual bool TrySetContentProperty (XamlParserInfo *p, XamlElementInstance *value) { return false; }
877 virtual bool TrySetContentProperty (XamlParserInfo *p, const char *value) { return CreateValueItemFromString (value); }
880 class XamlElementInfoEnum : public XamlElementInfo {
881 public:
882 XamlElementInfoEnum (const char *name) : XamlElementInfo (NULL, name, Type::INT32)
886 XamlElementInstance* CreateElementInstance (XamlParserInfo *p);
887 XamlElementInstance* CreateWrappedElementInstance (XamlParserInfo *p, Value *o);
888 XamlElementInstance* CreatePropertyElementInstance (XamlParserInfo *p, const char *name) { return NULL; }
891 class XamlElementInstanceEnum : public XamlElementInstance {
893 public:
894 XamlElementInstanceEnum (XamlElementInfoEnum *element_info, const char *name, ElementType type);
896 virtual bool IsDependencyObject ()
898 return false;
901 virtual Value *GetAsValue ()
903 return value;
906 bool CreateEnumFromString (const char* str);
908 // An enum type doesn't really support anything. It's just here so people can do <Visibility>Visible</Visibility>
909 virtual DependencyObject *CreateItem () { return NULL; }
910 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, XamlElementInstance *value) { return false; }
911 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, const char *value) { return false; }
912 virtual void AddChild (XamlParserInfo *p, XamlElementInstance *child) { }
913 virtual void SetAttributes (XamlParserInfo *p, const char **attr);
915 virtual bool TrySetContentProperty (XamlParserInfo *p, XamlElementInstance *value) { return false; }
916 virtual bool TrySetContentProperty (XamlParserInfo *p, const char *value) { return CreateEnumFromString (value); }
919 class XamlElementInstanceTemplate : public XamlElementInstanceNative {
920 public:
921 XamlElementInstanceTemplate (XamlElementInfoNative *element_info, XamlParserInfo *parser_info, const char *name, ElementType type, bool create_item = true)
922 : XamlElementInstanceNative (element_info, parser_info, name, type, create_item)
926 virtual bool IsTemplate ()
928 return true;
933 class DefaultNamespace : public XamlNamespace {
934 public:
935 DefaultNamespace () { }
937 virtual ~DefaultNamespace () { }
939 virtual XamlElementInfo* FindElement (XamlParserInfo *p, const char *el, const char **attr, bool create)
941 Type* t = Type::Find (p->deployment, el, false);
942 if (t && !kind_requires_managed_load (t->GetKind ()))
943 return new XamlElementInfoNative (t);
945 if (enums_is_enum_name (el))
946 return new XamlElementInfoEnum (g_strdup (el));
948 XamlElementInfo* managed_element = create_element_info_from_imported_managed_type (p, el, attr, create);
949 if (managed_element)
950 return managed_element;
952 return NULL;
956 virtual bool SetAttribute (XamlParserInfo *p, XamlElementInstance *item, const char *attr, const char *value)
958 return false;
961 virtual const char* GetUri () { return "http://schemas.microsoft.com/winfx/2006/xaml/presentation"; }
962 virtual const char* GetPrefix () { return ""; }
965 class XmlNamespace : public XamlNamespace {
966 public:
967 XmlNamespace () { }
969 virtual ~XmlNamespace () { }
971 virtual XamlElementInfo* FindElement (XamlParserInfo *p, const char *el, const char **attr, bool create)
973 return NULL;
976 virtual bool SetAttribute (XamlParserInfo *p, XamlElementInstance *item, const char *attr, const char *value)
978 if (!strcmp ("lang", attr)) {
979 if (item->IsDependencyObject ()) {
980 DependencyObject *dob = item->GetAsDependencyObject ();
981 if (dob->Is(Type::FRAMEWORKELEMENT)) {
982 ((FrameworkElement*)dob)->SetLanguage (value);
983 return true;
988 return false;
991 virtual const char* GetUri () { return "http://www.w3.org/XML/1998/namespace"; }
992 virtual const char* GetPrefix () { return "xml"; }
995 class XNamespace : public XamlNamespace {
996 public:
997 XNamespace () { }
999 virtual ~XNamespace () { }
1001 virtual XamlElementInfo* FindElement (XamlParserInfo *p, const char *el, const char **attr, bool create)
1003 return NULL;
1006 virtual char *FindTypeName (const char **attr, char **xmlns)
1008 char *res = NULL;
1010 if (!attr)
1011 return NULL;
1013 for (int i = 0; attr [i]; i += 2) {
1014 const char *ns = strchr (attr [i], '|');
1015 if (!ns)
1016 continue;
1018 if (strncmp (GetUri (), attr [i], ns - attr [i]) || strcmp ("Class", ns + 1))
1019 continue;
1021 ns = strchr (attr [i + 1], ';');
1022 if (!ns) {
1023 *xmlns = g_strdup ("");
1024 res = g_strdup (attr [i + 1]);
1025 } else {
1026 *xmlns = g_strdup (ns + 1);
1027 res = g_strndup (attr [i + 1], attr [i + 1] - ns);
1029 return res;
1031 return NULL;
1034 bool IsParentResourceDictionary (XamlElementInstance *parent)
1036 if (parent == NULL)
1037 return false;
1039 return Type::IsSubclassOf (Deployment::GetCurrent (), parent->info->GetKind (), Type::RESOURCE_DICTIONARY);
1042 virtual bool SetAttribute (XamlParserInfo *p, XamlElementInstance *item, const char *attr, const char *value)
1044 if (!strcmp ("Name", attr)) {
1046 // Causes breakage in airlines
1047 // Maybe x:Name overwrites but Name does not?
1049 // if (p->namescope->FindName (value)) {
1050 // parser_error (p, p->current_element->element_name, "x:Name", 2028, "The name already exists in the tree: %s.", value);
1051 // return false;
1052 // }
1055 if (IsParentResourceDictionary (p->current_element)) {
1056 if (item->GetKey ()) {
1057 // XXX don't know the proper values here...
1058 parser_error (p, item->element_name, NULL, 2028,
1059 "The name already exists in the tree: %s.", value);
1060 return false;
1064 if (item->GetName ()) {
1065 parser_error (p, item->element_name, NULL, 2016, "Cannot specify both Name and x:Name attributes.");
1066 return false;
1069 item->SetName (p, value);
1071 if (item->IsDependencyObject ()) {
1072 NameScope *scope = p->namescope;
1073 if (!item->GetAsDependencyObject ()->SetName (value, scope)) {
1074 if (IsParentResourceDictionary (p->current_element)) {
1075 // FIXME: inside of a resource dictionary this has an extremly
1076 // strange behavior. this isn't exactly right, since not only
1077 // does the exception get swallowed, but the name seems to also
1078 // be unregistered.
1080 else {
1081 parser_error (p, item->element_name, NULL, 2028,
1082 "The name already exists in the tree: %s.", value);
1083 return false;
1086 return true;
1089 return false;
1092 if (!strcmp ("Key", attr)) {
1093 if (item->GetKey () && IsParentResourceDictionary (p->current_element) && !Type::IsSubclassOf (p->deployment, item->info->GetKind (), Type::STORYBOARD)) {
1094 // XXX don't know the proper values here...
1095 parser_error (p, item->element_name, NULL, 2028,
1096 "The name already exists in the tree: %s.", value);
1097 return false;
1099 item->SetKey (p, value);
1100 return true;
1103 if (!strcmp ("Class", attr)) {
1104 if (!is_legal_top_level_kind (item->info->GetKind ())) {
1105 // XXX don't know the proper values here...
1106 parser_error (p, item->element_name, attr, -1,
1107 "Cannot specify x:Class type '%s' on value type element (%s).", value, item->element_name);
1108 return false;
1111 if (p->top_element != item) {
1112 // HAH: what a useless error message
1113 parser_error (p, item->element_name, attr, 2012,
1114 "Unknown attribute %s on element %s.", attr, item->element_name);
1115 return false;
1118 // While hydrating, we do not need to create the toplevel class, its created already
1119 if (p->hydrating)
1120 return true;
1121 else {
1122 parser_error (p, item->element_name, attr, 4005,
1123 "Cannot specify x:Class in xaml files outside of a xap.");
1124 return false;
1128 return false;
1131 virtual const char* GetUri () { return X_NAMESPACE_URI; }
1132 virtual const char* GetPrefix () { return "x"; }
1136 class PrimitiveNamespace : public XamlNamespace {
1138 private:
1139 char *prefix;
1142 public:
1143 PrimitiveNamespace (char *prefix)
1145 this->prefix = prefix;
1148 virtual ~PrimitiveNamespace ()
1150 if (prefix)
1151 g_free (prefix);
1154 virtual XamlElementInfo* FindElement (XamlParserInfo *p, const char *el, const char **attr, bool create)
1156 if (!strcmp ("String", el)) {
1157 Type* t = Type::Find (p->deployment, Type::STRING);
1158 // it's not as easy in this case, because primitive clr strings require that the
1159 // character data be read in verbatim, including all whitespace.
1160 XamlElementInfo *info = new XamlElementInfoNative (t);
1161 info->SetIsCDataVerbatim (true);
1162 return info;
1163 } else if (!strcmp ("Int32", el)) {
1164 Type* t = Type::Find (p->deployment, Type::INT32);
1165 return new XamlElementInfoNative (t);
1166 } else if (!strcmp ("Double", el)) {
1167 Type* t = Type::Find (p->deployment, Type::DOUBLE);
1168 return new XamlElementInfoNative (t);
1169 } else if (!strcmp ("Boolean", el)) {
1170 Type* t = Type::Find (p->deployment, Type::BOOL);
1171 return new XamlElementInfoNative (t);
1172 } else if (!strcmp ("TimeSpan", el)) {
1173 Type* t = Type::Find (p->deployment, Type::TIMESPAN);
1174 return new XamlElementInfoNative (t);
1177 return NULL;
1180 virtual bool SetAttribute (XamlParserInfo *p, XamlElementInstance *item, const char *attr, const char *value)
1182 return false;
1185 virtual const char* GetUri () { return PRIMITIVE_NAMESPACE_URI; }
1186 virtual const char* GetPrefix () { return prefix; }
1190 class MCIgnorableNamespace : public XamlNamespace {
1192 private:
1193 char *prefix;
1195 public:
1196 MCIgnorableNamespace (char *prefix)
1198 this->prefix = prefix;
1201 virtual ~MCIgnorableNamespace ()
1203 if (prefix)
1204 g_free (prefix);
1207 virtual XamlElementInfo* FindElement (XamlParserInfo *p, const char *el, const char **attr, bool create)
1209 return NULL;
1212 virtual bool SetAttribute (XamlParserInfo *p, XamlElementInstance *item, const char *attr, const char *value)
1214 if (!strcmp ("Ignorable", attr)) {
1215 const char *start = value;
1216 do {
1217 const char *space = strchr (start, ' ');
1218 char *prefix;
1219 if (space) {
1220 prefix = g_strndup (start, space - start);
1221 start = space + 1;
1222 } else {
1223 prefix = g_strdup (start);
1224 start = NULL;
1227 XamlNamespace *ns = (XamlNamespace *) g_hash_table_find (p->namespace_map, namespace_for_prefix, prefix);
1228 if (ns)
1229 ns->is_ignored = true;
1231 } while (start);
1233 return true;
1236 return false;
1239 virtual const char* GetUri () { return MC_IGNORABLE_NAMESPACE_URI; }
1240 virtual const char* GetPrefix () { return prefix; }
1244 static void
1245 destroy_created_namespace (gpointer data, gpointer user_data)
1247 XamlNamespace* ns = (XamlNamespace *) data;
1248 delete ns;
1252 class XamlElementInfoManaged : public XamlElementInfo {
1253 public:
1254 XamlElementInfoManaged (const char *xmlns, const char *name, XamlElementInfo *parent, Type::Kind dependency_type, Value *obj) : XamlElementInfo (xmlns, name, dependency_type)
1256 this->obj = obj;
1259 Value *obj;
1261 const char* GetName () { return name; }
1263 const char* GetContentProperty (XamlParserInfo *p);
1265 virtual bool RequiresManagedSet () { return true; }
1267 XamlElementInstance* CreateElementInstance (XamlParserInfo *p);
1268 XamlElementInstance* CreateWrappedElementInstance (XamlParserInfo *p, Value *o);
1269 XamlElementInstance* CreatePropertyElementInstance (XamlParserInfo *p, const char *name);
1273 class XamlElementInstanceManaged : public XamlElementInstance {
1274 public:
1275 XamlElementInstanceManaged (XamlElementInfo *info, const char *name, ElementType type, Value *obj);
1277 virtual bool IsDependencyObject ()
1279 return is_dependency_object;
1282 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, XamlElementInstance *value);
1283 virtual bool SetProperty (XamlParserInfo *p, XamlElementInstance *property, const char* value);
1284 virtual void AddChild (XamlParserInfo *p, XamlElementInstance *child);
1285 virtual void SetAttributes (XamlParserInfo *p, const char **attr);
1287 virtual bool TrySetContentProperty (XamlParserInfo *p, XamlElementInstance *value);
1288 virtual bool TrySetContentProperty (XamlParserInfo *p, const char *value);
1290 virtual void* GetManagedPointer ();
1291 virtual Value* GetParentPointer ();
1292 private:
1293 bool is_dependency_object;
1297 class XamlElementInfoImportedManaged : public XamlElementInfoManaged {
1298 public:
1299 XamlElementInfoImportedManaged (const char *name, XamlElementInfo *parent, Value *obj) : XamlElementInfoManaged (NULL, name, parent, obj->GetKind (), obj)
1303 const char* GetContentProperty (XamlParserInfo *p);
1305 XamlElementInstance* CreateElementInstance (XamlParserInfo *p);
1306 XamlElementInstance* CreateWrappedElementInstance (XamlParserInfo *p, Value *o);
1307 XamlElementInstance* CreatePropertyElementInstance (XamlParserInfo *p, const char *name);
1312 class ManagedNamespace : public XamlNamespace {
1313 public:
1314 char *xmlns;
1315 char *prefix;
1317 ManagedNamespace (char *xmlns, char *prefix)
1319 this->xmlns = xmlns;
1320 this->prefix = prefix;
1323 virtual ~ManagedNamespace ()
1325 g_free (xmlns);
1326 g_free (prefix);
1329 virtual XamlElementInfo* FindElement (XamlParserInfo *p, const char *el, const char **attr, bool create)
1331 char* type_name = NULL;
1332 char* type_xmlns = NULL;
1333 const char* use_xmlns = xmlns;
1335 if (!p->loader)
1336 return NULL;
1338 if (x_namespace) {
1339 // We might have an x:Class attribute specified, so we need to use that for the
1340 // type_name that we pass to LookupObject
1341 if (strcmp ("Application", el)) {
1342 type_name = x_namespace->FindTypeName (attr, &type_xmlns);
1343 if (type_name) {
1344 el = type_name;
1345 use_xmlns = type_xmlns;
1347 if (!p->hydrating) {
1348 parser_error (p, el, "x:Class", 4005, "Cannot specify x:Class in xaml files outside of a xap.");
1349 return NULL;
1355 Value *value = new Value ();
1356 if (!p->loader->LookupObject (p, p->GetTopElementPtr (), p->current_element ? p->current_element->GetAsValue () : NULL, use_xmlns, el, create, false, value)) {
1357 parser_error (p, el, NULL, 2007, "Unable to resolve managed type %s.", el);
1358 delete value;
1359 if (type_name)
1360 g_free (type_name);
1361 if (type_xmlns)
1362 g_free (type_xmlns);
1363 return NULL;
1366 if (p->hydrate_expecting) {
1368 // If we are hydrating a top level managed object, use the Value* passed
1369 // to Hydrate as our value
1371 Value *v = value;
1372 value = p->hydrate_expecting;
1373 delete v;
1376 XamlElementInfoManaged *info = new XamlElementInfoManaged (xmlns, g_strdup (el), NULL, value->GetKind (), value);
1377 if (type_name)
1378 g_free (type_name);
1379 if (type_xmlns)
1380 g_free (type_xmlns);
1381 return info;
1384 virtual bool SetAttribute (XamlParserInfo *p, XamlElementInstance *item, const char *attr, const char *value)
1386 if (is_ignored)
1387 return true;
1389 if (p->loader) {
1390 Value v = Value (value);
1391 return p->loader->SetProperty (p, p->GetTopElementPtr (), item->info->xmlns, item->GetAsValue (), item, item->GetParentPointer (), xmlns, attr, &v, NULL);
1393 return false;
1397 virtual const char* GetUri () { return xmlns; }
1398 virtual const char* GetPrefix () { return prefix; }
1401 bool
1402 XamlLoader::LookupObject (void *p, Value *top_level, Value *parent, const char* xmlns, const char* type_name, bool create, bool is_property, Value *value)
1404 if (callbacks.lookup_object) {
1405 if (!vm_loaded && !LoadVM ())
1406 return false;
1407 MoonError error;
1408 XamlCallbackData data = XamlCallbackData (this, p, top_level);
1409 bool res = callbacks.lookup_object (&data, parent, xmlns, type_name, create, is_property, value, &error);
1410 return res;
1413 return false;
1416 const char *
1417 XamlLoader::GetContentPropertyName (void *p, Value *top_level, Value *object)
1419 if (callbacks.get_content_property_name) {
1420 MoonError error;
1421 XamlCallbackData data = XamlCallbackData (this, p, top_level);
1422 return callbacks.get_content_property_name (&data, object, &error);
1424 return NULL;
1427 bool
1428 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)
1430 if (callbacks.set_property) {
1431 MoonError error;
1432 XamlCallbackData data = XamlCallbackData (this, p, top_level, flags);
1433 bool res = callbacks.set_property (&data, xmlns, target, target_data, target_parent, prop_xmlns, name, value, value_data, &error);
1435 if (error.number != MoonError::NO_ERROR) {
1436 parser_error ((XamlParserInfo *) p, ((XamlElementInstance *) target_data)->element_name, NULL, error.code, error.message);
1437 return false;
1440 return res;
1443 return false;
1446 bool
1447 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)
1449 if (callbacks.add_child) {
1450 MoonError error;
1451 XamlCallbackData data = XamlCallbackData (this, p, top_level);
1452 bool res = callbacks.add_child (&data, parent_parent, parent_is_property, parent_xmlns, parent, parent_data, child, child_data, &error);
1454 if (error.number != MoonError::NO_ERROR) {
1455 parser_error ((XamlParserInfo *) p, ((XamlElementInstance *) child_data)->element_name, NULL, error.code, error.message);
1456 return false;
1459 return res;
1461 return false;
1464 XamlLoader::XamlLoader (const char *resourceBase, const char* filename, const char* str, Surface* surface, XamlContext *context)
1466 Initialize (resourceBase, filename, str, surface, context);
1469 XamlLoader::XamlLoader (const char* filename, const char* str, Surface* surface, XamlContext *context)
1471 Initialize (NULL, filename, str, surface, context);
1474 void
1475 XamlLoader::Initialize (const char *resourceBase, const char* filename, const char* str, Surface* surface, XamlContext *context)
1477 this->filename = g_strdup (filename);
1478 this->resource_base = g_strdup (resourceBase);
1479 this->str = g_strdup (str);
1480 this->surface = surface;
1481 if (surface)
1482 surface->ref ();
1483 this->context = context;
1484 this->vm_loaded = false;
1485 this->error_args = NULL;
1486 this->expanding_template = false;
1487 this->import_default_xmlns = false;
1489 if (context) {
1490 callbacks = context->internal->callbacks;
1491 this->vm_loaded = true;
1493 if (!surface && context->internal->surface) {
1494 this->surface = context->internal->surface;
1495 this->surface->ref ();
1498 #if DEBUG
1499 if (!surface && debug_flags & RUNTIME_DEBUG_XAML) {
1500 printf ("XamlLoader::XamlLoader ('%s', '%s', %p): Initializing XamlLoader without a surface.\n",
1501 filename, str, surface);
1503 #endif
1506 XamlLoader::~XamlLoader ()
1508 g_free (filename);
1509 g_free (resource_base);
1510 g_free (str);
1511 if (surface)
1512 surface->unref ();
1513 surface = NULL;
1514 filename = NULL;
1515 str = NULL;
1516 if (error_args)
1517 error_args->unref();
1520 bool
1521 XamlLoader::LoadVM ()
1523 return false;
1526 XamlLoader*
1527 xaml_loader_new (const char *resourceBase, const char* filename, const char* str, Surface* surface)
1529 return new XamlLoader (resourceBase, filename, str, surface);
1532 void
1533 xaml_loader_free (XamlLoader* loader)
1535 delete loader;
1538 void
1539 xaml_loader_set_callbacks (XamlLoader* loader, XamlLoaderCallbacks callbacks)
1541 if (!loader) {
1542 LOG_XAML ("Trying to set callbacks for a null object\n");
1543 return;
1546 loader->callbacks = callbacks;
1547 loader->vm_loaded = true;
1550 static gboolean
1551 namespace_for_prefix (gpointer key, gpointer value, gpointer user_data)
1553 XamlNamespace *ns = (XamlNamespace *) value;
1554 const char *prefix = (const char *) user_data;
1556 if (!strcmp (prefix, ns->GetPrefix ()))
1557 return TRUE;
1558 return FALSE;
1561 char*
1562 xaml_uri_for_prefix (void *parser, char* prefix)
1564 XamlParserInfo *p = (XamlParserInfo *) parser;
1566 XamlNamespace *ns = (XamlNamespace *) g_hash_table_find (p->namespace_map, namespace_for_prefix, prefix);
1567 if (!ns)
1568 return NULL;
1570 return g_strdup (ns->GetUri ());
1574 // Called when we encounter an error. Note that memory ownership is taken for everything
1575 // except the message, this allows you to use g_strdup_printf when creating the error message
1577 static void
1578 parser_error (XamlParserInfo *p, const char *el, const char *attr, int error_code, const char *format, ...)
1580 char *message;
1581 va_list args;
1583 // Already failed
1584 if (p->error_args)
1585 return;
1587 // if parsing fails too early it's not safe (i.e. sigsegv) to call some functions, e.g. XML_GetCurrentLineNumber
1588 bool report_line_col = (error_code != XML_ERROR_XML_DECL);
1589 int line_number = report_line_col ? XML_GetCurrentLineNumber (p->parser) : 0;
1590 int char_position = report_line_col ? XML_GetCurrentColumnNumber (p->parser) : 0;
1592 va_start (args, format);
1593 message = g_strdup_vprintf (format, args);
1594 va_end (args);
1596 p->error_args = new ParserErrorEventArgs (message, p->file_name, line_number, char_position, error_code, el, attr);
1598 g_free (message);
1600 LOG_XAML ("PARSER ERROR, STOPPING PARSING: (%d) %s line: %d char: %d\n", error_code, message,
1601 line_number, char_position);
1603 XML_StopParser (p->parser, FALSE);
1606 void
1607 expat_parser_error (XamlParserInfo *p, XML_Error expat_error)
1609 // Already had an error
1610 if (p->error_args)
1611 return;
1613 LOG_XAML ("expat error is: %d\n", expat_error);
1615 switch (expat_error) {
1616 case XML_ERROR_DUPLICATE_ATTRIBUTE:
1617 parser_error (p, NULL, NULL, 7031, "wfc: unique attribute spec");
1618 break;
1619 case XML_ERROR_UNBOUND_PREFIX:
1620 parser_error (p, NULL, NULL, 7055, "undeclared prefix");
1621 break;
1622 case XML_ERROR_NO_ELEMENTS:
1623 parser_error (p, NULL, NULL, 7000, "unexpected end of input");
1624 break;
1625 case XML_ERROR_SYNTAX:
1626 parser_error (p, NULL, NULL, 2103, "syntax error");
1627 break;
1628 default:
1629 parser_error (p, NULL, NULL, expat_error, "Unhandled XML error %s", XML_ErrorString (expat_error));
1630 break;
1634 static void
1635 start_element (void *data, const char *el, const char **attr)
1637 XamlParserInfo *p = (XamlParserInfo *) data;
1638 XamlElementInfo *elem = NULL;
1639 XamlElementInstance *inst;
1640 Types *types = Deployment::GetCurrent ()->GetTypes ();
1642 if (!strcmp (el, INTERNAL_IGNORABLE_ELEMENT))
1643 return;
1645 if (p->ShouldBeginBuffering ()) {
1646 p->BeginBuffering ();
1647 return;
1650 if (p->InBufferingMode ()) {
1651 if (!strcmp (p->buffer_until_element, el))
1652 p->buffer_depth++;
1653 return;
1656 const char *dot = strchr (el, '.');
1657 if (!dot)
1658 elem = p->current_namespace->FindElement (p, el, attr, p->hydrate_expecting == NULL);
1660 if (p->error_args)
1661 return;
1664 if (elem) {
1665 if (p->hydrate_expecting){
1667 Type::Kind expecting_type = p->hydrate_expecting->GetObjectType ();
1669 if (!types->IsSubclassOf (expecting_type, elem->GetKind ())) {
1670 parser_error (p, el, NULL, -1, "Invalid top-level element found %s, expecting %s", el,
1671 types->Find (expecting_type)->GetName ());
1672 return;
1676 inst = elem->CreateWrappedElementInstance (p, p->hydrate_expecting);
1677 p->hydrate_expecting = NULL;
1678 } else
1679 inst = elem->CreateElementInstance (p);
1681 if (!inst)
1682 return;
1684 inst->parent = p->current_element;
1686 if (!p->top_element) {
1687 p->top_element = inst;
1688 if (inst->GetAsDependencyObject ())
1689 NameScope::SetNameScope (inst->GetAsDependencyObject (), p->namescope);
1692 if (inst->GetAsDependencyObject ())
1693 inst->GetAsDependencyObject ()->SetIsBeingParsed (true);
1695 inst->SetAttributes (p, attr);
1696 if (p->error_args)
1697 return;
1699 if (inst->IsDependencyObject ()) {
1700 if (p->current_element){
1701 if (p->current_element->info) {
1702 p->current_element->AddChild (p, inst);
1703 if (p->error_args)
1704 return;
1708 } else {
1709 // it's actually valid (from SL point of view) to have <Ellipse.Triggers> inside a <Rectangle>
1710 // however we can't add properties to something bad, like a <Recta.gle> element
1711 XamlElementInfo *prop_info = NULL;
1712 if (dot) {
1713 gchar *prop_elem = g_strndup (el, dot - el);
1714 prop_info = p->current_element->FindPropertyElement (p, el, dot);
1715 g_free (prop_elem);
1718 if (prop_info != NULL) {
1719 inst = prop_info->CreatePropertyElementInstance (p, g_strdup (el));
1720 inst->parent = p->current_element;
1722 if (attr [0] != NULL) {
1723 // It appears there is a bug in the error string but it matches the MS runtime
1724 parser_error (p, el, NULL, 2018, "The element %s does not support attributes.", attr[0]);
1725 return;
1728 if (prop_info && !strcmp (el, "TextBox.Text"))
1729 prop_info->SetIsCDataVerbatim (true);
1731 if (!p->top_element) {
1732 if (types->IsSubclassOf (prop_info->GetKind (), Type::COLLECTION)) {
1733 XamlElementInstance *wrap = prop_info->CreateElementInstance (p);
1734 NameScope::SetNameScope (wrap->GetAsDependencyObject (), p->namescope);
1735 p->top_element = wrap;
1736 p->current_element = wrap;
1737 return;
1740 } else {
1741 g_warning ("Unknown element: %s.", el);
1742 parser_error (p, el, NULL, 2007, "Unknown element: %s.", el);
1743 return;
1747 if (p->current_element) {
1748 p->current_element->children->Append (inst);
1750 p->current_element = inst;
1752 if (elem && element_begins_buffering (elem->GetKind ())) {
1753 p->QueueBeginBuffering (g_strdup (el), BUFFER_MODE_TEMPLATE);
1757 static bool
1758 allow_value_from_str_in_flush (XamlParserInfo *p, XamlElementInstance *parent)
1760 if (parent == NULL || parent->element_type != XamlElementInstance::PROPERTY || parent->parent == NULL || !parent->parent->IsDependencyObject ())
1761 return false;
1763 if (parent->info->GetKind () == Type::OBJECT)
1764 return true;
1766 return false;
1769 static void
1770 flush_char_data (XamlParserInfo *p)
1772 if (p->InBufferingMode ())
1773 return;
1775 if (!p->cdata || !p->current_element)
1776 return;
1778 if (p->current_element->info->IsCDataVerbatim()) {
1779 p->cdata->str = g_strstrip (p->cdata->str);
1782 if (p->current_element->element_type == XamlElementInstance::ELEMENT) {
1783 if (!p->current_element->TrySetContentProperty (p, p->cdata->str) && p->cdata_content) {
1784 if (allow_value_from_str_in_flush (p, p->current_element->parent)) {
1785 Value *v;
1786 if (value_from_str (p->current_element->info->GetKind (), NULL, p->cdata->str, &v)) {
1787 p->current_element->SetValue (v);
1788 goto cleanup;
1791 parser_error (p, p->current_element->element_name, NULL, 2011,
1792 "%s does not support text content.", p->current_element->element_name);
1794 } else if (p->current_element->element_type == XamlElementInstance::PROPERTY) {
1795 if (p->cdata_content && p->current_element->parent && !p->current_element->parent->SetProperty (p, p->current_element, p->cdata->str)) {
1796 parser_error (p, p->current_element->element_name, NULL, 2011,
1797 "%s does not support text content.", p->current_element->element_name);
1801 cleanup:
1802 if (p->cdata) {
1803 g_string_free (p->cdata, TRUE);
1804 p->cdata_content = false;
1805 p->cdata = NULL;
1809 static bool
1810 element_begins_buffering (Type::Kind kind)
1812 return Type::IsSubclassOf (Deployment::GetCurrent (), kind, Type::FRAMEWORKTEMPLATE);
1815 static gboolean
1816 is_default_namespace (gpointer key, gpointer value, gpointer user_data)
1818 return value == default_namespace;
1821 static void
1822 start_element_handler (void *data, const char *el, const char **attr)
1824 XamlParserInfo *p = (XamlParserInfo *) data;
1826 if (p->error_args)
1827 return;
1829 char **name = g_strsplit (el, "|", -1);
1830 XamlNamespace *next_namespace = NULL;
1831 char *element = NULL;
1833 if (g_strv_length (name) == 2) {
1834 // Find the proper namespace for our next element
1835 next_namespace = (XamlNamespace *) g_hash_table_lookup (p->namespace_map, name [0]);
1836 element = name [1];
1839 if (!next_namespace && p->implicit_default_namespace) {
1840 // Use the default namespace for the next element
1841 next_namespace = default_namespace;
1842 element = name [0];
1843 } else if (!next_namespace) {
1844 if (!g_hash_table_find (p->namespace_map, is_default_namespace, NULL))
1845 return parser_error (p, el, NULL, 2263, "AG_E_PARSER_MISSING_DEFAULT_NAMESPACE");
1848 if (next_namespace && next_namespace->is_ignored) {
1849 p->current_namespace = next_namespace;
1850 if (!p->InBufferingMode ())
1851 p->QueueBeginBuffering (g_strdup (element), BUFFER_MODE_IGNORE);
1853 start_element (data, element, attr); // This will force the buffering to start/build depth if needed
1854 return;
1857 p->next_element = element;
1859 flush_char_data (p);
1861 // Now update our namespace
1862 p->current_namespace = next_namespace;
1864 if (!p->current_namespace && !p->InBufferingMode ()) {
1865 if (name[1])
1866 parser_error (p, name[1], NULL, -1, "No handlers available for namespace: '%s' (%s)\n", name[0], el);
1867 else
1868 parser_error (p, name[1], NULL, -1, "No namespace mapping available for element: '%s'\n", el);
1870 g_strfreev (name);
1871 return;
1874 p->next_element = NULL;
1875 start_element (data, element, attr);
1877 g_strfreev (name);
1880 static char*
1881 get_element_name (XamlParserInfo* p, const char *el)
1883 char **names = g_strsplit (el, "|", -1);
1884 char *name = g_strdup (names [g_strv_length (names) - 1]);
1886 g_strfreev (names);
1888 return name;
1891 static GSList *
1892 create_resource_list (XamlParserInfo *p)
1894 GSList *list = NULL;
1895 XamlElementInstance *walk = p->current_element;
1897 Types * types = Deployment::GetCurrent ()->GetTypes ();
1898 while (walk) {
1899 if (walk->element_type == XamlElementInstance::ELEMENT && types->IsSubclassOf (walk->info->GetKind (), Type::FRAMEWORKELEMENT)) {
1900 FrameworkElement *fwe = (FrameworkElement *)walk->GetAsDependencyObject ();
1901 if (g_slist_index (list, fwe) == -1)
1902 list = g_slist_prepend (list, fwe);
1904 if (walk->element_type == XamlElementInstance::ELEMENT && types->IsSubclassOf (walk->info->GetKind (), Type::RESOURCE_DICTIONARY)) {
1905 ResourceDictionary *rd = (ResourceDictionary *) walk->GetAsDependencyObject ();
1906 if (g_slist_index (list, rd) == -1)
1907 list = g_slist_prepend (list, walk->GetAsDependencyObject ());
1909 walk = walk->parent;
1912 list = g_slist_reverse (list);
1913 return list;
1916 static XamlContext *
1917 create_xaml_context (XamlParserInfo *p, FrameworkTemplate *template_, XamlContext *parent_context)
1919 GSList *resources = create_resource_list (p);
1920 XamlContextInternal *ic = new XamlContextInternal (p->loader->callbacks, p->GetTopElementPtr (), template_, p->namespace_map, resources, parent_context ? parent_context->internal : NULL);
1921 return new XamlContext (ic);
1924 static void
1925 end_element_handler (void *data, const char *el)
1927 XamlParserInfo *p = (XamlParserInfo *) data;
1928 DependencyObject *obj;
1930 if (!strcmp (el, INTERNAL_IGNORABLE_ELEMENT))
1931 return;
1933 if (p->error_args)
1934 return;
1936 if (!p->current_element) {
1937 g_warning ("p->current_element == NULL, current_element = %p (%s)\n",
1938 p->current_element, p->current_element ? p->current_element->element_name : "<NULL>");
1939 return;
1942 if (p->InBufferingMode ()) {
1943 char* name = get_element_name (p, el);
1944 if (!strcmp (p->buffer_until_element, name)) {
1945 p->buffer_depth--;
1947 if (p->buffer_depth == 0) {
1948 if (p->buffer_mode == BUFFER_MODE_TEMPLATE) {
1949 // OK we are done buffering, the element we are buffering for
1950 FrameworkTemplate* template_ = (FrameworkTemplate *) p->current_element->GetAsDependencyObject ();
1952 char* buffer = p->ClearBuffer ();
1954 XamlContext *context = create_xaml_context (p, template_, p->loader->GetContext());
1956 if (p->validate_templates) {
1957 p->ValidateTemplate (buffer, context, template_);
1959 if (p->error_args)
1960 return;
1963 template_->SetXamlBuffer (context, buffer);
1964 p->current_element = p->current_element->parent;
1965 } else if (p->buffer_mode == BUFFER_MODE_IGNORE) {
1966 // For now we'll actually keep/clear this buffer because it makes testing easier
1967 char *buffer = p->ClearBuffer ();
1968 g_free (buffer);
1973 g_free (name);
1974 return;
1977 switch (p->current_element->element_type) {
1978 case XamlElementInstance::ELEMENT:
1980 p->current_element->SetDelayedProperties (p);
1981 flush_char_data (p);
1983 // according to http://blogs.msdn.com/devdave/archive/2008/10/11/control-lifecycle.aspx
1984 // default styles are apply when the end tag is read.
1986 if (p->current_element->IsDependencyObject () &&
1987 p->current_element->GetAsDependencyObject() &&
1988 p->current_element->GetAsDependencyObject()->Is(Type::CONTROL)) {
1990 Control *control = (Control*)p->current_element->GetAsDependencyObject();
1991 ManagedTypeInfo *key = control->GetDefaultStyleKey ();
1993 if (key) {
1994 if (Application::GetCurrent () == NULL)
1995 g_warning ("attempting to use a null application applying default style while parsing.");
1996 else
1997 Application::GetCurrent()->ApplyDefaultStyle (control, key);
2000 else if (!p->current_element->IsDependencyObject ()) {
2002 if (p->current_element->parent)
2003 p->current_element->parent->AddChild (p, p->current_element);
2005 break;
2006 case XamlElementInstance::PROPERTY: {
2007 List::Node *walk = p->current_element->children->First ();
2008 while (walk) {
2009 XamlElementInstance *child = (XamlElementInstance *) walk;
2010 if (p->current_element->parent) {
2011 p->current_element->parent->SetProperty (p, p->current_element, child);
2013 walk = walk->next;
2015 flush_char_data (p);
2016 break;
2020 if ((obj = p->current_element->GetAsDependencyObject ()))
2021 obj->SetIsBeingParsed (false);
2023 p->current_element = p->current_element->parent;
2026 static void
2027 char_data_handler (void *data, const char *in, int inlen)
2029 XamlParserInfo *p = (XamlParserInfo *) data;
2030 register const char *inptr = in;
2031 const char *inend = in + inlen;
2032 const char *start;
2034 if (p->InBufferingMode ())
2035 return;
2037 if (p->error_args)
2038 return;
2040 if (p->current_element && p->current_element->info->IsCDataVerbatim()) {
2041 if (!p->cdata)
2042 p->cdata = g_string_new ("");
2044 g_string_append_len (p->cdata, inptr, inlen);
2045 p->cdata_content = true;
2046 return;
2049 if (!p->cdata) {
2050 p->cdata = g_string_new ("");
2052 if (g_ascii_isspace (*inptr)) {
2053 g_string_append_c (p->cdata, ' ');
2054 inptr++;
2056 while (inptr < inend && g_ascii_isspace (*inptr))
2057 inptr++;
2060 if (inptr == inend)
2061 return;
2062 } else if (g_ascii_isspace (p->cdata->str[p->cdata->len - 1])) {
2063 // previous cdata chunk ended with lwsp, skip over leading lwsp for this chunk
2064 while (inptr < inend && g_ascii_isspace (*inptr))
2065 inptr++;
2068 while (inptr < inend) {
2069 start = inptr;
2070 while (inptr < inend && !g_ascii_isspace (*inptr))
2071 inptr++;
2073 if (inptr > start) {
2074 g_string_append_len (p->cdata, start, inptr - start);
2075 p->cdata_content = true;
2078 if (inptr < inend) {
2079 g_string_append_c (p->cdata, ' ');
2080 inptr++;
2082 while (inptr < inend && g_ascii_isspace (*inptr))
2083 inptr++;
2088 static void
2089 start_namespace_handler (void *data, const char *prefix, const char *uri)
2091 XamlParserInfo *p = (XamlParserInfo *) data;
2093 if (p->InBufferingMode ())
2094 return;
2096 if (p->error_args)
2097 return;
2099 if (p->loader != NULL && p->loader->callbacks.import_xaml_xmlns != NULL) {
2100 MoonError error;
2101 XamlCallbackData data = XamlCallbackData (p->loader, p, p->GetTopElementPtr ());
2102 if (!p->loader->callbacks.import_xaml_xmlns (&data, uri, &error))
2103 return parser_error (p, p->current_element ? p->current_element->element_name : NULL, prefix, 2005, "Unknown namespace %s", uri);
2106 for (int i = 0; default_namespace_names [i]; i++) {
2107 if (!strcmp (default_namespace_names [i], uri)) {
2108 g_hash_table_insert (p->namespace_map, g_strdup (uri), default_namespace);
2109 return;
2113 if (!strcmp (X_NAMESPACE_URI, uri)){
2114 g_hash_table_insert (p->namespace_map, g_strdup (uri), x_namespace);
2115 } else if (!strcmp (PRIMITIVE_NAMESPACE_URI, uri)) {
2116 PrimitiveNamespace *pn = new PrimitiveNamespace (g_strdup (prefix));
2117 g_hash_table_insert (p->namespace_map, g_strdup (uri), pn);
2118 p->AddCreatedNamespace (pn);
2119 } else if (!strcmp (MC_IGNORABLE_NAMESPACE_URI, uri)) {
2120 MCIgnorableNamespace *mc = new MCIgnorableNamespace (g_strdup (prefix));
2121 g_hash_table_insert (p->namespace_map, g_strdup (uri), mc);
2122 p->AddCreatedNamespace (mc);
2123 } else {
2124 if (!p->loader) {
2125 return parser_error (p, (p->current_element ? p->current_element->element_name : NULL), prefix, -1,
2126 "No managed element callback installed to handle %s", uri);
2129 if (!prefix) {
2130 parser_error (p, (p->current_element ? p->current_element->element_name : NULL), NULL, 2262,
2131 "AG_E_PARSER_NAMESPACE_NOT_SUPPORTED");
2132 return;
2135 ManagedNamespace *c = new ManagedNamespace (g_strdup (uri), g_strdup (prefix));
2136 g_hash_table_insert (p->namespace_map, g_strdup (c->xmlns), c);
2137 p->AddCreatedNamespace (c);
2141 static void
2142 start_doctype_handler (void *data,
2143 const XML_Char *doctype_name,
2144 const XML_Char *sysid,
2145 const XML_Char *pubid,
2146 int has_internal_subset)
2148 XamlParserInfo *p = (XamlParserInfo *) data;
2150 if (p->InBufferingMode ())
2151 return;
2153 if (sysid)
2154 return parser_error (p, NULL, NULL, 7050, "DTD was found but is prohibited");
2156 if (doctype_name)
2157 return parser_error (p, NULL, NULL, 7016, "incorrect document syntax.");
2160 static void
2161 add_default_namespaces (XamlParserInfo *p, bool sl_xmlns)
2163 if (sl_xmlns) {
2164 p->implicit_default_namespace = true;
2165 g_hash_table_insert (p->namespace_map, g_strdup ("http://schemas.microsoft.com/winfx/2006/xaml/presentation"), default_namespace);
2166 g_hash_table_insert (p->namespace_map, g_strdup (X_NAMESPACE_URI), x_namespace);
2168 g_hash_table_insert (p->namespace_map, g_strdup (XML_NAMESPACE_URI), xml_namespace);
2171 static void
2172 print_tree (XamlElementInstance *el, int depth)
2174 #if DEBUG
2175 if (debug_flags & RUNTIME_DEBUG_XAML) {
2176 for (int i = 0; i < depth; i++)
2177 printf ("\t");
2179 const char *name = NULL;
2181 if (!el) {
2182 printf (" -null- \n");
2183 return;
2186 if (el->element_type == XamlElementInstance::ELEMENT && el->IsDependencyObject ())
2187 name = el->GetAsDependencyObject ()->GetName ();
2188 printf ("%s (%s) (%p) (%s)\n", el->element_name, name ? name : "-no name-", el->parent, el->element_type == XamlElementInstance::PROPERTY ? "PROPERTY" : "ELEMENT");
2190 for (List::Node *walk = el->children->First (); walk != NULL; walk = walk->next) {
2191 XamlElementInstance *el = (XamlElementInstance *) walk;
2192 print_tree (el, depth + 1);
2195 #endif
2198 void
2199 xaml_parse_xmlns (const char* xmlns, char** type_name, char** ns, char** assembly)
2201 const char delimiters[] = ";";
2202 char* decl;
2203 char* buffer = g_strdup (xmlns);
2205 *type_name = NULL;
2206 *ns = NULL;
2207 *assembly = NULL;
2209 decl = strtok (buffer, delimiters);
2210 while (decl != NULL) {
2211 if (strstr (decl, "clr-namespace:") == decl) {
2212 if (*ns)
2213 g_free (*ns);
2214 *ns = g_strdup (decl + 14);
2215 } else if (strstr (decl, "assembly=") == decl) {
2216 if (*assembly)
2217 g_free (*assembly);
2218 *assembly = g_strdup (decl + 9);
2219 } else {
2220 if (*type_name)
2221 g_free (*type_name);
2222 *type_name = g_strdup (decl);
2225 decl = strtok (NULL, delimiters);
2227 g_free (buffer);
2230 Value *
2231 XamlLoader::CreateFromFile (const char *xaml_file, bool create_namescope,
2232 Type::Kind *element_type)
2234 Value *res = NULL;
2235 XamlParserInfo *parser_info = NULL;
2236 XML_Parser p = NULL;
2237 bool first_read = true;
2238 const char *inptr, *inend;
2239 TextStream *stream;
2240 char buffer[4096];
2241 ssize_t nread, n;
2243 LOG_XAML ("attemtping to load xaml file: %s\n", xaml_file);
2245 stream = new TextStream ();
2246 if (!stream->OpenFile (xaml_file, false)) {
2247 LOG_XAML ("can not open file\n");
2248 goto cleanup_and_return;
2251 if (!(p = XML_ParserCreateNS ("UTF-8", '|'))) {
2252 LOG_XAML ("can not create parser\n");
2253 goto cleanup_and_return;
2256 parser_info = new XamlParserInfo (p, xaml_file);
2258 parser_info->namescope->SetTemporary (!create_namescope);
2260 parser_info->loader = this;
2262 // TODO: This is just in here temporarily, to make life less difficult for everyone
2263 // while we are developing.
2264 add_default_namespaces (parser_info, false);
2266 XML_SetUserData (p, parser_info);
2268 XML_SetElementHandler (p, start_element_handler, end_element_handler);
2269 XML_SetCharacterDataHandler (p, char_data_handler);
2270 XML_SetNamespaceDeclHandler(p, start_namespace_handler, NULL);
2271 XML_SetDoctypeDeclHandler(p, start_doctype_handler, NULL);
2274 XML_SetProcessingInstructionHandler (p, proc_handler);
2277 while ((nread = stream->Read (buffer, sizeof (buffer))) >= 0) {
2278 inptr = buffer;
2279 n = nread;
2281 if (first_read && nread > 0) {
2282 // Remove preceding white space
2283 inend = buffer + nread;
2285 while (inptr < inend && g_ascii_isspace (*inptr))
2286 inptr++;
2288 if (inptr == inend)
2289 continue;
2291 n = (inend - inptr);
2292 first_read = false;
2295 parser_info->SetXmlBuffer (inptr);
2296 if (!XML_Parse (p, inptr, n, nread == 0)) {
2297 expat_parser_error (parser_info, XML_GetErrorCode (p));
2298 goto cleanup_and_return;
2301 if (nread == 0)
2302 break;
2305 print_tree (parser_info->top_element, 0);
2307 if (parser_info->top_element) {
2308 res = parser_info->top_element->GetAsValue ();
2309 // We want a copy because the old one is going to be deleted
2310 res = new Value (*res);
2312 if (element_type)
2313 *element_type = parser_info->top_element->info->GetKind ();
2315 if (parser_info->error_args) {
2316 *element_type = Type::INVALID;
2317 goto cleanup_and_return;
2321 cleanup_and_return:
2323 if (!parser_info)
2324 error_args = new ParserErrorEventArgs ("Error opening xaml file", xaml_file, 0, 0, 1, "", "");
2325 else if (parser_info->error_args) {
2326 error_args = parser_info->error_args;
2327 error_args->ref ();
2330 delete stream;
2332 if (p)
2333 XML_ParserFree (p);
2335 if (parser_info)
2336 delete parser_info;
2338 return res;
2341 Value *
2342 XamlLoader::CreateFromString (const char *xaml, bool create_namescope, Type::Kind *element_type, int flags)
2344 return HydrateFromString (xaml, NULL, create_namescope, element_type, flags);
2347 DependencyObject *
2348 value_to_dependency_object (Value *value)
2350 if (!value || !value->Is (Deployment::GetCurrent (), Type::DEPENDENCY_OBJECT))
2351 return NULL;
2352 return value->AsDependencyObject ();
2355 DependencyObject *
2356 XamlLoader::CreateDependencyObjectFromFile (const char *xaml, bool create_namescope, Type::Kind *element_type)
2358 return value_to_dependency_object (CreateFromFile (xaml, create_namescope, element_type));
2361 DependencyObject *
2362 XamlLoader::CreateDependencyObjectFromString (const char *xaml, bool create_namescope, Type::Kind *element_type)
2364 return value_to_dependency_object (CreateFromString (xaml, create_namescope, element_type, IMPORT_DEFAULT_XMLNS));
2368 * Hydrates an existing DependencyObject (@object) with the contents from the @xaml
2369 * data
2371 Value *
2372 XamlLoader::HydrateFromString (const char *xaml, Value *object, bool create_namescope, Type::Kind *element_type, int flags)
2374 XML_Parser p = XML_ParserCreateNS ("utf-8", '|');
2375 XamlParserInfo *parser_info = NULL;
2376 Value *res = NULL;
2377 char *start = (char*)xaml;
2378 char *prepend = NULL;
2379 char *append = NULL;
2380 char * inputs [4] = {NULL, NULL, NULL, NULL};
2382 inputs [0] = start;
2384 if (!p) {
2385 LOG_XAML ("can not create parser\n");
2386 goto cleanup_and_return;
2389 #if 0
2390 if (true) {
2391 static int id = 0;
2392 char filename[64];
2393 FILE *fp;
2395 sprintf (filename, "createFromXaml.%d.xaml", id++);
2396 if ((fp = fopen (filename, "wt")) != NULL) {
2397 fwrite (xaml, strlen (xaml), 1, fp);
2398 fclose (fp);
2401 #endif
2403 parser_info = new XamlParserInfo (p, NULL);
2405 parser_info->namescope->SetTemporary (!create_namescope);
2407 parser_info->loader = this;
2408 parser_info->validate_templates = (flags & VALIDATE_TEMPLATES) == VALIDATE_TEMPLATES;
2411 // If we are hydrating, we are not null
2413 if (object != NULL) {
2414 parser_info->hydrate_expecting = object;
2415 parser_info->hydrating = true;
2416 if (Type::IsSubclassOf (parser_info->deployment, object->GetKind (), Type::DEPENDENCY_OBJECT)) {
2417 DependencyObject *dob = object->AsDependencyObject ();
2418 dob->SetSurface (GetSurface());
2419 dob->SetResourceBase (GetResourceBase());
2421 } else {
2422 parser_info->hydrate_expecting = NULL;
2423 parser_info->hydrating = false;
2426 // from_str gets the default namespaces implictly added
2427 add_default_namespaces (parser_info, (flags & IMPORT_DEFAULT_XMLNS) == IMPORT_DEFAULT_XMLNS);
2429 XML_SetUserData (p, parser_info);
2431 XML_SetElementHandler (p, start_element_handler, end_element_handler);
2432 XML_SetCharacterDataHandler (p, char_data_handler);
2433 XML_SetNamespaceDeclHandler(p, start_namespace_handler, NULL);
2434 XML_SetDoctypeDeclHandler(p, start_doctype_handler, NULL);
2437 XML_SetProcessingInstructionHandler (p, proc_handler);
2440 if (context) {
2441 prepend = context->internal->CreateIgnorableTagOpen ();
2442 append = context->internal->CreateIgnorableTagClose ();
2444 inputs [0] = prepend;
2445 inputs [1] = start;
2446 inputs [2] = append;
2449 for (int i = 0; inputs [i]; i++) {
2450 char *start = inputs [i];
2452 // don't freak out if the <?xml ... ?> isn't on the first line (see #328907)
2453 while (g_ascii_isspace (*start))
2454 start++;
2456 parser_info->SetXmlBuffer (start);
2457 if (!XML_Parse (p, start, strlen (start), inputs [i + 1] == NULL)) {
2458 expat_parser_error (parser_info, XML_GetErrorCode (p));
2459 LOG_XAML ("error parsing: %s\n\n", xaml);
2460 goto cleanup_and_return;
2464 print_tree (parser_info->top_element, 0);
2466 if (parser_info->top_element) {
2467 if (is_legal_top_level_kind (parser_info->top_element->info->GetKind ())) {
2468 res = parser_info->top_element->GetAsValue ();
2469 res = new Value (*res);
2470 if (res->Is (parser_info->deployment, Type::DEPENDENCY_OBJECT) && object) {
2471 DependencyObject *dob = res->AsDependencyObject ();
2472 dob->unref ();
2473 dob->SetIsHydratedFromXaml (parser_info->hydrating);
2477 if (element_type)
2478 *element_type = parser_info->top_element->info->GetKind ();
2480 if (!res && !parser_info->error_args)
2481 parser_info->error_args = new ParserErrorEventArgs ("No DependencyObject found", "", 0, 0, 1, "", "");
2483 if (parser_info->error_args) {
2484 delete res;
2485 res = NULL;
2486 if (element_type)
2487 *element_type = Type::INVALID;
2488 goto cleanup_and_return;
2492 cleanup_and_return:
2494 if (parser_info->error_args) {
2495 error_args = parser_info->error_args;
2496 printf ("Could not parse element %s, attribute %s, error: %s\n",
2497 error_args->xml_element,
2498 error_args->xml_attribute,
2499 error_args->GetErrorMessage());
2502 if (p)
2503 XML_ParserFree (p);
2504 if (parser_info)
2505 delete parser_info;
2506 if (prepend)
2507 g_free (prepend);
2508 if (append)
2509 g_free (append);
2511 return res;
2514 Value *
2515 XamlLoader::CreateFromFileWithError (const char *xaml_file, bool create_namescope, Type::Kind *element_type, MoonError *error)
2517 Value *res = CreateFromFile (xaml_file, create_namescope, element_type);
2518 if (error_args && error_args->GetErrorCode () != -1)
2519 MoonError::FillIn (error, error_args);
2520 return res;
2523 Value *
2524 XamlLoader::CreateFromStringWithError (const char *xaml, bool create_namescope, Type::Kind *element_type, int flags, MoonError *error)
2526 Value *res = CreateFromString (xaml, create_namescope, element_type, flags);
2527 if (error_args && error_args->GetErrorCode () != -1)
2528 MoonError::FillIn (error, error_args);
2529 return res;
2532 Value *
2533 XamlLoader::HydrateFromStringWithError (const char *xaml, Value *object, bool create_namescope, Type::Kind *element_type, int flags, MoonError *error)
2535 Value *res = HydrateFromString (xaml, object, create_namescope, element_type, flags);
2536 if (error_args && error_args->GetErrorCode () != -1)
2537 MoonError::FillIn (error, error_args);
2538 return res;
2541 static int
2542 parse_int (const char **pp, const char *end)
2544 const char *p = *pp;
2545 #if 0
2546 if (optional && AtEnd)
2547 return 0;
2548 #endif
2550 int res = 0;
2551 int count = 0;
2553 while (p <= end && g_ascii_isdigit (*p)) {
2554 res = res * 10 + *p - '0';
2555 p++;
2556 count++;
2559 #if 0
2560 if (count == 0)
2561 formatError = true;
2562 #endif
2564 *pp = p;
2565 return res;
2568 static gint64
2569 parse_ticks (const char **pp, const char *end)
2571 gint64 mag = 1000000;
2572 gint64 res = 0;
2573 bool digitseen = false;
2575 const char *p = *pp;
2577 while (mag > 0 && p <= end && g_ascii_isdigit (*p)) {
2578 res = res + (*p - '0') * mag;
2579 p++;
2580 mag = mag / 10;
2581 digitseen = true;
2584 #if 0
2585 if (!digitseen)
2586 formatError = true;
2587 #endif
2589 *pp = p;
2590 return res;
2593 bool
2594 time_span_from_str (const char *str, TimeSpan *res)
2596 const char *end = str + strlen (str);
2597 const char *p;
2599 bool negative = false;
2600 int days;
2601 int hours;
2602 int minutes;
2603 int seconds;
2604 gint64 ticks;
2606 p = str;
2608 if (*p == '-') {
2609 p++;
2610 negative = true;
2613 days = parse_int (&p, end);
2615 if (*p == '.') {
2616 p++;
2617 hours = parse_int (&p, end);
2619 else {
2620 hours = days;
2621 days = 0;
2624 if (*p == ':') p++;
2625 minutes = parse_int (&p, end);
2626 if (*p == ':') p++;
2627 seconds = parse_int (&p, end);
2628 if (*p == '.') {
2629 p++;
2630 ticks = parse_ticks (&p, end);
2632 else {
2633 ticks = 0;
2636 gint64 t = (days * 86400) + (hours * 3600) + (minutes * 60) + seconds;
2637 t *= 10000000L;
2639 *res = negative ? (-t - ticks) : (t + ticks);
2641 return true;
2644 bool
2645 repeat_behavior_from_str (const char *str, RepeatBehavior *res)
2647 if (!g_ascii_strcasecmp ("Forever", str)) {
2648 *res = RepeatBehavior::Forever;
2649 return true;
2652 // check for "<float>x".
2654 // XXX more validation work is needed here.. but how do we
2655 // report an error?
2656 const char *x = strchr (str, 'x');
2657 if (x) {
2658 if (*(x + 1) != '\0') {
2659 return false;
2661 else {
2662 char *endptr;
2663 errno = 0;
2664 double d = g_ascii_strtod (str, &endptr);
2666 if (errno || endptr == str)
2667 return false;
2669 *res = RepeatBehavior (d);
2670 return true;
2674 /* XXX RepeatBehavior='XX:XX:XX' syntax is NOT correctly supported by
2675 Silverlight 1.0 (most likely a bug). It works fine in Silverlight 2.0
2676 though. We currently stick to the 2.0 behavior, not replicating the bug
2677 from 1.0.
2679 TimeSpan t;
2680 if (!time_span_from_str (str, &t))
2681 return false;
2683 *res = RepeatBehavior (t);
2685 return true;
2688 bool
2689 duration_from_str (const char *str, Duration *res)
2691 if (!g_ascii_strcasecmp ("Automatic", str)) {
2692 *res = Duration::Automatic;
2693 return true;
2696 if (!g_ascii_strcasecmp ("Forever", str)) {
2697 *res = Duration::Forever;
2698 return true;
2701 TimeSpan ts;
2702 if (!time_span_from_str (str, &ts))
2703 return false;
2705 *res = Duration (ts);
2706 return true;
2709 bool
2710 keytime_from_str (const char *str, KeyTime *res)
2712 if (!g_ascii_strcasecmp ("Uniform", str)) {
2713 *res = KeyTime::Uniform;
2714 return true;
2717 if (!g_ascii_strcasecmp ("Paced", str)) {
2718 *res = KeyTime::Paced;
2719 return true;
2722 /* check for a percentage first */
2723 const char *last = str + strlen(str) - 1;
2724 if (*last == '%') {
2725 char *ep;
2726 double pct = g_ascii_strtod (str, &ep);
2727 if (ep == last) {
2728 *res = KeyTime (pct);
2729 return true;
2733 TimeSpan ts;
2734 if (!time_span_from_str (str, &ts))
2735 return false;
2737 *res = KeyTime (ts);
2738 return true;
2741 bool
2742 key_spline_from_str (const char *str, KeySpline **res)
2744 PointCollection *pts = PointCollection::FromStr (str);
2746 if (!pts)
2747 return false;
2749 if (pts->GetCount () != 2) {
2750 pts->unref ();
2751 return false;
2754 *res = new KeySpline (*pts->GetValueAt (0)->AsPoint (), *pts->GetValueAt (1)->AsPoint ());
2756 pts->unref ();
2758 return true;
2761 Matrix *
2762 matrix_from_str (const char *str)
2764 if (!g_ascii_strcasecmp ("Identity", str)) {
2765 return new Matrix ();
2768 DoubleCollection *values = DoubleCollection::FromStr (str);
2769 Matrix *matrix;
2771 if (!values)
2772 return new Matrix ();
2774 if (values->GetCount () < 6) {
2775 values->unref ();
2776 return NULL;
2779 matrix = new Matrix ();
2780 matrix->SetM11 (values->GetValueAt (0)->AsDouble ());
2781 matrix->SetM12 (values->GetValueAt (1)->AsDouble ());
2782 matrix->SetM21 (values->GetValueAt (2)->AsDouble ());
2783 matrix->SetM22 (values->GetValueAt (3)->AsDouble ());
2784 matrix->SetOffsetX (values->GetValueAt (4)->AsDouble ());
2785 matrix->SetOffsetY (values->GetValueAt (5)->AsDouble ());
2787 values->unref ();
2789 return matrix;
2792 bool
2793 grid_length_from_str (const char *str, GridLength *grid_length)
2795 if (IS_NULL_OR_EMPTY (str)) {
2796 *grid_length = GridLength (0.0, GridUnitTypePixel);
2797 return true;
2800 if (str [0] == '*') {
2801 *grid_length = GridLength (1.0, GridUnitTypeStar);
2802 return true;
2805 // unit tests shows that "Auto", "auto", "aUtO"... all works
2806 if (!g_ascii_strcasecmp (str, "Auto")) {
2807 *grid_length = GridLength ();
2808 return true;
2811 char *endptr;
2812 errno = 0;
2813 double d = g_ascii_strtod (str, &endptr);
2815 if (errno || endptr == str)
2816 return false;
2818 *grid_length = GridLength (d, *endptr == '*' ? GridUnitTypeStar : GridUnitTypePixel);
2819 return true;
2822 static void
2823 advance (char **in)
2825 char *inptr = *in;
2827 while (*inptr && !g_ascii_isalnum (*inptr) && *inptr != '.' && *inptr != '-' && *inptr != '+')
2828 inptr = g_utf8_next_char (inptr);
2830 *in = inptr;
2833 static bool
2834 get_point (Point *p, char **in)
2836 char *end, *inptr = *in;
2837 double x, y;
2839 x = g_ascii_strtod (inptr, &end);
2840 if (end == inptr)
2841 return false;
2843 inptr = end;
2844 while (g_ascii_isspace (*inptr))
2845 inptr++;
2847 if (*inptr == ',')
2848 inptr++;
2850 while (g_ascii_isspace (*inptr))
2851 inptr++;
2853 y = g_ascii_strtod (inptr, &end);
2854 if (end == inptr)
2855 return false;
2857 p->x = x;
2858 p->y = y;
2860 *in = end;
2862 return true;
2865 static void
2866 make_relative (const Point *cp, Point *mv)
2868 mv->x += cp->x;
2869 mv->y += cp->y;
2872 static bool
2873 more_points_available (char **in)
2875 char *inptr = *in;
2877 while (g_ascii_isspace (*inptr) || *inptr == ',')
2878 inptr++;
2880 *in = inptr;
2882 return (g_ascii_isdigit (*inptr) || *inptr == '.' || *inptr == '-' || *inptr == '+');
2885 Geometry *
2886 geometry_from_str (const char *str)
2888 char *inptr = (char *) str;
2889 Point cp = Point (0, 0);
2890 Point cp1, cp2, cp3;
2891 Point start;
2892 char *end;
2893 PathGeometry *pg = NULL;
2894 FillRule fill_rule = FillRuleEvenOdd;
2895 bool cbz = false; // last figure is a cubic bezier curve
2896 bool qbz = false; // last figure is a quadratic bezier curve
2897 Point cbzp, qbzp; // points needed to create "smooth" beziers
2899 moon_path *path = moon_path_new (10);
2901 while (*inptr) {
2902 if (g_ascii_isspace (*inptr))
2903 inptr++;
2905 if (!inptr[0])
2906 break;
2908 bool relative = false;
2910 char c = *inptr;
2911 inptr = g_utf8_next_char (inptr);
2913 switch (c) {
2914 case 'f':
2915 case 'F':
2916 advance (&inptr);
2918 if (*inptr == '0')
2919 fill_rule = FillRuleEvenOdd;
2920 else if (*inptr == '1')
2921 fill_rule = FillRuleNonzero;
2922 else
2923 // FIXME: else it's a bad value and nothing should be rendered
2924 goto bad_pml; // partial: only this Path won't be rendered
2926 inptr = g_utf8_next_char (inptr);
2927 break;
2928 case 'm':
2929 relative = true;
2930 case 'M':
2931 if (!get_point (&cp1, &inptr))
2932 break;
2934 if (relative)
2935 make_relative (&cp, &cp1);
2937 // start point
2938 moon_move_to (path, cp1.x, cp1.y);
2940 start.x = cp.x = cp1.x;
2941 start.y = cp.y = cp1.y;
2943 advance (&inptr);
2944 while (more_points_available (&inptr)) {
2945 if (!get_point (&cp1, &inptr))
2946 break;
2948 if (relative)
2949 make_relative (&cp, &cp1);
2951 moon_line_to (path, cp1.x, cp1.y);
2954 cp.x = cp1.x;
2955 cp.y = cp1.y;
2956 cbz = qbz = false;
2957 break;
2959 case 'l':
2960 relative = true;
2961 case 'L':
2963 while (more_points_available (&inptr)) {
2964 if (!get_point (&cp1, &inptr))
2965 break;
2967 if (relative)
2968 make_relative (&cp, &cp1);
2970 moon_line_to (path, cp1.x, cp1.y);
2972 cp.x = cp1.x;
2973 cp.y = cp1.y;
2975 advance (&inptr);
2977 cbz = qbz = false;
2978 break;
2981 case 'h':
2982 relative = true;
2983 case 'H':
2985 double x = g_ascii_strtod (inptr, &end);
2986 if (end == inptr)
2987 break;
2989 inptr = end;
2991 if (relative)
2992 x += cp.x;
2993 cp = Point (x, cp.y);
2995 moon_line_to (path, cp.x, cp.y);
2996 cbz = qbz = false;
2997 break;
3000 case 'v':
3001 relative = true;
3002 case 'V':
3004 double y = g_ascii_strtod (inptr, &end);
3005 if (end == inptr)
3006 break;
3008 inptr = end;
3010 if (relative)
3011 y += cp.y;
3012 cp = Point (cp.x, y);
3014 moon_line_to (path, cp.x, cp.y);
3015 cbz = qbz = false;
3016 break;
3019 case 'c':
3020 relative = true;
3021 case 'C':
3023 while (more_points_available (&inptr)) {
3024 if (!get_point (&cp1, &inptr))
3025 break;
3027 if (relative)
3028 make_relative (&cp, &cp1);
3030 advance (&inptr);
3032 if (!get_point (&cp2, &inptr))
3033 break;
3035 if (relative)
3036 make_relative (&cp, &cp2);
3038 advance (&inptr);
3040 if (!get_point (&cp3, &inptr))
3041 break;
3043 if (relative)
3044 make_relative (&cp, &cp3);
3046 advance (&inptr);
3048 moon_curve_to (path, cp1.x, cp1.y, cp2.x, cp2.y, cp3.x, cp3.y);
3050 cp1.x = cp3.x;
3051 cp1.y = cp3.y;
3053 cp.x = cp3.x;
3054 cp.y = cp3.y;
3055 cbz = true;
3056 cbzp.x = cp2.x;
3057 cbzp.y = cp2.y;
3058 qbz = false;
3059 break;
3061 case 's':
3062 relative = true;
3063 case 'S':
3065 while (more_points_available (&inptr)) {
3066 if (!get_point (&cp2, &inptr))
3067 break;
3069 if (relative)
3070 make_relative (&cp, &cp2);
3072 advance (&inptr);
3074 if (!get_point (&cp3, &inptr))
3075 break;
3077 if (relative)
3078 make_relative (&cp, &cp3);
3080 if (cbz) {
3081 cp1.x = 2 * cp.x - cbzp.x;
3082 cp1.y = 2 * cp.y - cbzp.y;
3083 } else
3084 cp1 = cp;
3086 moon_curve_to (path, cp1.x, cp1.y, cp2.x, cp2.y, cp3.x, cp3.y);
3087 cbz = true;
3088 cbzp.x = cp2.x;
3089 cbzp.y = cp2.y;
3091 cp.x = cp3.x;
3092 cp.y = cp3.y;
3094 advance (&inptr);
3096 qbz = false;
3097 break;
3099 case 'q':
3100 relative = true;
3101 case 'Q':
3103 while (more_points_available (&inptr)) {
3104 if (!get_point (&cp1, &inptr))
3105 break;
3107 if (relative)
3108 make_relative (&cp, &cp1);
3110 advance (&inptr);
3112 if (!get_point (&cp2, &inptr))
3113 break;
3115 if (relative)
3116 make_relative (&cp, &cp2);
3118 advance (&inptr);
3120 moon_quad_curve_to (path, cp1.x, cp1.y, cp2.x, cp2.y);
3122 cp.x = cp2.x;
3123 cp.y = cp2.y;
3125 qbz = true;
3126 qbzp.x = cp1.x;
3127 qbzp.y = cp1.y;
3128 cbz = false;
3129 break;
3131 case 't':
3132 relative = true;
3133 case 'T':
3135 while (more_points_available (&inptr)) {
3136 if (!get_point (&cp2, &inptr))
3137 break;
3139 if (relative)
3140 make_relative (&cp, &cp2);
3142 if (qbz) {
3143 cp1.x = 2 * cp.x - qbzp.x;
3144 cp1.y = 2 * cp.y - qbzp.y;
3145 } else
3146 cp1 = cp;
3148 moon_quad_curve_to (path, cp1.x, cp1.y, cp2.x, cp2.y);
3149 qbz = true;
3150 qbzp.x = cp1.x;
3151 qbzp.y = cp1.y;
3153 cp.x = cp2.x;
3154 cp.y = cp2.y;
3156 advance (&inptr);
3158 cbz = false;
3159 break;
3161 case 'a':
3162 relative = true;
3163 case 'A':
3165 while (more_points_available (&inptr)) {
3166 if (!get_point (&cp1, &inptr))
3167 break;
3169 advance (&inptr);
3171 double angle = g_ascii_strtod (inptr, &end);
3172 if (end == inptr)
3173 break;
3175 inptr = end;
3176 advance (&inptr);
3178 int is_large = strtol (inptr, &end, 10);
3179 if (end == inptr)
3180 break;
3182 inptr = end;
3183 advance (&inptr);
3185 int sweep = strtol (inptr, &end, 10);
3186 if (end == inptr)
3187 break;
3189 inptr = end;
3190 advance (&inptr);
3192 if (!get_point (&cp2, &inptr))
3193 break;
3195 if (relative)
3196 make_relative (&cp, &cp2);
3198 moon_arc_to (path, cp1.x, cp1.y, angle, is_large, sweep, cp2.x, cp2.y);
3200 cp.x = cp2.x;
3201 cp.y = cp2.y;
3203 advance (&inptr);
3205 cbz = qbz = false;
3206 break;
3208 case 'z':
3209 case 'Z':
3210 moon_line_to (path, start.x, start.y);
3211 moon_close_path (path);
3212 moon_move_to (path, start.x, start.y);
3214 cp.x = start.x;
3215 cp.y = start.y;
3216 cbz = qbz = false;
3217 break;
3218 default:
3219 break;
3223 pg = new PathGeometry (path);
3224 pg->SetFillRule (fill_rule);
3225 return pg;
3227 bad_pml:
3228 moon_path_destroy (path);
3229 return NULL;
3232 static bool
3233 value_is_explicit_null (const char *str)
3235 return !strcmp ("{x:Null}", str);
3238 static bool
3239 is_managed_kind (Type::Kind kind)
3242 if (kind == Type::MANAGED ||
3243 kind == Type::OBJECT ||
3244 kind == Type::URI ||
3245 kind == Type::MANAGEDTYPEINFO ||
3246 kind == Type::DEPENDENCYPROPERTY)
3247 return true;
3249 return false;
3252 static bool
3253 kind_requires_managed_load (Type::Kind kind)
3255 if (kind == Type::USERCONTROL) {
3256 return true;
3259 return false;
3262 static bool
3263 is_legal_top_level_kind (Type::Kind kind)
3265 if (kind == Type::MANAGED || kind == Type::OBJECT || Type::IsSubclassOf (Deployment::GetCurrent (), kind, Type::DEPENDENCY_OBJECT))
3266 return true;
3267 return false;
3270 // NOTE: Keep definition in sync with class/System.Windows/Mono/NativeMethods.cs
3271 bool
3272 value_from_str_with_typename (const char *type_name, const char *prop_name, const char *str, Value **v)
3274 Type *t = Type::Find (Deployment::GetCurrent (), type_name);
3275 if (!t)
3276 return false;
3278 return value_from_str (t->GetKind (), prop_name, str, v);
3281 char *
3282 expand_property_path (XamlParserInfo *p, PropertyPath *path)
3284 if (!path->path)
3285 return NULL;
3287 bool expanded = false;
3288 GString *res = g_string_new (path->path);
3290 int len = strlen (res->str);
3291 for (int i = 0; i < len; i++) {
3292 if (res->str [i] == ':') {
3293 int e = i;
3294 int s = i - 1;
3295 int te = i + 1;
3296 for ( ; s > 0; s--) {
3297 if (!g_ascii_isalnum (res->str [s]))
3298 break;
3301 for ( ; te < len; te++) {
3302 if (!g_ascii_isalpha (res->str [te]) || res->str [te] == '_')
3303 break;
3306 char *prefix = g_strndup (res->str + s + 1, e - s - 1);
3307 char *type = g_strndup (res->str + e + 1, te - e - 1);
3309 res = g_string_erase (res, s + 1, te - s - 1);
3311 XamlNamespace *ns = (XamlNamespace *) g_hash_table_find (p->namespace_map, namespace_for_prefix, prefix);
3312 if (!ns) {
3313 g_free (prefix);
3314 g_free (type);
3315 g_string_free (res, true);
3316 return NULL;
3319 XamlElementInfo *info = ns->FindElement (p, type, NULL, false);
3321 if (!info) {
3322 g_free (prefix);
3323 g_free (type);
3324 g_string_free (res, true);
3325 return NULL;
3328 char *uri = g_strdup_printf ("'%s'", Type::Find (p->deployment, info->GetKind ())->GetName ());
3330 res = g_string_insert (res, s + 1, uri);
3331 i = s + 1 + strlen (uri);
3332 len = strlen (res->str);
3334 delete info;
3335 g_free (uri);
3336 g_free (prefix);
3337 g_free (type);
3339 expanded = true;
3343 if (!expanded) {
3344 g_string_free (res, true);
3345 return NULL;
3348 char *expanded_str = res->str;
3349 g_string_free (res, false);
3351 return expanded_str;
3354 bool
3355 value_from_str (Type::Kind type, const char *prop_name, const char *str, Value **v)
3357 bool v_set = false;
3359 value_from_str_with_parser (NULL, type, prop_name, str, v, &v_set);
3361 return v_set;
3364 bool
3365 xaml_bool_from_str (const char *s, bool *res)
3367 bool b;
3368 char *endptr;
3370 if (!g_ascii_strcasecmp ("true", s))
3371 b = true;
3372 else if (!g_ascii_strcasecmp ("false", s))
3373 b = false;
3374 else {
3375 // Check if it's a string representing a decimal value
3376 gint64 l;
3378 errno = 0;
3379 l = strtol (s, &endptr, 10);
3381 if (errno || endptr == s || *endptr || l > G_MAXINT32 || l < G_MININT32)
3382 return false;;
3384 if (l == 0)
3385 b = false;
3386 else
3387 b = true;
3390 *res = b;
3391 return true;
3394 static bool
3395 value_from_str_with_parser (XamlParserInfo *p, Type::Kind type, const char *prop_name, const char *str, Value **v, bool *v_set)
3397 char *endptr;
3398 *v = NULL;
3400 if (value_is_explicit_null (str)) {
3401 *v = NULL;
3402 *v_set = true;
3403 return true;
3406 char *s = g_strdup (str);
3408 if (type == Type::OBJECT || type == Type::STRING) {
3409 // object and string use the literal string
3411 else {
3412 // everything else depends on the string being stripped
3413 s = g_strstrip (s);
3416 switch (type) {
3417 case Type::OBJECT: {
3418 // not much more can do here, unless we want to try to
3419 // probe str to see if it's actually meant to be a
3420 // specific type. just assume it's a string.
3421 *v = new Value (s);
3422 *v_set = true;
3423 break;
3426 case Type::BOOL: {
3427 bool b;
3429 if (!xaml_bool_from_str (s, &b))
3430 break;
3432 *v = new Value (b);
3433 *v_set = true;
3434 break;
3436 case Type::DOUBLE: {
3437 double d;
3439 // empty string should not reset default values with 0
3441 // FIXME: this causes a 2.0 unit test to fail (PrimitiveTest.ParseEmptyDouble)
3442 if (IS_NULL_OR_EMPTY(s)) {
3443 g_free (s);
3444 return false;
3447 bool is_nan = false;
3448 if (!g_ascii_strcasecmp (s, "NAN"))
3449 is_nan = true;
3450 else {
3451 errno = 0;
3452 d = g_ascii_strtod (s, &endptr);
3455 if (is_nan || errno || endptr == s || *endptr) {
3456 if (prop_name
3457 && (!strcmp (prop_name, "Width") || !strcmp (prop_name, "Height"))
3458 && (!g_ascii_strcasecmp (s, "Auto") || is_nan))
3459 d = NAN;
3460 else
3461 break;
3464 *v = new Value (d);
3465 *v_set = true;
3466 break;
3468 case Type::INT64: {
3469 gint64 l;
3471 errno = 0;
3472 l = strtol (s, &endptr, 10);
3474 if (errno || endptr == s)
3475 break;
3477 *v = new Value (l, Type::INT64);
3478 *v_set = true;
3479 break;
3481 case Type::TIMESPAN: {
3482 TimeSpan ts;
3484 if (!time_span_from_str (s, &ts))
3485 break;
3487 *v = new Value (ts, Type::TIMESPAN);
3488 *v_set = true;
3489 break;
3491 case Type::INT32: {
3492 int i;
3494 if (IS_NULL_OR_EMPTY(s))
3495 i = 0;
3496 else if (g_ascii_isalpha (s[0]) && prop_name) {
3497 i = enums_str_to_int (prop_name, s);
3498 if (i == -1) {
3499 // g_warning ("'%s' enum is not valid on '%s' property", str, prop_name);
3500 break;
3502 } else {
3503 errno = 0;
3504 long l = strtol (s, &endptr, 10);
3506 if (errno || endptr == s)
3507 break;
3509 i = (int) l;
3512 *v = new Value (i);
3513 *v_set = true;
3514 break;
3516 case Type::CHAR: {
3517 gunichar unichar = g_utf8_get_char_validated (str, -1);
3518 const char *next;
3520 if ((int) unichar < 0)
3521 break;
3523 if (!(next = g_utf8_next_char (str)) || *next != '\0')
3524 break;
3526 *v = new Value (unichar, Type::CHAR);
3527 *v_set = true;
3528 break;
3530 case Type::STRING: {
3531 *v = new Value (str);
3532 *v_set = true;
3533 break;
3535 case Type::COLOR: {
3536 Color *c = color_from_str (s);
3537 if (c == NULL)
3538 break;
3539 *v = new Value (*c);
3540 *v_set = true;
3541 delete c;
3542 break;
3544 case Type::REPEATBEHAVIOR: {
3545 RepeatBehavior rb = RepeatBehavior::Forever;
3547 if (!repeat_behavior_from_str (s, &rb))
3548 break;
3550 *v = new Value (rb);
3551 *v_set = true;
3552 break;
3554 case Type::DURATION: {
3555 Duration d = Duration::Forever;
3557 if (!duration_from_str (s, &d))
3558 break;
3560 *v = new Value (d);
3561 *v_set = true;
3562 break;
3564 case Type::KEYTIME: {
3565 KeyTime kt = KeyTime::Paced;
3567 if (!keytime_from_str (s, &kt))
3568 break;
3570 *v = new Value (kt);
3571 *v_set = true;
3572 break;
3574 case Type::KEYSPLINE: {
3575 KeySpline *ks;
3577 if (!key_spline_from_str (s, &ks))
3578 break;
3580 *v = Value::CreateUnrefPtr (ks);
3581 *v_set = true;
3582 break;
3584 case Type::BRUSH:
3585 case Type::SOLIDCOLORBRUSH: {
3586 // Only solid color brushes can be specified using attribute syntax
3587 Color *c = color_from_str (s);
3589 if (c == NULL)
3590 break;
3592 SolidColorBrush *scb = new SolidColorBrush ();
3594 scb->SetColor (c);
3595 delete c;
3597 *v = Value::CreateUnrefPtr (scb);
3598 *v_set = true;
3599 break;
3601 case Type::POINT: {
3602 Point p;
3604 if (!Point::FromStr (s, &p))
3605 break;
3607 *v = new Value (p);
3608 *v_set = true;
3609 break;
3611 case Type::SIZE: {
3612 Size size;
3614 if (!Size::FromStr (s, &size))
3615 break;
3617 *v = new Value (size);
3618 *v_set = true;
3619 break;
3621 case Type::RECT: {
3622 Rect rect;
3624 if (!Rect::FromStr (s, &rect))
3625 break;
3627 *v = new Value (rect);
3628 *v_set = true;
3629 break;
3631 case Type::URI: {
3632 Uri uri;
3634 if (!uri.Parse (s)) {
3635 break;
3638 *v = new Value (uri);
3639 *v_set = true;
3640 break;
3642 case Type::DOUBLE_COLLECTION: {
3643 DoubleCollection *doubles = DoubleCollection::FromStr (s);
3644 if (!doubles) {
3645 *v = Value::CreateUnrefPtr (new DoubleCollection ());
3646 *v_set = true;
3647 break;
3650 *v = Value::CreateUnrefPtr (doubles);
3651 *v_set = true;
3652 break;
3654 case Type::POINT_COLLECTION: {
3655 PointCollection *points = PointCollection::FromStr (s);
3656 if (!points) {
3657 *v = Value::CreateUnrefPtr (new PointCollection ());
3658 *v_set = true;
3659 break;
3662 *v = Value::CreateUnrefPtr (points);
3663 *v_set = true;
3664 break;
3666 case Type::TRANSFORMGROUP: {
3667 if (IS_NULL_OR_EMPTY(s))
3668 break;
3670 Matrix *mv = matrix_from_str (s);
3671 if (!mv)
3672 break;
3674 TransformGroup *tg = new TransformGroup ();
3675 MatrixTransform *t = new MatrixTransform ();
3676 t->SetValue (MatrixTransform::MatrixProperty, Value (mv));
3678 tg->GetChildren()->Add (t);
3679 t->unref ();
3681 *v = new Value (tg);
3682 *v_set = true;
3683 tg->unref ();
3684 mv->unref ();
3685 break;
3687 case Type::TRANSFORM:
3689 if (!g_ascii_strcasecmp ("Identity", str)) {
3690 *v = NULL;
3691 *v_set = true;
3692 break;
3695 // Intentional fall through, you can create a matrix from a TRANSFORM property, but not using Identity
3696 case Type::MATRIXTRANSFORM:
3698 if (IS_NULL_OR_EMPTY(s))
3699 break;
3701 Matrix *mv = matrix_from_str (s);
3702 if (!mv)
3703 break;
3705 MatrixTransform *t = new MatrixTransform ();
3706 t->SetValue (MatrixTransform::MatrixProperty, Value (mv));
3708 *v = new Value (t);
3709 *v_set = true;
3710 t->unref ();
3711 mv->unref ();
3712 break;
3714 case Type::UNMANAGEDMATRIX:
3715 case Type::MATRIX: {
3716 // note: unlike TRANSFORM this creates an empty, identity, matrix for an empty string
3717 Matrix *matrix = matrix_from_str (s);
3718 if (!matrix)
3719 break;
3721 *v = new Value (matrix);
3722 *v_set = true;
3723 matrix->unref ();
3724 break;
3726 case Type::PATHGEOMETRY:
3727 case Type::GEOMETRY: {
3728 Geometry *geometry = geometry_from_str (s);
3730 if (!geometry)
3731 break;
3733 *v = new Value (geometry);
3734 *v_set = true;
3735 geometry->unref ();
3736 break;
3738 case Type::THICKNESS: {
3739 Thickness t;
3741 if (!Thickness::FromStr (s, &t))
3742 break;
3744 *v = new Value (t);
3745 *v_set = true;
3746 break;
3748 case Type::CORNERRADIUS: {
3749 CornerRadius c;
3751 if (!CornerRadius::FromStr (s, &c))
3752 break;
3754 *v = new Value (c);
3755 *v_set = true;
3756 break;
3758 case Type::GRIDLENGTH: {
3759 GridLength grid_length;
3761 if (!grid_length_from_str (s, &grid_length))
3762 break;
3764 *v = new Value (grid_length);
3765 *v_set = true;
3766 break;
3768 case Type::IMAGESOURCE:
3769 case Type::BITMAPIMAGE: {
3770 Uri uri;
3772 if (!uri.Parse (s))
3773 break;
3775 BitmapImage *bi = new BitmapImage ();
3777 bi->SetUriSource (&uri);
3779 *v = Value::CreateUnrefPtr (bi);
3780 *v_set = true;
3782 break;
3784 case Type::MULTISCALETILESOURCE:
3785 case Type::DEEPZOOMIMAGETILESOURCE: {
3786 // As far as I know the only thing you can create here is a URI based DeepZoomImageTileSource
3787 Uri uri;
3788 if (!uri.Parse (s))
3789 break;
3790 *v = Value::CreateUnrefPtr (new DeepZoomImageTileSource (&uri));
3791 *v_set = true;
3793 break;
3795 case Type::FONTFAMILY: {
3796 *v = new Value (FontFamily (s));
3797 *v_set = true;
3798 break;
3800 case Type::FONTWEIGHT: {
3801 int fw = enums_str_to_int ("FontWeight", s);
3802 if (fw != -1) {
3803 *v = new Value (FontWeight ((FontWeights)fw));
3804 *v_set = true;
3806 break;
3808 case Type::FONTSTYLE: {
3809 int fs = enums_str_to_int ("FontStyle", s);
3810 if (fs != -1) {
3811 *v = new Value (FontStyle ((FontStyles)fs));
3812 *v_set = true;
3814 break;
3816 case Type::FONTSTRETCH: {
3817 int fs = enums_str_to_int ("FontStretch", s);
3818 if (fs != -1) {
3819 *v = new Value (FontStretch ((FontStretches)fs));
3820 *v_set = true;
3822 break;
3824 case Type::PROPERTYPATH: {
3825 PropertyPath path (s);
3826 path.expanded_path = expand_property_path (p, &path);
3827 *v = new Value (path);
3828 *v_set = true;
3829 break;
3831 default:
3832 // we don't care about NULL or empty values
3833 if (!IS_NULL_OR_EMPTY (s)) {
3834 g_free (s);
3835 return true;
3839 g_free (s);
3840 return true;
3843 bool
3844 XamlElementInstance::TrySetContentProperty (XamlParserInfo *p, XamlElementInstance *value)
3846 const char* prop_name = info->GetContentProperty (p);
3848 if (!prop_name)
3849 return false;
3851 DependencyProperty *dep = DependencyProperty::GetDependencyProperty (Type::Find (p->deployment, info->GetKind ()), prop_name);
3852 if (!dep)
3853 return false;
3855 bool is_collection = Type::IsSubclassOf (p->deployment, dep->GetPropertyType(), Type::DEPENDENCY_OBJECT_COLLECTION);
3857 if (!is_collection && Type::IsSubclassOf (p->deployment, value->info->GetKind (), dep->GetPropertyType())) {
3858 MoonError err;
3859 if (!item->SetValueWithError (dep, value->GetAsValue (), &err)) {
3860 parser_error (p, value->element_name, NULL, err.code, err.message);
3861 return false;
3863 return true;
3866 // We only want to enter this if statement if we are NOT dealing with the content property element,
3867 // otherwise, attempting to use explicit property setting, would add the content property element
3868 // to the content property element collection
3869 if (is_collection && dep->GetPropertyType() != value->info->GetKind ()) {
3870 Value *col_v = item->GetValue (dep);
3871 Collection *col;
3873 if (!col_v) {
3874 col = collection_new (dep->GetPropertyType ());
3875 item->SetValue (dep, Value (col));
3876 col->unref ();
3877 } else {
3878 col = (Collection *) col_v->AsCollection ();
3881 MoonError err;
3882 if (-1 == col->AddWithError (value->GetAsValue (), &err)) {
3883 parser_error (p, value->element_name, NULL, err.code, err.message);
3884 return false;
3887 return true;
3890 return false;
3893 bool
3894 XamlElementInstance::TrySetContentProperty (XamlParserInfo *p, const char *value)
3896 const char* prop_name = info->GetContentProperty (p);
3897 if (!prop_name)
3898 return false;
3900 Type::Kind prop_type = p->current_element->info->GetKind ();
3901 DependencyProperty *content = DependencyProperty::GetDependencyProperty (Type::Find (p->deployment, prop_type), prop_name);
3903 // TODO: There might be other types that can be specified here,
3904 // but string is all i have found so far. If you can specify other
3905 // types, i should pull the property setting out of set_attributes
3906 // and use that code
3908 if (content && (content->GetPropertyType ()) == Type::STRING && value) {
3909 item->SetValue (content, Value (g_strstrip (p->cdata->str)));
3910 return true;
3911 } else if (Type::IsSubclassOf (p->deployment, info->GetKind (), Type::TEXTBLOCK)) {
3912 TextBlock *textblock = (TextBlock *) item;
3913 InlineCollection *inlines = textblock->GetInlines ();
3914 Inline *last = NULL;
3916 if (inlines && inlines->GetCount () > 0)
3917 last = inlines->GetValueAt (inlines->GetCount () - 1)->AsInline ();
3919 if (!p->cdata_content) {
3920 if (p->next_element && !strcmp (p->next_element, "Run") && last && last->GetObjectType () == Type::RUN &&
3921 !last->GetAutogenerated ()) {
3922 // LWSP between <Run> elements is to be treated as a single-SPACE <Run> element
3923 // Note: p->cdata is already canonicalized
3924 } else {
3925 // This is one of the following cases:
3927 // 1. LWSP before the first <Run> element
3928 // 2. LWSP after the last <Run> element
3929 // 3. LWSP between <Run> and <LineBreak> elements
3930 return true;
3932 } else {
3933 if (!p->next_element || !strcmp (p->next_element, "LineBreak"))
3934 g_strchomp (p->cdata->str);
3936 if (!last || last->GetObjectType () != Type::RUN || last->GetAutogenerated ())
3937 g_strchug (p->cdata->str);
3940 Run *run = new Run ();
3941 run->SetText (p->cdata->str);
3943 if (!inlines) {
3944 inlines = new InlineCollection ();
3945 textblock->SetInlines (inlines);
3946 inlines->unref ();
3949 inlines->Add (run);
3950 run->unref ();
3951 return true;
3954 return false;
3957 bool
3958 XamlElementInstance::SetUnknownAttribute (XamlParserInfo *p, const char *name, const char *value)
3960 if (!p->loader)
3961 return false;
3963 Value v = Value (value);
3964 if (!p->loader->SetProperty (p, p->GetTopElementPtr (), info->xmlns, GetAsValue (), this, GetParentPointer (), NULL, name, &v, NULL)) {
3965 return false;
3967 return true;
3970 void
3971 XamlElementInstance::SetDelayedProperties (XamlParserInfo *p)
3973 GSList *walk = delayed_properties;
3975 while (walk) {
3976 DelayedProperty *prop = (DelayedProperty *) walk->data;
3978 if (!p->loader->SetProperty (p, p->GetTopElementPtr (), info->xmlns, GetAsValue (), this, GetParentPointer (), prop->xmlns, prop->name, prop->value, NULL, XamlCallbackData::SETTING_DELAYED_PROPERTY)) {
3979 parser_error (p, element_name, prop->name, 2012,
3980 "Unknown property %s on element %s.",
3981 prop->name, element_name);
3982 return;
3985 walk = walk->next;
3990 XamlElementInfo *
3991 XamlElementInstance::FindPropertyElement (XamlParserInfo *p, const char *el, const char *dot)
3993 // We didn't find anything so try looking up in managed
3994 if (!p->loader)
3995 return NULL;
3997 Value *v = new Value ();
3998 if (p->loader->LookupObject (p, p->GetTopElementPtr (), GetAsValue (), p->current_namespace->GetUri (), el, false, true, v)) {
3999 char *type_name = g_strndup (el, dot - el);
4001 XamlElementInfoManaged *res = new XamlElementInfoManaged (g_strdup (p->current_namespace->GetUri ()), el, info, v->GetKind (), v);
4002 XamlElementInfo *container = p->current_namespace->FindElement (p, type_name, NULL, false);
4003 info->SetPropertyOwnerKind (container->GetKind ());
4004 g_free (type_name);
4005 return res;
4008 delete v;
4009 return NULL;
4012 static XamlElementInfo *
4013 create_element_info_from_imported_managed_type (XamlParserInfo *p, const char *name, const char **attr, bool create)
4015 if (!p->loader)
4016 return NULL;
4018 char* type_name = NULL;
4019 char* type_xmlns = NULL;
4020 const char* use_xmlns = NULL;
4022 if (x_namespace) {
4023 // We might have an x:Class attribute specified, so we need to use that for the
4024 // type_name that we pass to LookupObject
4025 if (strcmp ("Application", name)) {
4026 type_name = x_namespace->FindTypeName (attr, &type_xmlns);
4027 if (type_name) {
4028 name = type_name;
4029 use_xmlns = type_xmlns;
4031 if (!p->hydrating) {
4032 parser_error (p, name, "x:Class", 4005, "Cannot specify x:Class in xaml files outside of a xap.");
4033 return NULL;
4039 Value *v = new Value ();
4040 if (!p->loader->LookupObject (p, use_xmlns ? p->GetTopElementPtr () : NULL, NULL, use_xmlns, name, create, false, v)) {
4041 delete v;
4042 if (type_name)
4043 g_free (type_name);
4044 if (type_xmlns)
4045 g_free (type_xmlns);
4046 return NULL;
4049 XamlElementInfoImportedManaged *info = new XamlElementInfoImportedManaged (g_strdup (name), NULL, v);
4051 if (create) {
4052 if (v->Is (p->deployment, Type::DEPENDENCY_OBJECT))
4053 p->AddCreatedElement (v->AsDependencyObject());
4056 return info;
4060 const char *
4061 XamlElementInfoNative::GetContentProperty (XamlParserInfo *p)
4063 return type->GetContentPropertyName ();
4066 XamlElementInstance *
4067 XamlElementInfoNative::CreateElementInstance (XamlParserInfo *p)
4069 if (type->IsValueType ())
4070 return new XamlElementInstanceValueType (this, p, GetName (), XamlElementInstance::ELEMENT);
4071 else if (type->IsSubclassOf (Type::FRAMEWORKTEMPLATE))
4072 return new XamlElementInstanceTemplate (this, p, GetName (), XamlElementInstance::ELEMENT);
4073 else
4074 return new XamlElementInstanceNative (this, p, GetName (), XamlElementInstance::ELEMENT);
4077 XamlElementInstance *
4078 XamlElementInfoNative::CreateWrappedElementInstance (XamlParserInfo *p, Value *o)
4080 XamlElementInstance *res = new XamlElementInstanceNative (this, p, GetName (), XamlElementInstance::ELEMENT, false);
4081 res->SetDependencyObject (o->AsDependencyObject ());
4083 return res;
4086 XamlElementInfo *
4087 XamlElementInstanceNative::FindPropertyElement (XamlParserInfo *p, const char *el, const char *dot)
4089 if (IsDependencyObject ()) {
4090 const char *prop_name = dot + 1;
4091 DependencyProperty *prop = DependencyProperty::GetDependencyProperty (Type::Find (p->deployment, info->GetKind ()), prop_name);
4092 if (prop) {
4093 XamlElementInfoNative *info = new XamlElementInfoNative (Type::Find (p->deployment, prop->GetPropertyType ()));
4094 info->SetPropertyOwnerKind (prop->GetOwnerType ());
4095 return info;
4099 return XamlElementInstance::FindPropertyElement (p, el, dot);
4102 XamlElementInstance *
4103 XamlElementInfoNative::CreatePropertyElementInstance (XamlParserInfo *p, const char *name)
4105 return new XamlElementInstanceNative (this, p, name, XamlElementInstance::PROPERTY, false);
4108 XamlElementInstanceNative::XamlElementInstanceNative (XamlElementInfoNative *element_info, XamlParserInfo *parser_info, const char *name, ElementType type, bool create_item) :
4109 XamlElementInstance (element_info, name, type)
4111 this->element_info = element_info;
4112 this->parser_info = parser_info;
4113 if (create_item)
4114 SetDependencyObject (CreateItem ());
4119 DependencyObject *
4120 XamlElementInstanceNative::CreateItem ()
4122 XamlElementInstance *walk = parser_info->current_element;
4123 Type *type = element_info->GetType ();
4125 DependencyObject *item = NULL;
4126 DependencyProperty *dep = NULL;
4128 if (type->IsSubclassOf (Type::COLLECTION) || type->IsSubclassOf (Type::RESOURCE_DICTIONARY)) {
4129 // If we are creating a collection, try walking up the element tree,
4130 // to find the parent that we belong to and using that instance for
4131 // our collection, instead of creating a new one
4133 // We attempt to advance past the property setter, because we might be dealing with a
4134 // content element
4136 if (walk && walk->element_type == XamlElementInstance::PROPERTY) {
4137 char **prop_name = g_strsplit (walk->element_name, ".", -1);
4139 walk = walk->parent;
4140 dep = DependencyProperty::GetDependencyProperty (Type::Find (parser_info->deployment, walk->info->GetKind ()), prop_name [1]);
4142 g_strfreev (prop_name);
4143 } else if (walk && walk->info->GetContentProperty (parser_info)) {
4144 dep = DependencyProperty::GetDependencyProperty (Type::Find (parser_info->deployment, walk->info->GetKind ()),
4145 (char *) walk->info->GetContentProperty (parser_info));
4148 if (dep && Type::IsSubclassOf (parser_info->deployment, dep->GetPropertyType(), type->GetKind ())) {
4149 Value *v = ((DependencyObject * ) walk->GetAsDependencyObject ())->GetValue (dep);
4150 if (v) {
4151 item = v->AsDependencyObject ();
4152 dep = NULL;
4154 // note: if !v then the default collection is NULL (e.g. PathFigureCollection)
4158 if (!item) {
4159 item = element_info->GetType()->IsCtorVisible() ? element_info->GetType ()->CreateInstance () : NULL;
4161 if (item) {
4162 parser_info->AddCreatedElement (item);
4164 // in case we must store the collection into the parent
4165 if (dep && dep->GetPropertyType() == type->GetKind ()) {
4166 MoonError err;
4167 Value item_value (item);
4168 if (!((DependencyObject * ) walk->GetAsDependencyObject ())->SetValueWithError (dep, &item_value, &err))
4169 parser_error (parser_info, element_name, NULL, err.code, err.message);
4171 } else {
4172 parser_error (parser_info, element_name, NULL, 2007, "Unknown element: %s.", element_name);
4176 return item;
4179 bool
4180 XamlElementInstanceNative::SetProperty (XamlParserInfo *p, XamlElementInstance *property, XamlElementInstance *value)
4182 if (property->info->RequiresManagedSet () || value->info->RequiresManagedSet ())
4183 return p->loader->SetProperty (p, p->GetTopElementPtr (), NULL, GetAsValue (), this, GetParentPointer (), property->info->xmlns, property->element_name, value->GetAsValue (), NULL);
4185 return dependency_object_set_property (p, this, property, value, true);
4188 bool
4189 XamlElementInstanceNative::SetProperty (XamlParserInfo *p, XamlElementInstance *property, const char *value)
4191 char **prop_name = g_strsplit (property->element_name, ".", -1);
4192 Type *owner = Type::Find (p->deployment, prop_name [0]);
4193 DependencyProperty *dep;
4195 if (!owner)
4196 return false;
4198 dep = DependencyProperty::GetDependencyProperty (Type::Find (p->deployment, owner->GetKind ()), prop_name [1]);
4199 if (!dep)
4200 return false;
4202 return xaml_set_property_from_str (item, dep, value, NULL/*XXX*/);
4205 void
4206 XamlElementInstanceNative::AddChild (XamlParserInfo *p, XamlElementInstance *child)
4208 dependency_object_add_child (p, this, child, true);
4211 void
4212 XamlElementInstanceNative::SetAttributes (XamlParserInfo *p, const char **attr)
4214 dependency_object_set_attributes (p, this, attr);
4218 XamlElementInstanceValueType::XamlElementInstanceValueType (XamlElementInfoNative *element_info, XamlParserInfo *parser_info, const char *name, ElementType type) :
4219 XamlElementInstance (element_info, name, type)
4221 this->element_info = element_info;
4222 this->parser_info = parser_info;
4225 bool
4226 XamlElementInstanceValueType::CreateValueItemFromString (const char* str)
4229 bool res = value_from_str (element_info->GetType ()->GetKind (), NULL, str, &value);
4230 return res;
4233 void
4234 XamlElementInstanceValueType::SetAttributes (XamlParserInfo *p, const char **attr)
4236 value_type_set_attributes (p, this, attr);
4239 XamlElementInstanceEnum::XamlElementInstanceEnum (XamlElementInfoEnum *element_info, const char *name, ElementType type) :
4240 XamlElementInstance (element_info, name, type)
4244 bool
4245 XamlElementInstanceEnum::CreateEnumFromString (const char* str)
4247 int i = enums_str_to_int (element_name, str);
4248 if (i == -1)
4249 return false;
4251 value = new Value (i);
4252 return true;
4255 void
4256 XamlElementInstanceEnum::SetAttributes (XamlParserInfo *p, const char **attr)
4258 value_type_set_attributes (p, this, attr);
4261 XamlElementInstance *
4262 XamlElementInfoEnum::CreateElementInstance (XamlParserInfo *p)
4264 return new XamlElementInstanceEnum (this, name, XamlElementInstance::ELEMENT);
4267 XamlElementInstance *
4268 XamlElementInfoEnum::CreateWrappedElementInstance (XamlParserInfo *p, Value *o)
4270 XamlElementInstance *res = new XamlElementInstanceEnum (this, name, XamlElementInstance::ELEMENT);
4271 return res;
4274 const char *
4275 XamlElementInfoManaged::GetContentProperty (XamlParserInfo *p)
4277 if (!p->loader)
4278 return NULL;
4280 // TODO: We could cache this, but for now lets keep things as simple as possible.
4281 const char *res = p->loader->GetContentPropertyName (p, p->GetTopElementPtr (), obj);
4282 if (res)
4283 return res;
4284 return XamlElementInfo::GetContentProperty (p);
4287 XamlElementInstance *
4288 XamlElementInfoManaged::CreateElementInstance (XamlParserInfo *p)
4290 XamlElementInstanceManaged *inst = new XamlElementInstanceManaged (this, GetName (), XamlElementInstance::ELEMENT, obj);
4292 if (obj->Is (p->deployment, Type::DEPENDENCY_OBJECT))
4293 p->AddCreatedElement (inst->GetAsDependencyObject ());
4295 return inst;
4298 XamlElementInstance *
4299 XamlElementInfoManaged::CreateWrappedElementInstance (XamlParserInfo *p, Value *o)
4301 XamlElementInstanceManaged *inst = new XamlElementInstanceManaged (this, GetName (), XamlElementInstance::ELEMENT, o);
4303 return inst;
4306 XamlElementInstance *
4307 XamlElementInfoManaged::CreatePropertyElementInstance (XamlParserInfo *p, const char *name)
4309 XamlElementInstanceManaged *inst = new XamlElementInstanceManaged (this, name, XamlElementInstance::PROPERTY, obj);
4311 return inst;
4314 XamlElementInstanceManaged::XamlElementInstanceManaged (XamlElementInfo *info, const char *name, ElementType type, Value *obj) :
4315 XamlElementInstance (info, name, type)
4317 // The managed code owns our Value objects
4318 cleanup_value = false;
4320 this->value = obj;
4322 if (obj->Is (Deployment::GetCurrent (), Type::DEPENDENCY_OBJECT)) {
4323 this->is_dependency_object = true;
4324 this->SetDependencyObject (obj->AsDependencyObject ());
4326 else
4327 this->is_dependency_object = false;
4330 void *
4331 XamlElementInstanceManaged::GetManagedPointer ()
4333 if (value->Is (Deployment::GetCurrent (), Type::DEPENDENCY_OBJECT))
4334 return value->AsDependencyObject ();
4335 return value->AsManagedObject ();
4338 Value *
4339 XamlElementInstanceManaged::GetParentPointer ()
4341 XamlElementInstance *walk = parent;
4342 while (walk && walk->element_type != XamlElementInstance::ELEMENT)
4343 walk = walk->parent;
4345 if (!walk) {
4346 return NULL;
4349 return walk->GetAsValue ();
4352 bool
4353 XamlElementInstanceManaged::SetProperty (XamlParserInfo *p, XamlElementInstance *property, XamlElementInstance *value)
4355 if (GetAsDependencyObject () != NULL && dependency_object_set_property (p, this, property, value, false))
4356 return true;
4357 return p->loader->SetProperty (p, p->GetTopElementPtr (), info->xmlns, GetAsValue (), this, GetParentPointer (), property->info->xmlns, property->element_name, value->GetAsValue (), value);
4360 bool
4361 XamlElementInstanceManaged::SetProperty (XamlParserInfo *p, XamlElementInstance *property, const char *value)
4363 Value v = Value (value);
4364 return p->loader->SetProperty (p, p->GetTopElementPtr (), info->xmlns, GetAsValue (), this, GetParentPointer (), property->info->xmlns, property->element_name, &v, NULL);
4367 void
4368 XamlElementInstanceManaged::AddChild (XamlParserInfo *p, XamlElementInstance *child)
4370 if (element_type == XamlElementInstance::PROPERTY) {
4371 Value *prop = new Value (element_name);
4372 p->loader->AddChild (p, p->GetTopElementPtr (), GetParentPointer (), true, info->xmlns, prop, this, child->GetAsValue (), child);
4373 delete prop;
4374 return;
4377 p->loader->AddChild (p, p->GetTopElementPtr (), GetParentPointer (), false, info->xmlns, GetAsValue (), this, child->GetAsValue (), child);
4380 void
4381 XamlElementInstanceManaged::SetAttributes (XamlParserInfo *p, const char **attr)
4383 dependency_object_set_attributes (p, this, attr);
4386 bool
4387 XamlElementInstanceManaged::TrySetContentProperty (XamlParserInfo *p, XamlElementInstance *value)
4389 Value *v = value->GetAsValue ();
4390 const char* prop_name = info->GetContentProperty (p);
4392 return p->loader->SetProperty (p, p->GetTopElementPtr (), info->xmlns, GetAsValue (), this, GetParentPointer (), NULL, prop_name, v, value);
4395 bool
4396 XamlElementInstanceManaged::TrySetContentProperty (XamlParserInfo *p, const char *value)
4398 if (Type::IsSubclassOf (p->deployment, info->GetKind (), Type::CONTENTCONTROL)) {
4399 // Content controls are not allowed to have their content set as text, they need to have a child element
4400 // if you want to set the content of a contentcontrol to text you need to use attribute syntax
4401 return false;
4404 if (!XamlElementInstance::TrySetContentProperty (p, value)) {
4405 const char* prop_name = info->GetContentProperty (p);
4406 if (!p->cdata_content)
4407 return false;
4408 Value v = Value (value);
4409 bool res = p->loader->SetProperty (p, p->GetTopElementPtr (), info->xmlns, GetAsValue (), this, GetParentPointer (), NULL, prop_name, &v, NULL);
4410 return res;
4413 return false;
4416 XamlElementInstance *
4417 XamlElementInfoImportedManaged::CreateElementInstance (XamlParserInfo *p)
4419 XamlElementInstanceManaged *inst = new XamlElementInstanceManaged (this, name, XamlElementInstance::ELEMENT, obj);
4421 return inst;
4424 const char *
4425 XamlElementInfoImportedManaged::GetContentProperty (XamlParserInfo *p)
4427 if (!p->loader)
4428 return NULL;
4430 // TODO: Test, it's possible that managed objects that aren't DOs are allowed to have content properties.
4431 if (!obj->Is (p->deployment, Type::DEPENDENCY_OBJECT))
4432 return XamlElementInfo::GetContentProperty (p);
4435 // TODO: We could cache this, but for now lets keep things as simple as possible.
4436 const char *res = p->loader->GetContentPropertyName (p, p->GetTopElementPtr (), obj);
4437 if (res)
4438 return res;
4440 return XamlElementInfo::GetContentProperty (p);
4443 XamlElementInstance *
4444 XamlElementInfoImportedManaged::CreateWrappedElementInstance (XamlParserInfo *p, Value *o)
4446 XamlElementInstanceManaged *inst = new XamlElementInstanceManaged (this, Type::Find (p->deployment, o->GetKind ())->GetName (), XamlElementInstance::ELEMENT, o);
4448 return inst;
4451 XamlElementInstance *
4452 XamlElementInfoImportedManaged::CreatePropertyElementInstance (XamlParserInfo *p, const char *name)
4454 XamlElementInstanceManaged *inst = new XamlElementInstanceManaged (this, name, XamlElementInstance::PROPERTY, obj);
4456 return inst;
4461 /// Add Child funcs
4464 static const char*
4465 get_key_from_child (XamlElementInstance *child)
4467 const char *key = child->GetKey ();
4468 if (key)
4469 return key;
4471 key = child->GetName ();
4472 if (key)
4473 return key;
4475 if (child->IsDependencyObject ()) {
4476 DependencyObject *c = child->GetAsDependencyObject();
4478 if (Type::IsSubclassOf (c->GetDeployment (), Type::STYLE, child->info->GetKind ())) {
4479 Value *v = c->GetValue (Style::TargetTypeProperty);
4480 if (v && v->GetKind () == Type::MANAGEDTYPEINFO)
4481 key = v->AsManagedTypeInfo ()->full_name;
4483 if (key)
4484 return key;
4488 return NULL;
4491 static void
4492 dependency_object_add_child (XamlParserInfo *p, XamlElementInstance *parent, XamlElementInstance *child, bool fail_if_no_prop)
4494 Types *types = Deployment::GetCurrent ()->GetTypes ();
4495 if (parent->element_type == XamlElementInstance::PROPERTY) {
4497 if (parent->info->RequiresManagedSet ())
4498 return;
4500 char **prop_name = g_strsplit (parent->element_name, ".", -1);
4501 Type *owner = types->Find (prop_name [0]);
4503 if (owner) {
4504 DependencyProperty *dep = DependencyProperty::GetDependencyProperty (Type::Find (p->deployment, owner->GetKind ()), prop_name [1]);
4506 g_strfreev (prop_name);
4508 if (!dep) {
4509 g_warning ("Unknown element: %s.", parent->element_name);
4510 if (fail_if_no_prop)
4511 parser_error (p, parent->element_name, NULL, 2007, "Unknown element: %s.", parent->element_name);
4512 return;
4515 // XamlElementInfoEnum has Type::INVALID as
4516 // its kind, which is why that first check is
4517 // here.
4518 if (child->info->GetKind() != Type::MANAGED &&
4519 !types->Find (child->info->GetKind())->IsCtorVisible()) {
4520 // we can't instantiate this type
4521 return parser_error (p, child->element_name, NULL, 2007,
4522 "Unknown element: %s.", child->element_name);
4525 // Don't add the child element, if it is the entire collection
4526 if (dep->GetPropertyType() == child->info->GetKind ())
4527 return;
4529 Type::Kind prop_type = dep->GetPropertyType ();
4530 if (!types->IsSubclassOf (prop_type, Type::DEPENDENCY_OBJECT_COLLECTION)
4531 && !types->IsSubclassOf (prop_type, Type::RESOURCE_DICTIONARY))
4532 return;
4534 // Most common case, we will have a parent that we can snag the collection from
4535 DependencyObject *obj = (DependencyObject *) parent->parent->GetAsDependencyObject ();
4536 if (!obj)
4537 return;
4539 Value *col_v = obj->GetValue (dep);
4540 if (!col_v) {
4541 Type *col_type = types->Find (prop_type);
4542 DependencyObject *c_obj = col_type->CreateInstance ();
4543 obj->SetValue (dep, Value::CreateUnrefPtr (c_obj));
4544 col_v = obj->GetValue (dep);
4545 c_obj->unref ();
4547 Collection *col = col_v->AsCollection ();
4548 MoonError err;
4550 if (types->IsSubclassOf (prop_type, Type::DEPENDENCY_OBJECT_COLLECTION)) {
4551 Value child_val (child->GetAsDependencyObject ());
4552 if (-1 == col->AddWithError (&child_val, &err))
4553 return parser_error (p, child->element_name, NULL, err.code, err.message);
4555 else if (types->IsSubclassOf (prop_type, Type::RESOURCE_DICTIONARY)) {
4556 ResourceDictionary *dict = (ResourceDictionary *)col;
4558 const char *key = get_key_from_child (child);
4560 if (key == NULL) {
4561 // XXX don't know the proper values here...
4562 return parser_error (p, child->element_name, NULL, 2007,
4563 "You must specify an x:Key or x:Name for elements in a ResourceDictionary");
4566 Value *child_as_value = child->GetAsValue ();
4568 if (!child_as_value) {
4569 // XXX don't know the proper values here...
4570 return parser_error (p, child->element_name, NULL, 2007,
4571 "Error adding child to ResourceDictionary");
4574 bool added = dict->AddWithError (key, child_as_value, &err);
4575 if (!added)
4576 return parser_error (p, child->element_name, NULL, err.code, err.message);
4579 return;
4582 return;
4585 if (types->IsSubclassOf (parent->info->GetKind (), Type::DEPENDENCY_OBJECT_COLLECTION)) {
4586 Collection *col = (Collection *) parent->GetAsDependencyObject ();
4587 MoonError err;
4588 Value child_val ((DependencyObject*)child->GetAsDependencyObject ());
4590 if (-1 == col->AddWithError (&child_val, &err))
4591 return parser_error (p, child->element_name, NULL, err.code, err.message);
4592 return;
4594 else if (types->IsSubclassOf (parent->info->GetKind (), Type::RESOURCE_DICTIONARY)) {
4595 ResourceDictionary *dict = (ResourceDictionary *) parent->GetAsDependencyObject ();
4597 MoonError err;
4598 const char *key = get_key_from_child (child);
4600 if (key == NULL) {
4601 // XXX don't know the proper values here...
4602 return parser_error (p, child->element_name, NULL, 2007,
4603 "You must specify an x:Key or x:Name for elements in a ResourceDictionary");
4606 Value *child_as_value = child->GetAsValue ();
4607 bool added = dict->AddWithError (key, child_as_value, &err);
4608 if (!added)
4609 return parser_error (p, child->element_name, NULL, err.code, err.message);
4613 if (parent->element_type != XamlElementInstance::PROPERTY) {
4614 parent->TrySetContentProperty (p, child);
4617 // Do nothing if we aren't adding to a collection, or a content property collection
4622 /// set property funcs
4625 // these are just a bunch of special cases
4626 static void
4627 dependency_object_missed_property (XamlElementInstance *item, XamlElementInstance *prop, XamlElementInstance *value, char **prop_name)
4632 static bool
4633 set_managed_attached_property (XamlParserInfo *p, XamlElementInstance *item, XamlElementInstance *prop, XamlElementInstance *value)
4635 if (!p->loader)
4636 return false;
4638 return p->loader->SetProperty (p, p->GetTopElementPtr (), item->info->xmlns, item->GetAsValue (), item, item->GetParentPointer (), prop->info->xmlns, prop->element_name, value->GetAsValue (), value);
4641 static bool
4642 dependency_object_set_property (XamlParserInfo *p, XamlElementInstance *item, XamlElementInstance *property, XamlElementInstance *value, bool raise_errors)
4644 char **prop_name = g_strsplit (property->element_name, ".", -1);
4645 DependencyObject *dep = item->GetAsDependencyObject ();
4646 DependencyProperty *prop = NULL;
4647 bool res;
4648 Types *types = Deployment::GetCurrent ()->GetTypes ();
4650 if (types->Find (item->info->GetKind ())->IsValueType ()) {
4651 if (raise_errors) parser_error (p, item->element_name, NULL, -1, "Value types (%s) do not have properties.", property->element_name);
4652 g_strfreev (prop_name);
4653 return false;
4656 if (types->Find (property->info->GetPropertyOwnerKind ())->IsCustomType ()) {
4657 g_strfreev (prop_name);
4658 return set_managed_attached_property (p, item, property, value);
4661 if (!dep) {
4662 // FIXME is this really where this check should live
4663 if (raise_errors)
4664 parser_error (p, item->element_name, NULL, 2030,
4665 "Property element %s cannot be used inside another property element.",
4666 property->element_name);
4668 g_strfreev (prop_name);
4669 return false;
4672 prop = DependencyProperty::GetDependencyProperty (Type::Find (p->deployment, item->info->GetKind ()), prop_name [1]);
4674 if (prop) {
4675 if (prop->IsReadOnly ()) {
4676 if (raise_errors)
4677 parser_error (p, item->element_name, NULL, 2014,
4678 "The attribute %s is read only and cannot be set.", prop->GetName ());
4679 res = false;
4680 } else if (types->IsSubclassOf (value->info->GetKind (), prop->GetPropertyType())) {
4681 // an empty collection can be NULL and valid
4682 if (item->IsPropertySet (prop->GetName())) {
4683 if (raise_errors)
4684 parser_error (p, item->element_name, NULL, 2033,
4685 "Cannot specify the value multiple times for property: %s.",
4686 property->element_name);
4687 res = false;
4688 } else {
4689 MoonError err;
4691 // HACK - since the Setter is added to the collection *before* its properties are set
4692 // we find ourselves with a sealed Setter - which should not be possible at the parse time
4693 SetterBase *sb = NULL;
4694 if (types->IsSubclassOf (dep->GetObjectType (), Type::SETTERBASE)) {
4695 sb = (SetterBase*) dep;
4696 sb->SetIsSealed (false);
4699 if (!is_managed_kind (value->info->GetKind ()) && !value->info->RequiresManagedSet()) {
4700 if (!dep->SetValueWithError (prop, value->GetAsValue (), &err)) {
4701 if (raise_errors)
4702 parser_error (p, item->element_name, NULL, err.code, err.message);
4703 res = false;
4704 goto cleanup;
4707 } else {
4708 if (!p->loader->SetProperty (p, p->GetTopElementPtr (), NULL, item->GetAsValue (), item, item->GetParentPointer (), NULL, prop_name [1], value->GetAsValue (), NULL)) {
4709 if (raise_errors)
4710 parser_error (p, item->element_name, NULL, err.code, err.message);
4711 res = false;
4712 goto cleanup;
4717 // re-seal the Setter (end-HACK)
4718 if (sb)
4719 sb->SetIsSealed (true);
4721 item->MarkPropertyAsSet (prop->GetName());
4722 res = true;
4724 } else if (types->IsSubclassOf (prop->GetPropertyType (), Type::COLLECTION) || types->IsSubclassOf (prop->GetPropertyType (), Type::RESOURCE_DICTIONARY)) {
4725 // The items were added in add_child
4726 return true;
4727 } else {
4728 if (raise_errors)
4729 parser_error (p, item->element_name, NULL, 2010, "does not support %s as content.", value->element_name);
4730 res = false;
4732 } else {
4733 dependency_object_missed_property (item, property, value, prop_name);
4734 res = false;
4737 cleanup:
4738 g_strfreev (prop_name);
4739 return res;
4742 bool
4743 xaml_set_property_from_str (DependencyObject *obj, DependencyProperty *prop, const char *value, MoonError *error)
4745 Value *v = NULL;
4746 bool rv = true;
4748 if (!value_from_str (prop->GetPropertyType(), prop->GetName(), value, &v))
4749 return false;
4751 // it's possible for (a valid) value to be NULL (and we must keep the default value)
4752 if (v) {
4753 rv = obj->SetValueWithError (prop, v, error);
4754 delete v;
4757 return rv;
4760 bool
4761 xaml_is_valid_event_name (Deployment *deployment, Type::Kind kind, const char *name, bool allow_desktop_events)
4763 Type *type = Type::Find (deployment, kind);
4764 if (!type)
4765 return false;
4767 int event_id = type->LookupEvent (name);
4768 if (event_id == -1)
4769 return false;
4771 if (!allow_desktop_events || (moonlight_flags & RUNTIME_INIT_DESKTOP_EXTENSIONS) == 0) {
4772 // if we're not allowing desktop-only events, or if the user hasn't allowed them,
4773 // return false if the name corresponds to one of them.
4774 if (!strcmp (name, "MouseRightButtonDown") ||
4775 !strcmp (name, "MouseRightButtonUp") ||
4776 !strcmp (name, "MouseWheel"))
4777 return false;
4780 return true;
4783 static void
4784 value_type_set_attributes (XamlParserInfo *p, XamlElementInstance *item, const char **attr)
4786 // the only attributes value on value types seem to be x:Key
4787 // and x:Name, but reuse the generic namespace attribute stuff
4788 // anyway.
4790 for (int i = 0; attr [i]; i += 2) {
4791 // Skip empty attrs
4792 if (attr[i + 1] == NULL || attr[i + 1][0] == '\0')
4793 continue;
4795 char **attr_name = g_strsplit (attr [i], "|", -1);
4797 if (attr_name [1]) {
4799 XamlNamespace *ns = (XamlNamespace *) g_hash_table_lookup (p->namespace_map, attr_name [0]);
4801 if (!ns)
4802 return parser_error (p, item->element_name, attr[i], 7055, "undeclared prefix");
4804 ns->SetAttribute (p, item, attr_name [1], attr [i + 1]);
4806 g_strfreev (attr_name);
4808 // Setting managed attributes can cause errors galore
4809 if (p->error_args)
4810 return;
4812 continue;
4815 g_strfreev (attr_name);
4819 static void
4820 dependency_object_set_attributes (XamlParserInfo *p, XamlElementInstance *item, const char **attr)
4822 Types *types = Deployment::GetCurrent ()->GetTypes ();
4823 GList *delay_att = NULL;
4825 for (int i = 0; attr [i]; i += 2) {
4827 if (p->error_args)
4828 return;
4830 // Setting attributes like x:Class can change item->item, so we
4831 // need to make sure we have an up to date pointer
4832 DependencyObject *dep = item->GetAsDependencyObject ();
4833 char **attr_name = g_strsplit (attr [i], "|", -1);
4835 if (attr_name [1]) {
4836 XamlNamespace *ns = (XamlNamespace *) g_hash_table_lookup (p->namespace_map, attr_name [0]);
4838 if (ns != x_namespace) {
4839 delay_att = g_list_append (delay_att, GINT_TO_POINTER (i));
4840 g_strfreev (attr_name);
4841 continue;
4844 if (!ns) {
4845 g_strfreev (attr_name);
4846 return parser_error (p, item->element_name, attr[i], 5055, "undeclared prefix");
4849 ns->SetAttribute (p, item, attr_name [1], attr [i + 1]);
4851 g_strfreev (attr_name);
4853 // Setting managed attributes can cause errors galore
4854 if (p->error_args)
4855 return;
4857 continue;
4860 g_strfreev (attr_name);
4862 const char *pname = attr [i];
4863 char *atchname = NULL;
4864 for (int a = 0; attr [i][a]; a++) {
4865 if (attr [i][a] != '.')
4866 continue;
4867 atchname = g_strndup (attr [i], a);
4868 pname = attr [i] + a + 1;
4869 break;
4872 DependencyProperty *prop = NULL;
4873 if (atchname) {
4874 Type *attached_type = types->Find (atchname);
4875 if (attached_type)
4876 prop = DependencyProperty::GetDependencyProperty (attached_type, pname);
4877 } else {
4878 prop = DependencyProperty::GetDependencyProperty (Type::Find (p->deployment, item->info->GetKind ()), pname);
4881 if (prop) {
4882 if (prop->GetId () == DependencyObject::NameProperty) {
4884 if (item->GetName ()) {
4885 parser_error (p, item->element_name, NULL, 2016, "Cannot specify both Name and x:Name attributes.");
4886 return;
4889 // XXX toshok - I don't like doing this here... but it fixes airlines.
4890 item->SetKey (p, attr[i+1]);
4892 NameScope *scope = p->namescope;
4893 if (!item->GetAsDependencyObject ()->SetName (attr [i+1], scope)) {
4894 parser_error (p, item->element_name, NULL, 2028,
4895 "The name already exists in the tree: %s.", attr [i+1]);
4896 g_free (atchname);
4897 g_list_free (delay_att);
4898 return;
4900 continue;
4903 if (prop->IsReadOnly ()) {
4904 parser_error (p, item->element_name, NULL, 2014,
4905 "The attribute %s is read only and cannot be set.", prop->GetName ());
4906 g_free (atchname);
4907 g_list_free (delay_att);
4908 return;
4911 if (item->IsPropertySet (prop->GetName())) {
4912 parser_error (p, item->element_name, attr [i], 2033,
4913 "Cannot specify the value multiple times for property: %s.", prop->GetName ());
4914 g_free (atchname);
4915 g_list_free (delay_att);
4916 return;
4919 Value *v = NULL;
4920 bool v_set = false;
4921 char *attr_value = g_strdup (attr [i+1]);
4923 bool need_managed = false;
4924 if (attr[i+1][0] == '{') {
4925 if (attr[i+1][1] == '}') {
4926 // {} is an escape sequence so you can have strings like {StaticResource}
4927 char *nv = attr_value;
4928 attr_value = g_strdup (attr_value + 2);
4929 g_free (nv);
4931 else if (attr[i+1][strlen(attr[i+1]) - 1] == '}') {
4932 need_managed = true;
4936 if (!need_managed) {
4937 if (!value_from_str_with_parser (p, prop->GetPropertyType(), prop->GetName(), attr_value, &v, &v_set)) {
4938 delete v;
4939 g_free (attr_value);
4940 continue;
4944 Type::Kind propKind = prop->GetPropertyType ();
4946 if (need_managed || is_managed_kind (propKind) || types->Find (prop->GetOwnerType ())->IsCustomType () || (v && is_managed_kind (v->GetKind ()))) {
4947 bool str_value = false;
4948 if (!v_set) {
4949 v = new Value (attr [i + 1]); // Note that we passed the non escaped value, not attr_value
4950 v_set = true;
4951 str_value = true;
4954 // printf ("setting managed property: %s::%s to %s=%s\n", dep->GetType ()->GetName (), prop->GetName (), attr [i], attr [i + 1]);
4955 if (p->loader->SetProperty (p, p->GetTopElementPtr (), NULL, item->GetAsValue (), item, item->GetParentPointer (), NULL, g_strdup (attr [i]), v, NULL)) {
4956 delete v;
4957 g_free (attr_value);
4958 continue;
4959 } else {
4960 if (str_value) {
4961 delete v;
4962 v = NULL;
4964 if (!value_from_str_with_parser (p, prop->GetPropertyType(), prop->GetName(), attr_value, &v, &v_set)) {
4965 delete v;
4966 g_free (attr_value);
4967 continue;
4973 if (!v_set && !value_is_explicit_null (attr [i + 1])) { // Check the non escaped value
4974 parser_error (p, item->element_name, attr [i], 2024, "Invalid attribute value %s for property %s.", attr [i+1], attr [i]);
4976 g_free (attr_value);
4977 g_free (atchname);
4978 g_list_free (delay_att);
4979 return;
4982 MoonError err;
4983 // 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 ());
4984 if (!dep->SetValueWithError (prop, v, &err))
4985 parser_error (p, item->element_name, attr [i], err.code, err.message);
4986 else
4987 item->MarkPropertyAsSet (prop->GetName());
4989 delete v;
4990 g_free (attr_value);
4991 } else {
4992 delay_att = g_list_append (delay_att, GINT_TO_POINTER (i));
4995 if (atchname)
4996 g_free (atchname);
4999 GList *walk = g_list_first (delay_att);
5000 while (walk) {
5001 int i = GPOINTER_TO_INT (walk->data);
5003 if (p->error_args)
5004 return;
5006 char **attr_name = g_strsplit (attr [i], "|", -1);
5008 if (attr_name [1]) {
5009 XamlNamespace *ns = (XamlNamespace *) g_hash_table_lookup (p->namespace_map, attr_name [0]);
5011 if (ns == x_namespace) {
5012 // Skip these, they are handled earlier
5013 g_strfreev (attr_name);
5014 walk = walk->prev;
5017 if (!ns) {
5018 g_strfreev (attr_name);
5019 parser_error (p, item->element_name, attr[i], 5055, "undeclared prefix");
5020 break;
5023 ns->SetAttribute (p, item, attr_name [1], attr [i + 1]);
5025 g_strfreev (attr_name);
5027 // Setting managed attributes can cause errors galore
5028 if (p->error_args)
5029 break;
5030 } else {
5031 if (!item->SetUnknownAttribute (p, attr [i], attr [i + 1])) {
5032 parser_error (p, item->element_name, attr [i], 2012,
5033 "Unknown attribute %s on element %s.",
5034 attr [i], item->element_name);
5035 break;
5039 walk = walk->next;
5042 g_list_free (delay_att);
5046 static Value *
5047 lookup_named_item (XamlElementInstance *top, const char *name)
5049 Types *types = Deployment::GetCurrent ()->GetTypes ();
5050 XamlElementInstance *inst = top;
5052 while (inst) {
5053 if (inst->element_type == XamlElementInstance::ELEMENT) {
5054 ResourceDictionary *rd = NULL;
5055 Type::Kind kind = inst->info->GetKind ();
5057 if (types->IsSubclassOf (kind, Type::FRAMEWORKELEMENT)) {
5058 rd = inst->GetAsDependencyObject ()->GetValue (UIElement::ResourcesProperty)->AsResourceDictionary ();
5059 } else if (types->IsSubclassOf (kind, Type::RESOURCE_DICTIONARY)) {
5060 rd = (ResourceDictionary*) inst->GetAsDependencyObject ();
5063 if (rd) {
5064 bool exists;
5065 Value *res = lookup_resource_dictionary (rd, name, &exists);
5066 if (exists)
5067 return res;
5071 inst = inst->parent;
5074 return NULL;
5077 static Value *
5078 lookup_resource_dictionary (ResourceDictionary *rd, const char *name, bool *exists)
5080 *exists = false;
5081 Value *resource_value = rd->Get (name, exists);
5082 return *exists ? new Value (*resource_value) : NULL;
5085 Value *
5086 xaml_lookup_named_item (void *parser, void *instance, const char* name)
5088 XamlParserInfo *p = (XamlParserInfo *) parser;
5089 XamlElementInstance *inst = (XamlElementInstance *) instance;
5090 Value *res = NULL;
5092 if (inst)
5093 res = lookup_named_item (inst, name);
5095 XamlContext *context = p->loader->GetContext ();
5096 if (!res && context)
5097 context->internal->LookupNamedItem (name, &res);
5099 if (!res) {
5100 Application *app = Application::GetCurrent ();
5101 if (app) {
5102 ResourceDictionary *rd = app->GetResources ();
5104 bool exists = false;
5105 res = lookup_resource_dictionary (rd, name, &exists);
5107 if (res && Type::IsSubclassOf (p->deployment, res->GetKind (), Type::DEPENDENCY_OBJECT)) {
5108 DependencyObject *dob = res->AsDependencyObject ();
5109 NameScope::SetNameScope (dob, dob->FindNameScope ());
5114 return res;
5117 void *
5118 xaml_get_template_parent (void *parser, void *element_instance)
5120 XamlParserInfo *p = (XamlParserInfo *) parser;
5121 XamlElementInstance *item = (XamlElementInstance *) element_instance;
5123 return p->GetTemplateParent (item);
5126 char *
5127 xaml_get_element_key (void *parser, void *element_instance)
5129 XamlElementInstance *item = (XamlElementInstance *) element_instance;
5130 const char *key = item->GetKey ();
5131 if (!key)
5132 key = item->GetName ();
5133 return g_strdup (key);
5136 char *
5137 xaml_get_element_name (void *parser, void *element_instance)
5139 XamlElementInstance *item = (XamlElementInstance *) element_instance;
5140 return g_strdup (item->element_name);
5143 bool
5144 xaml_is_property_set (void *parser, void *element_instance, char *name)
5146 XamlElementInstance *item = (XamlElementInstance *) element_instance;
5147 return item->IsPropertySet (name);
5150 void
5151 xaml_mark_property_as_set (void *parser, void *element_instance, char *name)
5153 XamlElementInstance *item = (XamlElementInstance *) element_instance;
5154 item->MarkPropertyAsSet (g_strdup (name));
5157 void
5158 xaml_delay_set_property (void *parser, void *element_instance, const char *xmlns, const char *name, const Value *value)
5160 XamlElementInstance *item = (XamlElementInstance *) element_instance;
5161 item->DelaySetProperty (xmlns, name, value);
5164 void
5165 xaml_init (void)
5167 default_namespace = new DefaultNamespace ();
5168 x_namespace = new XNamespace ();
5169 xml_namespace = new XmlNamespace ();