5
// Michael Hutchinson <mhutchinson@novell.com>
7
// Copyright (c) 2009 Novell, Inc. (http://www.novell.com)
9
// Permission is hereby granted, free of charge, to any person obtaining a copy
10
// of this software and associated documentation files (the "Software"), to deal
11
// in the Software without restriction, including without limitation the rights
12
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
// copies of the Software, and to permit persons to whom the Software is
14
// furnished to do so, subject to the following conditions:
16
// The above copyright notice and this permission notice shall be included in
17
// all copies or substantial portions of the Software.
19
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28
using System.Xml.Linq;
30
using System.Collections.Generic;
31
using System.Globalization;
33
namespace MonoDevelop.MacDev.InterfaceBuilder
35
public abstract class IBObject
37
public bool EncodedWithXMLCoder { get; set; }
39
public int? Id { get; private set; }
41
protected void DeserializeContents (IEnumerable<XElement> children,
42
Dictionary<string, Func<IBObject>> constructors, IReferenceResolver resolver)
44
foreach (XElement child in children) {
45
XAttribute keyAtt = child.Attribute ("key");
46
string keyStr = keyAtt == null? null : keyAtt.Value;
47
if (child.Name == "bool" && keyStr == "EncodedWithXMLCoder") {
48
EncodedWithXMLCoder = child.Value == "YES";
50
object val = Deserialize (child, constructors, resolver);
52
OnPropertyDeserialized (keyStr, val, resolver);
53
} catch (Exception ex) {
54
MonoDevelop.Core.LoggingService.LogWarning (
55
"IB Parser: Error assigning {0}={1} to {2} in id {3}:\n{4}",
56
keyStr, val, GetType (), Id, ex);
62
protected virtual void OnPropertyDeserialized (string name, object value, IReferenceResolver resolver)
64
throw new InvalidOperationException (String.Format ("Unexpected property '{0}' of type '{1}' in type '{2}'",
65
name, value.GetType (), GetType ()));
68
public static object Deserialize (XElement element, Dictionary<string, Func<IBObject>> constructors, IReferenceResolver resolver)
70
var idAtt = element.Attribute ("id");
71
object val = DeserializeInner (element, constructors, resolver);
72
var ib = val as IBObject;
75
int id = Int32.Parse (idAtt.Value, CultureInfo.InvariantCulture);
80
resolver.Add (id, val);
85
ib.DeserializeContents (element.Elements (), constructors, resolver);
90
static object DeserializeInner (XElement element, Dictionary<string, Func<IBObject>> constructors, IReferenceResolver resolver)
92
switch (element.Name.ToString ()) {
94
return Int32.Parse (element.Value, CultureInfo.InvariantCulture);
96
return Int32.Parse (element.Attribute ("value").Value, CultureInfo.InvariantCulture);
100
XAttribute typeAtt = element.Attribute ("type");
101
if (typeAtt != null) {
102
switch (typeAtt.Value) {
104
//FIXME: figure out the encoding they're using. why do we have to remove the last char to make it decode?
105
string s = element.Value.Replace ("\n", "").Replace ("\r", "");
106
int last = (s.Length / 4 ) * 4;
107
return Encoding.UTF8.GetString (Convert.FromBase64String (s.Substring (0, last)));
109
throw new Exception (String.Format ("Unknown string encoding type {0}", typeAtt.Value));
112
return element.Value;
114
return element.Value;
116
return element.Value == "YES";
118
return element.Attribute ("value").Value == "YES";
120
return Double.Parse (element.Value, CultureInfo.InvariantCulture);
122
return float.Parse (element.Value, CultureInfo.InvariantCulture);
124
return float.Parse (element.Attribute ("value").Value, CultureInfo.InvariantCulture);
126
//FIXME: figure out the encoding they're using. it's not straight base 64
127
return new AppleEvilByteArrayEncoding (element.Value);
129
var refAtt = element.Attribute ("ref");
131
if (refAtt != null) {
132
xibRef = new IBReference (Int32.Parse (refAtt.Value, CultureInfo.InvariantCulture));
133
resolver.Add (xibRef);
135
//FIXME: handle null references more robustly
136
xibRef = new IBReference (Int32.MinValue);
140
var className = (string) element.Attribute ("class");
141
Func<IBObject> constructor;
143
if (constructors.TryGetValue (className, out constructor))
144
obj = constructor ();
146
obj = new UnknownIBObject (className);
150
var className = (string) element.Attribute ("class");
151
if (className == null)
152
return new NSArray ();
153
else if (className == "NSMutableArray")
154
return new NSMutableArray ();
155
throw new InvalidOperationException ("Unknown array class '" + className + "'");
158
var className = (string) element.Attribute ("class");
159
if (className == "NSMutableDictionary")
160
return new NSMutableDictionaryDirect ();
161
throw new InvalidOperationException ("Unknown dictionary class '" + className + "'");
164
throw new Exception (String.Format ("Cannot handle primitive type {0}", element.Name));
169
struct AppleEvilByteArrayEncoding
172
public AppleEvilByteArrayEncoding (string text)
182
public class IBProxyObject : IBObject
184
public string IBProxiedObjectIdentifier { get; set; }
185
public string TargetRuntimeIdentifier { get; set; }
187
protected override void OnPropertyDeserialized (string name, object value, IReferenceResolver resolver)
189
if (name == "IBProxiedObjectIdentifier")
190
IBProxiedObjectIdentifier = (string) value;
191
else if (name == "targetRuntimeIdentifier")
192
TargetRuntimeIdentifier = (string) value;
194
base.OnPropertyDeserialized (name, value, resolver);