Skip to content

Commit

Permalink
BAML decompiler: introduce proxy for unknown named types - closes ics…
Browse files Browse the repository at this point in the history
  • Loading branch information
siegfriedpammer committed Apr 8, 2012
1 parent 34b0cd7 commit 7345e82
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 70 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,44 +5,43 @@

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");
Expand All @@ -53,14 +52,14 @@ public override string ToString()
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)
Expand All @@ -70,17 +69,13 @@ public string Assembly
}
}

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;
Expand All @@ -90,7 +85,7 @@ public IType Type {
}
}

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); }
Expand All @@ -103,10 +98,10 @@ public string AssemblyQualifiedName {
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()
Expand All @@ -115,4 +110,57 @@ public override int GetHashCode()
}
}

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();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -968,7 +968,8 @@ void ReadDefAttribute()
string recordName = this.stringTable[identifier];
if (recordName != "Key") throw new NotSupportedException(recordName);
pd = new PropertyDeclaration(recordName, XamlTypeDeclaration);

if (keys == null)
keys = new List<KeyMapping>();
keys.Add(new KeyMapping(text) { Position = -1 });
break;
}
Expand Down Expand Up @@ -1020,7 +1021,7 @@ void ReadXmlnsProperty()
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));
Expand Down Expand Up @@ -1247,18 +1248,14 @@ void AddKeyToElement(string key)

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;
}

Expand All @@ -1271,7 +1268,7 @@ void ReadPIMapping()
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()
Expand Down Expand Up @@ -1452,7 +1449,7 @@ string GetTypeExtension(short typeIdentifier)

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"))
Expand All @@ -1479,7 +1476,7 @@ string FormatPropertyDeclaration(PropertyDeclaration propertyDeclaration, bool w
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)) {
Expand Down Expand Up @@ -1519,7 +1516,7 @@ object GetStaticResource(short identifier)
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()
Expand All @@ -1542,11 +1539,11 @@ void ReadTypeInfo()
{
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);
}
Expand Down Expand Up @@ -1579,14 +1576,13 @@ TypeDeclaration GetTypeDeclaration(short identifier)
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)
Expand Down Expand Up @@ -1616,8 +1612,8 @@ public override string NamespaceURI {
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))
Expand All @@ -1634,7 +1630,7 @@ public override string NamespaceURI {

XmlPIMapping mapping = FindByClrNamespaceAndAssemblyId(declaration);
if (mapping == null)
mapping = XmlPIMapping.Presentation;
mapping = XmlPIMapping.GetPresentationMapping(GetAssembly);

return mapping.XmlNamespace;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,19 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
/// </summary>
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;
}

Expand All @@ -37,11 +36,10 @@ public string XmlNamespace
}

/// <summary>
/// Restituisce l'id dell'assembly
/// Name of the assembly.
/// </summary>
public short AssemblyId
{
get { return _assemblyId; }
public string Assembly {
get { return assemblyName; }
}

/// <summary>
Expand All @@ -51,13 +49,10 @@ public string ClrNamespace
{
get { return _clrNamespace; }
}

/// <summary>
/// Restituisce il mapping di default di WPF
/// </summary>
public static XmlPIMapping Presentation

public static XmlPIMapping GetPresentationMapping(Func<short, string> assemblyResolve)
{
get { return _default; }
return new XmlPIMapping(PresentationNamespace, assemblyResolve(0), string.Empty);
}
}
}
3 changes: 2 additions & 1 deletion ILSpy/ILSpy.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@
<FileAlignment>4096</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<PlatformTarget>x86</PlatformTarget>
<RegisterForComInterop>False</RegisterForComInterop>
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
<BaseAddress>4194304</BaseAddress>
<FileAlignment>4096</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<OutputPath>bin\Debug\</OutputPath>
Expand Down

0 comments on commit 7345e82

Please sign in to comment.