Browse Source

fix #775 - Invalid BAML namespace decompilation

pull/728/merge
Siegfried Pammer 9 years ago
parent
commit
1604952c3b
  1. 38
      ILSpy.BamlDecompiler/BamlResourceEntryNode.cs
  2. 2
      ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj
  3. 9
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlElement.cs
  4. 402
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs
  5. 36
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlNamespace.cs
  6. 58
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlPIMapping.cs
  7. 31
      ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlToClrNamespaceMapping.cs
  8. 36
      ILSpy.BamlDecompiler/Tests/BamlTestRunner.cs
  9. 5
      ILSpy.BamlDecompiler/Tests/Cases/Issue775.xaml
  10. 2
      ILSpy.BamlDecompiler/Tests/Cases/MarkupExtension.xaml
  11. 2
      ILSpy.BamlDecompiler/Tests/Cases/SimplePropertyElement.xaml
  12. 3
      ILSpy.BamlDecompiler/Tests/ILSpy.BamlDecompiler.Tests.csproj

38
ILSpy.BamlDecompiler/BamlResourceEntryNode.cs

@ -56,12 +56,13 @@ namespace ILSpy.BamlDecompiler @@ -56,12 +56,13 @@ namespace ILSpy.BamlDecompiler
internal static XDocument LoadIntoDocument(IAssemblyResolver resolver, AssemblyDefinition asm, Stream stream)
{
XDocument xamlDocument;
using (XmlBamlReader reader = new XmlBamlReader(stream, new CecilTypeResolver(resolver, asm)))
using (XmlBamlReader reader = new XmlBamlReader(stream, new CecilTypeResolver(resolver, asm))) {
xamlDocument = XDocument.Load(reader);
ConvertConnectionIds(xamlDocument, asm);
ConvertToEmptyElements(xamlDocument.Root);
MoveNamespacesToRoot(xamlDocument);
return xamlDocument;
ConvertConnectionIds(xamlDocument, asm);
ConvertToEmptyElements(xamlDocument.Root);
MoveNamespacesToRoot(xamlDocument, reader.XmlnsDefinitions);
return xamlDocument;
}
}
static void ConvertConnectionIds(XDocument xamlDocument, AssemblyDefinition asm)
@ -74,12 +75,35 @@ namespace ILSpy.BamlDecompiler @@ -74,12 +75,35 @@ namespace ILSpy.BamlDecompiler
}
}
static void MoveNamespacesToRoot(XDocument xamlDocument)
class XAttributeComparer : IEqualityComparer<XAttribute>
{
public bool Equals(XAttribute x, XAttribute y)
{
if (ReferenceEquals(x, y))
return true;
if (x == null || y == null)
return false;
return x.ToString() == y.ToString();
}
public int GetHashCode(XAttribute obj)
{
return obj.ToString().GetHashCode();
}
}
static void MoveNamespacesToRoot(XDocument xamlDocument, IEnumerable<XmlNamespace> missingXmlns)
{
var additionalXmlns = new List<XAttribute> {
var additionalXmlns = new HashSet<XAttribute>(new XAttributeComparer()) {
new XAttribute("xmlns", XmlBamlReader.DefaultWPFNamespace),
new XAttribute(XName.Get("x", XNamespace.Xmlns.NamespaceName), XmlBamlReader.XWPFNamespace)
};
additionalXmlns.AddRange(
missingXmlns
.Where(ns => !string.IsNullOrWhiteSpace(ns.Prefix))
.Select(ns => new XAttribute(XName.Get(ns.Prefix, XNamespace.Xmlns.NamespaceName), ns.Namespace))
);
foreach (var element in xamlDocument.Root.DescendantsAndSelf()) {
if (element.Name.NamespaceName != XmlBamlReader.DefaultWPFNamespace && !additionalXmlns.Any(ka => ka.Value == element.Name.NamespaceName)) {

2
ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj

@ -112,7 +112,7 @@ @@ -112,7 +112,7 @@
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\XmlBamlSimpleProperty.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\XmlBamlText.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\XmlNamespace.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\XmlPIMapping.cs" />
<Compile Include="Ricciolo.StylesExplorer.MarkupReflection\XmlToClrNamespaceMapping.cs" />
</ItemGroup>
<ItemGroup />
<ItemGroup>

9
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlElement.cs

@ -1,14 +1,13 @@ @@ -1,14 +1,13 @@
// Copyright (c) Cristian Civera (cristian@aspitalia.com)
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System.Collections.Generic;
using System.Xml;
namespace Ricciolo.StylesExplorer.MarkupReflection
{
class XmlBamlElement : XmlBamlNode
{
XmlNamespaceCollection _namespaces = new XmlNamespaceCollection();
public XmlBamlElement()
{
}
@ -19,11 +18,9 @@ namespace Ricciolo.StylesExplorer.MarkupReflection @@ -19,11 +18,9 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
this.Namespaces.AddRange(parent.Namespaces);
}
public XmlNamespaceCollection Namespaces {
get { return _namespaces; }
}
public List<XmlNamespace> Namespaces { get; } = new List<XmlNamespace>();
public XmlBamlElement Parent { get; private set; }
public XmlBamlElement Parent { get; }
public TypeDeclaration TypeDeclaration { get; set; }

402
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlBamlReader.cs

@ -29,7 +29,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection @@ -29,7 +29,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
Stack<XmlBamlElement> elements = new Stack<XmlBamlElement>();
Stack<XmlBamlElement> readingElements = new Stack<XmlBamlElement>();
NodesCollection nodes = new NodesCollection();
List<XmlPIMapping> _mappings = new List<XmlPIMapping>();
List<XmlToClrNamespaceMapping> mappings = new List<XmlToClrNamespaceMapping>();
XmlBamlNode _currentNode;
readonly KnownInfo KnownInfo;
@ -94,15 +94,17 @@ namespace Ricciolo.StylesExplorer.MarkupReflection @@ -94,15 +94,17 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
readonly XmlNameTable _nameTable = new NameTable();
IDictionary<string, string> _rootNamespaces;
public const string XWPFNamespace = "http://schemas.microsoft.com/winfx/2006/xaml";
public const string DefaultWPFNamespace = "http://schemas.microsoft.com/winfx/2006/xaml/presentation";
public const string XWPFNamespace = XmlToClrNamespaceMapping.XamlNamespace;
public const string DefaultWPFNamespace = XmlToClrNamespaceMapping.PresentationNamespace;
public ISet<XmlNamespace> XmlnsDefinitions { get; } = new HashSet<XmlNamespace>();
public XmlBamlReader(Stream stream, ITypeResolver resolver)
{
if (stream == null)
throw new ArgumentNullException("stream");
throw new ArgumentNullException(nameof(stream));
if (resolver == null)
throw new ArgumentNullException("resolver");
throw new ArgumentNullException(nameof(resolver));
_resolver = resolver;
reader = new BamlBinaryReader(stream);
@ -111,86 +113,31 @@ namespace Ricciolo.StylesExplorer.MarkupReflection @@ -111,86 +113,31 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
KnownInfo = new KnownInfo(resolver);
}
///<summary>
///When overridden in a derived class, gets the value of the attribute with the specified <see cref="P:System.Xml.XmlReader.Name"></see>.
///</summary>
///
///<returns>
///The value of the specified attribute. If the attribute is not found, null is returned.
///</returns>
///
///<param name="name">The qualified name of the attribute. </param>
public override string GetAttribute(string name)
{
throw new NotImplementedException();
}
///<summary>
///When overridden in a derived class, gets the value of the attribute with the specified <see cref="P:System.Xml.XmlReader.LocalName"></see> and <see cref="P:System.Xml.XmlReader.NamespaceURI"></see>.
///</summary>
///
///<returns>
///The value of the specified attribute. If the attribute is not found, null is returned. This method does not move the reader.
///</returns>
///
///<param name="namespaceURI">The namespace URI of the attribute. </param>
///<param name="name">The local name of the attribute. </param>
public override string GetAttribute(string name, string namespaceURI)
{
throw new NotImplementedException();
}
///<summary>
///When overridden in a derived class, gets the value of the attribute with the specified index.
///</summary>
///
///<returns>
///The value of the specified attribute. This method does not move the reader.
///</returns>
///
///<param name="i">The index of the attribute. The index is zero-based. (The first attribute has index 0.) </param>
public override string GetAttribute(int i)
{
throw new NotImplementedException();
}
///<summary>
///When overridden in a derived class, moves to the attribute with the specified <see cref="P:System.Xml.XmlReader.Name"></see>.
///</summary>
///
///<returns>
///true if the attribute is found; otherwise, false. If false, the reader's position does not change.
///</returns>
///
///<param name="name">The qualified name of the attribute. </param>
public override bool MoveToAttribute(string name)
{
throw new NotImplementedException();
}
///<summary>
///When overridden in a derived class, moves to the attribute with the specified <see cref="P:System.Xml.XmlReader.LocalName"></see> and <see cref="P:System.Xml.XmlReader.NamespaceURI"></see>.
///</summary>
///
///<returns>
///true if the attribute is found; otherwise, false. If false, the reader's position does not change.
///</returns>
///
///<param name="name">The local name of the attribute. </param>
///<param name="ns">The namespace URI of the attribute. </param>
public override bool MoveToAttribute(string name, string ns)
{
throw new NotImplementedException();
}
///<summary>
///When overridden in a derived class, moves to the first attribute.
///</summary>
///
///<returns>
///true if an attribute exists (the reader moves to the first attribute); otherwise, false (the position of the reader does not change).
///</returns>
///
public override bool MoveToFirstAttribute()
{
intoAttribute = false;
@ -202,14 +149,6 @@ namespace Ricciolo.StylesExplorer.MarkupReflection @@ -202,14 +149,6 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
return false;
}
///<summary>
///When overridden in a derived class, moves to the next attribute.
///</summary>
///
///<returns>
///true if there is a next attribute; false if there are no more attributes.
///</returns>
///
public override bool MoveToNextAttribute()
{
intoAttribute = false;
@ -221,14 +160,6 @@ namespace Ricciolo.StylesExplorer.MarkupReflection @@ -221,14 +160,6 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
return false;
}
///<summary>
///When overridden in a derived class, moves to the element that contains the current attribute node.
///</summary>
///
///<returns>
///true if the reader is positioned on an attribute (the reader moves to the element that owns the attribute); false if the reader is not positioned on an attribute (the position of the reader does not change).
///</returns>
///
public override bool MoveToElement()
{
while (nodes.Peek() is XmlBamlProperty || nodes.Peek() is XmlBamlSimpleProperty)
@ -239,14 +170,6 @@ namespace Ricciolo.StylesExplorer.MarkupReflection @@ -239,14 +170,6 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
return true;
}
///<summary>
///When overridden in a derived class, parses the attribute value into one or more Text, EntityReference, or EndEntity nodes.
///</summary>
///
///<returns>
///true if there are nodes to return.false if the reader is not positioned on an attribute node when the initial call is made or if all the attribute values have been read.An empty attribute, such as, misc="", returns true with a single node with a value of String.Empty.
///</returns>
///
public override bool ReadAttributeValue()
{
if (!intoAttribute)
@ -257,15 +180,6 @@ namespace Ricciolo.StylesExplorer.MarkupReflection @@ -257,15 +180,6 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
return false;
}
///<summary>
///When overridden in a derived class, reads the next node from the stream.
///</summary>
///
///<returns>
///true if the next node was read successfully; false if there are no more nodes to read.
///</returns>
///
///<exception cref="T:System.Xml.XmlException">An error occurred while parsing the XML. </exception>
public override bool Read()
{
return ReadInternal();
@ -288,7 +202,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection @@ -288,7 +202,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
long position = reader.BaseStream.Position;
ComputeBytesToSkip();
bytesToSkip = ComputeBytesToSkip();
ProcessNext();
if (bytesToSkip > 0)
@ -318,12 +232,13 @@ namespace Ricciolo.StylesExplorer.MarkupReflection @@ -318,12 +232,13 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
currentType = BamlRecordType.DocumentEnd;
else
currentType = (BamlRecordType)type;
if (currentType.ToString().EndsWith("End"))
#if DEBUG
if (currentType.ToString().EndsWith("End", StringComparison.Ordinal))
Debug.Unindent();
Debug.WriteLine(string.Format("{0} (0x{0:x})", currentType));
if (currentType.ToString().EndsWith("Start"))
if (currentType.ToString().EndsWith("Start", StringComparison.Ordinal))
Debug.Indent();
#endif
}
bool SetNextNode()
@ -507,9 +422,8 @@ namespace Ricciolo.StylesExplorer.MarkupReflection @@ -507,9 +422,8 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
nodes.Enqueue(new XmlBamlText(text));
}
void ComputeBytesToSkip()
int ComputeBytesToSkip()
{
bytesToSkip = 0;
switch (currentType)
{
case BamlRecordType.PropertyWithConverter:
@ -528,8 +442,9 @@ namespace Ricciolo.StylesExplorer.MarkupReflection @@ -528,8 +442,9 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
case BamlRecordType.AttributeInfo:
case BamlRecordType.StringInfo:
case BamlRecordType.TypeSerializerInfo:
bytesToSkip = reader.ReadCompressedInt32();
break;
return reader.ReadCompressedInt32();
default:
return 0;
}
}
@ -552,77 +467,44 @@ namespace Ricciolo.StylesExplorer.MarkupReflection @@ -552,77 +467,44 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
}
}
///<summary>
///When overridden in a derived class, changes the <see cref="P:System.Xml.XmlReader.ReadState"></see> to Closed.
///</summary>
///
public override void Close()
{
//if (reader != null)
// reader.Close();
reader = null;
}
///<summary>
///When overridden in a derived class, resolves a namespace prefix in the current element's scope.
///</summary>
///
///<returns>
///The namespace URI to which the prefix maps or null if no matching prefix is found.
///</returns>
///
///<param name="prefix">The prefix whose namespace URI you want to resolve. To match the default namespace, pass an empty string. </param>
public override string LookupNamespace(string prefix)
{
if (readingElements.Count == 0) return null;
XmlNamespaceCollection namespaces = readingElements.Peek().Namespaces;
var namespaces = readingElements.Peek().Namespaces;
for (int x = 0; x < namespaces.Count; x++)
{
if (String.CompareOrdinal(namespaces[x].Prefix, prefix) == 0)
return namespaces[x].Namespace;
for (int i = 0; i < namespaces.Count; i++) {
if (String.CompareOrdinal(namespaces[i].Prefix, prefix) == 0)
return namespaces[i].Namespace;
}
return null;
}
///<summary>
///When overridden in a derived class, resolves the entity reference for EntityReference nodes.
///</summary>
///
///<exception cref="T:System.InvalidOperationException">The reader is not positioned on an EntityReference node; this implementation of the reader cannot resolve entities (<see cref="P:System.Xml.XmlReader.CanResolveEntity"></see> returns false). </exception>
public override void ResolveEntity()
{
throw new NotImplementedException();
}
///<summary>
///When overridden in a derived class, gets the type of the current node.
///</summary>
///
///<returns>
///One of the <see cref="T:System.Xml.XmlNodeType"></see> values representing the type of the current node.
///</returns>
///
public override XmlNodeType NodeType
{
get
{
get {
if (intoAttribute) return XmlNodeType.Text;
return this.CurrentNode.NodeType;
}
}
///<summary>
///When overridden in a derived class, gets the local name of the current node.
///</summary>
///
///<returns>
///The name of the current node with the prefix removed. For example, LocalName is book for the element &lt;bk:book&gt;.For node types that do not have a name (like Text, Comment, and so on), this property returns String.Empty.
///</returns>
///
public override string LocalName
{
get
@ -1033,37 +915,38 @@ namespace Ricciolo.StylesExplorer.MarkupReflection @@ -1033,37 +915,38 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
keys.Add(new KeyMapping(text) { Position = position });
}
void ReadXmlnsProperty()
{
string prefix = reader.ReadString();
string @namespace = reader.ReadString();
string[] textArray = new string[(uint)reader.ReadInt16()];
for (int i = 0; i < textArray.Length; i++)
{
for (int i = 0; i < textArray.Length; i++) {
textArray[i] = this.assemblyTable[reader.ReadInt16()];
}
XmlNamespaceCollection namespaces = elements.Peek().Namespaces;
// Mapping locale, ci aggiunto l'assembly
if (@namespace.StartsWith("clr-namespace:") && @namespace.IndexOf("assembly=") < 0)
{
XmlPIMapping mappingToChange = null;
foreach (XmlPIMapping mapping in this.Mappings)
{
if (String.CompareOrdinal(mapping.XmlNamespace, @namespace) == 0)
{
var namespaces = elements.Peek().Namespaces;
// The XmlnsProperty record corresponds to an assembly
// We need to add the assembly name to the entry.
if (@namespace.StartsWith("clr-namespace:", StringComparison.Ordinal) && @namespace.IndexOf("assembly=", StringComparison.Ordinal) < 0) {
XmlToClrNamespaceMapping mappingToChange = null;
foreach (XmlToClrNamespaceMapping mapping in mappings) {
if (String.CompareOrdinal(mapping.XmlNamespace, @namespace) == 0) {
mappingToChange = mapping;
break;
}
}
if (mappingToChange == null)
throw new InvalidOperationException("Cannot find mapping");
@namespace = String.Format("{0};assembly={1}", @namespace, mappingToChange.Assembly.Replace(" ", ""));
mappingToChange.XmlNamespace = @namespace;
if (mappingToChange.AssemblyId > 0) {
@namespace = String.Format("{0};assembly={1}", @namespace, mappingToChange.AssemblyName.Replace(" ", ""));
mappingToChange.XmlNamespace = @namespace;
}
}
namespaces.Add(new XmlNamespace(prefix, @namespace));
var ns = new XmlNamespace(prefix, @namespace);
XmlnsDefinitions.Add(ns);
namespaces.Add(ns);
}
void ReadElementEnd()
@ -1292,22 +1175,26 @@ namespace Ricciolo.StylesExplorer.MarkupReflection @@ -1292,22 +1175,26 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
nodes.Enqueue(property);
}
XmlPIMapping FindByClrNamespaceAndAssemblyId(TypeDeclaration declaration)
XmlToClrNamespaceMapping FindByClrNamespaceAndAssemblyId(TypeDeclaration declaration)
{
return FindByClrNamespaceAndAssemblyName(declaration.Namespace, declaration.Assembly);
}
XmlPIMapping FindByClrNamespaceAndAssemblyName(string clrNamespace, string assemblyName)
XmlToClrNamespaceMapping FindByClrNamespaceAndAssemblyName(string clrNamespace, string assemblyName)
{
if (clrNamespace == XamlTypeDeclaration.Namespace && assemblyName == XamlTypeDeclaration.Assembly)
return new XmlPIMapping(XmlPIMapping.XamlNamespace, assemblyName, clrNamespace);
for (int x = 0; x < Mappings.Count; x++) {
XmlPIMapping xp = Mappings[x];
if (string.Equals(xp.Assembly, assemblyName, StringComparison.Ordinal) && string.Equals(xp.ClrNamespace, clrNamespace, StringComparison.Ordinal))
if (assemblyName == XamlTypeDeclaration.Assembly) {
if (clrNamespace == XamlTypeDeclaration.Namespace)
return new XmlToClrNamespaceMapping(XmlToClrNamespaceMapping.XamlNamespace, -1, XamlTypeDeclaration.Assembly, XamlTypeDeclaration.Namespace);
return new XmlToClrNamespaceMapping(XmlToClrNamespaceMapping.PresentationNamespace, -1, assemblyName, clrNamespace);
}
for (int x = 0; x < mappings.Count; x++) {
XmlToClrNamespaceMapping xp = mappings[x];
if (string.Equals(xp.AssemblyName, assemblyName, StringComparison.Ordinal) && string.Equals(xp.ClrNamespace, clrNamespace, StringComparison.Ordinal))
return xp;
}
return null;
return new XmlToClrNamespaceMapping(XmlToClrNamespaceMapping.PresentationNamespace, -1, assemblyName, clrNamespace);
}
void ReadPIMapping()
@ -1316,7 +1203,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection @@ -1316,7 +1203,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
string clrNamespace = reader.ReadString();
short assemblyId = reader.ReadInt16();
Mappings.Add(new XmlPIMapping(xmlNamespace, GetAssembly(assemblyId), clrNamespace));
mappings.Add(new XmlToClrNamespaceMapping(xmlNamespace, assemblyId, GetAssembly(assemblyId), clrNamespace));
}
void ReadContentProperty()
@ -1484,7 +1371,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection @@ -1484,7 +1371,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
else
throw new InvalidOperationException("Invalid resource: " + resource.GetType());
string prefix = this.LookupPrefix(XmlPIMapping.XamlNamespace, false);
string prefix = this.LookupPrefix(XmlToClrNamespaceMapping.XamlNamespace, false);
if (String.IsNullOrEmpty(prefix))
return String.Format("{{Static {0}}}", name);
else
@ -1498,7 +1385,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection @@ -1498,7 +1385,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
string GetTypeExtension(short typeIdentifier)
{
string prefix = this.LookupPrefix(XmlPIMapping.XamlNamespace, false);
string prefix = this.LookupPrefix(XmlToClrNamespaceMapping.XamlNamespace, false);
if (String.IsNullOrEmpty(prefix))
return String.Format("{{Type {0}}}", FormatTypeDeclaration(GetTypeDeclaration(typeIdentifier)));
else
@ -1507,7 +1394,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection @@ -1507,7 +1394,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
string FormatTypeDeclaration(TypeDeclaration typeDeclaration)
{
XmlPIMapping mapping = FindByClrNamespaceAndAssemblyName(typeDeclaration.Namespace, typeDeclaration.Assembly);
XmlToClrNamespaceMapping mapping = FindByClrNamespaceAndAssemblyName(typeDeclaration.Namespace, typeDeclaration.Assembly);
string prefix = (mapping != null) ? this.LookupPrefix(mapping.XmlNamespace, false) : null;
string name = typeDeclaration.Name;
if (name.EndsWith("Extension"))
@ -1534,7 +1421,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection @@ -1534,7 +1421,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
bool differentType = ((propertyDeclaration.DeclaringType != propertyDeclaration.DeclaringType || !isDescendant));
if (withPrefix) {
XmlPIMapping mapping = FindByClrNamespaceAndAssemblyName(propertyDeclaration.DeclaringType.Namespace, propertyDeclaration.DeclaringType.Assembly);
XmlToClrNamespaceMapping mapping = FindByClrNamespaceAndAssemblyName(propertyDeclaration.DeclaringType.Namespace, propertyDeclaration.DeclaringType.Assembly);
string prefix = (mapping != null) ? this.LookupPrefix(mapping.XmlNamespace, false) : null;
if (!String.IsNullOrEmpty(prefix)) {
@ -1559,7 +1446,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection @@ -1559,7 +1446,7 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
PropertyDeclaration pd = this.GetPropertyDeclaration(propertyId);
object staticResource = GetStaticResource(index);
string prefix = this.LookupPrefix(XmlPIMapping.PresentationNamespace, false);
string prefix = this.LookupPrefix(XmlToClrNamespaceMapping.PresentationNamespace, false);
string value = String.Format("{{{0}{1}StaticResource {2}}}", prefix, (String.IsNullOrEmpty(prefix)) ? String.Empty : ":", staticResource);
XmlBamlProperty property = new XmlBamlProperty(elements.Peek(), PropertyType.Value, pd);
@ -1658,12 +1545,6 @@ namespace Ricciolo.StylesExplorer.MarkupReflection @@ -1658,12 +1545,6 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
get { return _currentNode; }
}
///<summary>
///When overridden in a derived class, gets the namespace URI (as defined in the W3C Namespace specification) of the node on which the reader is positioned.
///</summary>
///<returns>
///The namespace URI of the current node; otherwise an empty string.
///</returns>
public override string NamespaceURI {
get {
if (intoAttribute) return String.Empty;
@ -1676,8 +1557,8 @@ namespace Ricciolo.StylesExplorer.MarkupReflection @@ -1676,8 +1557,8 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
declaration = ((XmlBamlProperty)node).PropertyDeclaration.DeclaringType;
TypeDeclaration elementDeclaration = this.readingElements.Peek().TypeDeclaration;
XmlPIMapping propertyMapping = FindByClrNamespaceAndAssemblyId(declaration) ?? XmlPIMapping.GetPresentationMapping(GetAssembly);
XmlPIMapping elementMapping = FindByClrNamespaceAndAssemblyId(elementDeclaration) ?? XmlPIMapping.GetPresentationMapping(GetAssembly);
XmlToClrNamespaceMapping propertyMapping = FindByClrNamespaceAndAssemblyId(declaration);
XmlToClrNamespaceMapping elementMapping = FindByClrNamespaceAndAssemblyId(elementDeclaration);
if (((XmlBamlProperty)node).PropertyDeclaration.Name == "Name" &&
_resolver.IsLocalAssembly(((XmlBamlProperty)node).Parent.TypeDeclaration.Assembly))
@ -1699,36 +1580,23 @@ namespace Ricciolo.StylesExplorer.MarkupReflection @@ -1699,36 +1580,23 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
else
return String.Empty;
XmlPIMapping mapping = FindByClrNamespaceAndAssemblyId(declaration);
if (mapping == null)
mapping = XmlPIMapping.GetPresentationMapping(GetAssembly);
XmlToClrNamespaceMapping mapping = FindByClrNamespaceAndAssemblyId(declaration);
return mapping.XmlNamespace;
}
}
///<summary>
///When overridden in a derived class, gets the namespace prefix associated with the current node.
///</summary>
///<returns>
///The namespace prefix associated with the current node.
///</returns>
public override string Prefix
{
get
{
get {
if (!intoAttribute)
return ((IXmlNamespaceResolver)this).LookupPrefix(this.NamespaceURI) ?? String.Empty;
return String.Empty;
}
}
///<summary>
///When overridden in a derived class, gets a value indicating whether the current node can have a <see cref="P:System.Xml.XmlReader.Value"></see>.
///</summary>
///<returns>
///true if the node on which the reader is currently positioned can have a Value; otherwise, false. If false, the node has a value of String.Empty.
///</returns>
public override bool HasValue
{
get { return this.Value != null; }
@ -1742,16 +1610,9 @@ namespace Ricciolo.StylesExplorer.MarkupReflection @@ -1742,16 +1610,9 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
get { return _resolver; }
}
///<summary>
///When overridden in a derived class, gets the text value of the current node.
///</summary>
///<returns>
///The value returned depends on the <see cref="P:System.Xml.XmlReader.NodeType"></see> of the node. The following table lists node types that have a value to return. All other node types return String.Empty.Node type Value AttributeThe value of the attribute. CDATAThe content of the CDATA section. CommentThe content of the comment. DocumentTypeThe internal subset. ProcessingInstructionThe entire content, excluding the target. SignificantWhitespaceThe white space between markup in a mixed content model. TextThe content of the text node. WhitespaceThe white space between markup. XmlDeclarationThe content of the declaration.
///</returns>
public override string Value
{
get
{
get {
XmlBamlNode node = this.CurrentNode;
if (node is XmlBamlSimpleProperty)
return ((XmlBamlSimpleProperty)node).Value;
@ -1766,116 +1627,39 @@ namespace Ricciolo.StylesExplorer.MarkupReflection @@ -1766,116 +1627,39 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
}
}
/// <summary>
/// Return root namespaces
/// </summary>
public IDictionary<string, string> RootNamespaces
{
get { return _rootNamespaces; }
}
public IDictionary<string, string> RootNamespaces => _rootNamespaces;
///<summary>
///When overridden in a derived class, gets the depth of the current node in the XML document.
///</summary>
///<returns>
///The depth of the current node in the XML document.
///</returns>
public override int Depth
{
get { return this.readingElements.Count; }
}
public override int Depth => readingElements.Count;
///<summary>
///When overridden in a derived class, gets the base URI of the current node.
///</summary>
///<returns>
///The base URI of the current node.
///</returns>
public override string BaseURI
{
get { return String.Empty; }
}
public override string BaseURI => string.Empty;
///<summary>
///When overridden in a derived class, gets a value indicating whether the current node is an empty element (for example, &lt;MyElement/&gt;).
///</summary>
///<returns>
///true if the current node is an element (<see cref="P:System.Xml.XmlReader.NodeType"></see> equals XmlNodeType.Element) that ends with /&gt;; otherwise, false.
///</returns>
public override bool IsEmptyElement
{
get { return false; }
}
public override bool IsEmptyElement => false;
public override bool EOF => _eof;
///<summary>
///When overridden in a derived class, gets the number of attributes on the current node.
///</summary>
///<returns>
///The number of attributes on the current node.
///</returns>
public override int AttributeCount {
get { throw new NotImplementedException(); }
}
///<summary>
///When overridden in a derived class, gets a value indicating whether the reader is positioned at the end of the stream.
///</summary>
///<returns>
///true if the reader is positioned at the end of the stream; otherwise, false.
///</returns>
public override bool EOF {
get { return _eof; }
}
///<summary>
///When overridden in a derived class, gets the state of the reader.
///</summary>
///<returns>
///One of the <see cref="T:System.Xml.ReadState"></see> values.
///</returns>
public override ReadState ReadState {
get {
if (!initialized)
return ReadState.Initial;
else if (reader == null)
if (reader == null)
return ReadState.Closed;
else if (this.EOF)
if (this.EOF)
return ReadState.EndOfFile;
else
return ReadState.Interactive;
return ReadState.Interactive;
}
}
public List<XmlPIMapping> Mappings
{
get { return _mappings; }
}
///<summary>
///When overridden in a derived class, gets the <see cref="T:System.Xml.XmlNameTable"></see> associated with this implementation.
///</summary>
///<returns>
///The XmlNameTable enabling you to get the atomized version of a string within the node.
///</returns>
public override XmlNameTable NameTable
{
get { return _nameTable; }
}
public override XmlNameTable NameTable => _nameTable;
#region IXmlNamespaceResolver Members
///<summary>
///Gets a collection of defined prefix-namespace Mappings that are currently in scope.
///</summary>
///
///<returns>
///An <see cref="T:System.Collections.IDictionary"></see> that contains the current in-scope namespaces.
///</returns>
///
///<param name="scope">An <see cref="T:System.Xml.XmlNamespaceScope"></see> value that specifies the type of namespace nodes to return.</param>
IDictionary<string, string> IXmlNamespaceResolver.GetNamespacesInScope(XmlNamespaceScope scope)
{
XmlNamespaceCollection namespaces = readingElements.Peek().Namespaces;
var namespaces = readingElements.Peek().Namespaces;
Dictionary<String, String> list = new Dictionary<string, string>();
foreach (XmlNamespace ns in namespaces)
{
@ -1885,29 +1669,11 @@ namespace Ricciolo.StylesExplorer.MarkupReflection @@ -1885,29 +1669,11 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
return list;
}
///<summary>
///Gets the namespace URI mapped to the specified prefix.
///</summary>
///
///<returns>
///The namespace URI that is mapped to the prefix; null if the prefix is not mapped to a namespace URI.
///</returns>
///
///<param name="prefix">The prefix whose namespace URI you wish to find.</param>
string IXmlNamespaceResolver.LookupNamespace(string prefix)
{
return this.LookupNamespace(prefix);
}
///<summary>
///Gets the prefix that is mapped to the specified namespace URI.
///</summary>
///
///<returns>
///The prefix that is mapped to the namespace URI; null if the namespace URI is not mapped to a prefix.
///</returns>
///
///<param name="namespaceName">The namespace URI whose prefix you wish to find.</param>
string IXmlNamespaceResolver.LookupPrefix(string namespaceName)
{
return this.LookupPrefix(namespaceName, true);
@ -1922,12 +1688,10 @@ namespace Ricciolo.StylesExplorer.MarkupReflection @@ -1922,12 +1688,10 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
elements = this.elements;
if (elements.Count == 0) return null;
XmlNamespaceCollection namespaces = elements.Peek().Namespaces;
return LookupPrefix(namespaceName, namespaces);
return LookupPrefix(namespaceName, elements.Peek().Namespaces);
}
static string LookupPrefix(string namespaceName, XmlNamespaceCollection namespaces)
static string LookupPrefix(string namespaceName, IList<XmlNamespace> namespaces)
{
for (int x = 0; x < namespaces.Count; x++)
{
@ -1940,8 +1704,6 @@ namespace Ricciolo.StylesExplorer.MarkupReflection @@ -1940,8 +1704,6 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
#endregion
#region IntegerCollectionType
internal enum IntegerCollectionType : byte
{
Byte = 2,
@ -1950,7 +1712,5 @@ namespace Ricciolo.StylesExplorer.MarkupReflection @@ -1950,7 +1712,5 @@ namespace Ricciolo.StylesExplorer.MarkupReflection
Unknown = 0,
UShort = 3
}
#endregion
}
}

36
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlNamespace.cs

@ -1,47 +1,33 @@ @@ -1,47 +1,33 @@
// Copyright (c) Cristian Civera (cristian@aspitalia.com)
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System.Collections.Generic;
using System;
namespace Ricciolo.StylesExplorer.MarkupReflection
{
internal class XmlNamespace
public class XmlNamespace
{
private string _prefix;
private string _namespace;
public XmlNamespace(string prefix, string ns)
{
_prefix = prefix;
_namespace = ns;
Prefix = prefix;
Namespace = ns;
}
public string Prefix
{
get { return _prefix; }
}
public string Prefix { get; }
public string Namespace
{
get { return _namespace; }
}
public string Namespace { get; }
public override bool Equals(object obj)
{
if (obj is XmlNamespace)
{
XmlNamespace o = (XmlNamespace)obj;
return (o.Prefix.Equals(this.Prefix) && o.Namespace.Equals(this.Namespace));
}
return base.Equals(obj);
XmlNamespace o = obj as XmlNamespace;
if (o == null)
return false;
return o.Prefix.Equals(Prefix) && o.Namespace.Equals(Namespace);
}
public override int GetHashCode()
{
return _prefix.GetHashCode() + _namespace.GetHashCode() >> 20;
return Prefix.GetHashCode() + Namespace.GetHashCode() >> 20;
}
}
internal class XmlNamespaceCollection : List<XmlNamespace>
{}
}

58
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlPIMapping.cs

@ -1,58 +0,0 @@ @@ -1,58 +0,0 @@
// Copyright (c) Cristian Civera (cristian@aspitalia.com)
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System;
namespace Ricciolo.StylesExplorer.MarkupReflection
{
/// <summary>
/// Rappresenta la mappatura tra namespace XML e namespace CLR con relativo assembly
/// </summary>
public class XmlPIMapping
{
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, string assembly, string clrNamespace)
{
_xmlNamespace = xmlNamespace;
assemblyName = assembly;
_clrNamespace = clrNamespace;
}
/// <summary>
/// Restituisce o imposta il namespace XML
/// </summary>
public string XmlNamespace
{
get { return _xmlNamespace; }
set { _xmlNamespace = value;}
}
/// <summary>
/// Name of the assembly.
/// </summary>
public string Assembly {
get { return assemblyName; }
}
/// <summary>
/// Restituisce il namespace clr
/// </summary>
public string ClrNamespace
{
get { return _clrNamespace; }
}
public static XmlPIMapping GetPresentationMapping(Func<short, string> assemblyResolve)
{
return new XmlPIMapping(PresentationNamespace, assemblyResolve(0), string.Empty);
}
}
}

31
ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/XmlToClrNamespaceMapping.cs

@ -0,0 +1,31 @@ @@ -0,0 +1,31 @@
// Copyright (c) Cristian Civera (cristian@aspitalia.com)
// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt)
using System;
namespace Ricciolo.StylesExplorer.MarkupReflection
{
/// <summary>
/// Represents a mapping between an XML namespace and a CLR namespace and assembly.
/// </summary>
public class XmlToClrNamespaceMapping
{
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 XmlToClrNamespaceMapping(string xmlNamespace, short assemblyId, string assemblyName, string clrNamespace)
{
XmlNamespace = xmlNamespace;
AssemblyId = assemblyId;
AssemblyName = assemblyName;
ClrNamespace = clrNamespace;
}
public short AssemblyId { get; }
public string XmlNamespace { get; set; }
public string AssemblyName { get; }
public string ClrNamespace { get; }
}
}

36
ILSpy.BamlDecompiler/Tests/BamlTestRunner.cs

@ -21,68 +21,73 @@ namespace ILSpy.BamlDecompiler.Tests @@ -21,68 +21,73 @@ namespace ILSpy.BamlDecompiler.Tests
{
RunTest("cases/simple");
}
[Test]
public void SimpleDictionary()
{
RunTest("cases/simpledictionary");
}
[Test]
public void Resources()
{
RunTest("cases/resources");
}
[Test]
[Ignore("Broken on AppVeyor CI (extra x:ConnectionId attribute)")]
public void SimpleNames()
{
RunTest("cases/simplenames");
}
[Test]
public void AvalonDockBrushes()
{
RunTest("cases/avalondockbrushes");
}
[Test]
public void AvalonDockCommon()
{
RunTest("cases/avalondockcommon");
}
[Test]
public void AttachedEvent()
{
RunTest("cases/attachedevent");
}
[Test]
public void Dictionary1()
{
RunTest("cases/dictionary1");
}
[Test]
public void Issue775()
{
RunTest("cases/issue775");
}
[Test]
public void MarkupExtension()
{
RunTest("cases/markupextension");
}
[Test]
public void SimplePropertyElement()
{
RunTest("cases/simplepropertyelement");
}
[Test]
public void Issue445()
{
RunTest("cases/issue445");
}
[Test]
public void NamespacePrefix()
{
@ -94,13 +99,13 @@ namespace ILSpy.BamlDecompiler.Tests @@ -94,13 +99,13 @@ namespace ILSpy.BamlDecompiler.Tests
{
RunTest("cases/escapesequence");
}
#region RunTest
void RunTest(string name)
{
RunTest(name, typeof(BamlTestRunner).Assembly.Location, Path.Combine("..\\..\\Tests", name + ".xaml"));
}
void RunTest(string name, string asmPath, string sourcePath)
{
var resolver = new DefaultAssemblyResolver();
@ -135,8 +140,7 @@ namespace ILSpy.BamlDecompiler.Tests @@ -135,8 +140,7 @@ namespace ILSpy.BamlDecompiler.Tests
ResourceReader reader;
try {
reader = new ResourceReader(s);
}
catch (ArgumentException) {
} catch (ArgumentException) {
return null;
}
foreach (DictionaryEntry entry in reader.Cast<DictionaryEntry>().OrderBy(e => e.Key.ToString())) {
@ -148,7 +152,7 @@ namespace ILSpy.BamlDecompiler.Tests @@ -148,7 +152,7 @@ namespace ILSpy.BamlDecompiler.Tests
}
}
}
return null;
}
#endregion

5
ILSpy.BamlDecompiler/Tests/Cases/Issue775.xaml

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:MyNamespace="clr-namespace:ILSpy.BamlDecompiler.Tests.Cases">
<Style x:Key="style1">
<Setter Property="MyNamespace:CustomControl.CustomName" Value="Test" />
</Style>
</ResourceDictionary>

2
ILSpy.BamlDecompiler/Tests/Cases/MarkupExtension.xaml

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
<Label DataContext="{Binding Blub}" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Label DataContext="{Binding Blub}" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Label.Style>
<Style />
</Label.Style>

2
ILSpy.BamlDecompiler/Tests/Cases/SimplePropertyElement.xaml

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
<Label xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Label xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Label.Style>
<Style />
</Label.Style>

3
ILSpy.BamlDecompiler/Tests/ILSpy.BamlDecompiler.Tests.csproj

@ -129,6 +129,9 @@ @@ -129,6 +129,9 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Cases\Issue775.xaml">
<SubType>Designer</SubType>
</Page>
<Page Include="Cases\MarkupExtension.xaml" />
<Page Include="Cases\MyControl.xaml" />
<Page Include="Cases\NamespacePrefix.xaml" />

Loading…
Cancel
Save