[go: up one dir, main page]

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BAML→XAML decompile: fix nested Type names & MarkupExtension handling #188

Merged
merged 9 commits into from
Apr 26, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ THE SOFTWARE.
*/

using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Xml.Linq;
using dnlib.DotNet;
Expand Down Expand Up @@ -53,6 +54,8 @@ bool ProcessElement(XamlContext ctx, XElement elem) {
return doWork;
}

static bool IsXamlNsAttr(XAttribute attr) => attr.Name.Namespace == XamlContext.KnownNamespace_Xaml;

bool RewriteElement(XamlContext ctx, XElement parent, XElement elem) {
var type = parent.Annotation<XamlType>();
var property = elem.Annotation<XamlProperty>();
Expand All @@ -65,7 +68,7 @@ bool RewriteElement(XamlContext ctx, XElement parent, XElement elem) {
return false;
}

if (elem.Elements().Count() != 1 || elem.Attributes().Any(t => t.Name.Namespace != XNamespace.Xmlns))
if (elem.Elements().Count() != 1 || elem.Attributes().Any(IsXamlNsAttr))
return false;

var value = elem.Elements().Single();
Expand Down Expand Up @@ -118,6 +121,9 @@ bool CanInlineExt(XamlContext ctx, XElement ctxElement) {
ctxElement.Name != ctor)
return false;

if (ctxElement.Attributes().Any(IsXamlNsAttr))
return false;

foreach (var child in ctxElement.Elements()) {
if (!CanInlineExt(ctx, child))
return false;
Expand Down Expand Up @@ -153,8 +159,10 @@ XamlExtension InlineExtension(XamlContext ctx, XElement ctxElement) {

var ext = new XamlExtension(type);

foreach (var attr in ctxElement.Attributes().Where(attr => attr.Name.Namespace != XNamespace.Xmlns))
foreach (var attr in ctxElement.Attributes()) {
Debug2.Assert(!IsXamlNsAttr(attr));
ext.NamedArguments[attr.Name.LocalName] = attr.Value;
}

foreach (var child in ctxElement.Nodes()) {
if (child is not XElement elem)
Expand All @@ -174,7 +182,7 @@ XamlExtension InlineExtension(XamlContext ctx, XElement ctxElement) {

var property = elem.Annotation<XamlProperty>();
if (property is null || elem.Nodes().Count() != 1 ||
elem.Attributes().Any(attr => attr.Name.Namespace != XNamespace.Xmlns))
elem.Attributes().Any(IsXamlNsAttr))
return null;

var name = property.PropertyName;
Expand Down
13 changes: 11 additions & 2 deletions Extensions/dnSpy.BamlDecompiler/XamlContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,15 @@ void BuildPIMappings(BamlDocument document) {
}
}

static string NestedReflectionName(ITypeDefOrRef type, out string clrNs) {
var name = type.ReflectionFullName;
while (type.DeclaringType is ITypeDefOrRef declaringType)
type = declaringType;
clrNs = type.ReflectionNamespace;
name = name.Substring(clrNs.Length + 1);
return name;
}

public XamlType ResolveType(ushort id) {
if (typeMap.TryGetValue(id, out var xamlType))
return xamlType;
Expand All @@ -106,10 +115,10 @@ public XamlType ResolveType(ushort id) {
type = TypeNameParser.ParseReflectionThrow(Module, typeRec.TypeFullName, new DummyAssemblyRefFinder(assembly));
}

var clrNs = type.ReflectionNamespace;
var name = NestedReflectionName(type, out string clrNs);
var xmlNs = XmlNs.LookupXmlns(assembly, clrNs);

typeMap[id] = xamlType = new XamlType(assembly, clrNs, type.ReflectionName, GetXmlNamespace(xmlNs)) {
typeMap[id] = xamlType = new XamlType(assembly, clrNs, name, GetXmlNamespace(xmlNs)) {
ResolvedType = type
};

Expand Down