mirror of https://github.com/icsharpcode/ILSpy.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1737 lines
48 KiB
1737 lines
48 KiB
// 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; |
|
using System.Collections.Generic; |
|
using System.Diagnostics; |
|
using System.Globalization; |
|
using System.IO; |
|
using System.Linq; |
|
using System.Reflection; |
|
using System.Text; |
|
using System.Xml; |
|
using System.Windows.Media; |
|
|
|
namespace Ricciolo.StylesExplorer.MarkupReflection |
|
{ |
|
public class XmlBamlReader : XmlReader, IXmlNamespaceResolver |
|
{ |
|
BamlBinaryReader reader; |
|
Dictionary<short, string> assemblyTable = new Dictionary<short, string>(); |
|
Dictionary<short, string> stringTable = new Dictionary<short, string>(); |
|
Dictionary<short, TypeDeclaration> typeTable = new Dictionary<short, TypeDeclaration>(); |
|
Dictionary<short, PropertyDeclaration> propertyTable = new Dictionary<short, PropertyDeclaration>(); |
|
|
|
readonly IDotNetTypeResolver _resolver; |
|
|
|
BamlRecordType currentType; |
|
|
|
Stack<XmlBamlElement> elements = new Stack<XmlBamlElement>(); |
|
Stack<XmlBamlElement> readingElements = new Stack<XmlBamlElement>(); |
|
NodesCollection nodes = new NodesCollection(); |
|
List<XmlToClrNamespaceMapping> mappings = new List<XmlToClrNamespaceMapping>(); |
|
XmlBamlNode _currentNode; |
|
|
|
readonly KnownInfo KnownInfo; |
|
|
|
int complexPropertyOpened = 0; |
|
|
|
bool intoAttribute = false; |
|
bool initialized; |
|
bool _eof; |
|
|
|
#region Context |
|
Stack<ReaderContext> layer = new Stack<ReaderContext>(); |
|
|
|
class ReaderContext |
|
{ |
|
public bool IsDeferred { get; set; } |
|
public bool IsInStaticResource { get; set; } |
|
|
|
public ReaderContext Previous { get; private set; } |
|
|
|
public ReaderContext() |
|
{ |
|
Previous = this; |
|
} |
|
|
|
public ReaderContext(ReaderContext previous) |
|
{ |
|
Previous = previous; |
|
} |
|
} |
|
|
|
ReaderContext Current { |
|
get { |
|
if (!layer.Any()) |
|
layer.Push(new ReaderContext()); |
|
|
|
return layer.Peek(); |
|
} |
|
} |
|
|
|
int currentKey; |
|
List<KeyMapping> keys = new List<KeyMapping>(); |
|
|
|
void LayerPop() |
|
{ |
|
layer.Pop(); |
|
} |
|
|
|
void LayerPush() |
|
{ |
|
if (layer.Any()) |
|
layer.Push(new ReaderContext(layer.Peek())); |
|
else |
|
layer.Push(new ReaderContext()); |
|
} |
|
#endregion |
|
|
|
int bytesToSkip; |
|
|
|
static readonly MethodInfo staticConvertCustomBinaryToObjectMethod = Type.GetType("System.Windows.Markup.XamlPathDataSerializer,PresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35").GetMethod("StaticConvertCustomBinaryToObject", BindingFlags.Static | BindingFlags.Public); |
|
readonly TypeDeclaration XamlTypeDeclaration; |
|
readonly XmlNameTable _nameTable = new NameTable(); |
|
IDictionary<string, string> _rootNamespaces; |
|
|
|
public const string XWPFNamespace = XmlToClrNamespaceMapping.XamlNamespace; |
|
public const string DefaultWPFNamespace = XmlToClrNamespaceMapping.PresentationNamespace; |
|
|
|
public ISet<XmlNamespace> XmlnsDefinitions { get; } = new HashSet<XmlNamespace>(); |
|
|
|
public XmlBamlReader(Stream stream, IDotNetTypeResolver resolver) |
|
{ |
|
if (stream == null) |
|
throw new ArgumentNullException(nameof(stream)); |
|
if (resolver == null) |
|
throw new ArgumentNullException(nameof(resolver)); |
|
|
|
_resolver = resolver; |
|
reader = new BamlBinaryReader(stream); |
|
|
|
XamlTypeDeclaration = new TypeDeclaration(Resolver, "", "System.Windows.Markup", 0); |
|
KnownInfo = new KnownInfo(resolver); |
|
} |
|
|
|
public override string GetAttribute(string name) |
|
{ |
|
throw new NotImplementedException(); |
|
} |
|
|
|
public override string GetAttribute(string name, string namespaceURI) |
|
{ |
|
throw new NotImplementedException(); |
|
} |
|
|
|
public override string GetAttribute(int i) |
|
{ |
|
throw new NotImplementedException(); |
|
} |
|
|
|
public override bool MoveToAttribute(string name) |
|
{ |
|
throw new NotImplementedException(); |
|
} |
|
|
|
public override bool MoveToAttribute(string name, string ns) |
|
{ |
|
throw new NotImplementedException(); |
|
} |
|
|
|
public override bool MoveToFirstAttribute() |
|
{ |
|
intoAttribute = false; |
|
if (nodes.Count > 0 && (nodes.Peek() is XmlBamlProperty || nodes.Peek() is XmlBamlSimpleProperty)) |
|
{ |
|
_currentNode = nodes.Dequeue(); |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
public override bool MoveToNextAttribute() |
|
{ |
|
intoAttribute = false; |
|
if (nodes.Count > 0 && (nodes.Peek() is XmlBamlProperty || nodes.Peek() is XmlBamlSimpleProperty)) |
|
{ |
|
_currentNode = nodes.Dequeue(); |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
public override bool MoveToElement() |
|
{ |
|
while (nodes.Peek() is XmlBamlProperty || nodes.Peek() is XmlBamlSimpleProperty) |
|
{ |
|
nodes.Dequeue(); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
public override bool ReadAttributeValue() |
|
{ |
|
if (!intoAttribute) |
|
{ |
|
intoAttribute = true; |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
public override bool Read() |
|
{ |
|
return ReadInternal(); |
|
} |
|
|
|
bool ReadInternal() |
|
{ |
|
EnsureInit(); |
|
|
|
if (SetNextNode()) |
|
return true; |
|
|
|
try |
|
{ |
|
do |
|
{ |
|
ReadRecordType(); |
|
if (currentType == BamlRecordType.DocumentEnd) |
|
break; |
|
|
|
long position = reader.BaseStream.Position; |
|
|
|
bytesToSkip = ComputeBytesToSkip(); |
|
ProcessNext(); |
|
|
|
if (bytesToSkip > 0) |
|
// jump to the end of the record |
|
reader.BaseStream.Position = position + bytesToSkip; |
|
} |
|
//while (currentType != BamlRecordType.DocumentEnd); |
|
while (nodes.Count == 0 || (currentType != BamlRecordType.ElementEnd) || complexPropertyOpened > 0); |
|
|
|
if (!SetNextNode()) { |
|
_eof = true; |
|
return false; |
|
} |
|
return true; |
|
} |
|
catch (EndOfStreamException) |
|
{ |
|
_eof = true; |
|
return false; |
|
} |
|
} |
|
|
|
void ReadRecordType() |
|
{ |
|
byte type = reader.ReadByte(); |
|
if (type < 0) |
|
currentType = BamlRecordType.DocumentEnd; |
|
else |
|
currentType = (BamlRecordType)type; |
|
#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", StringComparison.Ordinal)) |
|
Debug.Indent(); |
|
#endif |
|
} |
|
|
|
bool SetNextNode() |
|
{ |
|
while (nodes.Count > 0) |
|
{ |
|
_currentNode = nodes.Dequeue(); |
|
|
|
if ((_currentNode is XmlBamlProperty)) continue; |
|
if ((_currentNode is XmlBamlSimpleProperty)) continue; |
|
|
|
if (NodeType == XmlNodeType.EndElement) |
|
{ |
|
if (readingElements.Count == 1) |
|
_rootNamespaces = ((IXmlNamespaceResolver)this).GetNamespacesInScope(XmlNamespaceScope.All); |
|
readingElements.Pop(); |
|
} |
|
else if (NodeType == XmlNodeType.Element) |
|
readingElements.Push((XmlBamlElement)_currentNode); |
|
|
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
void ProcessNext() |
|
{ |
|
switch (currentType) |
|
{ |
|
case BamlRecordType.DocumentStart: |
|
reader.ReadBytes(6); |
|
break; |
|
case BamlRecordType.DocumentEnd: |
|
break; |
|
case BamlRecordType.ElementStart: |
|
ReadElementStart(); |
|
break; |
|
case BamlRecordType.ElementEnd: |
|
ReadElementEnd(); |
|
break; |
|
case BamlRecordType.AssemblyInfo: |
|
ReadAssemblyInfo(); |
|
break; |
|
case BamlRecordType.StringInfo: |
|
ReadStringInfo(); |
|
break; |
|
case BamlRecordType.LineNumberAndPosition: |
|
reader.ReadInt32(); |
|
reader.ReadInt32(); |
|
break; |
|
case BamlRecordType.LinePosition: |
|
reader.ReadInt32(); |
|
break; |
|
case BamlRecordType.XmlnsProperty: |
|
ReadXmlnsProperty(); |
|
break; |
|
case BamlRecordType.ConnectionId: |
|
ReadConnectionId(); |
|
break; |
|
case BamlRecordType.DeferableContentStart: |
|
Current.IsDeferred = true; |
|
keys = new List<KeyMapping>(); |
|
currentKey = 0; |
|
reader.ReadInt32(); |
|
break; |
|
case BamlRecordType.DefAttribute: |
|
ReadDefAttribute(); |
|
break; |
|
case BamlRecordType.DefAttributeKeyType: |
|
ReadDefAttributeKeyType(); |
|
break; |
|
case BamlRecordType.DefAttributeKeyString: |
|
ReadDefAttributeKeyString(); |
|
break; |
|
case BamlRecordType.AttributeInfo: |
|
ReadAttributeInfo(); |
|
break; |
|
case BamlRecordType.PropertyListStart: |
|
ReadPropertyListStart(); |
|
break; |
|
case BamlRecordType.PropertyListEnd: |
|
ReadPropertyListEnd(); |
|
break; |
|
case BamlRecordType.Property: |
|
ReadProperty(); |
|
break; |
|
case BamlRecordType.PropertyWithConverter: |
|
ReadPropertyWithConverter(); |
|
break; |
|
case BamlRecordType.PropertyWithExtension: |
|
ReadPropertyWithExtension(); |
|
break; |
|
case BamlRecordType.PropertyDictionaryStart: |
|
ReadPropertyDictionaryStart(); |
|
break; |
|
case BamlRecordType.PropertyCustom: |
|
ReadPropertyCustom(); |
|
break; |
|
case BamlRecordType.PropertyDictionaryEnd: |
|
ReadPropertyDictionaryEnd(); |
|
break; |
|
case BamlRecordType.PropertyComplexStart: |
|
ReadPropertyComplexStart(); |
|
break; |
|
case BamlRecordType.PropertyComplexEnd: |
|
ReadPropertyComplexEnd(); |
|
break; |
|
case BamlRecordType.PIMapping: |
|
ReadPIMapping(); |
|
break; |
|
case BamlRecordType.TypeInfo: |
|
ReadTypeInfo(); |
|
break; |
|
case BamlRecordType.ContentProperty: |
|
ReadContentProperty(); |
|
break; |
|
case BamlRecordType.ConstructorParametersStart: |
|
ReadConstructorParametersStart(); |
|
break; |
|
case BamlRecordType.ConstructorParametersEnd: |
|
ReadConstructorParametersEnd(); |
|
break; |
|
case BamlRecordType.ConstructorParameterType: |
|
ReadConstructorParameterType(); |
|
break; |
|
case BamlRecordType.Text: |
|
ReadText(); |
|
break; |
|
case BamlRecordType.TextWithConverter: |
|
ReadTextWithConverter(); |
|
break; |
|
case BamlRecordType.TextWithId: |
|
ReadTextWithId(); |
|
break; |
|
case BamlRecordType.PropertyWithStaticResourceId: |
|
ReadPropertyWithStaticResourceIdentifier(); |
|
break; |
|
case BamlRecordType.OptimizedStaticResource: |
|
ReadOptimizedStaticResource(); |
|
break; |
|
case BamlRecordType.KeyElementStart: |
|
ReadKeyElementStart(); |
|
break; |
|
case BamlRecordType.KeyElementEnd: |
|
ReadKeyElementEnd(); |
|
break; |
|
case BamlRecordType.PropertyTypeReference: |
|
ReadPropertyTypeReference(); |
|
break; |
|
case BamlRecordType.StaticResourceStart: |
|
ReadStaticResourceStart(); |
|
break; |
|
case BamlRecordType.StaticResourceEnd: |
|
ReadStaticResourceEnd(); |
|
break; |
|
case BamlRecordType.StaticResourceId: |
|
ReadStaticResourceId(); |
|
break; |
|
case BamlRecordType.PresentationOptionsAttribute: |
|
ReadPresentationOptionsAttribute(); |
|
break; |
|
case BamlRecordType.TypeSerializerInfo: |
|
ReadTypeInfo(); |
|
break; |
|
case BamlRecordType.PropertyArrayStart: |
|
ReadPropertyArrayStart(); |
|
break; |
|
case BamlRecordType.PropertyArrayEnd: |
|
ReadPropertyArrayEnd(); |
|
break; |
|
default: |
|
throw new NotImplementedException("UnsupportedNode: " + currentType); |
|
} |
|
} |
|
|
|
void ReadConnectionId() |
|
{ |
|
int id = reader.ReadInt32(); |
|
nodes.Enqueue(new XmlBamlSimpleProperty(XWPFNamespace, "ConnectionId", id.ToString())); |
|
} |
|
|
|
void ReadTextWithId() |
|
{ |
|
short textId = reader.ReadInt16(); |
|
string text = stringTable[textId]; |
|
nodes.Enqueue(new XmlBamlText(text)); |
|
} |
|
|
|
int ComputeBytesToSkip() |
|
{ |
|
switch (currentType) |
|
{ |
|
case BamlRecordType.PropertyWithConverter: |
|
case BamlRecordType.DefAttributeKeyString: |
|
case BamlRecordType.PresentationOptionsAttribute: |
|
case BamlRecordType.Property: |
|
case BamlRecordType.PropertyCustom: |
|
case BamlRecordType.Text: |
|
case BamlRecordType.TextWithId: |
|
case BamlRecordType.TextWithConverter: |
|
case BamlRecordType.XmlnsProperty: |
|
case BamlRecordType.DefAttribute: |
|
case BamlRecordType.PIMapping: |
|
case BamlRecordType.AssemblyInfo: |
|
case BamlRecordType.TypeInfo: |
|
case BamlRecordType.AttributeInfo: |
|
case BamlRecordType.StringInfo: |
|
case BamlRecordType.TypeSerializerInfo: |
|
return reader.ReadCompressedInt32(); |
|
default: |
|
return 0; |
|
} |
|
} |
|
|
|
void EnsureInit() |
|
{ |
|
if (!initialized) |
|
{ |
|
int startChars = reader.ReadInt32(); |
|
String type = new String(new BinaryReader(reader.BaseStream, Encoding.Unicode).ReadChars(startChars >> 1)); |
|
if (type != "MSBAML") |
|
throw new NotSupportedException("Not a MS BAML"); |
|
|
|
int r = reader.ReadInt32(); |
|
int s = reader.ReadInt32(); |
|
int t = reader.ReadInt32(); |
|
if (((r != 0x600000) || (s != 0x600000)) || (t != 0x600000)) |
|
throw new NotSupportedException(); |
|
|
|
initialized = true; |
|
} |
|
} |
|
|
|
|
|
public override void Close() |
|
{ |
|
reader = null; |
|
} |
|
|
|
|
|
public override string LookupNamespace(string prefix) |
|
{ |
|
if (readingElements.Count == 0) return null; |
|
|
|
var namespaces = readingElements.Peek().Namespaces; |
|
|
|
for (int i = 0; i < namespaces.Count; i++) { |
|
if (String.CompareOrdinal(namespaces[i].Prefix, prefix) == 0) |
|
return namespaces[i].Namespace; |
|
} |
|
|
|
return null; |
|
} |
|
|
|
|
|
public override void ResolveEntity() |
|
{ |
|
throw new NotImplementedException(); |
|
} |
|
|
|
|
|
public override XmlNodeType NodeType |
|
{ |
|
get { |
|
if (intoAttribute) return XmlNodeType.Text; |
|
|
|
return CurrentNode.NodeType; |
|
} |
|
} |
|
|
|
|
|
public override string LocalName |
|
{ |
|
get |
|
{ |
|
if (intoAttribute) return string.Empty; |
|
|
|
String localName = string.Empty; |
|
|
|
XmlBamlNode node = CurrentNode; |
|
if (node is XmlBamlSimpleProperty) { |
|
var simpleNode = (XmlBamlSimpleProperty)node; |
|
localName = simpleNode.LocalName; |
|
} else if (node is XmlBamlProperty) |
|
{ |
|
PropertyDeclaration pd = ((XmlBamlProperty)node).PropertyDeclaration; |
|
localName = FormatPropertyDeclaration(pd, false, true, true); |
|
} |
|
else if (node is XmlBamlPropertyElement) |
|
{ |
|
XmlBamlPropertyElement property = (XmlBamlPropertyElement)node; |
|
string typeName = property.TypeDeclaration.Name; |
|
|
|
if (property.Parent.TypeDeclaration.Type.IsSubclassOf(property.PropertyDeclaration.DeclaringType.Type)) |
|
typeName = property.Parent.TypeDeclaration.Name; |
|
|
|
localName = String.Format("{0}.{1}", typeName, property.PropertyDeclaration.Name); |
|
} |
|
else if (node is XmlBamlElement) |
|
localName = ((XmlBamlElement)node).TypeDeclaration.Name; |
|
|
|
localName = NameTable.Add(localName); |
|
|
|
return localName; |
|
} |
|
} |
|
|
|
PropertyDeclaration GetPropertyDeclaration(short identifier) |
|
{ |
|
PropertyDeclaration declaration; |
|
if (identifier >= 0) |
|
{ |
|
declaration = propertyTable[identifier]; |
|
} |
|
else |
|
{ |
|
declaration = KnownInfo.KnownPropertyTable[-identifier]; |
|
} |
|
if (declaration == null) |
|
{ |
|
throw new NotSupportedException(); |
|
} |
|
return declaration; |
|
} |
|
|
|
object GetResourceName(short identifier) |
|
{ |
|
if (identifier >= 0) { |
|
PropertyDeclaration declaration = propertyTable[identifier]; |
|
return declaration; |
|
} else { |
|
identifier = (short)-identifier; |
|
bool isKey = true; |
|
if (identifier > 0xe8 && identifier < 0x1d0) { |
|
isKey = false; |
|
identifier -= 0xe8; |
|
} else if (identifier > 0x1d0 && identifier < 0x1d3) { |
|
identifier -= 0xe7; |
|
} else if (identifier > 0x1d3 && identifier < 0x1d6) { |
|
identifier -= 0xea; |
|
isKey = false; |
|
} |
|
ResourceName resource; |
|
if (!KnownInfo.KnownResourceTable.TryGetValue(identifier, out resource)) |
|
// resource = new ResourceName("???Resource" + identifier + "???"); |
|
throw new ArgumentException("Cannot find resource name " + identifier); |
|
if (isKey) |
|
return new ResourceName(resource.Name + "Key"); |
|
return resource; |
|
} |
|
} |
|
|
|
void ReadPropertyArrayStart() |
|
{ |
|
short identifier = reader.ReadInt16(); |
|
|
|
PropertyDeclaration pd = GetPropertyDeclaration(identifier); |
|
XmlBamlElement element = elements.Peek(); |
|
XmlBamlPropertyElement property = new XmlBamlPropertyElement(element, PropertyType.Array, pd); |
|
elements.Push(property); |
|
nodes.Enqueue(property); |
|
} |
|
|
|
void ReadPropertyArrayEnd() |
|
{ |
|
CloseElement(); |
|
} |
|
|
|
void ReadPropertyDictionaryStart() |
|
{ |
|
short identifier = reader.ReadInt16(); |
|
|
|
PropertyDeclaration pd = GetPropertyDeclaration(identifier); |
|
XmlBamlElement element = elements.Peek(); |
|
XmlBamlPropertyElement property = new XmlBamlPropertyElement(element, PropertyType.Dictionary, pd); |
|
elements.Push(property); |
|
nodes.Enqueue(property); |
|
} |
|
|
|
void ReadPropertyDictionaryEnd() |
|
{ |
|
CloseElement(); |
|
} |
|
|
|
void ReadPropertyCustom() |
|
{ |
|
short identifier = reader.ReadInt16(); |
|
short serializerTypeId = reader.ReadInt16(); |
|
bool isValueTypeId = (serializerTypeId & 0x4000) == 0x4000; |
|
if (isValueTypeId) |
|
serializerTypeId = (short)(serializerTypeId & ~0x4000); |
|
|
|
PropertyDeclaration pd = GetPropertyDeclaration(identifier); |
|
string value; |
|
switch (serializerTypeId) |
|
{ |
|
case 0x2e8: |
|
value = new BrushConverter().ConvertToString(SolidColorBrush.DeserializeFrom(reader)); |
|
break; |
|
case 0x2e9: |
|
value = new Int32CollectionConverter().ConvertToString(DeserializeInt32CollectionFrom(reader)); |
|
break; |
|
case 0x89: |
|
|
|
short typeIdentifier = reader.ReadInt16(); |
|
if (isValueTypeId) |
|
{ |
|
TypeDeclaration typeDeclaration = GetTypeDeclaration(typeIdentifier); |
|
string name = reader.ReadString(); |
|
value = FormatPropertyDeclaration(new PropertyDeclaration(name, typeDeclaration), true, false, true); |
|
} |
|
else |
|
value = FormatPropertyDeclaration(GetPropertyDeclaration(typeIdentifier), true, false, true); |
|
break; |
|
|
|
case 0x2ea: |
|
value = ((IFormattable)staticConvertCustomBinaryToObjectMethod.Invoke(null, new object[] { reader })).ToString("G", CultureInfo.InvariantCulture); |
|
break; |
|
case 0x2eb: |
|
case 0x2f0: |
|
value = Deserialize3DPoints(); |
|
break; |
|
case 0x2ec: |
|
value = DeserializePoints(); |
|
break; |
|
case 0xc3: |
|
// Enum |
|
uint num = reader.ReadUInt32(); |
|
value = num.ToString(); |
|
break; |
|
case 0x2e: |
|
int b = reader.ReadByte(); |
|
value = (b == 1) ? Boolean.TrueString : Boolean.FalseString; |
|
break; |
|
default: |
|
return; |
|
} |
|
|
|
XmlBamlProperty property = new XmlBamlProperty(elements.Peek(), PropertyType.Value, pd); |
|
property.Value = value; |
|
|
|
nodes.Enqueue(property); |
|
} |
|
|
|
string DeserializePoints() |
|
{ |
|
using (StringWriter writer = new StringWriter()) |
|
{ |
|
int num10 = reader.ReadInt32(); |
|
for (int k = 0; k < num10; k++) |
|
{ |
|
if (k != 0) |
|
writer.Write(" "); |
|
for (int m = 0; m < 2; m++) |
|
{ |
|
if (m != 0) |
|
writer.Write(","); |
|
writer.Write(reader.ReadCompressedDouble().ToString()); |
|
} |
|
} |
|
return writer.ToString(); |
|
} |
|
} |
|
|
|
string Deserialize3DPoints() |
|
{ |
|
using (StringWriter writer = new StringWriter()) |
|
{ |
|
int num14 = reader.ReadInt32(); |
|
for (int i = 0; i < num14; i++) |
|
{ |
|
if (i != 0) |
|
{ |
|
writer.Write(" "); |
|
} |
|
for (int j = 0; j < 3; j++) |
|
{ |
|
if (j != 0) |
|
{ |
|
writer.Write(","); |
|
} |
|
writer.Write(reader.ReadCompressedDouble().ToString()); |
|
} |
|
} |
|
return writer.ToString(); |
|
} |
|
} |
|
|
|
static Int32Collection DeserializeInt32CollectionFrom(BinaryReader reader) |
|
{ |
|
IntegerCollectionType type = (IntegerCollectionType)reader.ReadByte(); |
|
int capacity = reader.ReadInt32(); |
|
if (capacity < 0) |
|
throw new ArgumentException(); |
|
|
|
Int32Collection ints = new Int32Collection(capacity); |
|
switch (type) { |
|
case IntegerCollectionType.Byte: |
|
for (int i = 0; i < capacity; i++) |
|
ints.Add(reader.ReadByte()); |
|
return ints; |
|
case IntegerCollectionType.UShort: |
|
for (int j = 0; j < capacity; j++) |
|
ints.Add(reader.ReadUInt16()); |
|
return ints; |
|
case IntegerCollectionType.Integer: |
|
for (int k = 0; k < capacity; k++) |
|
ints.Add(reader.ReadInt32()); |
|
return ints; |
|
case IntegerCollectionType.Consecutive: |
|
int start = reader.ReadInt32(); |
|
for (int m = start; m < capacity + start; m++) |
|
ints.Add(m); |
|
return ints; |
|
} |
|
throw new ArgumentException(); |
|
} |
|
|
|
void ReadPropertyWithExtension() |
|
{ |
|
short identifier = reader.ReadInt16(); |
|
short x = reader.ReadInt16(); |
|
short valueIdentifier = reader.ReadInt16(); |
|
bool isValueType = (x & 0x4000) == 0x4000; |
|
bool isStaticType = (x & 0x2000) == 0x2000; |
|
x = (short)(x & 0xfff); |
|
|
|
PropertyDeclaration pd = GetPropertyDeclaration(identifier); |
|
short extensionIdentifier = (short)-(x & 0xfff); |
|
string value = String.Empty; |
|
|
|
switch (x) { |
|
case 0x25a: |
|
// StaticExtension |
|
value = GetStaticExtension(GetResourceName(valueIdentifier)); |
|
break; |
|
case 0x25b: // StaticResource |
|
case 0xbd: // DynamicResource |
|
if (isValueType) |
|
{ |
|
value = GetTypeExtension(valueIdentifier); |
|
} |
|
else if (isStaticType) |
|
{ |
|
TypeDeclaration extensionDeclaration = GetTypeDeclaration(extensionIdentifier); |
|
value = GetExtension(extensionDeclaration, GetStaticExtension(GetResourceName(valueIdentifier))); |
|
} |
|
else |
|
{ |
|
TypeDeclaration extensionDeclaration = GetTypeDeclaration(extensionIdentifier); |
|
value = GetExtension(extensionDeclaration, (string)stringTable[valueIdentifier]); |
|
} |
|
break; |
|
|
|
case 0x27a: |
|
// TemplateBinding |
|
PropertyDeclaration pdValue = GetPropertyDeclaration(valueIdentifier); |
|
value = GetTemplateBindingExtension(pdValue); |
|
break; |
|
default: |
|
throw new NotSupportedException("Unknown property with extension"); |
|
} |
|
|
|
XmlBamlProperty property = new XmlBamlProperty(elements.Peek(), PropertyType.Value, pd); |
|
property.Value = value; |
|
|
|
nodes.Enqueue(property); |
|
} |
|
|
|
void ReadProperty() |
|
{ |
|
short identifier = reader.ReadInt16(); |
|
string text = reader.ReadString(); |
|
|
|
EnqueueProperty(identifier, EscapeCurlyBraces(text)); |
|
} |
|
|
|
void ReadPropertyWithConverter() |
|
{ |
|
short identifier = reader.ReadInt16(); |
|
string text = reader.ReadString(); |
|
reader.ReadInt16(); |
|
|
|
EnqueueProperty(identifier, EscapeCurlyBraces(text)); |
|
} |
|
|
|
string EscapeCurlyBraces(string text) |
|
{ |
|
if (!text.StartsWith("{", StringComparison.OrdinalIgnoreCase)) |
|
return text; |
|
if (text.StartsWith("{}", StringComparison.OrdinalIgnoreCase)) |
|
return text; |
|
return "{}" + text; |
|
} |
|
|
|
bool HaveSeenNestedElement() |
|
{ |
|
XmlBamlElement element = elements.Peek(); |
|
int elementIndex = nodes.IndexOf(element); |
|
for (int i = elementIndex + 1; i < nodes.Count; i++) |
|
{ |
|
if (nodes[i] is XmlBamlEndElement) |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
void EnqueueProperty(short identifier, string text) |
|
{ |
|
PropertyDeclaration pd = GetPropertyDeclaration(identifier); |
|
XmlBamlElement element = FindXmlBamlElement(); |
|
// if we've already read a nested element for the current element, this property must be a nested element as well |
|
if (HaveSeenNestedElement()) |
|
{ |
|
XmlBamlPropertyElement property = new XmlBamlPropertyElement(element, PropertyType.Complex, pd); |
|
|
|
nodes.Enqueue(property); |
|
nodes.Enqueue(new XmlBamlText(text)); |
|
nodes.Enqueue(new XmlBamlEndElement(property)); |
|
} |
|
else |
|
{ |
|
XmlBamlProperty property = new XmlBamlProperty(element, PropertyType.Value, pd); |
|
property.Value = text; |
|
|
|
nodes.Enqueue(property); |
|
} |
|
} |
|
|
|
void ReadAttributeInfo() |
|
{ |
|
short key = reader.ReadInt16(); |
|
short identifier = reader.ReadInt16(); |
|
reader.ReadByte(); |
|
string name = reader.ReadString(); |
|
TypeDeclaration declaringType = GetTypeDeclaration(identifier); |
|
PropertyDeclaration property = new PropertyDeclaration(name, declaringType); |
|
propertyTable.Add(key, property); |
|
} |
|
|
|
void ReadDefAttributeKeyType() |
|
{ |
|
short typeIdentifier = reader.ReadInt16(); |
|
reader.ReadByte(); |
|
int position = reader.ReadInt32(); |
|
bool shared = reader.ReadBoolean(); |
|
bool sharedSet = reader.ReadBoolean(); |
|
|
|
string extension = GetTypeExtension(typeIdentifier); |
|
|
|
keys.Add(new KeyMapping(extension) { Shared = shared, SharedSet = sharedSet, Position = position }); |
|
} |
|
|
|
void ReadDefAttribute() |
|
{ |
|
string text = reader.ReadString(); |
|
short identifier = reader.ReadInt16(); |
|
|
|
PropertyDeclaration pd; |
|
switch (identifier) |
|
{ |
|
case -2: |
|
pd = new PropertyDeclaration("Uid", XamlTypeDeclaration); |
|
break; |
|
case -1: |
|
pd = new PropertyDeclaration("Name", XamlTypeDeclaration); |
|
break; |
|
default: |
|
string recordName = 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; |
|
} |
|
|
|
XmlBamlProperty property = new XmlBamlProperty(elements.Peek(), PropertyType.Key, pd); |
|
property.Value = text; |
|
|
|
nodes.Enqueue(property); |
|
} |
|
|
|
void ReadDefAttributeKeyString() |
|
{ |
|
short stringId = reader.ReadInt16(); |
|
int position = reader.ReadInt32(); |
|
bool shared = reader.ReadBoolean(); |
|
bool sharedSet = reader.ReadBoolean(); |
|
|
|
string text = stringTable[stringId]; |
|
Debug.Print("KeyString: " + text); |
|
if (text == null) |
|
throw new NotSupportedException(); |
|
|
|
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++) { |
|
textArray[i] = assemblyTable[reader.ReadInt16()]; |
|
} |
|
|
|
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"); |
|
if (mappingToChange.AssemblyId > 0) { |
|
@namespace = String.Format("{0};assembly={1}", @namespace, mappingToChange.AssemblyName.Replace(" ", "")); |
|
mappingToChange.XmlNamespace = @namespace; |
|
} |
|
} |
|
var ns = new XmlNamespace(prefix, @namespace); |
|
XmlnsDefinitions.Add(ns); |
|
namespaces.Add(ns); |
|
} |
|
|
|
void ReadElementEnd() |
|
{ |
|
CloseElement(); |
|
if (Current.IsDeferred) |
|
keys = null; |
|
LayerPop(); |
|
} |
|
|
|
void ReadPropertyComplexStart() |
|
{ |
|
short identifier = reader.ReadInt16(); |
|
|
|
PropertyDeclaration pd = GetPropertyDeclaration(identifier); |
|
XmlBamlElement element = FindXmlBamlElement(); |
|
|
|
XmlBamlPropertyElement property = new XmlBamlPropertyElement(element, PropertyType.Complex, pd); |
|
elements.Push(property); |
|
nodes.Enqueue(property); |
|
complexPropertyOpened++; |
|
} |
|
|
|
XmlBamlElement FindXmlBamlElement() |
|
{ |
|
return elements.Peek(); |
|
|
|
//XmlBamlElement element; |
|
//int x = nodes.Count - 1; |
|
//do |
|
//{ |
|
// element = nodes[x] as XmlBamlElement; |
|
// x--; |
|
//} while (element == null); |
|
//return element; |
|
} |
|
|
|
void ReadPropertyListStart() |
|
{ |
|
short identifier = reader.ReadInt16(); |
|
|
|
PropertyDeclaration pd = GetPropertyDeclaration(identifier); |
|
XmlBamlElement element = FindXmlBamlElement(); |
|
XmlBamlPropertyElement property = new XmlBamlPropertyElement(element, PropertyType.List, pd); |
|
elements.Push(property); |
|
nodes.Enqueue(property); |
|
} |
|
|
|
void ReadPropertyListEnd() |
|
{ |
|
CloseElement(); |
|
} |
|
|
|
void ReadPropertyComplexEnd() |
|
{ |
|
XmlBamlPropertyElement propertyElement = (XmlBamlPropertyElement) elements.Peek(); |
|
|
|
CloseElement(); |
|
|
|
complexPropertyOpened--; |
|
// this property could be a markup extension |
|
// try to convert it |
|
int elementIndex = nodes.IndexOf(propertyElement.Parent); |
|
int start = nodes.IndexOf(propertyElement) + 1; |
|
IEnumerator<XmlBamlNode> enumerator = nodes.GetEnumerator(); |
|
|
|
// move enumerator to the start of this property value |
|
// note whether there are any child elements before this one |
|
bool anyChildElement = false; |
|
for (int i = 0; i < start && enumerator.MoveNext(); i++) |
|
{ |
|
if (i > elementIndex && i < start - 1 && (enumerator.Current is XmlBamlEndElement)) |
|
anyChildElement = true; |
|
} |
|
|
|
if (!anyChildElement && IsExtension(enumerator) && start < nodes.Count - 1) { |
|
start--; |
|
nodes.RemoveAt(start); |
|
nodes.RemoveLast(); |
|
|
|
StringBuilder sb = new StringBuilder(); |
|
FormatElementExtension((XmlBamlElement) nodes[start], sb); |
|
|
|
XmlBamlProperty property = |
|
new XmlBamlProperty(elements.Peek(), PropertyType.Complex, propertyElement.PropertyDeclaration); |
|
property.Value = sb.ToString(); |
|
nodes.Add(property); |
|
} |
|
} |
|
|
|
void FormatElementExtension(XmlBamlElement element, StringBuilder sb) |
|
{ |
|
sb.Append("{"); |
|
sb.Append(FormatTypeDeclaration(element.TypeDeclaration)); |
|
|
|
int start = nodes.IndexOf(element); |
|
nodes.RemoveAt(start); |
|
|
|
string sep = " "; |
|
while (nodes.Count > start) |
|
{ |
|
XmlBamlNode node = nodes[start]; |
|
|
|
if (node is XmlBamlEndElement) |
|
{ |
|
sb.Append("}"); |
|
nodes.RemoveAt(start); |
|
break; |
|
} |
|
else if (node is XmlBamlPropertyElement) |
|
{ |
|
nodes.RemoveAt(start); |
|
|
|
sb.Append(sep); |
|
XmlBamlPropertyElement property = (XmlBamlPropertyElement)node; |
|
sb.Append(property.PropertyDeclaration.Name); |
|
sb.Append("="); |
|
|
|
node = nodes[start]; |
|
nodes.RemoveLast(); |
|
FormatElementExtension((XmlBamlElement)node, sb); |
|
} |
|
else if (node is XmlBamlElement) |
|
{ |
|
sb.Append(sep); |
|
FormatElementExtension((XmlBamlElement)node, sb); |
|
} |
|
else if (node is XmlBamlProperty) |
|
{ |
|
nodes.RemoveAt(start); |
|
|
|
sb.Append(sep); |
|
XmlBamlProperty property = (XmlBamlProperty)node; |
|
sb.Append(property.PropertyDeclaration.Name); |
|
sb.Append("="); |
|
sb.Append(property.Value); |
|
} |
|
else if (node is XmlBamlText) |
|
{ |
|
nodes.RemoveAt(start); |
|
|
|
sb.Append(sep); |
|
sb.Append(((XmlBamlText)node).Text); |
|
} |
|
sep = ", "; |
|
} |
|
} |
|
|
|
bool IsExtension(IEnumerator<XmlBamlNode> enumerator) |
|
{ |
|
while (enumerator.MoveNext()) { |
|
var node = enumerator.Current; |
|
if (node.NodeType == XmlNodeType.Element && !((XmlBamlElement)node).TypeDeclaration.IsExtension) |
|
return false; |
|
} |
|
|
|
return true; |
|
} |
|
|
|
void CloseElement() |
|
{ |
|
var e = elements.Pop(); |
|
if (!e.IsImplicit) |
|
nodes.Enqueue(new XmlBamlEndElement(e)); |
|
} |
|
|
|
void ReadElementStart() |
|
{ |
|
LayerPush(); |
|
short identifier = reader.ReadInt16(); |
|
sbyte flags = reader.ReadSByte(); |
|
if (flags < 0 || flags > 3) |
|
throw new NotImplementedException(); |
|
Debug.Print("ElementFlags: " + flags); |
|
|
|
TypeDeclaration declaration = GetTypeDeclaration(identifier); |
|
|
|
XmlBamlElement element; |
|
XmlBamlElement parentElement = null; |
|
if (elements.Count > 0) |
|
{ |
|
parentElement = elements.Peek(); |
|
element = new XmlBamlElement(parentElement); |
|
element.Position = reader.BaseStream.Position; |
|
|
|
// Porto l'inizio del padre all'inizio del primo figlio |
|
if (parentElement.Position == 0 && complexPropertyOpened == 0) |
|
parentElement.Position = element.Position; |
|
} |
|
else |
|
element = new XmlBamlElement(); |
|
|
|
// the type is defined in the local assembly, i.e., the main assembly |
|
// and this is the root element |
|
TypeDeclaration oldDeclaration = null; |
|
if (_resolver.IsLocalAssembly(declaration.Assembly) && parentElement == null) { |
|
oldDeclaration = declaration; |
|
declaration = GetKnownTypeDeclarationByName(declaration.Type.BaseType.AssemblyQualifiedName); |
|
} |
|
element.TypeDeclaration = declaration; |
|
element.IsImplicit = (flags & 2) == 2; |
|
elements.Push(element); |
|
if (!element.IsImplicit) |
|
nodes.Enqueue(element); |
|
|
|
if (oldDeclaration != null) { |
|
nodes.Enqueue(new XmlBamlSimpleProperty(XWPFNamespace, "Class", oldDeclaration.FullyQualifiedName.Replace('+', '.'))); |
|
} |
|
|
|
if (parentElement != null && complexPropertyOpened == 0 && !Current.IsInStaticResource && Current.Previous.IsDeferred) { |
|
if (keys != null && keys.Count > currentKey) { |
|
string key = keys[currentKey].KeyString; |
|
AddKeyToElement(key); |
|
currentKey++; |
|
} |
|
} |
|
} |
|
|
|
void AddKeyToElement(string key) |
|
{ |
|
PropertyDeclaration pd = new PropertyDeclaration("Key", XamlTypeDeclaration); |
|
XmlBamlProperty property = new XmlBamlProperty(elements.Peek(), PropertyType.Key, pd); |
|
|
|
property.Value = key; |
|
|
|
nodes.Enqueue(property); |
|
} |
|
|
|
XmlToClrNamespaceMapping FindByClrNamespaceAndAssemblyId(TypeDeclaration declaration) |
|
{ |
|
return FindByClrNamespaceAndAssemblyName(declaration.Namespace, declaration.Assembly); |
|
} |
|
|
|
XmlToClrNamespaceMapping FindByClrNamespaceAndAssemblyName(string clrNamespace, string assemblyName) |
|
{ |
|
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 new XmlToClrNamespaceMapping(XmlToClrNamespaceMapping.PresentationNamespace, -1, assemblyName, clrNamespace); |
|
} |
|
|
|
void ReadPIMapping() |
|
{ |
|
string xmlNamespace = reader.ReadString(); |
|
string clrNamespace = reader.ReadString(); |
|
short assemblyId = reader.ReadInt16(); |
|
|
|
mappings.Add(new XmlToClrNamespaceMapping(xmlNamespace, assemblyId, GetAssembly(assemblyId), clrNamespace)); |
|
} |
|
|
|
void ReadContentProperty() |
|
{ |
|
reader.ReadInt16(); |
|
|
|
// Non serve aprire niente, ?il default |
|
} |
|
|
|
static void ReadConstructorParametersStart() |
|
{ |
|
//this.constructorParameterTable.Add(this.elements.Peek()); |
|
//PromoteDataToComplexProperty(); |
|
} |
|
|
|
static void ReadConstructorParametersEnd() |
|
{ |
|
//this.constructorParameterTable.Remove(this.elements.Peek()); |
|
//properties.Pop(); |
|
} |
|
|
|
void ReadConstructorParameterType() |
|
{ |
|
short identifier = reader.ReadInt16(); |
|
|
|
//TypeDeclaration declaration = GetTypeDeclaration(identifier); |
|
nodes.Enqueue(new XmlBamlText(GetTypeExtension(identifier))); |
|
} |
|
|
|
void ReadText() |
|
{ |
|
string text = reader.ReadString(); |
|
|
|
nodes.Enqueue(new XmlBamlText(text)); |
|
} |
|
|
|
void ReadKeyElementStart() |
|
{ |
|
short typeIdentifier = reader.ReadInt16(); |
|
byte valueIdentifier = reader.ReadByte(); |
|
// TODO: handle shared |
|
//bool shared = (valueIdentifier & 1) != 0; |
|
//bool sharedSet = (valueIdentifier & 2) != 0; |
|
int position = reader.ReadInt32(); |
|
reader.ReadBoolean(); |
|
reader.ReadBoolean(); |
|
|
|
TypeDeclaration declaration = GetTypeDeclaration(typeIdentifier); |
|
|
|
XmlBamlPropertyElement property = new XmlBamlPropertyElement(elements.Peek(), PropertyType.Key, new PropertyDeclaration("Key", declaration)); |
|
property.Position = position; |
|
elements.Push(property); |
|
nodes.Enqueue(property); |
|
complexPropertyOpened++; |
|
} |
|
|
|
void ReadKeyElementEnd() |
|
{ |
|
XmlBamlPropertyElement propertyElement = (XmlBamlPropertyElement)elements.Peek(); |
|
|
|
CloseElement(); |
|
complexPropertyOpened--; |
|
if (complexPropertyOpened == 0) { |
|
int start = nodes.IndexOf(propertyElement); |
|
|
|
StringBuilder sb = new StringBuilder(); |
|
FormatElementExtension((XmlBamlElement)nodes[start], sb); |
|
keys.Add(new KeyMapping(sb.ToString()) { Position = -1 }); |
|
} |
|
} |
|
|
|
void ReadStaticResourceStart() |
|
{ |
|
Current.IsInStaticResource = true; |
|
short identifier = reader.ReadInt16(); |
|
byte flags = reader.ReadByte(); |
|
TypeDeclaration declaration = GetTypeDeclaration(identifier); |
|
var lastKey = keys.LastOrDefault(); |
|
if (lastKey == null) |
|
throw new InvalidOperationException("No key mapping found for StaticResourceStart!"); |
|
lastKey.StaticResources.Add(declaration); |
|
XmlBamlElement element; |
|
if (elements.Any()) |
|
element = new XmlBamlElement(elements.Peek()); |
|
else |
|
element = new XmlBamlElement(); |
|
element.TypeDeclaration = declaration; |
|
elements.Push(element); |
|
nodes.Enqueue(element); |
|
} |
|
|
|
void ReadStaticResourceEnd() |
|
{ |
|
CloseElement(); |
|
Current.IsInStaticResource = false; |
|
} |
|
|
|
void ReadStaticResourceId() |
|
{ |
|
short identifier = reader.ReadInt16(); |
|
object staticResource = GetStaticResource(identifier); |
|
} |
|
|
|
void ReadPresentationOptionsAttribute() |
|
{ |
|
string text = reader.ReadString(); |
|
short valueIdentifier = reader.ReadInt16(); |
|
|
|
PropertyDeclaration pd = new PropertyDeclaration(stringTable[valueIdentifier].ToString()); |
|
|
|
XmlBamlProperty property = new XmlBamlProperty(elements.Peek(), PropertyType.Value, pd); |
|
property.Value = text; |
|
} |
|
|
|
void ReadPropertyTypeReference() |
|
{ |
|
short identifier = reader.ReadInt16(); |
|
short typeIdentifier = reader.ReadInt16(); |
|
|
|
PropertyDeclaration pd = GetPropertyDeclaration(identifier); |
|
string value = GetTypeExtension(typeIdentifier); |
|
|
|
XmlBamlProperty property = new XmlBamlProperty(elements.Peek(), PropertyType.Value, pd); |
|
property.Value = value; |
|
|
|
nodes.Enqueue(property); |
|
} |
|
|
|
void ReadOptimizedStaticResource() |
|
{ |
|
byte flags = reader.ReadByte(); |
|
short typeIdentifier = reader.ReadInt16(); |
|
bool isValueType = (flags & 1) == 1; |
|
bool isStaticType = (flags & 2) == 2; |
|
object resource; |
|
|
|
if (isValueType) |
|
resource = GetTypeExtension(typeIdentifier); |
|
else if (isStaticType) { |
|
resource = GetStaticExtension(GetResourceName(typeIdentifier)); |
|
} else { |
|
resource = stringTable[typeIdentifier]; |
|
} |
|
|
|
var lastKey = keys.LastOrDefault(); |
|
if (lastKey == null) |
|
throw new InvalidOperationException("No key mapping found for OptimizedStaticResource!"); |
|
lastKey.StaticResources.Add(resource); |
|
} |
|
|
|
string GetTemplateBindingExtension(PropertyDeclaration propertyDeclaration) |
|
{ |
|
return String.Format("{{TemplateBinding {0}}}", FormatPropertyDeclaration(propertyDeclaration, true, false, false)); |
|
} |
|
|
|
string GetStaticExtension(object resource) |
|
{ |
|
if (resource == null) |
|
return null; |
|
string name; |
|
if (resource is ResourceName) |
|
name = ((ResourceName)resource).Name; |
|
else if (resource is PropertyDeclaration) |
|
name = FormatPropertyDeclaration(((PropertyDeclaration)resource), true, false, false); |
|
else |
|
throw new InvalidOperationException("Invalid resource: " + resource.GetType()); |
|
|
|
string prefix = LookupPrefix(XmlToClrNamespaceMapping.XamlNamespace, false); |
|
if (String.IsNullOrEmpty(prefix)) |
|
return String.Format("{{Static {0}}}", name); |
|
else |
|
return String.Format("{{{0}:Static {1}}}", prefix, name); |
|
} |
|
|
|
string GetExtension(TypeDeclaration declaration, string value) |
|
{ |
|
return String.Format("{{{0} {1}}}", FormatTypeDeclaration(declaration), value); |
|
} |
|
|
|
string GetTypeExtension(short typeIdentifier) |
|
{ |
|
string prefix = LookupPrefix(XmlToClrNamespaceMapping.XamlNamespace, false); |
|
if (String.IsNullOrEmpty(prefix)) |
|
return String.Format("{{Type {0}}}", FormatTypeDeclaration(GetTypeDeclaration(typeIdentifier))); |
|
else |
|
return String.Format("{{{0}:Type {1}}}", prefix, FormatTypeDeclaration(GetTypeDeclaration(typeIdentifier))); |
|
} |
|
|
|
string FormatTypeDeclaration(TypeDeclaration typeDeclaration) |
|
{ |
|
XmlToClrNamespaceMapping mapping = FindByClrNamespaceAndAssemblyName(typeDeclaration.Namespace, typeDeclaration.Assembly); |
|
string prefix = (mapping != null) ? LookupPrefix(mapping.XmlNamespace, false) : null; |
|
string name = typeDeclaration.Name; |
|
if (name.EndsWith("Extension", StringComparison.Ordinal)) |
|
name = name.Substring(0, name.Length - 9); |
|
if (String.IsNullOrEmpty(prefix)) |
|
return name; |
|
else |
|
return String.Format("{0}:{1}", prefix, name); |
|
} |
|
|
|
string FormatPropertyDeclaration(PropertyDeclaration propertyDeclaration, bool withPrefix, bool useReading, bool checkType) |
|
{ |
|
StringBuilder sb = new StringBuilder(); |
|
|
|
TypeDeclaration elementDeclaration = (useReading) ? readingElements.Peek().TypeDeclaration : elements.Peek().TypeDeclaration; |
|
|
|
IDependencyPropertyDescriptor descriptor = null; |
|
bool areValidTypes = elementDeclaration.Type != null && propertyDeclaration.DeclaringType.Type != null; |
|
if (areValidTypes) |
|
descriptor = Resolver.GetDependencyPropertyDescriptor(propertyDeclaration.Name, elementDeclaration.Type, propertyDeclaration.DeclaringType.Type); |
|
|
|
bool isDescendant = (areValidTypes && (propertyDeclaration.DeclaringType.Type.Equals(elementDeclaration.Type) || elementDeclaration.Type.IsSubclassOf(propertyDeclaration.DeclaringType.Type))); |
|
bool isAttached = (descriptor != null && descriptor.IsAttached); |
|
|
|
if (withPrefix) { |
|
XmlToClrNamespaceMapping mapping = FindByClrNamespaceAndAssemblyName(propertyDeclaration.DeclaringType.Namespace, propertyDeclaration.DeclaringType.Assembly); |
|
string prefix = (mapping != null) ? LookupPrefix(mapping.XmlNamespace, false) : null; |
|
|
|
if (!String.IsNullOrEmpty(prefix)) { |
|
sb.Append(prefix); |
|
sb.Append(":"); |
|
} |
|
} |
|
if ((!isDescendant || isAttached || !checkType) && propertyDeclaration.DeclaringType.Name.Length > 0) { |
|
sb.Append(propertyDeclaration.DeclaringType.Name); |
|
sb.Append("."); |
|
} |
|
sb.Append(propertyDeclaration.Name); |
|
|
|
return sb.ToString(); |
|
} |
|
|
|
void ReadPropertyWithStaticResourceIdentifier() |
|
{ |
|
short propertyId = reader.ReadInt16(); |
|
short index = reader.ReadInt16(); |
|
|
|
PropertyDeclaration pd = GetPropertyDeclaration(propertyId); |
|
object staticResource = GetStaticResource(index); |
|
|
|
string prefix = 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); |
|
property.Value = value; |
|
|
|
nodes.Enqueue(property); |
|
} |
|
|
|
object GetStaticResource(short identifier) |
|
{ |
|
int keyIndex = Math.Max(0, currentKey - 1); |
|
while (keyIndex > keys.Count) |
|
keyIndex--; |
|
while (keyIndex >= 0 && !keys[keyIndex].HasStaticResource(identifier)) |
|
keyIndex--; |
|
if (keyIndex >= 0 && identifier < keys[keyIndex].StaticResources.Count) |
|
return keys[keyIndex].StaticResources[(int)identifier]; |
|
// Debug.WriteLine(string.Format("Cannot find StaticResource: {0}", identifier)); |
|
// return "???" + identifier + "???"; |
|
throw new ArgumentException("Cannot find StaticResource: " + identifier, nameof(identifier)); |
|
} |
|
|
|
void ReadTextWithConverter() |
|
{ |
|
string text = reader.ReadString(); |
|
reader.ReadInt16(); |
|
|
|
nodes.Enqueue(new XmlBamlText(text)); |
|
} |
|
|
|
void ReadTypeInfo() |
|
{ |
|
short typeId = reader.ReadInt16(); |
|
short assemblyId = reader.ReadInt16(); |
|
string fullName = reader.ReadString(); |
|
assemblyId = (short)(assemblyId & 0xfff); |
|
TypeDeclaration declaration; |
|
int bracket = fullName.IndexOf('['); |
|
int length = bracket > -1 ? fullName.LastIndexOf('.', bracket) : fullName.LastIndexOf('.'); |
|
if (length != -1) |
|
{ |
|
string name = fullName.Substring(length + 1); |
|
string namespaceName = fullName.Substring(0, length); |
|
declaration = new TypeDeclaration(this, Resolver, name, namespaceName, assemblyId); |
|
} |
|
else |
|
{ |
|
declaration = new TypeDeclaration(this, Resolver, fullName, string.Empty, assemblyId); |
|
} |
|
typeTable.Add(typeId, declaration); |
|
} |
|
|
|
void ReadAssemblyInfo() |
|
{ |
|
short key = reader.ReadInt16(); |
|
string text = reader.ReadString(); |
|
assemblyTable.Add(key, text); |
|
} |
|
|
|
void ReadStringInfo() |
|
{ |
|
short key = reader.ReadInt16(); |
|
string text = reader.ReadString(); |
|
stringTable.Add(key, text); |
|
} |
|
|
|
TypeDeclaration GetTypeDeclaration(short identifier) |
|
{ |
|
TypeDeclaration declaration; |
|
if (identifier >= 0) |
|
declaration = typeTable[identifier]; |
|
else |
|
declaration = KnownInfo.KnownTypeTable[-identifier]; |
|
|
|
if (declaration == null) |
|
throw new NotSupportedException(); |
|
|
|
return declaration; |
|
} |
|
|
|
TypeDeclaration GetKnownTypeDeclarationByName(string assemblyQualifiedName) |
|
{ |
|
foreach (var type in KnownInfo.KnownTypeTable) { |
|
if (assemblyQualifiedName == type.AssemblyQualifiedName) |
|
return type; |
|
} |
|
return new ResolverTypeDeclaration(_resolver, assemblyQualifiedName); |
|
} |
|
|
|
internal string GetAssembly(short identifier) |
|
{ |
|
return assemblyTable[identifier]; |
|
} |
|
|
|
XmlBamlNode CurrentNode { |
|
get { return _currentNode; } |
|
} |
|
|
|
public override string NamespaceURI { |
|
get { |
|
if (intoAttribute) return String.Empty; |
|
|
|
TypeDeclaration declaration; |
|
XmlBamlNode node = CurrentNode; |
|
if (node is XmlBamlSimpleProperty) |
|
return ((XmlBamlSimpleProperty)node).NamespaceName; |
|
else if (node is XmlBamlProperty) { |
|
declaration = ((XmlBamlProperty)node).PropertyDeclaration.DeclaringType; |
|
TypeDeclaration elementDeclaration = readingElements.Peek().TypeDeclaration; |
|
|
|
XmlToClrNamespaceMapping propertyMapping = FindByClrNamespaceAndAssemblyId(declaration); |
|
XmlToClrNamespaceMapping elementMapping = FindByClrNamespaceAndAssemblyId(elementDeclaration); |
|
|
|
if (((XmlBamlProperty)node).PropertyDeclaration.Name == "Name" && |
|
_resolver.IsLocalAssembly(((XmlBamlProperty)node).Parent.TypeDeclaration.Assembly)) |
|
return XWPFNamespace; |
|
|
|
if (String.CompareOrdinal(propertyMapping.XmlNamespace, elementMapping.XmlNamespace) == 0 |
|
|| (elementDeclaration.Type != null && declaration.Type != null && elementDeclaration.Type.IsSubclassOf(declaration.Type))) |
|
return String.Empty; |
|
} |
|
else if (node is XmlBamlPropertyElement) |
|
{ |
|
XmlBamlPropertyElement property = (XmlBamlPropertyElement)node; |
|
declaration = property.TypeDeclaration; |
|
if (property.Parent.TypeDeclaration.Type.IsSubclassOf(property.PropertyDeclaration.DeclaringType.Type)) |
|
declaration = property.Parent.TypeDeclaration; |
|
} |
|
else if (node is XmlBamlElement) |
|
declaration = ((XmlBamlElement)node).TypeDeclaration; |
|
else |
|
return String.Empty; |
|
|
|
XmlToClrNamespaceMapping mapping = FindByClrNamespaceAndAssemblyId(declaration); |
|
|
|
return mapping.XmlNamespace; |
|
} |
|
} |
|
|
|
|
|
public override string Prefix |
|
{ |
|
get { |
|
if (!intoAttribute) |
|
return ((IXmlNamespaceResolver)this).LookupPrefix(NamespaceURI) ?? String.Empty; |
|
return String.Empty; |
|
} |
|
} |
|
|
|
|
|
public override bool HasValue |
|
{ |
|
get { return Value != null; } |
|
} |
|
|
|
/// <summary> |
|
/// Returns object used to resolve types |
|
/// </summary> |
|
public IDotNetTypeResolver Resolver |
|
{ |
|
get { return _resolver; } |
|
} |
|
|
|
public override string Value |
|
{ |
|
get { |
|
XmlBamlNode node = CurrentNode; |
|
if (node is XmlBamlSimpleProperty) |
|
return ((XmlBamlSimpleProperty)node).Value; |
|
else if (node is XmlBamlProperty) |
|
return ((XmlBamlProperty)node).Value.ToString(); |
|
else if (node is XmlBamlText) |
|
return ((XmlBamlText)node).Text; |
|
else if (node is XmlBamlElement) |
|
return String.Empty; |
|
|
|
return String.Empty; |
|
} |
|
} |
|
|
|
public IDictionary<string, string> RootNamespaces => _rootNamespaces; |
|
|
|
public override int Depth => readingElements.Count; |
|
|
|
public override string BaseURI => string.Empty; |
|
|
|
public override bool IsEmptyElement => false; |
|
|
|
public override bool EOF => _eof; |
|
|
|
public override int AttributeCount { |
|
get { throw new NotImplementedException(); } |
|
} |
|
|
|
public override ReadState ReadState { |
|
get { |
|
if (!initialized) |
|
return ReadState.Initial; |
|
if (reader == null) |
|
return ReadState.Closed; |
|
if (EOF) |
|
return ReadState.EndOfFile; |
|
return ReadState.Interactive; |
|
} |
|
} |
|
|
|
public override XmlNameTable NameTable => _nameTable; |
|
|
|
#region IXmlNamespaceResolver Members |
|
|
|
IDictionary<string, string> IXmlNamespaceResolver.GetNamespacesInScope(XmlNamespaceScope scope) |
|
{ |
|
var namespaces = readingElements.Peek().Namespaces; |
|
Dictionary<String, String> list = new Dictionary<string, string>(); |
|
foreach (XmlNamespace ns in namespaces) |
|
{ |
|
list.Add(ns.Prefix, ns.Namespace); |
|
} |
|
|
|
return list; |
|
} |
|
|
|
string IXmlNamespaceResolver.LookupNamespace(string prefix) |
|
{ |
|
return LookupNamespace(prefix); |
|
} |
|
|
|
string IXmlNamespaceResolver.LookupPrefix(string namespaceName) |
|
{ |
|
return LookupPrefix(namespaceName, true); |
|
} |
|
|
|
string LookupPrefix(string namespaceName, bool useReading) |
|
{ |
|
Stack<XmlBamlElement> elements; |
|
if (useReading) |
|
elements = readingElements; |
|
else |
|
elements = this.elements; |
|
|
|
if (elements.Count == 0) return null; |
|
return LookupPrefix(namespaceName, elements.Peek().Namespaces); |
|
} |
|
|
|
static string LookupPrefix(string namespaceName, IList<XmlNamespace> namespaces) |
|
{ |
|
for (int x = 0; x < namespaces.Count; x++) |
|
{ |
|
if (String.CompareOrdinal(namespaces[x].Namespace, namespaceName) == 0) |
|
return namespaces[x].Prefix; |
|
} |
|
|
|
return null; |
|
} |
|
|
|
#endregion |
|
|
|
internal enum IntegerCollectionType : byte |
|
{ |
|
Byte = 2, |
|
Consecutive = 1, |
|
Integer = 4, |
|
Unknown = 0, |
|
UShort = 3 |
|
} |
|
} |
|
} |