/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Framework / System / Windows / Markup / ParserContext.cs / 1 / ParserContext.cs
//----------------------------------------------------------------------------
//
// File: ParserContext.cs
//
// Description:
// class for the main TypeConverterContext object passed to type converters
//
//
// History:
// 8/02/01: rogerg Created
// 05/23/03: peterost Ported to wcp
// 03/16/05: chandras Changed the XmlnsDictionary usage
//
// Copyright (C) 2001 by Microsoft Corporation. All rights reserved.
//
//---------------------------------------------------------------------------
using System;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Xml;
using MS.Utility;
using System.Diagnostics;
#if PBTCOMPILER
namespace MS.Internal.Markup
#else
using System.Windows;
using System.Security;
using MS.Internal;
namespace System.Windows.Markup
#endif
{
#if PBTCOMPILER
///
/// The IUriContext interface allows elements (like Frame, PageViewer) and type converters
/// (like BitmapImage TypeConverters) a way to ensure that base uri is set on them by the
/// parser, codegen for xaml, baml and caml cases. The elements can then use this base uri
/// to navigate.
///
internal interface IUriContext
{
///
/// Provides the base uri of the current context.
///
Uri BaseUri
{
get;
set;
}
}
#endif
///
/// Provides all the context information required by Parser
///
#if PBTCOMPILER
internal class ParserContext : IUriContext
#else
public class ParserContext : IUriContext
#endif
{
#region Public Methods
///
/// Constructor
///
public ParserContext()
{
Initialize();
}
// Initialize the ParserContext to a known, default state. DO NOT wipe out
// data that may be able to be shared between seperate parses, such as the
// xamlTypeMapper and the map table.
internal void Initialize()
{
_xmlnsDictionary = null; // created on its first use
#if !PBTCOMPILER
_nameScopeStack = null;
#endif
_xmlLang = String.Empty;
_xmlSpace = String.Empty;
}
#if !PBTCOMPILER
///
/// Constructor that takes the XmlParserContext.
/// A parserContext object will be built based on this.
///
/// xmlParserContext to use
public ParserContext(XmlParserContext xmlParserContext)
{
if (xmlParserContext == null)
{
throw new ArgumentNullException( "xmlParserContext" );
}
_xmlLang = xmlParserContext.XmlLang;
TypeConverter typeConverter = TypeDescriptor.GetConverter(typeof(XmlSpace));
if (typeConverter != null)
_xmlSpace = (string) typeConverter.ConvertToString(null, XamlReaderHelper.EnglishUSCulture, xmlParserContext.XmlSpace);
else
_xmlSpace = String.Empty;
_xmlnsDictionary = new XmlnsDictionary() ;
if (xmlParserContext.BaseURI != null && xmlParserContext.BaseURI.Length > 0)
{
_baseUri = new Uri(xmlParserContext.BaseURI, UriKind.RelativeOrAbsolute);
}
XmlNamespaceManager xmlnsManager = xmlParserContext.NamespaceManager;
if (null != xmlnsManager)
{
foreach (string key in xmlnsManager)
{
_xmlnsDictionary.Add(key, xmlnsManager.LookupNamespace(key));
}
}
}
#endif
#if !PBTCOMPILER
///
/// Constructor overload that takes an XmlReader, in order to
/// pull the BaseURI, Lang, and Space from it.
///
internal ParserContext( XmlReader xmlReader )
{
if( xmlReader.BaseURI != null && xmlReader.BaseURI.Length != 0 )
{
BaseUri = new Uri( xmlReader.BaseURI );
}
XmlLang = xmlReader.XmlLang;
if( xmlReader.XmlSpace != System.Xml.XmlSpace.None )
{
XmlSpace = xmlReader.XmlSpace.ToString();
}
}
#endif
#if !PBTCOMPILER
///
/// Constructor that takes the ParserContext.
/// A parserContext object will be built based on this.
///
/// xmlParserContext to use
internal ParserContext(ParserContext parserContext)
{
_xmlLang = parserContext.XmlLang;
_xmlSpace = parserContext.XmlSpace;
_xamlTypeMapper = parserContext.XamlTypeMapper;
_mapTable = parserContext.MapTable;
_baseUri = parserContext.BaseUri;
_rootElement = parserContext._rootElement;
if (parserContext._nameScopeStack != null)
_nameScopeStack = (Stack)parserContext._nameScopeStack.Clone();
else
_nameScopeStack = null;
// Don't want to force the lazy init so we just set privates
_skipJournaledProperties = parserContext._skipJournaledProperties;
_xmlnsDictionary = null;
// when there are no namespace prefix mappings in incoming ParserContext,
// we are not going to create an empty XmlnsDictionary.
if (parserContext._xmlnsDictionary != null &&
parserContext._xmlnsDictionary.Count > 0)
{
_xmlnsDictionary = new XmlnsDictionary();
XmlnsDictionary xmlDictionaryFrom = parserContext.XmlnsDictionary;
if (null != xmlDictionaryFrom)
{
foreach (string key in xmlDictionaryFrom.Keys)
{
_xmlnsDictionary[key] = xmlDictionaryFrom[key];
}
}
}
}
#endif
///
/// Pushes the context scope stack (modifications to the ParserContext only apply to levels below
/// the modification in the stack, except for the XamlTypeMapper property)
///
internal void PushScope()
{
_repeat++;
_currentFreezeStackFrame.IncrementRepeatCount();
// Wait till the context needs XmlnsDictionary, create on first use.
if (_xmlnsDictionary != null)
_xmlnsDictionary.PushScope();
}
///
/// Pops the context scope stack
///
internal void PopScope()
{
// Pop state off of the _langSpaceStack
if (_repeat > 0)
{
_repeat--;
}
else
{
if (null != _langSpaceStack && _langSpaceStack.Count > 0)
{
_repeat = (int) _langSpaceStack.Pop();
_targetType = (Type) _langSpaceStack.Pop();
_xmlSpace = (string) _langSpaceStack.Pop();
_xmlLang = (string) _langSpaceStack.Pop();
}
}
// Pop state off of _currentFreezeStackFrame
if (!_currentFreezeStackFrame.DecrementRepeatCount())
{
// If the end of the current frame has been reached, pop
// the next frame off the freeze stack
_currentFreezeStackFrame = (FreezeStackFrame) _freezeStack.Pop();
}
// Wait till the context needs XmlnsDictionary, create on first use.
if (_xmlnsDictionary != null)
_xmlnsDictionary.PopScope();
}
///
/// XmlNamespaceDictionary
///
public XmlnsDictionary XmlnsDictionary
{
get
{
// Entry Point to others, initialize if null.
if (_xmlnsDictionary == null)
_xmlnsDictionary = new XmlnsDictionary();
return _xmlnsDictionary;
}
}
///
/// XmlLang property
///
public string XmlLang
{
get
{
return _xmlLang;
}
set
{
EndRepeat();
_xmlLang = (null == value ? String.Empty : value);
}
}
///
/// XmlSpace property
///
// (Why isn't this of type XmlSpace?)
public string XmlSpace
{
get
{
return _xmlSpace;
}
set
{
EndRepeat();
_xmlSpace = value;
}
}
//
// TargetType
//
// Keep track of the Style/Template TargetType's in the current context. This allows Setters etc
// to interpret properties without walking up the reader stack to see it. This is internal and
// hard-coded to target type, but the intent in the future is to generalize this so that we don't
// have to have the custom parser, and so that the designer can provide the same contextual information.
//
internal Type TargetType
{
get
{
return _targetType;
}
#if !PBTCOMPILER
set
{
EndRepeat();
_targetType = value;
}
#endif
}
// Items specific to XAML
///
/// XamlTypeMapper that should be used when resolving XML
///
public XamlTypeMapper XamlTypeMapper
{
get
{
return _xamlTypeMapper ;
}
set
{
// The BamlMapTable must always be kept in [....] with the XamlTypeMapper. If
// the XamlTypeMapper changes, then the map table must also be reset.
if (_xamlTypeMapper != value)
{
_xamlTypeMapper = value;
_mapTable = new BamlMapTable(value);
_xamlTypeMapper.MapTable = _mapTable;
}
}
}
#if !PBTCOMPILER
///
/// Gets or sets the list of INameScopes in parent chain
///
internal Stack NameScopeStack
{
get
{
if (_nameScopeStack == null)
_nameScopeStack = new Stack(2);
return _nameScopeStack;
}
}
#endif
///
/// Gets or sets the base Uri
///
public Uri BaseUri
{
get
{
return _baseUri ;
}
set
{
_baseUri = value;
}
}
#if !PBTCOMPILER
///
/// Should DependencyProperties marked with the Journal metadata flag be set or skipped?
///
///
internal bool SkipJournaledProperties
{
get { return _skipJournaledProperties; }
set { _skipJournaledProperties = value; }
}
//
// The Assembly which hosts the Baml stream.
//
///
/// Critical - because it sets the value of the _streamCreatedAssembly field, and that is
/// SecurityCritical Data as this field is used by the BamlRecordReader to
/// allow legitimate internal types in Partial Trust.
///
internal Assembly StreamCreatedAssembly
{
get { return _streamCreatedAssembly.Value; }
[SecurityCritical]
set { _streamCreatedAssembly.Value = value; }
}
#endif
///
/// Operator for Converting a ParserContext to an XmlParserContext
///
/// ParserContext to Convert
/// XmlParserContext
public static implicit operator XmlParserContext(ParserContext parserContext)
{
return ParserContext.ToXmlParserContext(parserContext);
}
///
/// Operator for Converting a ParserContext to an XmlParserContext
///
/// ParserContext to Convert
/// XmlParserContext
public static XmlParserContext ToXmlParserContext(ParserContext parserContext)
{
if (parserContext == null)
{
throw new ArgumentNullException( "parserContext" );
}
XmlNamespaceManager xmlnsMgr = new XmlNamespaceManager(new NameTable());
XmlSpace xmlSpace = System.Xml.XmlSpace.None;
if (parserContext.XmlSpace != null && parserContext.XmlSpace.Length != 0)
{
TypeConverter typeConverter = TypeDescriptor.GetConverter(typeof(System.Xml.XmlSpace));
if (null != typeConverter)
{
try
{
xmlSpace = (System.Xml.XmlSpace)typeConverter.ConvertFromString(null, XamlReaderHelper.EnglishUSCulture, parserContext.XmlSpace);
}
catch (System.FormatException) // If it's not a valid space value, ignore it
{
xmlSpace = System.Xml.XmlSpace.None;
}
}
}
// We start getting Keys list only if we have non-empty dictionary
if (parserContext._xmlnsDictionary != null)
{
foreach (string key in parserContext._xmlnsDictionary.Keys)
{
xmlnsMgr.AddNamespace(key, parserContext._xmlnsDictionary[key]);
}
}
XmlParserContext xmlParserContext = new XmlParserContext(null, xmlnsMgr, parserContext.XmlLang, xmlSpace);
if( parserContext.BaseUri == null)
{
xmlParserContext.BaseURI = null;
}
else
{
string serializedSafe = parserContext.BaseUri.GetComponents(UriComponents.SerializationInfoString, UriFormat.SafeUnescaped);
Uri sameUri = new Uri(serializedSafe);
string cannonicalString = sameUri.GetComponents(UriComponents.SerializationInfoString, UriFormat.UriEscaped);
xmlParserContext.BaseURI = cannonicalString;
}
return xmlParserContext;
}
#endregion Public Methods
#region Internal
// Reset stack to default state
private void EndRepeat()
{
if (_repeat > 0)
{
if (null == _langSpaceStack)
{
_langSpaceStack = new Stack(1);
}
_langSpaceStack.Push(XmlLang);
_langSpaceStack.Push(XmlSpace);
_langSpaceStack.Push(TargetType);
_langSpaceStack.Push(_repeat);
_repeat = 0;
}
}
///
/// LineNumber for the first character in the given
/// stream. This is used when parsing a section of a larger file so
/// that proper line number in the overall file can be calculated.
///
internal int LineNumber
{
get { return _lineNumber; }
#if !PBTCOMPILER
set { _lineNumber = value; }
#endif
}
///
/// LinePosition for the first character in the given
/// stream. This is used when parsing a section of a larger file so
/// that proper line positions in the overall file can be calculated.
///
internal int LinePosition
{
get { return _linePosition; }
#if !PBTCOMPILER
set { _linePosition = value; }
#endif
}
#if !PBTCOMPILER
internal bool IsDebugBamlStream
{
get { return _isDebugBamlStream; }
set { _isDebugBamlStream = value; }
}
///
/// Gets or sets the object at the root of the portion of the tree
/// currently being parsed. Note that this may not be the very top of the tree
/// if the parsing operation is scoped to a specific subtree, such as in Style
/// parsing.
///
internal object RootElement
{
get { return _rootElement; }
set { _rootElement = value; }
}
// If this is false (default), then the parser does not own the stream and so if
// it has any defer loaded content, it needs to copy it into a byte array since
// the owner\caller will close the stream when parsing is complete. Currently, this
// is set to true only by the theme engine since the stream is a system-wide resource
// an dso will always be open for teh lifetime of the process laoding the theme and so
// it can be re-used for perf reasons.
internal bool OwnsBamlStream
{
get { return _ownsBamlStream; }
set { _ownsBamlStream = value; }
}
#endif
///
/// Allows sharing a map table between instances of BamlReaders and Writers.
///
internal BamlMapTable MapTable
{
get { return _mapTable; }
#if !PBTCOMPILER
set
{
// The XamlTypeMapper and the map table must always be kept in [....]. If the
// map table changes, update the XamlTypeMapper also
if (_mapTable != value)
{
_mapTable = value;
_xamlTypeMapper = _mapTable.XamlTypeMapper;
_xamlTypeMapper.MapTable = _mapTable;
}
}
#endif
}
#if !PBTCOMPILER
///
/// Allows accessing the associated BamlRecordReader for doing custom processing
/// and searches of the reader stack during parse time.
///
internal BamlRecordReader BamlReader
{
get { return _bamlRecordReader; }
set { _bamlRecordReader = value; }
}
internal IStyleConnector StyleConnector
{
get { return _styleConnector; }
set { _styleConnector = value; }
}
// Keep a cached ProvideValueProvider so that we don't have to keep re-creating one.
internal ProvideValueServiceProvider ProvideValueProvider
{
get
{
if (_provideValueServiceProvider == null)
{
_provideValueServiceProvider = new ProvideValueServiceProvider(this);
}
return _provideValueServiceProvider;
}
}
///
/// This is used to resolve a StaticResourceId record within a deferred content
/// section against a StaticResourceExtension on the parent dictionary.
///
internal List