From 7345e8259d636e5765bb13beef9160d17acee383 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sun, 8 Apr 2012 16:39:53 +0200 Subject: [PATCH] BAML decompiler: introduce proxy for unknown named types - closes #298 --- .../TypeDeclaration.cs | 106 +++++++++++++----- .../XmlBamlReader.cs | 44 ++++---- .../XmlPIMapping.cs | 27 ++--- ILSpy/ILSpy.csproj | 3 +- 4 files changed, 110 insertions(+), 70 deletions(-) diff --git a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/TypeDeclaration.cs b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/TypeDeclaration.cs index e42dd24ce..95ae027ab 100644 --- a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/TypeDeclaration.cs +++ b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/TypeDeclaration.cs @@ -5,44 +5,43 @@ using System; namespace Ricciolo.StylesExplorer.MarkupReflection { - internal class TypeDeclaration + class TypeDeclaration { - private readonly XmlBamlReader reader; - private readonly bool _isExtension; - private IType _type; - private bool _typeLoaded; - private readonly ITypeResolver resolver; + readonly XmlBamlReader reader; + readonly bool _isExtension; + IType _type; + bool _typeLoaded; + readonly ITypeResolver resolver; + + protected TypeDeclaration(ITypeResolver resolver) + { + this.resolver = resolver; + } public TypeDeclaration(ITypeResolver resolver, string name, string namespaceName, short assemblyId) - : this(null, resolver, name, namespaceName, assemblyId, true) + : this(null, resolver, name, namespaceName, assemblyId) { } public TypeDeclaration(ITypeResolver resolver, string name, string enclosingTypeName, string namespaceName, short assemblyId) - : this(null, resolver, name, namespaceName, assemblyId, true) + : this(null, resolver, name, namespaceName, assemblyId) { this.EnclosingTypeName = enclosingTypeName; } public TypeDeclaration(ITypeResolver resolver, string name, string namespaceName, short assemblyId, bool isExtension) - : this(null, resolver, name, namespaceName, assemblyId, true) + : this(null, resolver, name, namespaceName, assemblyId) { _isExtension = isExtension; } public TypeDeclaration(XmlBamlReader reader, ITypeResolver resolver, string name, string namespaceName, short assemblyId) - : this(reader, resolver, name, namespaceName, assemblyId, true) - { - } - - public TypeDeclaration(XmlBamlReader reader, ITypeResolver resolver, string name, string namespaceName, short assemblyId, bool isKnown) { this.reader = reader; this.resolver = resolver; this.Name = name; this.Namespace = namespaceName; this.AssemblyId = assemblyId; - this.IsKnown = isKnown; if (!_isExtension) _isExtension = name.EndsWith("Extension"); @@ -53,14 +52,14 @@ namespace Ricciolo.StylesExplorer.MarkupReflection return this.Name; } - public string EnclosingTypeName { get; private set; } + protected virtual string EnclosingTypeName { get; set; } public bool IsExtension { get { return _isExtension; } } - public string Assembly + public virtual string Assembly { get { if (reader != null) @@ -70,17 +69,13 @@ namespace Ricciolo.StylesExplorer.MarkupReflection } } - public short AssemblyId { get; private set; } + public virtual short AssemblyId { get; protected set; } - public string Name { get; private set; } - - public bool IsKnown { get; private set; } + public virtual string Name { get; protected set; } public IType Type { - get - { - if (!_typeLoaded) - { + get { + if (!_typeLoaded) { if (this.Name.Length > 0) _type = resolver.GetTypeByAssemblyQualifiedName(AssemblyQualifiedName); _typeLoaded = true; @@ -90,7 +85,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection } } - public string Namespace { get; private set; } + public virtual string Namespace { get; protected set; } public string FullyQualifiedName { get { return EnclosingTypeName == null ? string.Format("{0}.{1}", Namespace, Name) : string.Format("{0}.{1}+{2}", Namespace, EnclosingTypeName, Name); } @@ -103,10 +98,10 @@ namespace Ricciolo.StylesExplorer.MarkupReflection public override bool Equals(object obj) { TypeDeclaration td = obj as TypeDeclaration; - if (td != null) + if (td != null && !(obj is ResolverTypeDeclaration)) return (this.Name == td.Name && this.EnclosingTypeName == td.EnclosingTypeName && this.Namespace == td.Namespace && this.AssemblyId == td.AssemblyId); - else - return false; + + return false; } public override int GetHashCode() @@ -115,4 +110,57 @@ namespace Ricciolo.StylesExplorer.MarkupReflection } } + class ResolverTypeDeclaration : TypeDeclaration + { + string assembly; + + public override short AssemblyId { + get { throw new NotSupportedException(); } + protected set { throw new NotSupportedException(); } + } + + public ResolverTypeDeclaration(ITypeResolver resolver, string assemblyQualifiedName) + : base(resolver) + { + string name, @namespace, assembly; + ParseName(assemblyQualifiedName, out name, out @namespace, out assembly); + Name = name; + Namespace = @namespace; + this.assembly = assembly; + } + + void ParseName(string assemblyQualifiedName, out string name, out string @namespace, out string assembly) + { + int commaSeparator = assemblyQualifiedName.IndexOf(", "); + assembly = ""; + if (commaSeparator >= 0) { + assembly = assemblyQualifiedName.Substring(commaSeparator + 2); + assemblyQualifiedName = assemblyQualifiedName.Remove(commaSeparator); + } + int namespaceSeparator = assemblyQualifiedName.LastIndexOf('.'); + @namespace = ""; + if (namespaceSeparator >= 0) { + @namespace = assemblyQualifiedName.Substring(0, namespaceSeparator); + } + name = assemblyQualifiedName.Substring(namespaceSeparator + 1); + } + + public override string Assembly { + get { return assembly; } + } + + public override bool Equals(object obj) + { + ResolverTypeDeclaration td = obj as ResolverTypeDeclaration; + if (td != null) + return (this.Name == td.Name && this.EnclosingTypeName == td.EnclosingTypeName && this.Namespace == td.Namespace); + + return false; + } + + public override int GetHashCode() + { + return this.Name.GetHashCode() ^ this.EnclosingTypeName.GetHashCode() ^ this.Namespace.GetHashCode(); + } + } } diff --git a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs index 0c1ec8712..a8d7d8ba0 100644 --- a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs +++ b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs @@ -968,7 +968,8 @@ namespace Ricciolo.StylesExplorer.MarkupReflection string recordName = this.stringTable[identifier]; if (recordName != "Key") throw new NotSupportedException(recordName); pd = new PropertyDeclaration(recordName, XamlTypeDeclaration); - + if (keys == null) + keys = new List(); keys.Add(new KeyMapping(text) { Position = -1 }); break; } @@ -1020,7 +1021,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection if (mappingToChange == null) throw new InvalidOperationException("Cannot find mapping"); - @namespace = String.Format("{0};assembly={1}", @namespace, GetAssembly(mappingToChange.AssemblyId).Replace(" ", "")); + @namespace = String.Format("{0};assembly={1}", @namespace, mappingToChange.Assembly.Replace(" ", "")); mappingToChange.XmlNamespace = @namespace; } namespaces.Add(new XmlNamespace(prefix, @namespace)); @@ -1247,18 +1248,14 @@ namespace Ricciolo.StylesExplorer.MarkupReflection XmlPIMapping FindByClrNamespaceAndAssemblyId(TypeDeclaration declaration) { - return FindByClrNamespaceAndAssemblyId(declaration.Namespace, declaration.AssemblyId); + return FindByClrNamespaceAndAssemblyName(declaration.Namespace, declaration.Assembly); } - - XmlPIMapping FindByClrNamespaceAndAssemblyId(string clrNamespace, int assemblyId) + + XmlPIMapping FindByClrNamespaceAndAssemblyName(string clrNamespace, string assemblyName) { - if (clrNamespace == XamlTypeDeclaration.Namespace && assemblyId == XamlTypeDeclaration.AssemblyId) - return new XmlPIMapping(XmlPIMapping.XamlNamespace, 0, clrNamespace); - - for (int x = 0; x < Mappings.Count; x++) - { + for (int x = 0; x < Mappings.Count; x++) { XmlPIMapping xp = Mappings[x]; - if (xp.AssemblyId == assemblyId && String.CompareOrdinal(xp.ClrNamespace, clrNamespace) == 0) + if (string.Equals(xp.Assembly, assemblyName, StringComparison.Ordinal) && string.Equals(xp.ClrNamespace, clrNamespace, StringComparison.Ordinal)) return xp; } @@ -1271,7 +1268,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection string clrNamespace = reader.ReadString(); short assemblyId = reader.ReadInt16(); - Mappings.Add(new XmlPIMapping(xmlNamespace, assemblyId, clrNamespace)); + Mappings.Add(new XmlPIMapping(xmlNamespace, GetAssembly(assemblyId), clrNamespace)); } void ReadContentProperty() @@ -1452,7 +1449,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection string FormatTypeDeclaration(TypeDeclaration typeDeclaration) { - XmlPIMapping mapping = FindByClrNamespaceAndAssemblyId(typeDeclaration.Namespace, typeDeclaration.AssemblyId); + XmlPIMapping mapping = FindByClrNamespaceAndAssemblyName(typeDeclaration.Namespace, typeDeclaration.Assembly); string prefix = (mapping != null) ? this.LookupPrefix(mapping.XmlNamespace, false) : null; string name = typeDeclaration.Name; if (name.EndsWith("Extension")) @@ -1479,7 +1476,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection bool differentType = ((propertyDeclaration.DeclaringType != propertyDeclaration.DeclaringType || !isDescendant)); if (withPrefix) { - XmlPIMapping mapping = FindByClrNamespaceAndAssemblyId(propertyDeclaration.DeclaringType.Namespace, propertyDeclaration.DeclaringType.AssemblyId); + XmlPIMapping mapping = FindByClrNamespaceAndAssemblyName(propertyDeclaration.DeclaringType.Namespace, propertyDeclaration.DeclaringType.Assembly); string prefix = (mapping != null) ? this.LookupPrefix(mapping.XmlNamespace, false) : null; if (!String.IsNullOrEmpty(prefix)) { @@ -1519,7 +1516,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection return keys[currentKey - 1].StaticResources[(int)identifier]; // return "???" + identifier + "???"; - throw new ArgumentException("Cannot find StaticResource", "identifier"); + throw new ArgumentException("Cannot find StaticResource: " + identifier, "identifier"); } void ReadTextWithConverter() @@ -1542,11 +1539,11 @@ namespace Ricciolo.StylesExplorer.MarkupReflection { string name = fullName.Substring(length + 1); string namespaceName = fullName.Substring(0, length); - declaration = new TypeDeclaration(this, this.Resolver, name, namespaceName, assemblyId, false); + declaration = new TypeDeclaration(this, this.Resolver, name, namespaceName, assemblyId); } else { - declaration = new TypeDeclaration(this, this.Resolver, fullName, string.Empty, assemblyId, false); + declaration = new TypeDeclaration(this, this.Resolver, fullName, string.Empty, assemblyId); } this.typeTable.Add(typeId, declaration); } @@ -1579,14 +1576,13 @@ namespace Ricciolo.StylesExplorer.MarkupReflection return declaration; } - TypeDeclaration GetKnownTypeDeclarationByName(string name) + TypeDeclaration GetKnownTypeDeclarationByName(string assemblyQualifiedName) { foreach (var type in KnownInfo.KnownTypeTable) { - if (name == type.AssemblyQualifiedName) + if (assemblyQualifiedName == type.AssemblyQualifiedName) return type; } - - throw new NotSupportedException("Type '" + name + "' not found!"); + return new ResolverTypeDeclaration(_resolver, assemblyQualifiedName); } internal string GetAssembly(short identifier) @@ -1616,8 +1612,8 @@ namespace Ricciolo.StylesExplorer.MarkupReflection declaration = ((XmlBamlProperty)node).PropertyDeclaration.DeclaringType; TypeDeclaration elementDeclaration = this.readingElements.Peek().TypeDeclaration; - XmlPIMapping propertyMapping = FindByClrNamespaceAndAssemblyId(declaration) ?? XmlPIMapping.Presentation; - XmlPIMapping elementMapping = FindByClrNamespaceAndAssemblyId(elementDeclaration) ?? XmlPIMapping.Presentation; + XmlPIMapping propertyMapping = FindByClrNamespaceAndAssemblyId(declaration) ?? XmlPIMapping.GetPresentationMapping(GetAssembly); + XmlPIMapping elementMapping = FindByClrNamespaceAndAssemblyId(elementDeclaration) ?? XmlPIMapping.GetPresentationMapping(GetAssembly); if (((XmlBamlProperty)node).PropertyDeclaration.Name == "Name" && _resolver.IsLocalAssembly(((XmlBamlProperty)node).Parent.TypeDeclaration.Assembly)) @@ -1634,7 +1630,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection XmlPIMapping mapping = FindByClrNamespaceAndAssemblyId(declaration); if (mapping == null) - mapping = XmlPIMapping.Presentation; + mapping = XmlPIMapping.GetPresentationMapping(GetAssembly); return mapping.XmlNamespace; } diff --git a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlPIMapping.cs b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlPIMapping.cs index 3c321c8f1..750b2a909 100644 --- a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlPIMapping.cs +++ b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlPIMapping.cs @@ -10,20 +10,19 @@ namespace Ricciolo.StylesExplorer.MarkupReflection /// public class XmlPIMapping { - private string _xmlNamespace; - private short _assemblyId; - private string _clrNamespace; - private static XmlPIMapping _default = new XmlPIMapping(PresentationNamespace, 0, String.Empty); + string _xmlNamespace; + string assemblyName; + string _clrNamespace; public const string XamlNamespace = "http://schemas.microsoft.com/winfx/2006/xaml"; public const string PresentationNamespace = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"; public const string PresentationOptionsNamespace = "http://schemas.microsoft.com/winfx/2006/xaml/presentation/options"; public const string McNamespace = "http://schemas.openxmlformats.org/markup-compatibility/2006"; - public XmlPIMapping(string xmlNamespace, short assemblyId, string clrNamespace) + public XmlPIMapping(string xmlNamespace, string assembly, string clrNamespace) { _xmlNamespace = xmlNamespace; - _assemblyId = assemblyId; + assemblyName = assembly; _clrNamespace = clrNamespace; } @@ -37,11 +36,10 @@ namespace Ricciolo.StylesExplorer.MarkupReflection } /// - /// Restituisce l'id dell'assembly + /// Name of the assembly. /// - public short AssemblyId - { - get { return _assemblyId; } + public string Assembly { + get { return assemblyName; } } /// @@ -51,13 +49,10 @@ namespace Ricciolo.StylesExplorer.MarkupReflection { get { return _clrNamespace; } } - - /// - /// Restituisce il mapping di default di WPF - /// - public static XmlPIMapping Presentation + + public static XmlPIMapping GetPresentationMapping(Func assemblyResolve) { - get { return _default; } + return new XmlPIMapping(PresentationNamespace, assemblyResolve(0), string.Empty); } } } \ No newline at end of file diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index eee97c1bd..8d42f84bf 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -31,10 +31,11 @@ 4096 - AnyCPU + x86 False Auto 4194304 + 4096 bin\Debug\