using System;
using System.Collections.Generic;
using System.IO;
using System.Xaml;
using System.Diagnostics;
using System.ComponentModel;
using System.Reflection;
using System.Windows.Media.Media3D;
using System.Windows.Media;
using MS.Internal;
using System.Globalization;
using XamlReaderHelper = System.Windows.Markup.XamlReaderHelper;
namespace System.Windows.Baml2006
{
public class Baml2006Reader : XamlReader, IXamlLineInfo, IFreezeFreezables
{
private Baml2006ReaderSettings _settings;
private bool _isBinaryProvider;
private bool _isEof;
private int _lookingForAKeyOnAMarkupExtensionInADictionaryDepth;
private XamlNodeList _lookingForAKeyOnAMarkupExtensionInADictionaryNodeList;
private BamlBinaryReader _binaryReader;
private Baml2006ReaderContext _context;
private XamlNodeQueue _xamlMainNodeQueue;
private XamlNodeList _xamlTemplateNodeList;
private XamlReader _xamlNodesReader;
private XamlWriter _xamlNodesWriter;
private Stack _xamlWriterStack = new Stack();
private Dictionary _typeConverterMap = new Dictionary();
private Dictionary _enumTypeConverterMap = new Dictionary();
private Dictionary _freezeCache;
private const Int16 ExtensionIdMask = 0x0FFF;
private const Int16 TypeExtensionValueMask = 0x4000;
private const Int16 StaticExtensionValueMask = 0x2000;
private const sbyte ReaderFlags_AddedToTree = 0x02;
private object _root;
#region Constructors
public Baml2006Reader(string fileName)
{
if (fileName == null)
{
throw new ArgumentNullException("fileName");
}
var stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
var schemaContext = new Baml2006SchemaContext(null);
var settings = System.Windows.Markup.XamlReader.CreateBamlReaderSettings();
settings.OwnsStream = true;
Initialize(stream, schemaContext, settings);
}
public Baml2006Reader(Stream stream)
{
if (stream == null)
{
throw new ArgumentNullException("stream");
}
var schemaContext = new Baml2006SchemaContext(null);
var settings = new Baml2006ReaderSettings();
Initialize(stream, schemaContext, settings);
}
public Baml2006Reader(Stream stream, XamlReaderSettings xamlReaderSettings)
{
if (stream == null)
{
throw new ArgumentNullException("stream");
}
if (xamlReaderSettings == null)
{
throw new ArgumentNullException("xamlReaderSettings");
}
Baml2006SchemaContext schemaContext;
if (xamlReaderSettings.ValuesMustBeString)
{
schemaContext = new Baml2006SchemaContext(xamlReaderSettings.LocalAssembly, System.Windows.Markup.XamlReader.XamlV3SharedSchemaContext);
}
else
{
schemaContext = new Baml2006SchemaContext(xamlReaderSettings.LocalAssembly);
}
var settings = new Baml2006ReaderSettings(xamlReaderSettings);
Initialize(stream, schemaContext, settings);
}
internal Baml2006Reader(Stream stream,
Baml2006SchemaContext schemaContext,
Baml2006ReaderSettings settings)
{
if (stream == null)
{
throw new ArgumentNullException("stream");
}
if (schemaContext == null)
{
throw new ArgumentNullException("schemaContext");
}
Initialize(stream, schemaContext, settings ?? new Baml2006ReaderSettings());
}
internal Baml2006Reader(
Stream stream,
Baml2006SchemaContext baml2006SchemaContext,
Baml2006ReaderSettings baml2006ReaderSettings,
object root)
: this(stream, baml2006SchemaContext, baml2006ReaderSettings)
{
_root = root;
}
private void Initialize(Stream stream,
Baml2006SchemaContext schemaContext,
Baml2006ReaderSettings settings)
{
schemaContext.Settings = settings;
_settings = settings;
_context = new Baml2006ReaderContext(schemaContext);
_xamlMainNodeQueue = new XamlNodeQueue(schemaContext);
_xamlNodesReader = _xamlMainNodeQueue.Reader;
_xamlNodesWriter = _xamlMainNodeQueue.Writer;
_lookingForAKeyOnAMarkupExtensionInADictionaryDepth = -1;
_isBinaryProvider = !settings.ValuesMustBeString;
// Since the reader owns the stream and is responsible for its lifetime
// it can safely hand out shared streams.
if (_settings.OwnsStream)
{
stream = new SharedStream(stream);
}
_binaryReader = new BamlBinaryReader(stream);
_context.TemplateStartDepth = -1;
if (!_settings.IsBamlFragment)
{
Process_Header();
}
}
#endregion
#region XamlReader Members
override public bool Read()
{
if (IsDisposed)
{
throw new ObjectDisposedException("Baml2006Reader");
}
if (IsEof)
{
return false;
}
while (!_xamlNodesReader.Read())
{
if (!Process_BamlRecords())
{
_isEof = true;
return false;
}
}
if (_binaryReader.BaseStream.Length == _binaryReader.BaseStream.Position &&
_xamlNodesReader.NodeType != XamlNodeType.EndObject)
{
_isEof = true;
return false;
}
return true;
}
override public XamlNodeType NodeType
{
get { return _xamlNodesReader.NodeType; }
}
override public bool IsEof
{
get { return _isEof; }
}
override public NamespaceDeclaration Namespace
{
get { return _xamlNodesReader.Namespace; }
}
override public XamlSchemaContext SchemaContext
{
get { return _xamlNodesReader.SchemaContext; }
}
override public XamlType Type
{
get { return _xamlNodesReader.Type; }
}
override public object Value
{
get { return _xamlNodesReader.Value; }
}
override public XamlMember Member
{
get { return _xamlNodesReader.Member; }
}
protected override void Dispose(bool disposing)
{
if (_binaryReader != null)
{
if (_settings.OwnsStream)
{
SharedStream sharedStream = _binaryReader.BaseStream as SharedStream;
if (sharedStream != null && sharedStream.SharedCount < 1)
{
// The reader is responsible for the streams lifetime and no one is sharing the stream
_binaryReader.Close();
}
}
_binaryReader = null;
_context = null;
}
}
#endregion
#region IXamlLineInfo Members
bool IXamlLineInfo.HasLineInfo
{
get { return _context.CurrentFrame != null; }
}
int IXamlLineInfo.LineNumber
{
get { return _context.CurrentFrame.LineNumber; }
}
int IXamlLineInfo.LinePosition
{
get { return _context.CurrentFrame.LineOffset; }
}
#endregion
#region Internal Methods
internal List ReadKeys()
{
_context.KeyList = new List();
_context.CurrentFrame.IsDeferredContent = true;
bool keepReading = true;
while (keepReading)
{
Baml2006RecordType recordType = Read_RecordType();
switch (recordType)
{
case Baml2006RecordType.KeyElementStart:
Process_KeyElementStart();
while (true)
{
recordType = Read_RecordType();
if (recordType == Baml2006RecordType.KeyElementEnd)
{
Process_KeyElementEnd();
break;
}
else
{
_binaryReader.BaseStream.Seek(-1, SeekOrigin.Current);
Process_OneBamlRecord();
}
}
break;
case Baml2006RecordType.StaticResourceStart:
Process_StaticResourceStart();
while (true)
{
recordType = Read_RecordType();
if (recordType == Baml2006RecordType.StaticResourceEnd)
{
Process_StaticResourceEnd();
break;
}
else
{
_binaryReader.BaseStream.Seek(-1, SeekOrigin.Current);
Process_OneBamlRecord();
}
}
break;
case Baml2006RecordType.DefAttributeKeyType:
Process_DefAttributeKeyType();
break;
case Baml2006RecordType.DefAttributeKeyString:
Process_DefAttributeKeyString();
break;
case Baml2006RecordType.OptimizedStaticResource:
Process_OptimizedStaticResource();
break;
default:
keepReading = false;
_binaryReader.BaseStream.Seek(-1, SeekOrigin.Current);
break;
}
// If we're at the end of the stream, just return
if (_binaryReader.BaseStream.Length == _binaryReader.BaseStream.Position)
{
keepReading = false;
break;
}
}
// ValuePosition is relative to the end of the Keys Section.
// Patch the relative offsets to absolute positions now that we know where the keys end.
// And record the size of each record. (in bytes)
KeyRecord previousKeyRecord = null;
long endOfKeysStartOfObjects = _binaryReader.BaseStream.Position;
foreach (KeyRecord keyRecord in _context.KeyList)
{
keyRecord.ValuePosition += endOfKeysStartOfObjects;
if (previousKeyRecord != null)
{
previousKeyRecord.ValueSize = (int)(keyRecord.ValuePosition - previousKeyRecord.ValuePosition);
}
previousKeyRecord = keyRecord;
}
previousKeyRecord.ValueSize = (int)(_binaryReader.BaseStream.Length - previousKeyRecord.ValuePosition);
keepReading = false;
return _context.KeyList;
}
internal XamlReader ReadObject(KeyRecord record)
{
// This means we're at the end of the Deferred Content
// Break out and return null
if (record.ValuePosition == _binaryReader.BaseStream.Length)
{
return null;
}
_binaryReader.BaseStream.Seek(record.ValuePosition, SeekOrigin.Begin);
_context.CurrentKey = _context.KeyList.IndexOf(record);
if (_xamlMainNodeQueue.Count > 0)
{
//
throw new XamlParseException();
}
if (Read_RecordType() != Baml2006RecordType.ElementStart)
{
throw new XamlParseException();
}
XamlWriter oldQueueWriter = _xamlNodesWriter;
// estimates from statistical examiniation of Theme Resource Data.
// small RD entries appear to have about a 2.2 bytes to XamlNode ration.
// larger RD entries are less dense (due to data) at about 4.25.
// Presizing the XamlNodeLists save upto 50% in memory useage for same.
int initialSizeOfNodeList = (record.ValueSize < 800)
? (int)(record.ValueSize / 2.2)
: (int)(record.ValueSize / 4.25);
initialSizeOfNodeList = (initialSizeOfNodeList < 8) ? 8 : initialSizeOfNodeList;
var result = new XamlNodeList(_xamlNodesReader.SchemaContext, initialSizeOfNodeList);
_xamlNodesWriter = result.Writer;
Baml2006ReaderFrame baseFrame = _context.CurrentFrame;
Process_ElementStart();
while (baseFrame != _context.CurrentFrame)
{
Process_OneBamlRecord();
}
_xamlNodesWriter.Close();
_xamlNodesWriter = oldQueueWriter;
return result.GetReader();
}
internal Type GetTypeOfFirstStartObject(KeyRecord record)
{
_context.CurrentKey = _context.KeyList.IndexOf(record);
// This means we're at the end of the Deferred Content
// Break out and return null
if (record.ValuePosition == _binaryReader.BaseStream.Length)
{
return null;
}
_binaryReader.BaseStream.Seek(record.ValuePosition, SeekOrigin.Begin);
if (Read_RecordType() != Baml2006RecordType.ElementStart)
{
throw new XamlParseException();
}
return BamlSchemaContext.GetClrType(_binaryReader.ReadInt16());
}
#endregion
#region Private Methods
// Processes BAML records until we can return at least one XAML node.
private bool Process_BamlRecords()
{
int initialCount = _xamlMainNodeQueue.Count;
while (Process_OneBamlRecord())
{
if (_xamlMainNodeQueue.Count > initialCount)
{
return true;
}
}
return false;
}
// Reads one Baml record and returns whether it can return a XAML node or not.
private bool Process_OneBamlRecord()
{
// If we're at the end, Exit out.
if (_binaryReader.BaseStream.Position == _binaryReader.BaseStream.Length)
{
_isEof = true;
return false;
}
Baml2006RecordType recordType = Read_RecordType();
switch (recordType)
{
// Not useful to us so we skip.
case Baml2006RecordType.DocumentStart:
SkipBytes(6);
break;
// At the end so break out.
case Baml2006RecordType.DocumentEnd:
return false;
#region Object Records
case Baml2006RecordType.ElementStart:
Process_ElementStart();
break;
case Baml2006RecordType.ElementEnd:
Process_ElementEnd();
break;
case Baml2006RecordType.NamedElementStart:
// This is only used by template code, and only as a temporary record, so should never occur here.
throw new XamlParseException();
case Baml2006RecordType.KeyElementStart:
Process_KeyElementStart();
break;
case Baml2006RecordType.KeyElementEnd:
Process_KeyElementEnd();
break;
#endregion
#region Property Records
case Baml2006RecordType.XmlnsProperty:
// This is only valid right after an ElementStart and before any other real nodes.
// Should never be seen here.
throw new XamlParseException("Found unexpected Xmlns BAML record");
case Baml2006RecordType.Property:
Process_Property();
break;
case Baml2006RecordType.PropertyCustom:
Process_PropertyCustom();
break;
case Baml2006RecordType.PropertyWithConverter:
Process_PropertyWithConverter();
break;
case Baml2006RecordType.PropertyWithExtension:
Process_PropertyWithExtension();
break;
case Baml2006RecordType.PropertyTypeReference:
Process_PropertyTypeReference();
break;
case Baml2006RecordType.PropertyStringReference:
Process_PropertyStringReference();
break;
case Baml2006RecordType.PropertyWithStaticResourceId:
Process_PropertyWithStaticResourceId();
break;
case Baml2006RecordType.ContentProperty:
Process_ContentProperty();
break;
case Baml2006RecordType.RoutedEvent:
Process_RoutedEvent();
break;
case Baml2006RecordType.ClrEvent:
Process_ClrEvent();
break;
case Baml2006RecordType.ConstructorParametersStart:
Process_ConstructorParametersStart();
break;
case Baml2006RecordType.ConstructorParameterType:
Process_ConstructorParameterType();
break;
case Baml2006RecordType.ConstructorParametersEnd:
Process_ConstructorParametersEnd();
break;
case Baml2006RecordType.PropertyComplexStart:
Process_PropertyComplexStart();
break;
case Baml2006RecordType.PropertyArrayStart:
case Baml2006RecordType.PropertyIListStart:
Process_PropertyArrayStart();
break;
case Baml2006RecordType.PropertyIDictionaryStart:
Process_PropertyIDictionaryStart();
break;
// Just need to output EndMember so we handle all at once.
case Baml2006RecordType.PropertyComplexEnd:
case Baml2006RecordType.PropertyArrayEnd:
case Baml2006RecordType.PropertyIListEnd:
Process_PropertyEnd();
break;
case Baml2006RecordType.PropertyIDictionaryEnd:
Process_PropertyIDictionaryEnd();
break;
#endregion
#region Property values
case Baml2006RecordType.StaticResourceId:
Process_StaticResourceId();
break;
case Baml2006RecordType.StaticResourceStart:
// these are Key records, but they are read here in BRAT mode.
// BRAT == BAML Reader As Text.
Process_StaticResourceStart();
break;
case Baml2006RecordType.StaticResourceEnd:
// these are Key records, but they are read here in BRAT mode.
Process_StaticResourceEnd();
break;
case Baml2006RecordType.OptimizedStaticResource:
// these are Key records, but they are read here in BRAT mode.
Process_OptimizedStaticResource();
break;
case Baml2006RecordType.Text:
Process_Text();
break;
case Baml2006RecordType.TextWithConverter:
Process_TextWithConverter();
break;
case Baml2006RecordType.TextWithId:
Process_TextWithId();
break;
case Baml2006RecordType.LiteralContent:
Process_LiteralContent();
break;
#endregion
case Baml2006RecordType.DefAttribute:
Process_DefAttribute();
break;
case Baml2006RecordType.DefAttributeKeyString:
Process_DefAttributeKeyString();
break;
case Baml2006RecordType.DefAttributeKeyType:
Process_DefAttributeKeyType();
break;
case Baml2006RecordType.DefTag:
Process_DefTag();
break;
case Baml2006RecordType.DeferableContentStart:
Process_DeferableContentStart();
break;
case Baml2006RecordType.EndAttributes:
Process_EndAttributes();
break;
case Baml2006RecordType.XmlAttribute:
Process_XmlAttribute();
break;
case Baml2006RecordType.PresentationOptionsAttribute:
Process_PresentationOptionsAttribute();
break;
#region Schema Records
case Baml2006RecordType.ProcessingInstruction:
Process_ProcessingInstruction();
break;
case Baml2006RecordType.PIMapping:
Process_PIMapping();
break;
case Baml2006RecordType.AssemblyInfo:
Process_AssemblyInfo();
break;
case Baml2006RecordType.TypeInfo:
Process_TypeInfo();
break;
case Baml2006RecordType.TypeSerializerInfo:
Process_TypeSerializerInfo();
break;
case Baml2006RecordType.AttributeInfo:
Process_AttributeInfo();
break;
case Baml2006RecordType.StringInfo:
Process_StringInfo();
break;
#endregion
#region Debugging Records
case Baml2006RecordType.LinePosition:
Process_LinePosition();
break;
case Baml2006RecordType.LineNumberAndPosition:
Process_LineNumberAndPosition();
break;
case Baml2006RecordType.Comment:
Process_Comment();
break;
#endregion
case Baml2006RecordType.ConnectionId:
Process_ConnectionId();
break;
case Baml2006RecordType.Unknown:
default:
throw new XamlParseException(string.Format(CultureInfo.CurrentCulture, SR.Get(SRID.UnknownBamlRecord, recordType)));
}
return true;
}
// Have not seen a BAML file that has this...
private void Process_ProcessingInstruction()
{
throw new NotImplementedException();
}
// Have not seen a BAML file that has this...
private void Process_DefTag()
{
throw new NotImplementedException();
}
// Have not seen a BAML file that has this...
private void Process_EndAttributes()
{
throw new NotImplementedException();
}
// Have not seen a BAML file that has this...
private void Process_XmlAttribute()
{
throw new NotImplementedException();
}
// This is for the f:Freeze directive. Need work in System.Xaml to support returning this.
private void Process_PresentationOptionsAttribute()
{
Common_Process_Property();
Read_RecordSize();
string value = _binaryReader.ReadString();
string name = _context.SchemaContext.GetString(_binaryReader.ReadInt16());
if (_context.TemplateStartDepth < 0)
{
_xamlNodesWriter.WriteStartMember(System.Windows.Markup.XamlReaderHelper.Freeze);
_xamlNodesWriter.WriteValue(value); // Do we need to parse the boolean value?
_xamlNodesWriter.WriteEndMember();
}
}
// Have not seen a BAML file that has this...
private void Process_Comment()
{
throw new NotImplementedException();
}
// String for Content. Sometimes also drops out the Content Property
private void Process_LiteralContent()
{
Read_RecordSize();
string value = _binaryReader.ReadString();
int lineNumber = _binaryReader.ReadInt32();
int lineOffset = _binaryReader.ReadInt32();
bool shouldInjectContentProperty = _context.CurrentFrame.Member == null;
if (shouldInjectContentProperty)
{
if (_context.CurrentFrame.XamlType.ContentProperty != null)
{
Common_Process_Property();
_xamlNodesWriter.WriteStartMember(_context.CurrentFrame.XamlType.ContentProperty);
}
else
{
throw new NotImplementedException();
}
}
if (!_isBinaryProvider)
{
_xamlNodesWriter.WriteStartObject(XamlLanguage.XData);
XamlMember xDataTextProperty = XamlLanguage.XData.GetMember("Text");
_xamlNodesWriter.WriteStartMember(xDataTextProperty);
_xamlNodesWriter.WriteValue(value);
_xamlNodesWriter.WriteEndMember();
_xamlNodesWriter.WriteEndObject();
}
else
{
var xData = new System.Windows.Markup.XData();
xData.Text = value;
_xamlNodesWriter.WriteValue(xData);
}
if (shouldInjectContentProperty)
{
_xamlNodesWriter.WriteEndMember();
}
}
// Text to be written for type converters. Also drops a InitProperty as well
private void Process_TextWithConverter()
{
Read_RecordSize();
string value = _binaryReader.ReadString();
short converterId = _binaryReader.ReadInt16();
bool shouldDropProperty = _context.CurrentFrame.Member == null;
if (shouldDropProperty)
{
Common_Process_Property();
//
_xamlNodesWriter.WriteStartMember(XamlLanguage.Initialization);
}
//
_xamlNodesWriter.WriteValue(value);
if (shouldDropProperty)
{
_xamlNodesWriter.WriteEndMember();
}
}
private void Process_StaticResourceEnd()
{
XamlWriter writer = GetLastStaticResource().ResourceNodeList.Writer;
writer.WriteEndObject();
writer.Close();
_context.InsideStaticResource = false;
_xamlNodesWriter = _xamlWriterStack.Pop();
_context.PopScope();
}
private void Process_StaticResourceStart()
{
XamlType type = BamlSchemaContext.GetXamlType(_binaryReader.ReadInt16());
byte flags = _binaryReader.ReadByte();
//
StaticResource staticResource = new StaticResource(type, BamlSchemaContext);
_context.LastKey.StaticResources.Add(staticResource);
_context.InsideStaticResource = true;
_xamlWriterStack.Push(_xamlNodesWriter);
_xamlNodesWriter = staticResource.ResourceNodeList.Writer;
_context.PushScope();
_context.CurrentFrame.XamlType = type;
}
private void Process_StaticResourceId()
{
InjectPropertyAndFrameIfNeeded(_context.SchemaContext.GetXamlType(typeof(StaticResourceExtension)), 0);
short resourceId = _binaryReader.ReadInt16();
object value = _context.KeyList[_context.CurrentKey - 1].StaticResources[resourceId];
// If we are just loading the BAML to create a node stream (like localization, BRAT mode)
// then these will be StaticResources. (not to be confused with StaticResourceExtensions)
// If we are loading the BAML and setting Resource Dictionary DeferrableContent property
// then these will have been upgraded to StaticResourceHolders (an ME).
var staticResource = value as StaticResource;
if (staticResource != null)
{
XamlServices.Transform(staticResource.ResourceNodeList.GetReader(), _xamlNodesWriter, false);
}
else
{
_xamlNodesWriter.WriteValue(value);
}
}
private void Process_ClrEvent()
{
throw new NotImplementedException();
}
private void Process_RoutedEvent()
{
throw new NotImplementedException();
}
private void Process_PropertyStringReference()
{
throw new NotImplementedException();
}
private void Process_OptimizedStaticResource()
{
byte flags = _binaryReader.ReadByte();
short keyId = _binaryReader.ReadInt16();
var optimizedStaticResource = new OptimizedStaticResource(flags, keyId);
if (_isBinaryProvider)
{
// Compute the Value from the ValueId
// This code could/should be in "OptimizedStaticResource.Value", but that class
// doesn't have access to the BamlSchemaContext or the GetStaticExtension()
// method below.
if (optimizedStaticResource.IsKeyTypeExtension)
{
XamlType xamlType = BamlSchemaContext.GetXamlType(keyId);
optimizedStaticResource.KeyValue = xamlType.UnderlyingType;
}
else if (optimizedStaticResource.IsKeyStaticExtension)
{
Type memberType;
object providedValue;
string propertyName = GetStaticExtensionValue(keyId, out memberType, out providedValue);
if (providedValue == null)
{
var staticExtension = new System.Windows.Markup.StaticExtension(propertyName);
staticExtension.MemberType = memberType;
providedValue = staticExtension.ProvideValue(null);
}
optimizedStaticResource.KeyValue = providedValue;
}
else
{
optimizedStaticResource.KeyValue = _context.SchemaContext.GetString(keyId);
}
}
var staticResources = _context.LastKey.StaticResources;
staticResources.Add(optimizedStaticResource);
}
private void Process_DeferableContentStart()
{
Int32 contentSize = _binaryReader.ReadInt32();
if (_isBinaryProvider && contentSize > 0)
{
object binaryData = null;
if (_settings.OwnsStream)
{
// Creates a SharedStream that will be used be shared
long position = _binaryReader.BaseStream.Position;
binaryData = new SharedStream(_binaryReader.BaseStream, position, contentSize);
_binaryReader.BaseStream.Seek(position + contentSize, SeekOrigin.Begin);
}
else
{
// The stream may be closed after the end of the baml read
// Copy the defered content so that it is available after the read has completed
binaryData = new MemoryStream(_binaryReader.ReadBytes(contentSize));
}
Common_Process_Property();
_xamlNodesWriter.WriteStartMember(BamlSchemaContext.ResourceDictionaryDeferredContentProperty);
_xamlNodesWriter.WriteValue(binaryData);
_xamlNodesWriter.WriteEndMember();
}
else
{
_context.KeyList = new List();
_context.CurrentKey = 0;
_context.CurrentFrame.IsDeferredContent = true;
}
}
private void Process_DefAttribute()
{
Read_RecordSize();
string value = _binaryReader.ReadString();
Int16 stringId = _binaryReader.ReadInt16();
XamlMember property = BamlSchemaContext.GetXamlDirective(XamlLanguage.Xaml2006Namespace, BamlSchemaContext.GetString(stringId));
if (property == XamlLanguage.Key)
{
_context.CurrentFrame.Key = new KeyRecord(false, false, 0, value);
}
else
{
Common_Process_Property();
_xamlNodesWriter.WriteStartMember(property);
_xamlNodesWriter.WriteValue(value);
_xamlNodesWriter.WriteEndMember();
}
}
private void Process_DefAttributeKeyString()
{
Read_RecordSize();
Int16 keyStringId = _binaryReader.ReadInt16();
Int32 valuePosition = _binaryReader.ReadInt32();
bool isShared = _binaryReader.ReadBoolean();
bool isSharedSet = _binaryReader.ReadBoolean();
string value = _context.SchemaContext.GetString(keyStringId);
KeyRecord key = new KeyRecord(isShared, isSharedSet, valuePosition, value);
if (_context.CurrentFrame.IsDeferredContent)
{
_context.KeyList.Add(key);
}
else
{
_context.CurrentFrame.Key = key;
}
}
private void Process_DefAttributeKeyType()
{
Int16 typeId = _binaryReader.ReadInt16();
byte flags = _binaryReader.ReadByte();
Int32 valuePosition = _binaryReader.ReadInt32();
bool isShared = _binaryReader.ReadBoolean();
bool isSharedSet = _binaryReader.ReadBoolean();
Type type = Baml2006SchemaContext.KnownTypes.GetKnownType(typeId);
if (type == null)
{
type = BamlSchemaContext.GetClrType(typeId);
}
KeyRecord key = new KeyRecord(isShared, isSharedSet, valuePosition, type);
if (_context.CurrentFrame.IsDeferredContent)
{
_context.KeyList.Add(key);
}
else
{
_context.CurrentFrame.Key = key;
}
}
private bool IsStringOnlyWhiteSpace(string value)
{
for (int i = 0; i < value.Length; i++)
{
if (!Char.IsWhiteSpace(value[i]))
return false;
}
return true;
}
// Need to write just a text node out but the V3 markup compiler has a bug where it will occasionally output
// text even though it shouldn't. The checks are to get around that.
private void Process_Text()
{
Read_RecordSize();
string textValue = _binaryReader.ReadString();
Process_Text_Helper(textValue);
}
// Need to look up a string in the string table via ID.
private void Process_TextWithId()
{
Read_RecordSize();
short textId = _binaryReader.ReadInt16();
string textValue = BamlSchemaContext.GetString(textId);
Process_Text_Helper(textValue);
}
private void Process_Text_Helper(string stringValue)
{
//
if (_context.InsideKeyRecord != true && _context.InsideStaticResource != true)
{
InjectPropertyAndFrameIfNeeded(_context.SchemaContext.GetXamlType(typeof(String)), 0);
}
// Whitespace inside PositionalParameters is interpreted according to MarkupExtension syntax rules,
// which means that if the compiler left it in the BAML, it's significant.
// Otherwise, it's possible that the compiler wasn't sure whether the whitespace was significant,
// so we may need to strip it here.
if (IsStringOnlyWhiteSpace(stringValue) &&
_context.CurrentFrame.Member != XamlLanguage.PositionalParameters)
{
if (_context.CurrentFrame.XamlType != null && _context.CurrentFrame.XamlType.IsCollection)
{
if (!_context.CurrentFrame.XamlType.IsWhitespaceSignificantCollection)
{
return;
}
}
else
{
if (_context.CurrentFrame.Member.Type != null &&
!_context.CurrentFrame.Member.Type.UnderlyingType.IsAssignableFrom(typeof(String)))
return;
}
}
_xamlNodesWriter.WriteValue(stringValue);
}
private void Process_ConstructorParametersEnd()
{
_xamlNodesWriter.WriteEndMember();
_context.CurrentFrame.Member = null;
}
private void Process_ConstructorParametersStart()
{
Common_Process_Property();
_xamlNodesWriter.WriteStartMember(XamlLanguage.PositionalParameters);
_context.CurrentFrame.Member = XamlLanguage.PositionalParameters;
}
private void Process_ConstructorParameterType()
{
Int16 typeId = _binaryReader.ReadInt16();
if (_isBinaryProvider)
{
_xamlNodesWriter.WriteValue(BamlSchemaContext.GetXamlType(typeId).UnderlyingType);
}
else
{
_xamlNodesWriter.WriteStartObject(XamlLanguage.Type);
_xamlNodesWriter.WriteStartMember(XamlLanguage.PositionalParameters);
_xamlNodesWriter.WriteValue(Logic_GetFullyQualifiedNameForType(BamlSchemaContext.GetXamlType(typeId)));
_xamlNodesWriter.WriteEndMember();
_xamlNodesWriter.WriteEndObject();
}
}
private void Process_Header()
{
Int32 stringLength = _binaryReader.ReadInt32();
//
byte[] headerString = _binaryReader.ReadBytes(stringLength);
//
Int32 readerVersion = _binaryReader.ReadInt32();
Int32 updateVersion = _binaryReader.ReadInt32();
Int32 writerVersion = _binaryReader.ReadInt32();
}
private void Process_ElementStart()
{
XamlType type;
Int16 typeId = _binaryReader.ReadInt16();
// Obfuscated root types remain unobfuscated in BAML.
// Reflect the root instance for the root type in case of obfuscation.
if (_root != null && _context.CurrentFrame.Depth == 0)
{
Type rootType = _root.GetType();
type = BamlSchemaContext.GetXamlType(rootType);
}
else
{
type = BamlSchemaContext.GetXamlType(typeId);
}
SByte flags = _binaryReader.ReadSByte();
//
if (flags < 0 || flags > 3)
{
throw new XamlParseException();
}
InjectPropertyAndFrameIfNeeded(type, flags);
_context.PushScope();
_context.CurrentFrame.XamlType = type;
//Peek ahead to read all the Xmlns properties
bool isPeeking = true;
do
{
Baml2006RecordType recordType = Read_RecordType();
switch (recordType)
{
case Baml2006RecordType.XmlnsProperty:
Process_XmlnsProperty();
break;
case Baml2006RecordType.AssemblyInfo:
Process_AssemblyInfo();
break;
case Baml2006RecordType.LinePosition:
Process_LinePosition();
break;
case Baml2006RecordType.LineNumberAndPosition:
Process_LineNumberAndPosition();
break;
default:
// We have peeked far enough undo the last Read_RecordType()
SkipBytes(-1);
isPeeking = false;
break;
}
}
while (isPeeking);
// Determine if the object was retrieved or not
//
bool isRetrieved = (flags & ReaderFlags_AddedToTree) > 0;
if (isRetrieved)
{
_xamlNodesWriter.WriteGetObject();
}
else
{
_xamlNodesWriter.WriteStartObject(_context.CurrentFrame.XamlType);
}
// If you're the first element, write out the BaseUri
if (_context.CurrentFrame.Depth == 1)
{
if (_settings.BaseUri != null && !String.IsNullOrEmpty(_settings.BaseUri.ToString()))
{
_xamlNodesWriter.WriteStartMember(XamlLanguage.Base);
_xamlNodesWriter.WriteValue(_settings.BaseUri.ToString());
_xamlNodesWriter.WriteEndMember();
}
}
// Need to output the keys if we're in deferred content
if (_context.PreviousFrame.IsDeferredContent && _context.InsideStaticResource == false)
{
// If we're providing binary, that means we've delay loaded the ResourceDictionary
// and the object we're currently creating doens't actually need the key.
if (!_isBinaryProvider)
{
_xamlNodesWriter.WriteStartMember(XamlLanguage.Key);
KeyRecord record = _context.KeyList[_context.CurrentKey];
// We have a string for a key, just write it out.
if (!String.IsNullOrEmpty(record.KeyString))
{
_xamlNodesWriter.WriteValue(record.KeyString);
}
else if (record.KeyType != null)
{
_xamlNodesWriter.WriteStartObject(XamlLanguage.Type);
_xamlNodesWriter.WriteStartMember(XamlLanguage.PositionalParameters);
_xamlNodesWriter.WriteValue(Logic_GetFullyQualifiedNameForType(SchemaContext.GetXamlType(record.KeyType)));
_xamlNodesWriter.WriteEndMember();
_xamlNodesWriter.WriteEndObject();
}
else
{
// This is the complex key scenario. Just write everything out to the writer.
XamlServices.Transform(record.KeyNodeList.GetReader(), _xamlNodesWriter, false);
}
_xamlNodesWriter.WriteEndMember();
}
_context.CurrentKey++;
}
}
private void Process_ElementEnd()
{
RemoveImplicitFrame();
if (_context.CurrentFrame.Key != null)
{
_xamlNodesWriter.WriteStartMember(XamlLanguage.Key);
KeyRecord keyRecord = _context.CurrentFrame.Key;
if (keyRecord.KeyType != null)
{
if (_isBinaryProvider)
{
_xamlNodesWriter.WriteValue(keyRecord.KeyType);
}
else
{
_xamlNodesWriter.WriteStartObject(XamlLanguage.Type);
_xamlNodesWriter.WriteStartMember(XamlLanguage.PositionalParameters);
_xamlNodesWriter.WriteValue(Logic_GetFullyQualifiedNameForType(SchemaContext.GetXamlType(keyRecord.KeyType)));
_xamlNodesWriter.WriteEndMember();
_xamlNodesWriter.WriteEndObject();
}
}
else if (keyRecord.KeyNodeList != null)
{
XamlServices.Transform(keyRecord.KeyNodeList.GetReader(), _xamlNodesWriter, false);
}
else
{
_xamlNodesWriter.WriteValue(keyRecord.KeyString);
}
_xamlNodesWriter.WriteEndMember();
_context.CurrentFrame.Key = null;
}
if (_context.CurrentFrame.DelayedConnectionId != -1)
{
_xamlNodesWriter.WriteStartMember(XamlLanguage.ConnectionId);
if (_isBinaryProvider)
{
_xamlNodesWriter.WriteValue(_context.CurrentFrame.DelayedConnectionId);
}
else
{
_xamlNodesWriter.WriteValue(_context.CurrentFrame.DelayedConnectionId.ToString(System.Windows.Markup.TypeConverterHelper.InvariantEnglishUS));
}
_xamlNodesWriter.WriteEndMember();
}
_xamlNodesWriter.WriteEndObject();
if (_context.CurrentFrame.IsDeferredContent)
{
_context.KeyList = null;
}
_context.PopScope();
}
private void Process_KeyElementStart()
{
Int16 typeId = _binaryReader.ReadInt16();
byte flags = _binaryReader.ReadByte();
Int32 valuePosition = _binaryReader.ReadInt32();
bool isShared = _binaryReader.ReadBoolean();
bool isSharedSet = _binaryReader.ReadBoolean();
XamlType type = _context.SchemaContext.GetXamlType(typeId);
_context.PushScope();
_context.CurrentFrame.XamlType = type;
// Store a key record that can be accessed later.
// This is a complex scenario so we need to write to the keyList
KeyRecord key = new KeyRecord(isShared, isSharedSet, valuePosition, _context.SchemaContext);
key.Flags = flags;
key.KeyNodeList.Writer.WriteStartObject(type);
_context.InsideKeyRecord = true;
// Push the current writer onto a stack and add the KeyNodeList writer.
// All subsequent calls will be added to that writer.
_xamlWriterStack.Push(_xamlNodesWriter);
_xamlNodesWriter = key.KeyNodeList.Writer;
if (_context.PreviousFrame.IsDeferredContent)
{
_context.KeyList.Add(key);
}
else
{
_context.PreviousFrame.Key = key;
}
}
private void Process_KeyElementEnd()
{
KeyRecord key = null;
if (_context.PreviousFrame.IsDeferredContent)
{
key = _context.LastKey;
}
else
{
key = _context.PreviousFrame.Key;
}
key.KeyNodeList.Writer.WriteEndObject();
key.KeyNodeList.Writer.Close();
// Revert the writer
_xamlNodesWriter = _xamlWriterStack.Pop();
_context.InsideKeyRecord = false;
_context.PopScope();
}
private void Process_Property()
{
Common_Process_Property();
Read_RecordSize();
// Turns out if we have an EventSetter and this Property BamlRecord, we want to expand the property
// to be the Event=Property, Handler=Value
if (_context.CurrentFrame.XamlType.UnderlyingType == typeof(EventSetter))
{
// Write Event=Property
_xamlNodesWriter.WriteStartMember(_context.SchemaContext.EventSetterEventProperty);
XamlMember eventProperty = GetProperty(_binaryReader.ReadInt16(), false);
Type currentType = eventProperty.DeclaringType.UnderlyingType;
// Force load the Statics by walking up the hierarchy and running class constructors
while (null != currentType)
{
MS.Internal.WindowsBase.SecurityHelper.RunClassConstructor(currentType);
currentType = currentType.BaseType;
}
RoutedEvent routedEvent = EventManager.GetRoutedEventFromName(eventProperty.Name,
eventProperty.DeclaringType.UnderlyingType);
_xamlNodesWriter.WriteValue(routedEvent);
_xamlNodesWriter.WriteEndMember();
// Write Handler=Value
_xamlNodesWriter.WriteStartMember(_context.SchemaContext.EventSetterHandlerProperty);
_xamlNodesWriter.WriteValue(_binaryReader.ReadString());
_xamlNodesWriter.WriteEndMember();
}
else
{
XamlMember property = GetProperty(_binaryReader.ReadInt16(), _context.CurrentFrame.XamlType);
_xamlNodesWriter.WriteStartMember(property);
_xamlNodesWriter.WriteValue(_binaryReader.ReadString());
_xamlNodesWriter.WriteEndMember();
}
}
private void Common_Process_Property()
{
if (_context.InsideKeyRecord || _context.InsideStaticResource)
{
return;
}
RemoveImplicitFrame();
// baml property start is only valid betweeen ElementStart and ElementEnd
if (_context.CurrentFrame.XamlType == null)
{
throw new XamlParseException(SR.Get(SRID.PropertyFoundOutsideStartElement));
}
// new start properties not appear without having ended an old property
if (_context.CurrentFrame.Member != null)
{
throw new XamlParseException(SR.Get(SRID.PropertyOutOfOrder, _context.CurrentFrame.Member));
}
// Emit NS nodes for xmlns records encountered between ElementStart and Property
// The first xmlns also has the prefix for the SO node we will emit later
}
private System.Windows.Media.Int32Collection GetInt32Collection()
{
BinaryReader reader = new BinaryReader(_binaryReader.BaseStream);
System.Windows.Markup.XamlInt32CollectionSerializer.IntegerCollectionType type =
(System.Windows.Markup.XamlInt32CollectionSerializer.IntegerCollectionType)reader.ReadByte();
int capacity = reader.ReadInt32();
if (capacity < 0)
{
throw new ArgumentException(SR.Get(SRID.IntegerCollectionLengthLessThanZero, new object[0]));
}
System.Windows.Media.Int32Collection ints = new System.Windows.Media.Int32Collection(capacity);
switch (type)
{
case System.Windows.Markup.XamlInt32CollectionSerializer.IntegerCollectionType.Byte:
for (int i = 0; i < capacity; i++)
{
ints.Add(reader.ReadByte());
}
return ints;
case System.Windows.Markup.XamlInt32CollectionSerializer.IntegerCollectionType.UShort:
for (int j = 0; j < capacity; j++)
{
ints.Add(reader.ReadUInt16());
}
return ints;
case System.Windows.Markup.XamlInt32CollectionSerializer.IntegerCollectionType.Integer:
for (int k = 0; k < capacity; k++)
{
int num7 = reader.ReadInt32();
ints.Add(num7);
}
return ints;
case System.Windows.Markup.XamlInt32CollectionSerializer.IntegerCollectionType.Consecutive:
{
int num2 = reader.ReadInt32();
for (int m = 0; m < capacity; m++)
{
ints.Add(num2 + m);
}
return ints;
}
}
throw new InvalidOperationException(SR.Get(SRID.UnableToConvertInt32));
}
private XamlMember GetProperty(Int16 propertyId, XamlType parentType)
{
XamlMember property = BamlSchemaContext.GetProperty(propertyId, parentType);
return property;
}
private XamlMember GetProperty(Int16 propertyId, bool isAttached)
{
XamlMember property = BamlSchemaContext.GetProperty(propertyId, isAttached);
return property;
}
// (property, serializer, value) value is binary data that needs to be de-serialized
private void Process_PropertyCustom()
{
Common_Process_Property();
int recordSize = Read_RecordSize();
XamlMember property = GetProperty(_binaryReader.ReadInt16(), _context.CurrentFrame.XamlType);
_xamlNodesWriter.WriteStartMember(property);
short serializerTypeId = _binaryReader.ReadInt16();
// If it is a value type
if ((serializerTypeId & TypeExtensionValueMask) == TypeExtensionValueMask)
{
serializerTypeId &= (short)(~TypeExtensionValueMask);
}
if (_isBinaryProvider)
{
WriteTypeConvertedInstance(serializerTypeId, recordSize - 5); // Header is fixed length
}
else
{
// Need to translate Binary back to text.
_xamlNodesWriter.WriteValue(GetTextFromBinary(_binaryReader.ReadBytes(recordSize - 5),
serializerTypeId, property, _context.CurrentFrame.XamlType));
}
_xamlNodesWriter.WriteEndMember();
}
// Writes either Binary or the type converted binary.
// Things like boolean, enum, strings, and DPs can be type since they aren't thread affine
private bool WriteTypeConvertedInstance(short converterId, int dataByteSize)
{
TypeConverter converter;
switch (converterId)
{
case Baml2006SchemaContext.KnownTypes.XamlInt32CollectionSerializer:
_xamlNodesWriter.WriteValue(GetInt32Collection());
break;
case Baml2006SchemaContext.KnownTypes.EnumConverter:
converter = new EnumConverter(_context.CurrentFrame.XamlType.UnderlyingType);
_xamlNodesWriter.WriteValue(converter.ConvertFrom(_binaryReader.ReadBytes(dataByteSize)));
break;
case Baml2006SchemaContext.KnownTypes.BooleanConverter:
Debug.Assert(dataByteSize == 1);
_xamlNodesWriter.WriteValue((_binaryReader.ReadBytes(1)[0] == 0) ? false : true);
break;
case Baml2006SchemaContext.KnownTypes.StringConverter:
_xamlNodesWriter.WriteValue(_binaryReader.ReadString());
break;
case Baml2006SchemaContext.KnownTypes.DependencyPropertyConverter:
DependencyProperty property = null;
if (dataByteSize == 2)
{
property = BamlSchemaContext.GetDependencyProperty(_binaryReader.ReadInt16());
}
else
{
Type type = BamlSchemaContext.GetXamlType(_binaryReader.ReadInt16()).UnderlyingType;
property = DependencyProperty.FromName(_binaryReader.ReadString(), type);
}
_xamlNodesWriter.WriteValue(property);
break;
case Baml2006SchemaContext.KnownTypes.XamlBrushSerializer:
case Baml2006SchemaContext.KnownTypes.XamlPathDataSerializer:
case Baml2006SchemaContext.KnownTypes.XamlPoint3DCollectionSerializer:
case Baml2006SchemaContext.KnownTypes.XamlPointCollectionSerializer:
case Baml2006SchemaContext.KnownTypes.XamlVector3DCollectionSerializer:
DeferredBinaryDeserializerExtension deserializerME = new DeferredBinaryDeserializerExtension(this, _binaryReader, converterId, dataByteSize);
_xamlNodesWriter.WriteValue(deserializerME);
break;
default:
throw new NotImplementedException();
}
return true;
}
// (property, value, typeconverter) The value is string data that needs to be type converted
private void Process_PropertyWithConverter()
{
Common_Process_Property();
Read_RecordSize();
XamlMember property = GetProperty(_binaryReader.ReadInt16(), _context.CurrentFrame.XamlType);
_xamlNodesWriter.WriteStartMember(property);
object value = _binaryReader.ReadString();
short typeConverterId = _binaryReader.ReadInt16();
if (_isBinaryProvider &&
typeConverterId < 0 &&
-typeConverterId != System.Windows.Baml2006.Baml2006SchemaContext.KnownTypes.StringConverter)
{
TypeConverter converter = null;
if (-typeConverterId == Baml2006SchemaContext.KnownTypes.EnumConverter)
{
Type propertyType = property.Type.UnderlyingType;
// Setter.Value is of type object but will write out EnumConverter.
if (propertyType.IsEnum)
{
if (!_enumTypeConverterMap.TryGetValue(propertyType, out converter))
{
converter = new EnumConverter(propertyType);
_enumTypeConverterMap[propertyType] = converter;
}
}
}
else
{
if (!_typeConverterMap.TryGetValue(typeConverterId, out converter))
{
converter = Baml2006SchemaContext.KnownTypes.CreateKnownTypeConverter(typeConverterId);
_typeConverterMap[typeConverterId] = converter;
}
}
if (converter != null)
{
value = new TypeConverterMarkupExtension(converter, value);
}
}
_xamlNodesWriter.WriteValue(value);
_xamlNodesWriter.WriteEndMember();
}
// (property, markup extension, value) including the well known WPF TemplateBinding, StaticResource or DynamicResource markup extensions
// Writes out a property with a markup extension. However, if there is a x:Static, Type, or TemplateBinding inside the ME, we code that
// specially. e.g. Property="{FooExtension {x:Static f:Foo.Bar}}" would be written out as one Baml Record
private void Process_PropertyWithExtension()
{
Common_Process_Property();
short propertyId = _binaryReader.ReadInt16();
Int16 extensionId = _binaryReader.ReadInt16();
Int16 valueId = _binaryReader.ReadInt16();
XamlMember property = GetProperty(propertyId, _context.CurrentFrame.XamlType);
Int16 extensionTypeId = (Int16)(extensionId & ExtensionIdMask);
XamlType extensionType = BamlSchemaContext.GetXamlType((short)(-extensionTypeId));
bool isValueTypeExtension = (extensionId & TypeExtensionValueMask) == TypeExtensionValueMask;
bool isValueStaticExtension = (extensionId & StaticExtensionValueMask) == StaticExtensionValueMask;
Type typeExtensionType = null;
Type memberType = null;
object value = null;
// Write out the main Extension {FooExtension
_xamlNodesWriter.WriteStartMember(property);
// If we're in the binary case, we try to write the value out directly
bool handled = false;
if (_isBinaryProvider)
{
object param = null;
object providedValue = null;
if (isValueStaticExtension)
{
Type ownerType = null;
string staticExParam = GetStaticExtensionValue(valueId, out ownerType, out providedValue);
// If it's a Known command or a SystemResourceKey, send the value across directly
if (providedValue != null)
{
param = providedValue;
}
else
{
System.Windows.Markup.StaticExtension staticExtension =
new System.Windows.Markup.StaticExtension(staticExParam);
Debug.Assert(ownerType != null);
staticExtension.MemberType = ownerType;
param = staticExtension.ProvideValue(null); // if MemberType is set we don't need ITypeResolver
}
}
else if (isValueTypeExtension)
{
param = BamlSchemaContext.GetXamlType(valueId).UnderlyingType;
}
else
{
// For all other scenarios, we want to just write out the type
if (extensionTypeId == Baml2006SchemaContext.TemplateBindingTypeId)
{
param = _context.SchemaContext.GetDependencyProperty(valueId);
}
else if (extensionTypeId == Baml2006SchemaContext.StaticExtensionTypeId)
{
param = GetStaticExtensionValue(valueId, out memberType, out providedValue);
}
else if (extensionTypeId == Baml2006SchemaContext.TypeExtensionTypeId)
{
param = BamlSchemaContext.GetXamlType(valueId).UnderlyingType;
}
else
{
param = BamlSchemaContext.GetString(valueId);
}
}
// Doing == comparison since we only know how to create those quickly here
if (extensionTypeId == Baml2006SchemaContext.DynamicResourceTypeId)
{
value = new DynamicResourceExtension(param);
handled = true;
}
else if (extensionTypeId == Baml2006SchemaContext.StaticResourceTypeId)
{
value = new StaticResourceExtension(param);
handled = true;
}
else if (extensionTypeId == Baml2006SchemaContext.TemplateBindingTypeId)
{
value = new TemplateBindingExtension((DependencyProperty)param);
handled = true;
}
else if (extensionTypeId == Baml2006SchemaContext.TypeExtensionTypeId)
{
value = param;
handled = true;
}
else if (extensionTypeId == Baml2006SchemaContext.StaticExtensionTypeId)
{
if (providedValue != null)
{
value = providedValue;
}
else
{
System.Windows.Markup.StaticExtension staticExtension = new System.Windows.Markup.StaticExtension((string)param);
staticExtension.MemberType = memberType;
value = staticExtension;
}
handled = true;
}
if (handled)
{
_xamlNodesWriter.WriteValue(value);
_xamlNodesWriter.WriteEndMember();
return;
}
}
if (!handled)
{
_xamlNodesWriter.WriteStartObject(extensionType);
_xamlNodesWriter.WriteStartMember(XamlLanguage.PositionalParameters);
if (isValueStaticExtension)
{
Type ownerType = null;
object providedValue;
value = GetStaticExtensionValue(valueId, out ownerType, out providedValue);
// If it's a Known command or a SystemResourceKey, send the value across directly
if (providedValue != null)
{
_xamlNodesWriter.WriteValue(providedValue);
}
else
{
// Special case for {x:Static ...} inside the main extension
_xamlNodesWriter.WriteStartObject(XamlLanguage.Static);
_xamlNodesWriter.WriteStartMember(XamlLanguage.PositionalParameters);
_xamlNodesWriter.WriteValue(value);
_xamlNodesWriter.WriteEndMember();
// In BAML scenario, we want to pass MemberType directly along cuz it's optimal
if (ownerType != null)
{
_xamlNodesWriter.WriteStartMember(BamlSchemaContext.StaticExtensionMemberTypeProperty);
_xamlNodesWriter.WriteValue(ownerType);
_xamlNodesWriter.WriteEndMember();
}
_xamlNodesWriter.WriteEndObject();
}
}
else if (isValueTypeExtension)
{
// Special case for {x:Type ...} inside the main extension
_xamlNodesWriter.WriteStartObject(XamlLanguage.Type);
_xamlNodesWriter.WriteStartMember(BamlSchemaContext.TypeExtensionTypeProperty);
typeExtensionType = BamlSchemaContext.GetXamlType(valueId).UnderlyingType;
if (_isBinaryProvider)
{
_xamlNodesWriter.WriteValue(typeExtensionType);
}
else
{
_xamlNodesWriter.WriteValue(Logic_GetFullyQualifiedNameForType(BamlSchemaContext.GetXamlType(valueId)));
}
_xamlNodesWriter.WriteEndMember();
_xamlNodesWriter.WriteEndObject();
}
else
{
// For all other scenarios, we want to just write out the type
if (extensionTypeId == Baml2006SchemaContext.TemplateBindingTypeId)
{
if (this._isBinaryProvider)
{
value = BitConverter.GetBytes(valueId);
}
else
{
value = Logic_GetFullyQualifiedNameForMember(valueId);
}
}
else if (extensionTypeId == Baml2006SchemaContext.StaticExtensionTypeId)
{
// If we're here, that means we're not a binary provider which means we can't
// support writing the provided value out directly.
object providedValue;
value = GetStaticExtensionValue(valueId, out memberType, out providedValue);
}
else if (extensionTypeId == Baml2006SchemaContext.TypeExtensionTypeId)
{
value = BamlSchemaContext.GetXamlType(valueId).UnderlyingType;
}
else
{
value = BamlSchemaContext.GetString(valueId);
}
_xamlNodesWriter.WriteValue(value);
}
_xamlNodesWriter.WriteEndMember();
if (memberType != null)
{
_xamlNodesWriter.WriteStartMember(BamlSchemaContext.StaticExtensionMemberTypeProperty);
_xamlNodesWriter.WriteValue(memberType);
_xamlNodesWriter.WriteEndMember();
}
}
_xamlNodesWriter.WriteEndObject();
_xamlNodesWriter.WriteEndMember();
}
// (property, value) value is a Type object
private void Process_PropertyTypeReference()
{
Common_Process_Property();
XamlMember property = GetProperty(_binaryReader.ReadInt16(), _context.CurrentFrame.XamlType);
XamlType type = BamlSchemaContext.GetXamlType(_binaryReader.ReadInt16());
_xamlNodesWriter.WriteStartMember(property);
if (_isBinaryProvider)
{
_xamlNodesWriter.WriteValue(type.UnderlyingType);
}
else
{
_xamlNodesWriter.WriteStartObject(XamlLanguage.Type);
_xamlNodesWriter.WriteStartMember(XamlLanguage.PositionalParameters);
_xamlNodesWriter.WriteValue(Logic_GetFullyQualifiedNameForType(type));
_xamlNodesWriter.WriteEndMember();
_xamlNodesWriter.WriteEndObject();
}
_xamlNodesWriter.WriteEndMember();
}
// (property, resourcekey)
private void Process_PropertyWithStaticResourceId()
{
Common_Process_Property();
short propertyId = _binaryReader.ReadInt16();
Int16 resourceId = _binaryReader.ReadInt16();
XamlMember property = _context.SchemaContext.GetProperty(propertyId, _context.CurrentFrame.XamlType);
// PropertyWithStaticResourceId records live inside compiled resource Dictionary Entries.
// The "Id" in ResourceId is the index into the KeyList[current].StaticResources[].
// If you are reading the BAML in BRAT mode then the entries will be StaticResource
// and OptimizedStaticResource elements. (not ME's)
// If the Dictionary KeyList was loaded into a ResourceDictionary's DeferredContent Property then the
// KeyList[].StaticResource elements are processed and replaced with StaticResourceHolders. (an ME)
Object resource = _context.KeyList[_context.CurrentKey - 1].StaticResources[resourceId];
// resource is either a StaticResource, OptimizedStaticResource or StaticResourceHolder.
// We store them in a List