private BamlKeyInfo CheckForSharedness()
        {
            IBamlDictionaryKey dictKey = (IBamlDictionaryKey)_currentBamlRecord;
            Debug.Assert(dictKey != null, "Bad Key record");
            if (!dictKey.SharedSet)
                return null;

            BamlKeyInfo info = new BamlKeyInfo();
            info.Value = dictKey.Shared.ToString();
            info.AssemblyName = string.Empty;
            info.Prefix = (string)_prefixDictionary[XamlReaderHelper.DefinitionNamespaceURI];
            info.XmlNamespace = XamlReaderHelper.DefinitionNamespaceURI;
            info.ClrNamespace = string.Empty;
            info.Name = XamlReaderHelper.DefinitionShared;
            info.LocalName = info.Name;
            info.RecordType = BamlRecordType.DefAttribute;
            info.Offset = dictKey.ValuePosition;

            return info;
        }
        /***************************************************************************\
        *
        * BamlReader.ProcessKeyTree
        *
        * Read a tree of baml records that make up a dictionary key and translate them
        * back in the compact syntax representation of a MarkupExtension section.
        * When we encounter KeyElementEnd record, then stop.
        *
        \***************************************************************************/

        private BamlKeyInfo ProcessKeyTree()
        {
            BamlKeyElementStartRecord keyStartRecord = _currentBamlRecord as BamlKeyElementStartRecord;
            Debug.Assert(keyStartRecord != null, "Bad Key Element Start record");

            // Translate the type information held in the baml record into
            // the "{prefix:Classname " format that would be used on
            // a x:Key attribute.
            BamlTypeInfoRecord typeInfo = MapTable.GetTypeInfoFromId(keyStartRecord.TypeId);
            string markupString = typeInfo.TypeFullName;
            markupString = markupString.Substring(markupString.LastIndexOf(".", StringComparison.Ordinal) + 1);
            string assemblyName;
            string prefix;
            string xmlNamespace;
            GetAssemblyAndPrefixAndXmlns(typeInfo, out assemblyName, out prefix, out xmlNamespace);
            if (prefix != string.Empty)
            {
                markupString = "{" + prefix + ":" + markupString + " ";
            }
            else
            {
                markupString = "{" + markupString + " ";
            }

            bool notDone = true;
            BamlNodeInfo nodeInfo;

            // Keep track of whether we have written a property or not at a given nesting
            // level so that we know when to add commas between properties.  Also keep
            // track of when we have entered a constructor parameter section and when
            // we have written out the first parameter to handle adding commas between
            // constructor parameters.
            Stack readProperty = new Stack();
            Stack readConstructor = new Stack();
            Stack readFirstConstructor = new Stack();
            readProperty.Push(false);         // Property has not yet been read
            readConstructor.Push(false);      // Constructor section has not been read
            readFirstConstructor.Push(false); // First constructor parameter has not been read

            while (notDone)
            {
                // Read the next record.  Some of the processing below reads ahead one
                // record and sets _haveUnprocessedRecord to true, in which case we
                // don't want to read another one.
                if (!_haveUnprocessedRecord)
                {
                    GetNextRecord();
                }
                else
                {
                    _haveUnprocessedRecord = false;
                }

                switch (_currentBamlRecord.RecordType)
                {
                    // The following five records are internal to the BAMLReader and
                    // are not exposed publicly.  They are used to update the map table
                    // that maps ids to assemblies, types and attributes.
                    case BamlRecordType.AssemblyInfo:
                        ReadAssemblyInfoRecord();
                        break;

                    case BamlRecordType.TypeInfo:
                    case BamlRecordType.TypeSerializerInfo:
                        MapTable.LoadTypeInfoRecord((BamlTypeInfoRecord)_currentBamlRecord);
                        break;

                    case BamlRecordType.AttributeInfo:
                        MapTable.LoadAttributeInfoRecord((BamlAttributeInfoRecord)_currentBamlRecord);
                        break;

                    case BamlRecordType.StringInfo:
                        MapTable.LoadStringInfoRecord((BamlStringInfoRecord)_currentBamlRecord);
                        break;


                    case BamlRecordType.PropertyComplexStart:
                        ReadPropertyComplexStartRecord();
                        nodeInfo = (BamlNodeInfo)_nodeStack.Pop();
                        if ((bool)readProperty.Pop())
                        {
                            markupString += ", ";
                        }
                        markupString += nodeInfo.LocalName + "=";
                        readProperty.Push(true);
                        break;

                    case BamlRecordType.PropertyComplexEnd:
                        break;

                    case BamlRecordType.Text:
                    case BamlRecordType.TextWithId:

                        BamlTextWithIdRecord textWithIdRecord = _currentBamlRecord as BamlTextWithIdRecord;
                        if (textWithIdRecord != null)
                        {
                            // Get the value string from the string table, and cache it in the
                            // record.
                            textWithIdRecord.Value = MapTable.GetStringFromStringId(
                                                            textWithIdRecord.ValueId);
                        }

                        // If the text contains '{' or '}' then we have to escape these
                        // so that it won't be interpreted as a MarkupExtension
                        string escapedString = EscapeString(((BamlTextRecord)_currentBamlRecord).Value);
                        if ((bool)readFirstConstructor.Peek())
                        {
                            markupString += ", ";
                        }
                        markupString += escapedString;
                        if ((bool)readConstructor.Peek())
                        {
                            readFirstConstructor.Pop();
                            readFirstConstructor.Push(true);
                        }
                        break;

                    case BamlRecordType.ElementStart:
                        // Process commas between constructor parameters
                        if ((bool)readFirstConstructor.Peek())
                        {
                            markupString += ", ";
                        }
                        if ((bool)readConstructor.Peek())
                        {
                            readFirstConstructor.Pop();
                            readFirstConstructor.Push(true);
                        }
                        // Setup for the next level
                        readProperty.Push(false);
                        readConstructor.Push(false);
                        readFirstConstructor.Push(false);
                        // Write element type. Translate the type information held in the
                        // baml record into the "prefix:Classname" format
                        BamlElementStartRecord elementStartRecord = _currentBamlRecord as BamlElementStartRecord;
                        BamlTypeInfoRecord elementTypeInfo = MapTable.GetTypeInfoFromId(elementStartRecord.TypeId);
                        string typename = elementTypeInfo.TypeFullName;
                        typename = typename.Substring(typename.LastIndexOf(".", StringComparison.Ordinal) + 1);
                        GetAssemblyAndPrefixAndXmlns(elementTypeInfo, out assemblyName, out prefix, out xmlNamespace);
                        if (prefix != string.Empty)
                        {
                            markupString += "{" + prefix + ":" + typename + " ";
                        }
                        else
                        {
                            markupString = "{" + typename + " ";
                        }
                        break;

                    case BamlRecordType.ElementEnd:
                        readProperty.Pop();
                        readConstructor.Pop();
                        readFirstConstructor.Pop();
                        markupString += "}";
                        break;

                    case BamlRecordType.ConstructorParametersStart:
                        readConstructor.Pop();
                        readConstructor.Push(true);
                        break;

                    case BamlRecordType.ConstructorParametersEnd:
                        readConstructor.Pop();
                        readConstructor.Push(false);
                        readFirstConstructor.Pop();
                        readFirstConstructor.Push(false);
                        break;

                    case BamlRecordType.ConstructorParameterType:
                        // Process commas between constructor parameters
                        if ((bool)readFirstConstructor.Peek())
                        {
                            markupString += ", ";
                        }
                        if ((bool)readConstructor.Peek())
                        {
                            readFirstConstructor.Pop();
                            readFirstConstructor.Push(true);
                        }
                        BamlConstructorParameterTypeRecord constTypeRecord = _currentBamlRecord as BamlConstructorParameterTypeRecord;
                        markupString += GetTypeValueString(constTypeRecord.TypeId);
                        break;

                    case BamlRecordType.Property:
                    case BamlRecordType.PropertyWithConverter:
                        {
                            string value = ((BamlPropertyRecord)_currentBamlRecord).Value;
                            BamlPropertyInfo propertyInfo = ReadPropertyRecordCore(value);
                            if ((bool)readProperty.Pop())
                            {
                                markupString += ", ";
                            }
                            markupString += propertyInfo.LocalName + "=" + propertyInfo.Value;
                            readProperty.Push(true);
                        }
                        break;

                    case BamlRecordType.PropertyCustom:
                        {
                            BamlPropertyInfo propertyInfo = GetPropertyCustomRecordInfo();
                            if ((bool)readProperty.Pop())
                            {
                                markupString += ", ";
                            }
                            markupString += propertyInfo.LocalName + "=" + propertyInfo.Value;
                            readProperty.Push(true);
                        }
                        break;

                    case BamlRecordType.PropertyStringReference:
                        {
                            string value = MapTable.GetStringFromStringId(((BamlPropertyStringReferenceRecord)_currentBamlRecord).StringId);
                            BamlPropertyInfo propertyInfo = ReadPropertyRecordCore(value);
                            if ((bool)readProperty.Pop())
                            {
                                markupString += ", ";
                            }
                            markupString += propertyInfo.LocalName + "=" + propertyInfo.Value;
                            readProperty.Push(true);
                        }
                        break;

                    case BamlRecordType.PropertyTypeReference:
                        {
                            string value = GetTypeValueString(((BamlPropertyTypeReferenceRecord)_currentBamlRecord).TypeId);
                            string attributeName = MapTable.GetAttributeNameFromId(
                                                          ((BamlPropertyTypeReferenceRecord)_currentBamlRecord).AttributeId);
                            if ((bool)readProperty.Pop())
                            {
                                markupString += ", ";
                            }
                            markupString += attributeName + "=" + value;
                            readProperty.Push(true);
                        }
                        break;

                    case BamlRecordType.PropertyWithExtension:
                        {
                            string value = GetExtensionValueString((BamlPropertyWithExtensionRecord)_currentBamlRecord);
                            string attributeName = MapTable.GetAttributeNameFromId(
                                                          ((BamlPropertyWithExtensionRecord)_currentBamlRecord).AttributeId);
                            if ((bool)readProperty.Pop())
                            {
                                markupString += ", ";
                            }
                            markupString += attributeName + "=" + value;
                            readProperty.Push(true);
                        }
                        break;

                    case BamlRecordType.KeyElementEnd:
                        markupString += "}";
                        notDone = false;
                        _haveUnprocessedRecord = false;
                        break;

                    default:
                        // Can't have any other type of record at this point.
                        throw new InvalidOperationException(SR.Get(SRID.ParserUnknownBaml,
                                         ((int)_currentBamlRecord.RecordType).ToString(CultureInfo.CurrentCulture)));
                }
            }

            // At this point the markup string representing the MarkupExtension should
            // be complete, so set this as the value for this key.
            BamlKeyInfo info = new BamlKeyInfo();
            info.Value = markupString;
            info.AssemblyName = string.Empty;
            info.Prefix = (string)_prefixDictionary[XamlReaderHelper.DefinitionNamespaceURI];
            info.XmlNamespace = XamlReaderHelper.DefinitionNamespaceURI;
            info.ClrNamespace = string.Empty;
            info.Name = XamlReaderHelper.DefinitionName;
            info.LocalName = info.Name;
            info.RecordType = BamlRecordType.DefAttribute;
            info.Offset = ((IBamlDictionaryKey)keyStartRecord).ValuePosition;

            return info;

        }
        /***************************************************************************\
        *
        * BamlReader.ProcessDeferKey
        *
        * Read a single baml record.  If it is a defer key, add it to the table of
        * keys.  If we encounter something that is not a 'key', then set the
        *_haveUnprocessedRecord flag.
        *
        \***************************************************************************/

        private void ProcessDeferKey()
        {
            switch (_currentBamlRecord.RecordType)
            {
                // The following three records are internal to the BAMLReader and
                // are not exposed publicly.  They are used to update the map table
                // that maps ids to assemblies, types and attributes.
                case BamlRecordType.DefAttributeKeyString:
                    BamlDefAttributeKeyStringRecord stringKeyRecord = _currentBamlRecord as BamlDefAttributeKeyStringRecord;
                    if (stringKeyRecord != null)
                    {
                        BamlKeyInfo info;

                        // The "Shared"ness is stored in the BAML with the Key
                        // But at the XAML level it is a sibling attribute of the key.
                        info = CheckForSharedness();
                        if (null != info)
                            _deferKeys.Add(info);

                        // Get the value string from the string table, and cache it in the
                        // record.
                        stringKeyRecord.Value = MapTable.GetStringFromStringId(
                                                        stringKeyRecord.ValueId);

                        // Add information to the key list to indicate we have a x:Key
                        // attribute
                        info = new BamlKeyInfo();
                        info.Value = stringKeyRecord.Value;
                        info.AssemblyName = string.Empty;
                        info.Prefix = (string)_prefixDictionary[XamlReaderHelper.DefinitionNamespaceURI];
                        info.XmlNamespace = XamlReaderHelper.DefinitionNamespaceURI;
                        info.ClrNamespace = string.Empty;
                        info.Name = XamlReaderHelper.DefinitionName;
                        info.LocalName = info.Name;
                        info.RecordType = BamlRecordType.DefAttribute;
                        info.Offset = ((IBamlDictionaryKey)stringKeyRecord).ValuePosition;
                        _deferKeys.Add(info);
                    }
                    break;

                case BamlRecordType.DefAttributeKeyType:
                    BamlDefAttributeKeyTypeRecord typeKeyRecord = _currentBamlRecord as BamlDefAttributeKeyTypeRecord;
                    if (typeKeyRecord != null)
                    {
                        // Translate the type information held in the baml record into
                        // the {x:Type prefix:Classname} format that would be used on
                        // a x:Key attribute.
                        string typeExtensionPrefix = (string)_prefixDictionary[XamlReaderHelper.DefinitionNamespaceURI];
                        string typeExtensionName;
                        if (typeExtensionPrefix != string.Empty)
                        {
                            typeExtensionName = "{" + typeExtensionPrefix + ":Type ";
                        }
                        else
                        {
                            typeExtensionName = "{Type ";
                        }
                        BamlTypeInfoRecord typeInfo = MapTable.GetTypeInfoFromId(typeKeyRecord.TypeId);
                        string typeName = typeInfo.TypeFullName;
                        typeName = typeName.Substring(typeName.LastIndexOf(".", StringComparison.Ordinal) + 1);
                        string assemblyName;
                        string prefix;
                        string xmlNamespace;
                        GetAssemblyAndPrefixAndXmlns(typeInfo, out assemblyName, out prefix, out xmlNamespace);
                        if (prefix != string.Empty)
                        {
                            typeName = typeExtensionName + prefix + ":" + typeName + "}";
                        }
                        else
                        {
                            typeName = typeExtensionName + typeName + "}";
                        }

                        // Add information to the key list to indicate we have a x:Key
                        // attribute
                        BamlKeyInfo info = new BamlKeyInfo();
                        info.Value = typeName;
                        info.AssemblyName = string.Empty;
                        info.Prefix = typeExtensionPrefix;
                        info.XmlNamespace = XamlReaderHelper.DefinitionNamespaceURI;
                        info.ClrNamespace = string.Empty;
                        info.Name = XamlReaderHelper.DefinitionName;
                        info.LocalName = info.Name;
                        info.RecordType = BamlRecordType.DefAttribute;
                        info.Offset = ((IBamlDictionaryKey)typeKeyRecord).ValuePosition;
                        _deferKeys.Add(info);
                    }
                    break;

                case BamlRecordType.KeyElementStart:
                    {
                        BamlKeyInfo info;

                        // The "Shared"ness is stored in the BAML with the Key
                        // But at the XAML level it is a sibling attribute of the key.
                        info = CheckForSharedness();
                        if(null != info)
                            _deferKeys.Add(info);

                        // Process the subtree that is stored as part of a key tree and
                        // translate this back into a compact MarkupExtension string.
                        // Add information to the key list to indicate we have a x:Key
                        // with a MarkupExtension
                        info = ProcessKeyTree();
                        _deferKeys.Add(info);
                    }
                    break;

                case BamlRecordType.StaticResourceStart:
                case BamlRecordType.OptimizedStaticResource:
                    {
                        // Process the subtree stored as part of a StaticResource
                        List<BamlRecord> srRecords = new List<BamlRecord>();

                        // This is for the start record
                        _currentBamlRecord.Pin();
                        srRecords.Add(_currentBamlRecord);

                        // Note that BamlOptmizedStaticResourceRecord is a singleton record
                        if (_currentBamlRecord.RecordType == BamlRecordType.StaticResourceStart)
                        {
                            // Process the subtree that is stored as part of this static resource
                            ProcessStaticResourceTree(srRecords);
                        }

                        // Add the current StaticResource record to the list of StaticResources held per key
                        BamlKeyInfo keyInfo = _deferKeys[_deferKeys.Count-1];
                        keyInfo.StaticResources.Add(srRecords);
                    }
                    break;

                // Any other record types are not processed here
                default:
                    _haveUnprocessedRecord = true;
                    break;
            }
        }