File: winforms\Managed\System\Resources\ResXResourceReader.cs
Project: ndp\fx\src\System.Windows.Forms.csproj (System.Windows.Forms)
//------------------------------------------------------------------------------
// <copyright file="ResXResourceReader.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------
 
#if SYSTEM_WEB  // See DevDiv 9030
namespace System.PrivateResources {
#else
namespace System.Resources {
#endif
 
    using System.Diagnostics;
    using System.Runtime.Serialization;
    using System;
    using System.Windows.Forms;
    using System.Reflection;
    using Microsoft.Win32;
    using System.Drawing;
    using System.IO;
    using System.Text;
    using System.ComponentModel;
    using System.Collections;
    using System.Collections.Specialized;
    using System.Runtime.CompilerServices;
    using System.Resources;
    using System.Xml;
    using System.ComponentModel.Design;
    using System.Globalization;
#if SYSTEM_WEB
    using System.Web;   // This is needed to access the SR resource strings
#endif
    
    /// <include file='doc\ResXResourceReader.uex' path='docs/doc[@for="ResXResourceReader"]/*' />
    /// <devdoc>
    ///     ResX resource reader.
    /// </devdoc>
    [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.InheritanceDemand, Name="FullTrust")]
    [System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Name="FullTrust")]
#if SYSTEM_WEB
    internal class ResXResourceReader : IResourceReader {
#else
    public class ResXResourceReader : IResourceReader {
#endif
 
        //static readonly char[] SpecialChars = new char[]{' ', '\r', '\n'};
 
        //IFormatter binaryFormatter = null;
        string fileName = null;
        TextReader reader = null;
        Stream stream = null;
        string fileContents = null;
        AssemblyName[] assemblyNames;
        string basePath;
        bool isReaderDirty = false;
 
        ITypeResolutionService typeResolver;
        IAliasResolver aliasResolver =null;
 
        ListDictionary resData = null;
        ListDictionary resMetadata = null;
        string resHeaderVersion = null;
        string resHeaderMimeType = null;
        string resHeaderReaderType = null;
        string resHeaderWriterType = null;
        bool useResXDataNodes = false;
 
 
        private ResXResourceReader(ITypeResolutionService typeResolver) {
            this.typeResolver = typeResolver;
            this.aliasResolver = new ReaderAliasResolver();
        }
 
        private ResXResourceReader(AssemblyName[] assemblyNames) {
            this.assemblyNames = assemblyNames;
            this.aliasResolver = new ReaderAliasResolver();
        }
 
 
        public ResXResourceReader(string fileName) : this(fileName, (ITypeResolutionService)null, (IAliasResolver)null) {
        }
        public ResXResourceReader(string fileName, ITypeResolutionService typeResolver) : this(fileName, typeResolver, (IAliasResolver)null) {
        }
        internal ResXResourceReader(string fileName, ITypeResolutionService typeResolver, IAliasResolver aliasResolver) {
            this.fileName = fileName;
            this.typeResolver = typeResolver;
            this.aliasResolver = aliasResolver;
            if(this.aliasResolver == null) {
                 this.aliasResolver = new ReaderAliasResolver();
            }
        }
 
        public ResXResourceReader(TextReader reader) : this(reader, (ITypeResolutionService)null, (IAliasResolver)null) {
        }
        public ResXResourceReader(TextReader reader, ITypeResolutionService typeResolver) : this(reader, typeResolver, (IAliasResolver)null) {
        }
        internal ResXResourceReader(TextReader reader, ITypeResolutionService typeResolver, IAliasResolver aliasResolver) {
            this.reader = reader;
            this.typeResolver = typeResolver;
            this.aliasResolver = aliasResolver;
            if(this.aliasResolver == null) {
                 this.aliasResolver = new ReaderAliasResolver();
            }
        }
        
 
        public ResXResourceReader(Stream stream) : this(stream, (ITypeResolutionService)null, (IAliasResolver)null) {
        }
        public ResXResourceReader(Stream stream, ITypeResolutionService typeResolver) : this(stream, typeResolver, (IAliasResolver)null) {
        }
        internal ResXResourceReader(Stream stream, ITypeResolutionService typeResolver, IAliasResolver aliasResolver) {
            this.stream = stream;
            this.typeResolver = typeResolver;
            this.aliasResolver = aliasResolver;
            if(this.aliasResolver == null) {
                 this.aliasResolver = new ReaderAliasResolver();
            }
        }
 
        public ResXResourceReader(Stream stream, AssemblyName[] assemblyNames) : this(stream, assemblyNames, (IAliasResolver)null){
        }
        internal ResXResourceReader(Stream stream, AssemblyName[] assemblyNames, IAliasResolver aliasResolver) {
            this.stream = stream;
            this.assemblyNames = assemblyNames;
            this.aliasResolver = aliasResolver;
            if(this.aliasResolver == null) {
                 this.aliasResolver = new ReaderAliasResolver();
            }
        }
 
        public ResXResourceReader(TextReader reader, AssemblyName[] assemblyNames) : this(reader, assemblyNames, (IAliasResolver)null){
        }
        internal ResXResourceReader(TextReader reader, AssemblyName[] assemblyNames, IAliasResolver aliasResolver) {
            this.reader = reader;
            this.assemblyNames = assemblyNames;
            this.aliasResolver = aliasResolver;
            if(this.aliasResolver == null) {
                 this.aliasResolver = new ReaderAliasResolver();
            }
        }
 
        public ResXResourceReader(string fileName, AssemblyName[] assemblyNames) : this(fileName, assemblyNames, (IAliasResolver)null){
        }
        internal ResXResourceReader(string fileName, AssemblyName[] assemblyNames, IAliasResolver aliasResolver) {
            this.fileName = fileName;
            this.assemblyNames = assemblyNames;
            this.aliasResolver = aliasResolver;
            if(this.aliasResolver == null) {
                 this.aliasResolver = new ReaderAliasResolver();
            }
        }
 
        
 
        /// <include file='doc\ResXResourceReader.uex' path='docs/doc[@for=".Finalize"]/*' />
        ~ResXResourceReader() {
            Dispose(false);
        }
 
        /// <include file='doc\ResXResourceReader.uex' path='docs/doc[@for="ResXResourceReader.BasePath"]/*' />
        /// <devdoc>
        ///     BasePath for relatives filepaths with ResXFileRefs.
        /// </devdoc>
        public string BasePath {
            get {
                return basePath;
            }
            set {
                if(isReaderDirty) {
                    throw new InvalidOperationException(SR.GetString(SR.InvalidResXBasePathOperation));
                }
                basePath = value;
            }
        }
 
#if UNUSED
        /// <devdoc>
        ///     Retrieves the resource data set. This will demand load it.
        /// </devdoc>
        private ListDictionary ResData {
            get {
                EnsureResData();
                return resData;
            }
        }
 
        /// <devdoc>
        ///     Returns the typeResolver used to find types defined in the ResX contents.
        /// </devdoc>
        private ITypeResolutionService TypeResolver {
            get {
                return this.typeResolver;
            }
        }
#endif
 
        /// <include file='doc\ResXResourceReader.uex' path='docs/doc[@for="ResXResourceReader.ResXResourceReader5"]/*' />
        /// <devdoc>
        ///     ResXFileRef's TypeConverter automatically unwraps it, creates the referenced
        ///     object and returns it. This property gives the user control over whether this unwrapping should
        ///     happen, or a ResXFileRef object should be returned. Default is true for backward compat and common case
        ///     scenario.
        /// </devdoc>
        public bool UseResXDataNodes {
            get {
                return this.useResXDataNodes;
            }
            set {
                if(isReaderDirty) {
                    throw new InvalidOperationException(SR.GetString(SR.InvalidResXBasePathOperation));
                }
                this.useResXDataNodes = value;
            }
        }
 
        /// <include file='doc\ResXResourceReader.uex' path='docs/doc[@for="ResXResourceReader.Close"]/*' />
        /// <devdoc>
        ///     Closes and files or streams being used by the reader.
        /// </devdoc>
        // NOTE: Part of IResourceReader - not protected by class level LinkDemand.
        public void Close() {
            ((IDisposable)this).Dispose();
        }
 
        /// <include file='doc\ResXResourceReader.uex' path='docs/doc[@for="ResXResourceReader.IDisposable.Dispose"]/*' />
        /// <internalonly/>
        // NOTE: Part of IDisposable - not protected by class level LinkDemand.
        void IDisposable.Dispose() {
            GC.SuppressFinalize(this);
            Dispose(true);
        }
 
        /// <include file='doc\ResXResourceReader.uex' path='docs/doc[@for="ResXResourceReader.Dispose"]/*' />
        protected virtual void Dispose(bool disposing) {
            if (disposing) {
                if (fileName != null && stream != null) {
                    stream.Close();
                    stream = null;
                }
 
                if (reader != null) {
                    reader.Close();
                    reader = null;
                }
            }
        }
 
        private void SetupNameTable(XmlReader reader) {
            reader.NameTable.Add(ResXResourceWriter.TypeStr);
            reader.NameTable.Add(ResXResourceWriter.NameStr);
            reader.NameTable.Add(ResXResourceWriter.DataStr);
            reader.NameTable.Add(ResXResourceWriter.MetadataStr);
            reader.NameTable.Add(ResXResourceWriter.MimeTypeStr);
            reader.NameTable.Add(ResXResourceWriter.ValueStr);
            reader.NameTable.Add(ResXResourceWriter.ResHeaderStr);
            reader.NameTable.Add(ResXResourceWriter.VersionStr);
            reader.NameTable.Add(ResXResourceWriter.ResMimeTypeStr);
            reader.NameTable.Add(ResXResourceWriter.ReaderStr);
            reader.NameTable.Add(ResXResourceWriter.WriterStr);
            reader.NameTable.Add(ResXResourceWriter.BinSerializedObjectMimeType);
            reader.NameTable.Add(ResXResourceWriter.SoapSerializedObjectMimeType);
            reader.NameTable.Add(ResXResourceWriter.AssemblyStr);
            reader.NameTable.Add(ResXResourceWriter.AliasStr);
        }
 
        /// <devdoc>
        ///     Demand loads the resource data.
        /// </devdoc>
        private void EnsureResData() {
            if (resData == null) {
                resData = new ListDictionary();
                resMetadata = new ListDictionary();
 
                XmlTextReader contentReader = null;
 
                try {
                    // Read data in any which way
                    if (fileContents != null) {
                        contentReader = new XmlTextReader(new StringReader(fileContents));
                    }
                    else if (reader != null) {
                        contentReader = new XmlTextReader(reader);
                    }
                    else if (fileName != null || stream != null) {
                        if (stream == null) {
                            stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
                        }
 
                        contentReader = new XmlTextReader(stream);
                    }
 
                    SetupNameTable(contentReader);
                    contentReader.WhitespaceHandling = WhitespaceHandling.None;
                    ParseXml(contentReader);
                }
                finally {
                    if (fileName != null && stream != null) {
                        stream.Close();
                        stream = null;
                    }
                }
            }
        }                                
 
 
 
        /// <include file='doc\ResXResourceReader.uex' path='docs/doc[@for="ResXResourceReader.FromFileContents"]/*' />
        /// <devdoc>
        ///     Creates a reader with the specified file contents.
        /// </devdoc>
        public static ResXResourceReader FromFileContents(string fileContents) {
            return FromFileContents(fileContents, (ITypeResolutionService)null);
        }
 
        /// <include file='doc\ResXResourceReader.uex' path='docs/doc[@for="ResXResourceReader.FromFileContents1"]/*' />
        /// <internalonly/>
        /// <devdoc>
        ///     Creates a reader with the specified file contents.
        /// </devdoc>
        public static ResXResourceReader FromFileContents(string fileContents, ITypeResolutionService typeResolver) {
            ResXResourceReader result = new ResXResourceReader(typeResolver);
            result.fileContents = fileContents;
            return result;
        }
 
        /// <include file='doc\ResXResourceReader.uex' path='docs/doc[@for="ResXResourceReader.FromFileContents1"]/*' />
        /// <internalonly/>
        /// <devdoc>
        ///     Creates a reader with the specified file contents.
        /// </devdoc>
        public static ResXResourceReader FromFileContents(string fileContents, AssemblyName[] assemblyNames) {
            ResXResourceReader result = new ResXResourceReader(assemblyNames);
            result.fileContents = fileContents;
            return result;
        }
 
        /// <include file='doc\ResXResourceReader.uex' path='docs/doc[@for="ResXResourceReader.IEnumerable.GetEnumerator"]/*' />
        /// <internalonly/>
        // NOTE: Part of IEnumerable - not protected by class level LinkDemand.
        IEnumerator IEnumerable.GetEnumerator() {
            return GetEnumerator();
        }
 
        /// <include file='doc\ResXResourceReader.uex' path='docs/doc[@for="ResXResourceReader.GetEnumerator"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        // NOTE: Part of IResourceReader - not protected by class level LinkDemand.
        public IDictionaryEnumerator GetEnumerator() {
            isReaderDirty = true;
            EnsureResData();
            return resData.GetEnumerator();
        }
 
        /// <include file='doc\ResXResourceReader.uex' path='docs/doc[@for="ResXResourceReader.GetMetadataEnumerator"]/*' />
        /// <devdoc>
        ///    Returns a dictionary enumerator that can be used to enumerate the <metadata> elements in the .resx file.
        /// </devdoc>
        public IDictionaryEnumerator GetMetadataEnumerator() {
            EnsureResData();
            return resMetadata.GetEnumerator();
        }
 
        /// <devdoc>
        ///    Attempts to return the line and column (Y, X) of the XML reader.
        /// </devdoc>
        private Point GetPosition(XmlReader reader) {
            Point pt = new Point(0, 0);
            IXmlLineInfo lineInfo = reader as IXmlLineInfo;
 
            if (lineInfo != null) {
                pt.Y = lineInfo.LineNumber;
                pt.X = lineInfo.LinePosition;
            }
 
            return pt;
        }
 
 
        private void ParseXml(XmlTextReader reader) {
            bool success = false;
            try {
                try {
                    while (reader.Read()) {
                        if (reader.NodeType == XmlNodeType.Element) {
                            string s = reader.LocalName;
                            
                            if (reader.LocalName.Equals(ResXResourceWriter.AssemblyStr)) {
                                ParseAssemblyNode(reader, false);
                            }
                            else if (reader.LocalName.Equals(ResXResourceWriter.DataStr)) {
                                ParseDataNode(reader, false);
                            }
                            else if (reader.LocalName.Equals(ResXResourceWriter.ResHeaderStr)) {
                                ParseResHeaderNode(reader);
                            }
                            else if (reader.LocalName.Equals(ResXResourceWriter.MetadataStr)) {
                                ParseDataNode(reader, true);
                            }
                        }
                    }
 
                    success = true;
                }
                catch (SerializationException se) {
                    Point pt = GetPosition(reader);
                    string newMessage = SR.GetString(SR.SerializationException, reader[ResXResourceWriter.TypeStr], pt.Y, pt.X, se.Message);
                    XmlException xml = new XmlException(newMessage, se, pt.Y, pt.X);
                    SerializationException newSe = new SerializationException(newMessage, xml);
 
                    throw newSe;
                }
                catch (TargetInvocationException tie) {
                    Point pt = GetPosition(reader);
                    string newMessage = SR.GetString(SR.InvocationException, reader[ResXResourceWriter.TypeStr], pt.Y, pt.X, tie.InnerException.Message);
                    XmlException xml = new XmlException(newMessage, tie.InnerException, pt.Y, pt.X);
                    TargetInvocationException newTie = new TargetInvocationException(newMessage, xml);
 
                    throw newTie;
                }
                catch (XmlException e) {
                    throw new ArgumentException(SR.GetString(SR.InvalidResXFile, e.Message), e);
                }
                catch (Exception e) {
                    if (ClientUtils.IsSecurityOrCriticalException(e)) {
                        throw;
                    } else {
                        Point pt = GetPosition(reader);
                        XmlException xmlEx = new XmlException(e.Message, e, pt.Y, pt.X);
                        throw new ArgumentException(SR.GetString(SR.InvalidResXFile, xmlEx.Message), xmlEx);
                    }
                }
            }
            finally {
                if (!success) {
                    resData = null;
                    resMetadata = null;
                }
            }
 
            bool validFile = false;
 
            if (object.Equals(resHeaderMimeType, ResXResourceWriter.ResMimeType)) {
 
                Type readerType = typeof(ResXResourceReader);
                Type writerType = typeof(ResXResourceWriter);
 
                string readerTypeName = resHeaderReaderType;
                string writerTypeName = resHeaderWriterType;
                if (readerTypeName != null &&readerTypeName.IndexOf(',') != -1) {
                    readerTypeName = readerTypeName.Split(new char[] {','})[0].Trim();
                }
                if (writerTypeName != null && writerTypeName.IndexOf(',') != -1) {
                    writerTypeName = writerTypeName.Split(new char[] {','})[0].Trim();
                }
 
// Don't check validity, since our reader/writer classes are in System.Web.Compilation,
// while the file format has them in System.Resources.  
#if SYSTEM_WEB
                validFile = true;
#else
                if (readerTypeName != null && 
                    writerTypeName != null && 
                    readerTypeName.Equals(readerType.FullName) && 
                    writerTypeName.Equals(writerType.FullName)) {
                    validFile = true;
                }
#endif
            }
 
            if (!validFile) {
                resData = null;
                resMetadata = null;
                throw new ArgumentException(SR.GetString(SR.InvalidResXFileReaderWriterTypes));
            }
        }
 
        private void ParseResHeaderNode(XmlReader reader) {
            string name = reader[ResXResourceWriter.NameStr];
            if (name != null) {
                reader.ReadStartElement();
 
                // The "1.1" schema requires the correct casing of the strings
                // in the resheader, however the "1.0" schema had a different
                // casing. By checking the Equals first, we should 
                // see significant performance improvements.
                //
 
                if (object.Equals(name, ResXResourceWriter.VersionStr)) {
                    if (reader.NodeType == XmlNodeType.Element) {
                        resHeaderVersion = reader.ReadElementString();
                    }
                    else {
                        resHeaderVersion = reader.Value.Trim();
                    }
                }
                else if (object.Equals(name, ResXResourceWriter.ResMimeTypeStr)) {
                    if (reader.NodeType == XmlNodeType.Element) {
                        resHeaderMimeType = reader.ReadElementString();
                    }
                    else {
                        resHeaderMimeType = reader.Value.Trim();
                    }
                }
                else if (object.Equals(name, ResXResourceWriter.ReaderStr)) {
                    if (reader.NodeType == XmlNodeType.Element) {
                        resHeaderReaderType = reader.ReadElementString();
                    }
                    else {
                        resHeaderReaderType = reader.Value.Trim();
                    }
                }
                else if (object.Equals(name, ResXResourceWriter.WriterStr)) {
                    if (reader.NodeType == XmlNodeType.Element) {
                        resHeaderWriterType = reader.ReadElementString();
                    }
                    else {
                        resHeaderWriterType = reader.Value.Trim();
                    }
                }
                else {
                    switch (name.ToLower(CultureInfo.InvariantCulture)) {
                        case ResXResourceWriter.VersionStr:
                            if (reader.NodeType == XmlNodeType.Element) {
                                resHeaderVersion = reader.ReadElementString();
                            }
                            else {
                                resHeaderVersion = reader.Value.Trim();
                            }
                            break;
                        case ResXResourceWriter.ResMimeTypeStr:
                            if (reader.NodeType == XmlNodeType.Element) {
                                resHeaderMimeType = reader.ReadElementString();
                            }
                            else {
                                resHeaderMimeType = reader.Value.Trim();
                            }
                            break;
                        case ResXResourceWriter.ReaderStr:
                            if (reader.NodeType == XmlNodeType.Element) {
                                resHeaderReaderType = reader.ReadElementString();
                            }
                            else {
                                resHeaderReaderType = reader.Value.Trim();
                            }
                            break;
                        case ResXResourceWriter.WriterStr:
                            if (reader.NodeType == XmlNodeType.Element) {
                                resHeaderWriterType = reader.ReadElementString();
                            }
                            else {
                                resHeaderWriterType = reader.Value.Trim();
                            }
                            break;
                    }
                }
            }
        }
 
#if UNUSED
        private string GetSimpleName(string typeName) {
             int indexStart = typeName.IndexOf(",");
             return typeName.Substring(0, indexStart); 
        }
#endif
 
        private void ParseAssemblyNode(XmlReader reader, bool isMetaData)
        {
            string alias = reader[ResXResourceWriter.AliasStr];
            string typeName = reader[ResXResourceWriter.NameStr];
 
            AssemblyName assemblyName = new AssemblyName(typeName);
            
            if (string.IsNullOrEmpty(alias)) {
                alias = assemblyName.Name;
            }
            aliasResolver.PushAlias(alias, assemblyName);
        }
        
 
        private void ParseDataNode(XmlTextReader reader, bool isMetaData) {
            DataNodeInfo nodeInfo = new DataNodeInfo();
            
            nodeInfo.Name = reader[ResXResourceWriter.NameStr];
            string typeName = reader[ResXResourceWriter.TypeStr];
 
            string alias = null;
            AssemblyName assemblyName = null;
            
            if (!string.IsNullOrEmpty(typeName)) {
                alias  = GetAliasFromTypeName(typeName);
            }
            if (!string.IsNullOrEmpty(alias)) {
                assemblyName = aliasResolver.ResolveAlias(alias);
            }
            if (assemblyName != null )
            {
                nodeInfo.TypeName = GetTypeFromTypeName(typeName) + ", " + assemblyName.FullName;
            }
            else {
                nodeInfo.TypeName = reader[ResXResourceWriter.TypeStr];
            }
            
            nodeInfo.MimeType = reader[ResXResourceWriter.MimeTypeStr];
 
            bool finishedReadingDataNode = false;
            nodeInfo.ReaderPosition = GetPosition(reader);
            while(!finishedReadingDataNode && reader.Read()) {
                if(reader.NodeType == XmlNodeType.EndElement && ( reader.LocalName.Equals(ResXResourceWriter.DataStr) || reader.LocalName.Equals(ResXResourceWriter.MetadataStr) )) {
                    // we just found </data>, quit or </metadata>
                    finishedReadingDataNode = true;
                } else {
                    // could be a <value> or a <comment>
                    if (reader.NodeType == XmlNodeType.Element) {
                        if (reader.Name.Equals(ResXResourceWriter.ValueStr)) {
                            WhitespaceHandling oldValue = reader.WhitespaceHandling;
                            try {
                                // based on the documentation at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemxmlxmltextreaderclasswhitespacehandlingtopic.asp 
                                // this is ok because:
                                // "Because the XmlTextReader does not have DTD information available to it,
                                // SignificantWhitepsace nodes are only returned within the an xml:space='preserve' scope." 
                                // the xml:space would not be present for anything else than string and char (see ResXResourceWriter)
                                // so this would not cause any breaking change while reading data from Everett (we never outputed
                                // xml:space then) or from whidbey that is not specifically either a string or a char.
                                // However please note that manually editing a resx file in Everett and in Whidbey because of the addition
                                // of xml:space=preserve might have different consequences...
                                reader.WhitespaceHandling = WhitespaceHandling.Significant;
                                nodeInfo.ValueData = reader.ReadString();
                            } finally {
                                reader.WhitespaceHandling = oldValue;
                            }
                        } else if (reader.Name.Equals(ResXResourceWriter.CommentStr)) {
                            nodeInfo.Comment = reader.ReadString();
                        }
                    } else {
                        // weird, no <xxxx> tag, just the inside of <data> as text
                        nodeInfo.ValueData = reader.Value.Trim();
                    }
                }
            }            
 
            if (nodeInfo.Name==null) {
                throw new ArgumentException(SR.GetString(SR.InvalidResXResourceNoName, nodeInfo.ValueData));
            }
 
            ResXDataNode dataNode = new ResXDataNode(nodeInfo, BasePath);
 
            if(UseResXDataNodes) {
                resData[nodeInfo.Name] = dataNode;
            } else {
                IDictionary data = (isMetaData ? resMetadata : resData);
                if(assemblyNames == null) {
                    data[nodeInfo.Name] = dataNode.GetValue(typeResolver);
                } else {
                    data[nodeInfo.Name] = dataNode.GetValue(assemblyNames);
                }
            }
        }
 
        private string GetAliasFromTypeName(string typeName) {
             
             int indexStart = typeName.IndexOf(",");
             return typeName.Substring(indexStart + 2); 
        
        }
 
        private string GetTypeFromTypeName(string typeName) {
             
             int indexStart = typeName.IndexOf(",");
             return typeName.Substring(0, indexStart); 
        
        }
 
 
        private sealed class ReaderAliasResolver : IAliasResolver {
            private Hashtable cachedAliases;
 
            internal ReaderAliasResolver() {
                this.cachedAliases = new Hashtable();
            }
 
            public AssemblyName ResolveAlias(string alias) {
 
                AssemblyName result = null;
                if(cachedAliases != null) {
                    result = (AssemblyName)cachedAliases[alias];
                } 
                return result;
            }
 
            public void PushAlias(string alias, AssemblyName name) {
                if (this.cachedAliases != null && !string.IsNullOrEmpty(alias)) {
                    cachedAliases[alias] = name;
                }
            }
            
        }
    }
}