File: System\Windows\Markup\BamlRecords.cs
Web Access
Project: src\src\Microsoft.DotNet.Wpf\src\PresentationFramework\PresentationFramework.csproj (PresentationFramework)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
/***************************************************************************\
*
* Purpose:  Contains implementation for specific BamlRecords
*
\***************************************************************************/
 
using System;
using System.IO;
using System.Collections;
using System.Globalization;
using System.ComponentModel;
using System.Diagnostics;
using System.Reflection;
using System.Collections.Specialized;
 
#if !PBTCOMPILER
using System.Windows;
using System.Windows.Media;
using System.Windows.Threading;
 
using MS.Internal.PresentationFramework; // SafeSecurityHelper
#endif
 
using MS.Utility;
 
// Disabling 1634 and 1691:
// In order to avoid generating warnings about unknown message numbers and
// unknown pragmas when compiling C# source code with the C# compiler,
// you need to disable warnings 1634 and 1691. (Presharp Documentation)
#pragma warning disable 1634, 1691
 
#if PBTCOMPILER
namespace MS.Internal.Markup
#else
namespace System.Windows.Markup
#endif
{
    // Types of records.  Note that this is a superset of XamlNodeTypes
    internal enum BamlRecordType : byte
    {
        /// <summary>
        /// Unknown Node
        /// </summary>
        // !!BamlRecordManager class relies on Unknown = 0 for initialization
        Unknown = 0,
 
        /// <summary>
        /// Start Document Node
        /// </summary>
        DocumentStart,              // 1
 
        /// <summary>
        /// End Document Node
        /// </summary>
        DocumentEnd,                // 2
 
        /// <summary>
        /// Start Element Node, which may be a CLR object or a DependencyObject
        /// </summary>
        ElementStart,               // 3
 
        /// <summary>
        /// End Element Node
        /// </summary>
        ElementEnd,                 // 4
 
        /// <summary>
        /// Property Node, which may be a CLR property or a DependencyProperty
        /// </summary>
        Property,                   // 5
 
        /// <summary>
        /// Binary serialization of a property
        /// </summary>
        PropertyCustom,             // 6
 
        /// <summary>
        /// Complex Property Node
        /// </summary>
        PropertyComplexStart,       // 7
 
        /// <summary>
        /// End Complex Property Node
        /// </summary>
        PropertyComplexEnd,         // 8
 
        /// <summary>
        /// Start Array Property Node
        /// </summary>
        PropertyArrayStart,         // 9
 
        /// <summary>
        /// End Array Property Node
        /// </summary>
        PropertyArrayEnd,           // 10
 
        /// <summary>
        /// Star IList Property Node
        /// </summary>
        PropertyIListStart,         // 11
 
        /// <summary>
        /// End PropertyIListStart Node
        /// </summary>
        PropertyIListEnd,           // 12
 
        /// <summary>
        /// Start IDictionary Property Node
        /// </summary>
        PropertyIDictionaryStart,   // 13
 
        /// <summary>
        /// End IDictionary Property Node
        /// </summary>
        PropertyIDictionaryEnd,     // 14
 
        /// <summary>
        /// LiteralContent Node
        /// </summary>
        LiteralContent,             // 15
 
        /// <summary>
        /// Text Node
        /// </summary>
        Text,                       // 16
 
        /// <summary>
        /// Text that has an associated custom typeconverter
        /// </summary>
        TextWithConverter,          // 17
 
        /// <summary>
        /// RoutedEventNode
        /// </summary>
        RoutedEvent,                // 18
 
        /// <summary>
        /// ClrEvent Node
        /// </summary>
        ClrEvent,                   // 19
 
        /// <summary>
        /// XmlnsProperty Node
        /// </summary>
        XmlnsProperty,              // 20
 
        /// <summary>
        /// XmlAttribute Node
        /// </summary>
        XmlAttribute,               // 21
 
        /// <summary>
        /// Processing Intstruction Node
        /// </summary>
        ProcessingInstruction,      // 22
 
        /// <summary>
        /// Comment Node
        /// </summary>
        Comment,                    // 23
 
        /// <summary>
        /// DefTag Node
        /// </summary>
        DefTag,                     // 24
 
        /// <summary>
        /// x:name="value" attribute.  One typical use of this
        /// attribute is to define a key to use when inserting an item into an IDictionary
        /// </summary>
        DefAttribute,               // 25
 
        /// <summary>
        /// EndAttributes Node
        /// </summary>
        EndAttributes,              // 26
 
        /// <summary>
        /// PI xml - clr namespace mapping
        /// </summary>
        PIMapping,                  // 27
 
        /// <summary>
        /// Assembly information
        /// </summary>
        AssemblyInfo,               // 28
 
        /// <summary>
        /// Type information
        /// </summary>
        TypeInfo,                   // 29
 
        /// <summary>
        /// Type information for a Type that has an associated custom serializer
        /// </summary>
        TypeSerializerInfo,         // 30
 
        /// <summary>
        /// Attribute (eg - properties and events) information
        /// </summary>
        AttributeInfo,              // 31
 
        /// <summary>
        /// Resource information
        /// </summary>
        StringInfo,                 // 32
 
        /// <summary>
        /// Property Resource Reference
        /// </summary>
        PropertyStringReference,    // 33
 
        /// <summary>
        /// Record for setting a property to a Type reference.  This is used for
        /// properties that are of type "Type"
        /// </summary>
        PropertyTypeReference,      // 34
 
        /// <summary>
        /// Property that has a simple MarkupExtension value.
        /// </summary>
        PropertyWithExtension,      // 35
 
        /// <summary>
        /// Property that has an associated custom typeconverter
        /// </summary>
        PropertyWithConverter,      // 36
 
        /// <summary>
        /// Start a deferable content block
        /// </summary>
        DeferableContentStart,      // 37
 
        /// <summary>
        /// x:name="value" attribute when used within a defer load
        /// dictionary.  These keys are hoisted to the front of the dictionary when
        /// written to baml.
        /// </summary>
        DefAttributeKeyString,      // 38
 
        /// <summary>
        /// Implied key that is a Type attribute when used within a defer load
        /// dictionary.  These keys are hoisted to the front of the dictionary when
        /// written to baml.
        /// </summary>
        DefAttributeKeyType,        // 39
 
        /// <summary>
        /// This marks the start of an element tree that is used as the key in
        /// an IDictionary.
        /// </summary>
        KeyElementStart,            // 40
 
 
        /// <summary>
        /// This marks the end of an element tree that is used as the key in
        /// an IDictionary.
        /// </summary>
        KeyElementEnd,              // 41
 
        /// <summary>
        /// Record marks the start of a section containing constructor parameters
        /// </summary>
        ConstructorParametersStart, // 42
 
        /// <summary>
        /// Record marks the end of a section containing constructor parameters
        /// </summary>
        ConstructorParametersEnd,   // 43
 
        /// <summary>
        /// Constructor parameter that has been resolved to a Type.
        /// </summary>
        ConstructorParameterType,   // 44
 
        /// <summary>
        /// Record that has info about which event or id to connect to in an object tree.
        /// </summary>
        ConnectionId,               // 45
 
        /// <summary>
        /// Record that set the conntent property context for the element
        /// </summary>
        ContentProperty,            // 46
 
        /// <summary>
        /// ElementStartRecord that also carries an element name.
        /// </summary>
        NamedElementStart,          // 47
 
        /// <summary>
        /// Start of StaticResourceExtension within the header of a deferred section.
        /// </summary>
        StaticResourceStart,        // 48
 
        /// <summary>
        /// End of a StaticResourceExtension within the header of a deferred section.
        /// </summary>
        StaticResourceEnd,          // 49
 
        /// <summary>
        /// BamlRecord that carries an identifier for a StaticResourceExtension
        /// within the header of a deferred section.
        /// </summary>
        StaticResourceId,           // 50
 
        /// <summary>
        /// This is a TextRecord that holds an Id for the String value it represents.
        /// </summary>
        TextWithId,                 // 51
 
        /// <summary>
        /// PresentationOptions:Freeze="value" attribute. Used for ignorable
        /// WPF-specific parsing options
        /// </summary>
        PresentationOptionsAttribute, // 52
 
        /// <summary>
        /// Debugging information record that holds the source XAML linenumber.
        /// </summary>
        LineNumberAndPosition,      // 53
 
        /// <summary>
        /// Debugging information record that holds the source XAML line position.
        /// </summary>
        LinePosition,               // 54
 
        /// <summary>
        /// OptimizedStaticResourceExtension within the header of a deferred section.
        /// </summary>
        OptimizedStaticResource,      // 55
 
        /// <summary>
        /// BamlPropertyRecord that carries an identifier for a StaticResourceExtension
        /// within the header of a deferred section.
        /// </summary>
        PropertyWithStaticResourceId, // 56
 
        /// <summary>
        /// Placeholder to mark last record
        /// </summary>
        LastRecordType
    }
 
    /// <summary>
    /// Some attributes have special usages or cause additional actions when they
    /// are set on an element.  This can be have some other effects
    /// such as setting the xml:lang or xml:space values in the parser context.
    /// The PropertyUsage describes addition effects or usage for this property.
    /// </summary>
    internal enum BamlAttributeUsage : short
    {
        /// <summary> A regular property that has no other use </summary>
        Default = 0,
 
        /// <summary> A property that has xml:lang information </summary>
        XmlLang,
 
        /// <summary> A property that has xml:space information </summary>
        XmlSpace,
 
        /// <summary> A property that has the RuntimeIdProperty information </summary>
        RuntimeName,
    }
 
    // This class handles allocation, read and write management of baml records.
    internal class BamlRecordManager
    {
#if !PBTCOMPILER
        // Genericaly load and create the proper class.
        // This method assumes the seek pointer has already moved passed the recordType
        // field and is at the RecordSize or record contents (depending on record).
        // This method is used so the caller can first read the type of record, and expects
        // to get back the entire record, or nothing (for async support).
        internal BamlRecord ReadNextRecord(
            BinaryReader   bamlBinaryReader,
            long           bytesAvailable,
            BamlRecordType recordType)
        {
            BamlRecord bamlRecord; // = null
 
            // Create the proper BamlRecord based on the recordType.  The assembly,
            // type and attribute records are created every time, since they are
            // used by the BamlMapTable.  The other records are re-used, so they
            // are created once and cached.
            switch(recordType)
            {
                case BamlRecordType.AssemblyInfo:
                    bamlRecord = new BamlAssemblyInfoRecord();
                    break;
                case BamlRecordType.TypeInfo:
                    bamlRecord = new BamlTypeInfoRecord();
                    break;
                case BamlRecordType.TypeSerializerInfo:
                    bamlRecord = new BamlTypeInfoWithSerializerRecord();
                    break;
                case BamlRecordType.AttributeInfo:
                    bamlRecord = new BamlAttributeInfoRecord();
                    break;
                case BamlRecordType.StringInfo:
                    bamlRecord = new BamlStringInfoRecord();
                    break;
                case BamlRecordType.DefAttributeKeyString:
                    bamlRecord = new BamlDefAttributeKeyStringRecord();
                    break;
                case BamlRecordType.DefAttributeKeyType:
                    bamlRecord = new BamlDefAttributeKeyTypeRecord();
                    break;
                case BamlRecordType.KeyElementStart:
                    bamlRecord = new BamlKeyElementStartRecord();
                    break;
 
                default:
 
                    // Get the current record from the cache.  If there's nothing there yet,
                    // or if what is there is pinned, then create one.  Note that records in the
                    // read cache are implicitly recycled, and records in the write cache are explicitly
                    // recycled (i.e., there's a ReleaseWriteRecord, but no ReleaseReadRecord).
 
                    bamlRecord = _readCache[(int)recordType];
                    if (null == bamlRecord || bamlRecord.IsPinned )
                    {
                        bamlRecord = _readCache[(int)recordType] = AllocateRecord(recordType);
                    }
 
                    break;
            }
 
            bamlRecord.Next = null;
 
            if (null != bamlRecord)
            {
                // If LoadRecordSize indicates it can determine the record size
                // and has determined that there is enough content to load the
                // entire record, then continue.
                if (bamlRecord.LoadRecordSize(bamlBinaryReader, bytesAvailable) &&
                    bytesAvailable >= bamlRecord.RecordSize)
                {
                    bamlRecord.LoadRecordData(bamlBinaryReader);
                }
                else
                {
                    bamlRecord = null;
                }
            }
 
            return bamlRecord;
        }
 
        /// <summary>
        /// Return the object if it should be treated as IAddChild, otherwise return null
        /// </summary>
        static internal IAddChild AsIAddChild(object obj)
        {
            IAddChild iac = obj as IAddChildInternal;
            return iac;
        }
#endif
 
        /// <summary>
        /// True if type should be treated as IAddChild
        /// </summary>
        static internal bool TreatAsIAddChild(Type parentObjectType)
        {
            return (KnownTypes.Types[(int)KnownElements.IAddChildInternal].IsAssignableFrom( parentObjectType ));
        }
 
        static internal BamlRecordType GetPropertyStartRecordType(Type propertyType, bool propertyCanWrite)
        {
            BamlRecordType recordType;
            if (propertyType.IsArray)
            {
                recordType = BamlRecordType.PropertyArrayStart;
            }
#if PBTCOMPILER
            else if (ReflectionHelper.GetMscorlibType(typeof(IDictionary)).IsAssignableFrom(propertyType))
            {
                recordType = BamlRecordType.PropertyIDictionaryStart;
            }
            else if (ReflectionHelper.GetMscorlibType(typeof(IList)).IsAssignableFrom(propertyType) ||
               BamlRecordManager.TreatAsIAddChild(propertyType) ||
               (ReflectionHelper.GetMscorlibType(typeof(IEnumerable)).IsAssignableFrom(propertyType) && !propertyCanWrite))
#else
            else if (typeof(IDictionary).IsAssignableFrom(propertyType))
            {
                recordType = BamlRecordType.PropertyIDictionaryStart;
            }
            else if ((typeof(IList).IsAssignableFrom(propertyType) ||
                       BamlRecordManager.TreatAsIAddChild(propertyType) ||
                       (typeof(IEnumerable).IsAssignableFrom(propertyType) && !propertyCanWrite)))
#endif
            {
                // we're a list if:
                // 1) the property type is an IList.
                // 2) the property type is an IAddChild (internal).
                // 3) the property type is an IEnumerable and read-only and the parent is an IAddChild (internal).
                // for the third case, we can't check the parent until run-time.
                recordType = BamlRecordType.PropertyIListStart;
            }
            else
            {
                recordType = BamlRecordType.PropertyComplexStart;
            }
 
            return recordType;
        }
 
#if !PBTCOMPILER
        internal BamlRecord CloneRecord(BamlRecord record)
        {
            BamlRecord newRecord;
 
            switch (record.RecordType)
            {
                case BamlRecordType.ElementStart:
                    if (record is BamlNamedElementStartRecord)
                    {
                        newRecord= new BamlNamedElementStartRecord();
                    }
                    else
                    {
                        newRecord = new BamlElementStartRecord();
                    }
                    break;
 
                case BamlRecordType.PropertyCustom:
                    if (record is BamlPropertyCustomWriteInfoRecord)
                    {
                        newRecord = new BamlPropertyCustomWriteInfoRecord();
                    }
                    else
                    {
                        newRecord = new BamlPropertyCustomRecord();
                    }
                    break;
 
                default:
                    newRecord = AllocateRecord(record.RecordType);
                    break;
            }
 
            record.Copy(newRecord);
 
            return newRecord;
        }
#endif
 
        // Helper function to create a BamlRecord from a BamlRecordType
        private BamlRecord AllocateWriteRecord(BamlRecordType recordType)
        {
            BamlRecord record;
 
            switch (recordType)
            {
                case BamlRecordType.PropertyCustom:
                    record = new BamlPropertyCustomWriteInfoRecord();
                    break;
 
                default:
                    record = AllocateRecord(recordType);
                    break;
            }
 
            return record;
        }
 
        // Helper function to create a BamlRecord from a BamlRecordType
        private BamlRecord AllocateRecord(BamlRecordType recordType)
        {
            BamlRecord record;
 
            switch(recordType)
            {
                case BamlRecordType.DocumentStart:
                    record = new BamlDocumentStartRecord();
                    break;
                case BamlRecordType.DocumentEnd:
                    record = new BamlDocumentEndRecord();
                    break;
                case BamlRecordType.ConnectionId:
                    record = new BamlConnectionIdRecord();
                    break;
                case BamlRecordType.ElementStart:
                    record = new BamlElementStartRecord();
                    break;
                case BamlRecordType.ElementEnd:
                    record = new BamlElementEndRecord();
                    break;
                case BamlRecordType.DeferableContentStart:
                    record = new BamlDeferableContentStartRecord();
                    break;
                case BamlRecordType.DefAttributeKeyString:
                    record = new BamlDefAttributeKeyStringRecord();
                    break;
                case BamlRecordType.DefAttributeKeyType:
                    record = new BamlDefAttributeKeyTypeRecord();
                    break;
                case BamlRecordType.LiteralContent:
                    record = new BamlLiteralContentRecord();
                    break;
                case BamlRecordType.Property:
                    record = new BamlPropertyRecord();
                    break;
                case BamlRecordType.PropertyWithConverter:
                    record = new BamlPropertyWithConverterRecord();
                    break;
                case BamlRecordType.PropertyStringReference:
                    record = new BamlPropertyStringReferenceRecord();
                    break;
                case BamlRecordType.PropertyTypeReference:
                    record = new BamlPropertyTypeReferenceRecord();
                    break;
                case BamlRecordType.PropertyWithExtension:
                    record = new BamlPropertyWithExtensionRecord();
                    break;
                case BamlRecordType.PropertyCustom:
                    record = new BamlPropertyCustomRecord();
                    break;
                case BamlRecordType.PropertyComplexStart:
                    record = new BamlPropertyComplexStartRecord();
                    break;
                case BamlRecordType.PropertyComplexEnd:
                    record = new BamlPropertyComplexEndRecord();
                    break;
                case BamlRecordType.RoutedEvent:
                    record = new BamlRoutedEventRecord();
                    break;
                case BamlRecordType.PropertyArrayStart:
                    record = new BamlPropertyArrayStartRecord();
                    break;
                case BamlRecordType.PropertyArrayEnd:
                    record = new BamlPropertyArrayEndRecord();
                    break;
                case BamlRecordType.PropertyIListStart:
                    record = new BamlPropertyIListStartRecord();
                    break;
                case BamlRecordType.PropertyIListEnd:
                    record = new BamlPropertyIListEndRecord();
                    break;
                case BamlRecordType.PropertyIDictionaryStart:
                    record = new BamlPropertyIDictionaryStartRecord();
                    break;
                case BamlRecordType.PropertyIDictionaryEnd:
                    record = new BamlPropertyIDictionaryEndRecord();
                    break;
                case BamlRecordType.Text:
                    record = new BamlTextRecord();
                    break;
                case BamlRecordType.TextWithConverter:
                    record = new BamlTextWithConverterRecord();
                    break;
                case BamlRecordType.TextWithId:
                    record = new BamlTextWithIdRecord();
                    break;
                case BamlRecordType.XmlnsProperty:
                    record = new BamlXmlnsPropertyRecord();
                    break;
                case BamlRecordType.PIMapping:
                    record = new BamlPIMappingRecord();
                    break;
                case BamlRecordType.DefAttribute:
                    record = new BamlDefAttributeRecord();
                    break;
                case BamlRecordType.PresentationOptionsAttribute:
                    record = new BamlPresentationOptionsAttributeRecord();
                    break;
                case BamlRecordType.KeyElementStart:
                    record = new BamlKeyElementStartRecord();
                    break;
                case BamlRecordType.KeyElementEnd:
                    record = new BamlKeyElementEndRecord();
                    break;
                case BamlRecordType.ConstructorParametersStart:
                    record = new BamlConstructorParametersStartRecord();
                    break;
                case BamlRecordType.ConstructorParametersEnd:
                    record = new BamlConstructorParametersEndRecord();
                    break;
                case BamlRecordType.ConstructorParameterType:
                    record = new BamlConstructorParameterTypeRecord();
                    break;
                case BamlRecordType.ContentProperty:
                    record = new BamlContentPropertyRecord();
                    break;
                case BamlRecordType.AssemblyInfo:
                case BamlRecordType.TypeInfo:
                case BamlRecordType.TypeSerializerInfo:
                case BamlRecordType.AttributeInfo:
                case BamlRecordType.StringInfo:
                    Debug.Assert(false,"Assembly, Type and Attribute records are not cached, so don't ask for one.");
                    record = null;
                    break;
                case BamlRecordType.StaticResourceStart:
                    record = new BamlStaticResourceStartRecord();
                    break;
                case BamlRecordType.StaticResourceEnd:
                    record = new BamlStaticResourceEndRecord();
                    break;
                case BamlRecordType.StaticResourceId:
                    record = new BamlStaticResourceIdRecord();
                    break;
                case BamlRecordType.LineNumberAndPosition:
                    record = new BamlLineAndPositionRecord();
                    break;
                case BamlRecordType.LinePosition:
                    record = new BamlLinePositionRecord();
                    break;
                case BamlRecordType.OptimizedStaticResource:
                    record = new BamlOptimizedStaticResourceRecord();
                    break;
                case BamlRecordType.PropertyWithStaticResourceId:
                    record = new BamlPropertyWithStaticResourceIdRecord();
                    break;
                default:
                    Debug.Assert(false,"Unknown RecordType");
                    record = null;
                    break;
            }
 
            return record;
        }
 
        // This should only be called from BamlRecordWriter -- it gets a record from the record
        // cache that must be freed with ReleaseRecord before GetRecord is called again.
        internal BamlRecord GetWriteRecord(BamlRecordType recordType)
        {
            // Create the cache of records used in writing, on demand
 
            if( _writeCache == null )
            {
                _writeCache = new BamlRecord[(int)BamlRecordType.LastRecordType];
            }
 
            BamlRecord record = _writeCache[(int)recordType];
            if (null == record)
            {
                record = AllocateWriteRecord(recordType);
            }
            else
            {
                _writeCache[(int)recordType] = null;
            }
 
            // It is important to set RecordSize for variable size records
            // to a negative number to indicate that it has not been set yet.
            // Fixed size records should ignore this set.
            record.RecordSize = -1;
            return record;
        }
 
 
        //+---------------------------------------------------------------------------------------------
        //
        //  ReleaseWriteRecord
        //
        //  Frees a record originally claimed with GetWriteRecord. Note that records in the
        //  read cache are implicitly recycled, and records in the write cache are explicitly
        //  recycled (i.e., there's a ReleaseWriteRecord, but no ReleaseReadRecord).
        //
        //+---------------------------------------------------------------------------------------------
 
        internal void ReleaseWriteRecord(BamlRecord record)
        {
            // Put the write record back into the cache, if we're allowed to recycle it.
 
            if( !record.IsPinned )
            {
                Debug.Assert(null == _writeCache[(int)record.RecordType]);
                if (null != _writeCache[(int)record.RecordType])
                {
                    // This is really an internal error.
                    throw new InvalidOperationException(SR.ParserMultiBamls);
                }
                _writeCache[(int)record.RecordType] = record;
            }
        }
 
 
        // Cache of BamlRecords, used during read, to avoid lots of records from being
        // created.  If a record gets pinned (BamlRecord.IsPinned gets set), it is not re-used.
 
        #if !PBTCOMPILER
        BamlRecord[] _readCache = new BamlRecord[(int)BamlRecordType.LastRecordType];
        #endif
 
        // Cache of BamlRecords, used during write, also to avoid lots of records
        // from being created.
 
        BamlRecord[] _writeCache = null; //new BamlRecord[(int)BamlRecordType.LastRecordType];
    }
 
    // The base of all baml records.  This gives a fixed size record that contains
    // line number information used for generating error messages.  Note that the
    // line number information is not currently written out to the baml stream.
    internal abstract class BamlRecord
    {
 #region Methods
 
#if !PBTCOMPILER
        // If there are enough bytes available, load the record size from the
        // binary reader.  For fixed size records that derive from BamlRecord,
        // there is no size field in the baml file, so this always succeeds.
        internal virtual bool LoadRecordSize(
            BinaryReader bamlBinaryReader,
            long         bytesAvailable)
        {
            return true;
        }
 
        // Load record data.  This does not include the record type, or the
        // size field, which are loaded separately.  If the subclass has no
        // specific data to load, then don't override this.
        internal virtual void  LoadRecordData(BinaryReader bamlBinaryReader)
        {
        }
#endif
 
        // Writes data at the current position seek pointer points
        // to byte after the end of record when done.
        internal virtual void Write(BinaryWriter bamlBinaryWriter)
        {
            // BamlRecords may be used without a stream, so if you attempt to write when there
            // isn't a writer, just ignore it.
            if (bamlBinaryWriter == null)
            {
                return;
            }
 
            // Baml records always start with record type
            bamlBinaryWriter.Write((byte) RecordType);
 
            // IMPORTANT:  The RecordType is the last thing written before calling
            //             WriteRecordData.  Some records assume the record type is located
            //             directly before the current stream location and may change it, so
            //             don't change where the record type is written in the stream!!!
            //             Paint is one example of a DP object that will seek back to change
            //             the record type if it is unable to serialize itself.
            WriteRecordData(bamlBinaryWriter);
        }
 
        // Write contents of the record, excluding size (if any) and record type.
        // If the subclass has no specific data to write out, don't override this.
        internal virtual void WriteRecordData(BinaryWriter bamlBinaryWriter)
        {
        }
 
 
#endregion Methods
 
#region Properties
 
        // Actual size of the complete BamlRecord (excluding RecordType) in bytes.
        // Currently limited to 2 gigabytes.  Default size is 0 bytes of data.
        // Subclasses must override if they have a different size.
        internal virtual Int32 RecordSize
        {
            get { return 0; }
            set { Debug.Assert (value == -1, "Setting fixed record to an invalid size"); }
        }
 
        // Identifies the type off BAML record.  This is used when casting to
        // a BamlRecord subclass.  All subclasses **MUST** override this.
        internal virtual BamlRecordType RecordType
        {
            get
            {
                Debug.Assert(false, "Must override RecordType");
                return BamlRecordType.Unknown;
            }
        }
 
 
#if !PBTCOMPILER
        // Next Record pointer - used in BamlObjectFactory
        internal BamlRecord Next
        {
            get { return _nextRecord; }
            set { _nextRecord = value ; }
        }
#endif
 
        // The BamlRecorManager keeps a cache of baml records and tries to reuse them automatically.
        // To keep a record from being cached, it can be pinned.  For correct pinning we keep a
        // pin count.  To save working set, we only have two bits for the reference count.
        // So if the reference count reaches three the record becomes permanently pinned.
 
        internal bool IsPinned
        {
            get
            {
                return PinnedCount > 0;
            }
        }
 
        // (See comment on IsPinned.)
        internal int PinnedCount
        {
            get
            {
                return _flags[_pinnedFlagSection];
            }
 
            set
            {
                Debug.Assert( value <= 3 && value >= 0 );
                _flags[_pinnedFlagSection] = value;
            }
        }
 
        // (See comment on IsPinned.)
        internal void Pin()
        {
            if( PinnedCount < 3 )
            {
                ++PinnedCount;
            }
        }
 
#if !PBTCOMPILER
        // (See comment on IsPinned.)
        internal void Unpin()
        {
            if( PinnedCount < 3 )
            {
                --PinnedCount;
            }
        }
 
        internal virtual void Copy(BamlRecord record)
        {
            record._flags = _flags;
            record._nextRecord = _nextRecord;
        }
 
#endif
 
 
 
#endregion Properties
 
#region Data
 
        // Internal flags for efficient storage
        // NOTE: bits here are used by sub-classes also.
        // This BitVector32 field is shared by subclasses to save working set.  Sharing flags like this
        // is easier in e.g. FrameworkElement, where the class hierarchy is linear, but can be bug-prone otherwise.  To make the
        // code less fragile, each class abstractly provides it's last section to subclasses(LastFlagsSection), which they can
        // use in their call to CreateSection.
 
        internal BitVector32 _flags;
 
        // Allocate space in _flags.
 
        private static BitVector32.Section _pinnedFlagSection = BitVector32.CreateSection( 3 /* Allocates two bits to store values up to 3 */ );
 
        // This provides subclasses with a referece section to create their own section.
        internal static BitVector32.Section LastFlagsSection
        {
            get { return _pinnedFlagSection; }
        }
 
 
#if !PBTCOMPILER
        private BamlRecord _nextRecord = null;
#endif
 
 
        // Size of the record type field in the baml file.
        internal const int RecordTypeFieldLength = 1;
 
#if !PBTCOMPILER
        public override string ToString()
        {
            return string.Create(CultureInfo.InvariantCulture, $"{RecordType}");
        }
 
        protected static string GetTypeName(int typeId)
        {
            string typeName = typeId.ToString(CultureInfo.InvariantCulture);
            if(typeId < 0)
            {
                KnownElements elm = (KnownElements)(-typeId);
                typeName = elm.ToString();
            }
            return typeName;
        }
 
 
        // This helper checks for records that indicate that you're out of
        // an element start, and into it's "content" (in the xml sense).
        // We have to infer this, because unlike Xml, Baml doesn't provide
        // an end-attributes record.
 
        internal static bool IsContentRecord( BamlRecordType bamlRecordType )
        {
            return bamlRecordType == BamlRecordType.PropertyComplexStart
                   ||
                   bamlRecordType == BamlRecordType.PropertyArrayStart
                   ||
                   bamlRecordType == BamlRecordType.PropertyIListStart
                   ||
                   bamlRecordType == BamlRecordType.PropertyIDictionaryStart
                   ||
                   bamlRecordType == BamlRecordType.Text;
        }
 
#endif
 
#endregion Data
    }
 
    // An abstract base class for records that record their size as part of the
    // baml stream.
    internal abstract class BamlVariableSizedRecord : BamlRecord
    {
 #region Methods
 
#if !PBTCOMPILER
        // If there are enough bytes available, load the record size from the
        // binary reader.  The default action is to load the 4 byte size from
        // the reader, if there are at least 4 bytes available.
        internal override bool LoadRecordSize(
            BinaryReader bamlBinaryReader,
            long         bytesAvailable)
        {
           int recordSize;
           bool loadedSize = LoadVariableRecordSize(bamlBinaryReader, bytesAvailable, out recordSize);
           if (loadedSize)
           {
               RecordSize = recordSize;
           }
           return loadedSize;
        }
 
        // If there are enough bytes available, load the record size from the
        // binary reader.  The default action is to load the 4 byte size from
        // the reader, if there are at least 4 bytes available.
        internal static bool LoadVariableRecordSize(
                BinaryReader bamlBinaryReader,
                long         bytesAvailable,
            out int          recordSize)
        {
            if (bytesAvailable >= MaxRecordSizeFieldLength)
            {
                recordSize = ((BamlBinaryReader)bamlBinaryReader).Read7BitEncodedInt();
                return true;
            }
            else
            {
                recordSize = -1;
                return false;
            }
        }
#endif
 
        protected int ComputeSizeOfVariableLengthRecord(long start, long end)
        {
            int size = (Int32)(end - start);
            int sizeOfSize = BamlBinaryWriter.SizeOf7bitEncodedSize(size);
            sizeOfSize = BamlBinaryWriter.SizeOf7bitEncodedSize(sizeOfSize+size);
            return (sizeOfSize+size);
        }
 
        // Writes data at the current position seek pointer points
        // to byte after the end of record when done.
        internal override void Write(BinaryWriter bamlBinaryWriter)
        {
            // BamlRecords may be used without a stream, so if you attempt to write when there
            // isn't a writer, just ignore it.
            if (bamlBinaryWriter == null)
            {
                return;
            }
 
 
            // Baml records always start with record type
            bamlBinaryWriter.Write((byte) RecordType);
 
            // Remember the file location of this baml record.  This
            // is needed if we have to come back later to update the sync mode.
            // IMPORTANT:  The RecordType is the last thing written before calling
            //             WriteRecordData.  Some records assume the record type is located
            //             directly before the current stream location and may change it, so
            //             don't change where the record type is written in the stream!!!
            //             Paint is one example of a DP object that will seek back to change
            //             the record type if it is unable to serialize itself.
 
            //  Write just the data, this is just to measure the size.
            long startSeekPosition = bamlBinaryWriter.Seek(0,SeekOrigin.Current);
            WriteRecordData(bamlBinaryWriter);
            long endSeekPosition = bamlBinaryWriter.Seek(0,SeekOrigin.Current);
 
            Debug.Assert(RecordSize < 0);
            RecordSize = ComputeSizeOfVariableLengthRecord(startSeekPosition, endSeekPosition);
 
            // seek back to the begining,  this time write the size, then the data.
            bamlBinaryWriter.Seek((int)startSeekPosition, SeekOrigin.Begin);
            WriteRecordSize(bamlBinaryWriter);
            WriteRecordData(bamlBinaryWriter);
        }
 
        // Write the size of this record.  The default action is to write the 4 byte
        // size, which may be overwritten later once WriteRecordData has been called.
        internal void WriteRecordSize(BinaryWriter bamlBinaryWriter)
        {
            ((BamlBinaryWriter)bamlBinaryWriter).Write7BitEncodedInt(RecordSize);
        }
 
#if !PBTCOMPILER
        internal override void Copy(BamlRecord record)
        {
            base.Copy(record);
 
            BamlVariableSizedRecord newRecord = (BamlVariableSizedRecord)record;
            newRecord._recordSize = _recordSize;
        }
#endif
 
#endregion Methods
 
#region Properties
 
        // Actual size of the complete BamlRecord in bytes.  Currently
        // limited to 2 gigabytes.
        internal override Int32 RecordSize
        {
            get { return _recordSize; }
            set { _recordSize = value; }
        }
 
        // This provides subclasses with a referece section to create their own section.
        internal new static BitVector32.Section LastFlagsSection
        {
            get { return BamlRecord.LastFlagsSection; }
        }
 
 
#endregion Properties
 
#region Data
 
        // Size of the RecordSize field in the baml file.  This must be in
        // sync the type type of _recordSize below.
        internal const int MaxRecordSizeFieldLength = 4;
 
        Int32          _recordSize = -1;   // we use a 7 bit encoded variable size
 
#endregion Data
    }
 
    internal class BamlXmlnsPropertyRecord : BamlVariableSizedRecord
    {
#region Methods
 
#if !PBTCOMPILER
        // LoadRecord specific data
        internal override void  LoadRecordData(BinaryReader bamlBinaryReader)
        {
            Prefix  =  bamlBinaryReader.ReadString();
            XmlNamespace  =   bamlBinaryReader.ReadString();
 
            short count = bamlBinaryReader.ReadInt16();
 
            if (count > 0)
            {
                AssemblyIds = new short[count];
 
                for (short i = 0; i < count; i++)
                {
                    AssemblyIds[i] = bamlBinaryReader.ReadInt16();
                }
            }
            else
            {
                AssemblyIds = null;
            }
        }
#endif
 
        // write record specific Data.
        internal override void WriteRecordData(BinaryWriter bamlBinaryWriter)
        {
            bamlBinaryWriter.Write(Prefix);
            bamlBinaryWriter.Write(XmlNamespace);
 
            // Write the AssemblyIds which contain XmlnsDefinitionAttribute
            // for this xmlns Uri.
            // The format should be CountN Id1 Id2 ... IdN
            //
            short count = 0;
 
            if (AssemblyIds != null && AssemblyIds.Length > 0)
            {
                count = (short) AssemblyIds.Length;
            }
 
            bamlBinaryWriter.Write(count);
 
            if (count > 0)
            {
                for (short i = 0; i < count; i++)
                {
                    bamlBinaryWriter.Write(AssemblyIds[i]);
                }
            }
        }
 
#if !PBTCOMPILER
        internal override void Copy(BamlRecord record)
        {
            base.Copy(record);
 
            BamlXmlnsPropertyRecord newRecord = (BamlXmlnsPropertyRecord)record;
            newRecord._prefix = _prefix;
            newRecord._xmlNamespace = _xmlNamespace;
            newRecord._assemblyIds = _assemblyIds;
        }
#endif
 
#endregion Methods
 
#region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.XmlnsProperty; }
        }
 
        internal string Prefix
        {
            get { return _prefix; }
            set {_prefix = value; }
        }
 
        internal string XmlNamespace
        {
            get { return _xmlNamespace; }
            set { _xmlNamespace = value; }
        }
 
        internal short[] AssemblyIds
        {
            get { return _assemblyIds; }
            set { _assemblyIds = value; }
        }
 
#endregion Properties
 
#region Data
 
        string _prefix;
        string _xmlNamespace;
        short[] _assemblyIds;
 
#endregion Data
    }
 
    internal class BamlPIMappingRecord : BamlVariableSizedRecord
    {
#region Methods
 
#if !PBTCOMPILER
        // LoadRecord specific data
        internal override void  LoadRecordData(BinaryReader bamlBinaryReader)
        {
            XmlNamespace  =  bamlBinaryReader.ReadString();
            ClrNamespace  =  bamlBinaryReader.ReadString();
            AssemblyId    =  bamlBinaryReader.ReadInt16();
        }
#endif
        // write record specific Data.
        internal override void WriteRecordData(BinaryWriter bamlBinaryWriter)
        {
            // write out an int for record size but we'll go back and fill
            bamlBinaryWriter.Write(XmlNamespace);
            bamlBinaryWriter.Write(ClrNamespace);
            bamlBinaryWriter.Write(AssemblyId);
        }
 
#if !PBTCOMPILER
        internal override void Copy(BamlRecord record)
        {
            base.Copy(record);
 
            BamlPIMappingRecord newRecord = (BamlPIMappingRecord)record;
            newRecord._xmlns = _xmlns;
            newRecord._clrns = _clrns;
        }
#endif
 
#endregion Methods
 
#region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.PIMapping; }
        }
 
        internal string XmlNamespace
        {
            get { return _xmlns; }
            set {_xmlns = value; }
        }
 
        internal string ClrNamespace
        {
            get { return _clrns; }
            set { _clrns = value; }
        }
 
        internal short AssemblyId
        {
            get
            {
                short value = (short) _flags[_assemblyIdLowSection];
                value |= (short) (_flags[_assemblyIdHighSection] << 8);
 
                return value;
            }
 
            set
            {
                _flags[_assemblyIdLowSection] = (short)  (value & 0xff);
                _flags[_assemblyIdHighSection] = (short) ((value & 0xff00) >> 8);
            }
        }
 
        // Allocate space in _flags.
        // BitVector32 doesn't support 16 bit sections, so we have to break
        // it up into 2 sections.
 
        private static BitVector32.Section _assemblyIdLowSection
            = BitVector32.CreateSection( (short)0xff, BamlVariableSizedRecord.LastFlagsSection );
 
        private static BitVector32.Section _assemblyIdHighSection
            = BitVector32.CreateSection( (short)0xff, _assemblyIdLowSection );
 
#if !PBTCOMPILER
        // This provides subclasses with a referece section to create their own section.
        internal new static BitVector32.Section LastFlagsSection
        {
            get { return _assemblyIdHighSection; }
        }
#endif
 
 
 
#endregion Properties
 
#region Data
        string _xmlns;
        string _clrns;
#endregion Data
 
    }
 
    // Common base class for variables sized records that contain a string value
    internal abstract class BamlStringValueRecord : BamlVariableSizedRecord
    {
#region Methods
 
#if !PBTCOMPILER
        // LoadRecord specific data
        internal override void  LoadRecordData(BinaryReader bamlBinaryReader)
        {
            Value  =  bamlBinaryReader.ReadString();
        }
#endif
 
        // write record specific Data.
        internal override void WriteRecordData(BinaryWriter bamlBinaryWriter)
        {
            bamlBinaryWriter.Write(Value);
        }
 
#if !PBTCOMPILER
        internal override void Copy(BamlRecord record)
        {
            base.Copy(record);
 
            BamlStringValueRecord newRecord = (BamlStringValueRecord)record;
            newRecord._value = _value;
        }
#endif
 
#endregion Methods
 
#region Properties
 
        internal string Value
        {
            get { return _value; }
            set { _value = value; }
        }
 
#endregion Properties
 
#region Data
        string _value;
#endregion Data
 
    }
 
    // Common methods for baml records that serve as keys in a dictionary.
    internal interface IBamlDictionaryKey
    {
        // Update the pointer to the Value that was written out when WriteRecordData
        // was first called.
        void UpdateValuePosition(
            Int32        newPosition,
            BinaryWriter bamlBinaryWriter);
 
        // Relative stream position in the baml stream where the value associated
        // with this key starts.  It is relative to the end of the keys section,
        // or the start of the values section.
        Int32 ValuePosition { get; set; }
 
        // The actual key object used in the dictionary.  This may be a string,
        // field, type or other object.
        object KeyObject { get; set; }
 
        // Position in the stream where ValuePosition was written.  This is needed
        // when updating the ValuePosition.
        Int64 ValuePositionPosition { get; set; }
 
        // True if the value associated with this key is shared.
        bool Shared { get; set; }
 
        // Whether Shared was set.
        bool SharedSet { get; set; }
 
#if !PBTCOMPILER
        object[] StaticResourceValues {get; set;}
#endif
    }
 
    // Common interface implemented by BamlRecords that
    // use optimized storage for MarkupExtensions.
    internal interface IOptimizedMarkupExtension
    {
        short ExtensionTypeId
        {
            get;
        }
 
        short ValueId
        {
            get;
        }
 
        bool IsValueTypeExtension
        {
            get;
        }
 
        bool IsValueStaticExtension
        {
            get;
        }
    }
 
    // BamlRecord use in a defer loaded dictionary as the key for adding a value.
    // The value is a type that is refered to using a TypeID
    internal class BamlDefAttributeKeyTypeRecord : BamlElementStartRecord, IBamlDictionaryKey
    {
        internal BamlDefAttributeKeyTypeRecord()
        {
            Pin(); // Don't allow this record to be recycled in the read cache.
        }
 
#region Methods
 
#if !PBTCOMPILER
        // LoadRecord specific data
        internal override void LoadRecordData(BinaryReader bamlBinaryReader)
        {
            base.LoadRecordData(bamlBinaryReader);
            _valuePosition =  bamlBinaryReader.ReadInt32();
            ((IBamlDictionaryKey)this).Shared = bamlBinaryReader.ReadBoolean();
            ((IBamlDictionaryKey)this).SharedSet = bamlBinaryReader.ReadBoolean();
        }
#endif
 
        // Write record specific Data.
        internal override void WriteRecordData(BinaryWriter bamlBinaryWriter)
        {
            base.WriteRecordData(bamlBinaryWriter);
            _valuePositionPosition = bamlBinaryWriter.Seek(0, SeekOrigin.Current);
            bamlBinaryWriter.Write(_valuePosition);
            bamlBinaryWriter.Write(((IBamlDictionaryKey)this).Shared);
            bamlBinaryWriter.Write(((IBamlDictionaryKey)this).SharedSet);
        }
 
        // Update the pointer to the Value that was written out when WriteRecordData
        // was first called.  At that time the true position was probably not known,
        // so it is written out later.  Be certain to leave the passed writer pointing
        // to the same location it was at when this call was made.
        void IBamlDictionaryKey.UpdateValuePosition(
            Int32        newPosition,
            BinaryWriter bamlBinaryWriter)
        {
            Debug.Assert(_valuePositionPosition != -1,
                    "Must call WriteRecordData before updating position");
 
            // Use relative positions to reduce the possibility of truncation,
            // since Seek takes a 32 bit int, but position is a 64 bit int.
            Int64 existingPosition = bamlBinaryWriter.Seek(0, SeekOrigin.Current);
            Int32 deltaPosition = (Int32)(_valuePositionPosition-existingPosition);
 
            bamlBinaryWriter.Seek(deltaPosition, SeekOrigin.Current);
            bamlBinaryWriter.Write(newPosition);
            bamlBinaryWriter.Seek(-ValuePositionSize-deltaPosition, SeekOrigin.Current);
        }
 
#if !PBTCOMPILER
        internal override void Copy(BamlRecord record)
        {
            base.Copy(record);
 
            BamlDefAttributeKeyTypeRecord newRecord = (BamlDefAttributeKeyTypeRecord)record;
            newRecord._valuePosition = _valuePosition;
            newRecord._valuePositionPosition = _valuePositionPosition;
            newRecord._keyObject = _keyObject;
            newRecord._staticResourceValues = _staticResourceValues;
        }
#endif
 
#endregion Methods
 
#region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.DefAttributeKeyType; }
        }
 
        // Relative stream position in the baml stream where the value associated
        // with this key starts.  It is relative to the end of the keys section,
        // or the start of the values section.
        Int32 IBamlDictionaryKey.ValuePosition
        {
            get { return _valuePosition; }
            set { _valuePosition = value; }
        }
 
        // The actual key used in the defer loaded dictionary.  For this type of
        // record the key is a Type that is obtained at runtime from the base
        // classes TypeId
        object IBamlDictionaryKey.KeyObject
        {
            get { return _keyObject; }
            set { _keyObject = value; }
        }
 
        // Position in the stream where ValuePosition was written.  This is needed
        // when updating the ValuePosition.
        Int64 IBamlDictionaryKey.ValuePositionPosition
        {
            get { return _valuePositionPosition; }
            set { _valuePositionPosition = value; }
        }
 
        // True if the value associated with this key is shared.
        bool IBamlDictionaryKey.Shared
        {
            get
            {
                return _flags[_sharedSection] == 1 ? true : false;
            }
 
            set
            {
                _flags[_sharedSection] = value ? 1 : 0;
            }
        }
 
        // Whether Shared was set
        bool IBamlDictionaryKey.SharedSet
        {
            get
            {
                return _flags[_sharedSetSection] == 1 ? true : false;
            }
 
            set
            {
                _flags[_sharedSetSection] = value ? 1 : 0;
            }
        }
 
#if !PBTCOMPILER
        object[] IBamlDictionaryKey.StaticResourceValues
        {
            get { return _staticResourceValues; }
            set { _staticResourceValues = value; }
        }
#endif
 
 
        // Allocate space in _flags.
 
        private static BitVector32.Section _sharedSection
            = BitVector32.CreateSection( 1, BamlElementStartRecord.LastFlagsSection );
 
        private static BitVector32.Section _sharedSetSection
            = BitVector32.CreateSection( 1, _sharedSection );
 
#if !PBTCOMPILER
        // This provides subclasses with a referece section to create their own section.
        internal new static BitVector32.Section LastFlagsSection
        {
            get { return _sharedSetSection; }
        }
#endif
 
 
 
#endregion Properties
 
#region Data
 
        // Size in bytes of the ValuePosition field written out to baml.  This
        // must be in sync with the size of _valuePosition below.
        internal const Int32 ValuePositionSize = 4;
 
        // Relative position in the stream where the value associated with this key starts
        Int32 _valuePosition;
 
        // Position in the stream where ValuePosition was written.  This is needed
        // when updating the ValuePosition.
        Int64 _valuePositionPosition = -1;
 
        // Actual object key used by a dictionary.  This is a Type object
        object _keyObject = null;
 
#if !PBTCOMPILER
        object[] _staticResourceValues;
#endif
 
#endregion Data
    }
 
 
    // BamlRecord for x:Key attribute when used in a defer loaded dictionary
    // as the key for adding a value.  The value is stored as a string.
    internal class BamlDefAttributeKeyStringRecord : BamlStringValueRecord, IBamlDictionaryKey
    {
        internal BamlDefAttributeKeyStringRecord()
        {
            Pin(); // Don't allow this record to be recycled in the read cache.
        }
 
#region Methods
 
#if !PBTCOMPILER
        // LoadRecord specific data
        internal override void LoadRecordData(BinaryReader bamlBinaryReader)
        {
            ValueId = bamlBinaryReader.ReadInt16();
            _valuePosition =  bamlBinaryReader.ReadInt32();
            ((IBamlDictionaryKey)this).Shared = bamlBinaryReader.ReadBoolean();
            ((IBamlDictionaryKey)this).SharedSet = bamlBinaryReader.ReadBoolean();
            _keyObject = null;
        }
#endif
 
        // Write record specific Data.
        internal override void WriteRecordData(BinaryWriter bamlBinaryWriter)
        {
            bamlBinaryWriter.Write(ValueId);
            _valuePositionPosition = bamlBinaryWriter.Seek(0, SeekOrigin.Current);
            bamlBinaryWriter.Write(_valuePosition);
            bamlBinaryWriter.Write(((IBamlDictionaryKey)this).Shared);
            bamlBinaryWriter.Write(((IBamlDictionaryKey)this).SharedSet);
        }
 
        // Update the pointer to the Value that was written out when WriteRecordData
        // was first called.  At that time the true position was probably not known,
        // so it is written out later.  Be certain to leave the passed writer pointing
        // to the same location it was at when this call was made.
        void IBamlDictionaryKey.UpdateValuePosition(
            Int32        newPosition,
            BinaryWriter bamlBinaryWriter)
        {
            Debug.Assert(_valuePositionPosition != -1,
                    "Must call WriteRecordData before updating position");
 
            // Use relative positions to reduce the possibility of truncation,
            // since Seek takes a 32 bit int, but position is a 64 bit int.
            Int64 existingPosition = bamlBinaryWriter.Seek(0, SeekOrigin.Current);
            Int32 deltaPosition = (Int32)(_valuePositionPosition-existingPosition);
 
            bamlBinaryWriter.Seek(deltaPosition, SeekOrigin.Current);
            bamlBinaryWriter.Write(newPosition);
            bamlBinaryWriter.Seek(-ValuePositionSize-deltaPosition, SeekOrigin.Current);
        }
 
#if !PBTCOMPILER
        internal override void Copy(BamlRecord record)
        {
            base.Copy(record);
 
            BamlDefAttributeKeyStringRecord newRecord = (BamlDefAttributeKeyStringRecord)record;
            newRecord._valuePosition = _valuePosition;
            newRecord._valuePositionPosition = _valuePositionPosition;
            newRecord._keyObject = _keyObject;
            newRecord._valueId = _valueId;
            newRecord._staticResourceValues = _staticResourceValues;
        }
#endif
 
#endregion Methods
 
#region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.DefAttributeKeyString; }
        }
 
        // Relative stream position in the baml stream where the value associated
        // with this key starts.  It is relative to the end of the keys section,
        // or the start of the values section.
        Int32 IBamlDictionaryKey.ValuePosition
        {
            get { return _valuePosition; }
            set { _valuePosition = value; }
        }
 
        // True if the value associated with this key is shared.
        bool IBamlDictionaryKey.Shared
        {
            get
            {
                return _flags[_sharedSection] == 1 ? true : false;
            }
 
            set
            {
                _flags[_sharedSection] = value ? 1 : 0;
            }
        }
 
        // Whether Shared was set
        bool IBamlDictionaryKey.SharedSet
        {
            get
            {
                return _flags[_sharedSetSection] == 1 ? true : false;
            }
 
            set
            {
                _flags[_sharedSetSection] = value ? 1 : 0;
            }
        }
 
        // Allocate space in _flags.
 
        private static BitVector32.Section _sharedSection
            = BitVector32.CreateSection( 1, BamlStringValueRecord.LastFlagsSection );
 
        private static BitVector32.Section _sharedSetSection
            = BitVector32.CreateSection( 1,  _sharedSection );
 
#if !PBTCOMPILER
        // This provides subclasses with a referece section to create their own section.
        internal new static BitVector32.Section LastFlagsSection
        {
            get { return _sharedSetSection; }
        }
#endif
 
 
        // The following are NOT written out to BAML but are cached at runtime
 
        // The string value translated into a key object.  The string may represent
        // a type, field, or other object that can be translated into an object using
        // using the Mapper.
        object IBamlDictionaryKey.KeyObject
        {
            get { return _keyObject; }
            set { _keyObject = value; }
        }
 
        // Position in the stream where ValuePosition was written.  This is needed
        // when updating the ValuePosition.
        Int64 IBamlDictionaryKey.ValuePositionPosition
        {
            get { return _valuePositionPosition; }
            set { _valuePositionPosition = value; }
        }
 
        internal Int16 ValueId
        {
            get { return _valueId; }
            set { _valueId = value; }
        }
 
 
#if !PBTCOMPILER
        object[] IBamlDictionaryKey.StaticResourceValues
        {
            get { return _staticResourceValues; }
            set { _staticResourceValues = value; }
        }
#endif
 
#endregion Properties
 
#region Data
 
        // Size in bytes of the ValuePosition field written out to baml.  This
        // must be in sync with the size of _valuePosition below.
        internal const Int32 ValuePositionSize = 4;
 
        // Relative position in the stream where the value associated with this key starts
        Int32 _valuePosition;
 
        // Position in the stream where ValuePosition was written.  This is needed
        // when updating the ValuePosition.
        Int64 _valuePositionPosition = -1;
 
        // Actual object key used by a dictionary.  This is the Value string
        // after conversion.
        object _keyObject = null;
 
        Int16 _valueId;
 
#if !PBTCOMPILER
        object[] _staticResourceValues;
#endif
 
#endregion Data
    }
 
    // BamlRecord for x:Whatever attribute
    internal class BamlDefAttributeRecord : BamlStringValueRecord
    {
#region Methods
 
#if !PBTCOMPILER
        // LoadRecord specific data
        internal override void  LoadRecordData(BinaryReader bamlBinaryReader)
        {
            Value      =  bamlBinaryReader.ReadString();
            NameId     =  bamlBinaryReader.ReadInt16();
            Name       =  null;
        }
#endif
 
        // write record specific Data.
        internal override void WriteRecordData(BinaryWriter bamlBinaryWriter)
        {
            bamlBinaryWriter.Write(Value);
            bamlBinaryWriter.Write(NameId);
        }
 
#if !PBTCOMPILER
        internal override void Copy(BamlRecord record)
        {
            base.Copy(record);
 
            BamlDefAttributeRecord newRecord = (BamlDefAttributeRecord)record;
            newRecord._name = _name;
            newRecord._nameId = _nameId;
            newRecord._attributeUsage = _attributeUsage;
        }
#endif
 
#endregion Methods
 
#region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.DefAttribute; }
        }
 
        // The following is written out the baml file.
 
        internal Int16 NameId
        {
            get { return _nameId; }
            set { _nameId = value; }
        }
 
        // The following are cached locally, but not written to baml.
 
        internal string Name
        {
#if !PBTCOMPILER
            get { return _name; }
#endif
            set { _name = value; }
        }
 
        // Some attributes have special usage, such as setting the XmlLang and XmlSpace
        // strings in the parser context.  This is flagged with this property
        internal BamlAttributeUsage AttributeUsage
        {
#if !PBTCOMPILER
            get { return _attributeUsage; }
#endif
            set { _attributeUsage = value; }
        }
 
#endregion Properties
 
#if !PBTCOMPILER
        public override string ToString()
        {
            return string.Create(CultureInfo.InvariantCulture,
                $"{RecordType} nameId({NameId}) is '{Name}' usage={AttributeUsage}");
        }
#endif
 
#region Data
        string _name;
        Int16  _nameId;
        BamlAttributeUsage _attributeUsage;
#endregion Data
 
    }
 
    // BamlRecord for PresentationOptions:Whatever attribute
    internal class BamlPresentationOptionsAttributeRecord : BamlStringValueRecord
    {
#region Methods
 
#if !PBTCOMPILER
        // LoadRecord specific data
        internal override void  LoadRecordData(BinaryReader bamlBinaryReader)
        {
            Value      =  bamlBinaryReader.ReadString();
            NameId     =  bamlBinaryReader.ReadInt16();
            Name       =  null;
        }
#endif
 
        // write record specific Data.
        internal override void WriteRecordData(BinaryWriter bamlBinaryWriter)
        {
            bamlBinaryWriter.Write(Value);
            bamlBinaryWriter.Write(NameId);
        }
 
#if !PBTCOMPILER
        internal override void Copy(BamlRecord record)
        {
            base.Copy(record);
 
            BamlPresentationOptionsAttributeRecord newRecord = (BamlPresentationOptionsAttributeRecord)record;
            newRecord._name = _name;
            newRecord._nameId = _nameId;
        }
#endif
 
#endregion Methods
 
#region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.PresentationOptionsAttribute; }
        }
 
        // The following is written out the baml file.
 
        internal Int16 NameId
        {
            get { return _nameId; }
            set { _nameId = value; }
        }
 
        // The following are cached locally, but not written to baml.
 
        internal string Name
        {
#if !PBTCOMPILER
            get { return _name; }
#endif
            set { _name = value; }
        }
 
#endregion Properties
 
#if !PBTCOMPILER
        public override string ToString()
        {
            return string.Create(CultureInfo.InvariantCulture, $"{RecordType} nameId({NameId}) is '{Name}'");
        }
#endif
 
#region Data
        string _name;
        Int16  _nameId;
#endregion Data
 
    }
 
    //
    // BamlPropertyComplexStartRecord is for Complex DependencyProperty declarations
    // in markup, where the actual type and value is determined by subsequent records.
    //
    internal class BamlPropertyComplexStartRecord : BamlRecord
    {
#region Methods
 
#if !PBTCOMPILER
        internal override void  LoadRecordData(BinaryReader bamlBinaryReader)
        {
            AttributeId   = bamlBinaryReader.ReadInt16();
        }
#endif
 
        internal override void WriteRecordData(BinaryWriter bamlBinaryWriter)
        {
            bamlBinaryWriter.Write(AttributeId);
        }
 
#if !PBTCOMPILER
        internal override void Copy(BamlRecord record)
        {
            base.Copy(record);
 
            BamlPropertyComplexStartRecord newRecord = (BamlPropertyComplexStartRecord)record;
            newRecord._attributeId = _attributeId;
        }
#endif
 
#endregion Methods
 
#region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.PropertyComplexStart; }
        }
 
        internal short AttributeId
        {
            get { return _attributeId; }
            set { _attributeId = value; }
        }
 
        internal override Int32 RecordSize
        {
            get { return 2; }
            set { Debug.Assert (value == -1, "Wrong size set for complex prop record"); }
        }
 
#endregion Properties
 
#if !PBTCOMPILER
        public override string ToString()
        {
            return string.Create(CultureInfo.InvariantCulture, $"{RecordType} attr({_attributeId})");
        }
#endif
 
#region Data
        short _attributeId = -1;
#endregion Data
 
    }
 
    //
    // BamlPropertyStringReferenceRecord is for Property values that are written
    // out as references into the string table.
    //
    internal class BamlPropertyStringReferenceRecord : BamlPropertyComplexStartRecord
    {
        #region Methods
 
#if !PBTCOMPILER
        internal override void LoadRecordData(BinaryReader bamlBinaryReader)
        {
            AttributeId = bamlBinaryReader.ReadInt16();
            StringId  = bamlBinaryReader.ReadInt16();
        }
#endif
 
        internal override void WriteRecordData(BinaryWriter bamlBinaryWriter)
        {
            bamlBinaryWriter.Write(AttributeId);
            bamlBinaryWriter.Write(StringId);
        }
 
#if !PBTCOMPILER
        internal override void Copy(BamlRecord record)
        {
            base.Copy(record);
 
            BamlPropertyStringReferenceRecord newRecord = (BamlPropertyStringReferenceRecord)record;
            newRecord._stringId = _stringId;
        }
#endif
 
        #endregion Methods
 
        #region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.PropertyStringReference; }
        }
 
        internal short StringId
        {
            get { return _stringId; }
#if !PBTCOMPILER
            set { _stringId = value; }
#endif
        }
 
        internal override Int32 RecordSize
        {
            get { return 4; }
            set { Debug.Assert (value == -1, "Wrong size set for complex prop record"); }
        }
 
        #endregion Properties
 
        #region Data
        short _stringId = 0;
 
        #endregion Data
    }
 
    //
    // BamlPropertyTypeReferenceRecord is for Property values that are written
    // out as references into the type table.  So the property value is a 'Type' object.
    //
    internal class BamlPropertyTypeReferenceRecord : BamlPropertyComplexStartRecord
    {
        #region Methods
 
#if !PBTCOMPILER
        internal override void LoadRecordData(BinaryReader bamlBinaryReader)
        {
            AttributeId = bamlBinaryReader.ReadInt16();
            TypeId  = bamlBinaryReader.ReadInt16();
        }
#endif
 
        internal override void WriteRecordData(BinaryWriter bamlBinaryWriter)
        {
            bamlBinaryWriter.Write(AttributeId);
            bamlBinaryWriter.Write(TypeId);
        }
 
#if !PBTCOMPILER
        internal override void Copy(BamlRecord record)
        {
            base.Copy(record);
 
            BamlPropertyTypeReferenceRecord newRecord = (BamlPropertyTypeReferenceRecord)record;
            newRecord._typeId = _typeId;
        }
#endif
 
        #endregion Methods
 
        #region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.PropertyTypeReference; }
        }
 
        internal short TypeId
        {
            get { return _typeId; }
            set { _typeId = value; }
        }
 
        internal override Int32 RecordSize
        {
            get { return 4; }
            set { Debug.Assert (value == -1, "Wrong size set for complex prop record"); }
        }
 
        #endregion Properties
 
        #region Data
        short _typeId = 0;
        #endregion Data
    }
 
    //
    // BamlPropertyWithConverterRecord information for property with custom type converter
    //
    internal class BamlPropertyWithConverterRecord : BamlPropertyRecord
    {
        #region Methods
 
#if !PBTCOMPILER
        internal override void LoadRecordData(BinaryReader bamlBinaryReader)
        {
            base.LoadRecordData(bamlBinaryReader);
            ConverterTypeId  = bamlBinaryReader.ReadInt16();
        }
#endif
 
        internal override void WriteRecordData(BinaryWriter bamlBinaryWriter)
        {
            base.WriteRecordData(bamlBinaryWriter);
            bamlBinaryWriter.Write(ConverterTypeId);
        }
 
#if !PBTCOMPILER
        internal override void Copy(BamlRecord record)
        {
            base.Copy(record);
 
            BamlPropertyWithConverterRecord newRecord = (BamlPropertyWithConverterRecord)record;
            newRecord._converterTypeId = _converterTypeId;
        }
#endif
 
        #endregion Methods
 
        #region Properties
 
        // The following are stored in the baml stream
 
        // ID of this type converter.  Referenced in other baml records where a
        // Type is needed.
        internal short ConverterTypeId
        {
            get { return _converterTypeId; }
            set { _converterTypeId = value; }
        }
 
        // Additional properties not stored in the baml stream
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.PropertyWithConverter; }
        }
 
        #endregion Properties
 
        #region Data
 
        short _converterTypeId = 0;
 
        #endregion Data
    }
 
    //
    // BamlPropertyRecord is for DependencyProperty values that are written
    // out as strings.
    //
    internal class BamlPropertyRecord : BamlStringValueRecord
    {
#region Methods
 
#if !PBTCOMPILER
        internal override void  LoadRecordData(BinaryReader bamlBinaryReader)
        {
            AttributeId   = bamlBinaryReader.ReadInt16();
            Value         = bamlBinaryReader.ReadString();
        }
#endif
 
        internal override void WriteRecordData(BinaryWriter bamlBinaryWriter)
        {
            bamlBinaryWriter.Write(AttributeId);
            bamlBinaryWriter.Write(Value);
        }
 
#if !PBTCOMPILER
        internal override void Copy(BamlRecord record)
        {
            base.Copy(record);
 
            BamlPropertyRecord newRecord = (BamlPropertyRecord)record;
            newRecord._attributeId = _attributeId;
        }
#endif
 
#endregion Methods
 
#region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.Property; }
        }
 
        internal short AttributeId
        {
            get { return _attributeId; }
            set { _attributeId = value; }
        }
 
#endregion Properties
 
#if !PBTCOMPILER
        public override string ToString()
        {
            return string.Create(CultureInfo.InvariantCulture, $"{RecordType} attr({_attributeId}) <== '{Value}'");
        }
#endif
 
#region Data
        short  _attributeId = -1;
#endregion Data
 
 
    }
 
    //
    // BamlPropertyWithExtensionRecord is for property values that are Markup extensions
    // with a single param member that are written out as attributeIds.
    //
    internal class BamlPropertyWithExtensionRecord : BamlRecord, IOptimizedMarkupExtension
    {
        #region Methods
 
#if !PBTCOMPILER
        internal override void LoadRecordData(BinaryReader bamlBinaryReader)
        {
            AttributeId = bamlBinaryReader.ReadInt16();
            short extensionTypeId = bamlBinaryReader.ReadInt16();
            ValueId = bamlBinaryReader.ReadInt16();
 
            // The upper 4 bits of the ExtensionTypeId are used as flags
            _extensionTypeId = (short)(extensionTypeId & ExtensionIdMask);
            IsValueTypeExtension = (extensionTypeId & TypeExtensionValueMask) == TypeExtensionValueMask;
            IsValueStaticExtension = (extensionTypeId & StaticExtensionValueMask) == StaticExtensionValueMask;
        }
#endif
 
        internal override void WriteRecordData(BinaryWriter bamlBinaryWriter)
        {
            bamlBinaryWriter.Write(AttributeId);
            short extensionTypeId = ExtensionTypeId;
            if (IsValueTypeExtension)
            {
                extensionTypeId |= TypeExtensionValueMask;
            }
            else if (IsValueStaticExtension)
            {
                extensionTypeId |= StaticExtensionValueMask;
            }
            bamlBinaryWriter.Write(extensionTypeId);
            bamlBinaryWriter.Write(ValueId);
        }
 
#if !PBTCOMPILER
        internal override void Copy(BamlRecord record)
        {
            base.Copy(record);
 
            BamlPropertyWithExtensionRecord newRecord = (BamlPropertyWithExtensionRecord)record;
            newRecord._attributeId = _attributeId;
            newRecord._extensionTypeId = _extensionTypeId;
            newRecord._valueId = _valueId;
        }
#endif
 
        #endregion Methods
 
        #region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.PropertyWithExtension; }
        }
 
        // Id of the property whose value is the simple ME
        internal short AttributeId
        {
            get { return _attributeId; }
            set { _attributeId = value; }
        }
 
        // KnownElement Id of the MarkupExtension
        public short ExtensionTypeId
        {
            get { return _extensionTypeId; }
            set
            {
                // we shouldn't ever be intruding on the flags portion of the ExtensionTypeId
                Debug.Assert(value <= ExtensionIdMask);
                _extensionTypeId = value;
            }
        }
 
        // For StaticExtension: AttributeId of a member
        // For TemplateBindingExtension: AttributeId of a DependencyProperty
        // For a DynamicResourceExtension:
        //      StringId if the value is a string
        //      TypeId if the value is a TypeExtension
        //      AttributeId of the member if the value is a StaticExtension
        public short ValueId
        {
            get { return _valueId; }
            set { _valueId = value; }
        }
 
        internal override Int32 RecordSize
        {
            get { return 6; }
            set { Debug.Assert(value == -1, "Wrong size set for complex prop record"); }
        }
 
        // For DynamicResourceExtension, if the value is itself a simple TypeExtension
        public bool IsValueTypeExtension
        {
            get { return _flags[_isValueTypeExtensionSection] == 1 ? true : false; }
            set { _flags[_isValueTypeExtensionSection] = value ? 1 : 0; }
        }
 
        // For DynamicResourceExtension, if the value is itself a simple StaticExtension
        public bool IsValueStaticExtension
        {
            get { return _flags[_isValueStaticExtensionSection] == 1 ? true : false; }
            set { _flags[_isValueStaticExtensionSection] = value ? 1 : 0; }
        }
 
        // Allocate space in _flags.
        private static BitVector32.Section _isValueTypeExtensionSection
            = BitVector32.CreateSection(1, BamlRecord.LastFlagsSection);
 
        private static BitVector32.Section _isValueStaticExtensionSection
            = BitVector32.CreateSection(1, _isValueTypeExtensionSection);
 
#if !PBTCOMPILER
        // This provides subclasses with a referece section to create their own section.
        internal new static BitVector32.Section LastFlagsSection
        {
            get { return _isValueStaticExtensionSection; }
        }
 
        public override string ToString()
        {
            return string.Create(CultureInfo.InvariantCulture,
                $"{RecordType} attr({_attributeId}) extn({_extensionTypeId}) valueId({_valueId})");
        }
#endif
 
        #endregion Properties
 
        #region Data
        short _attributeId = -1;
        short _extensionTypeId = 0;
        short _valueId = 0;
 
        private static readonly short ExtensionIdMask = 0x0FFF;
        private static readonly short TypeExtensionValueMask = 0x4000;
        private static readonly short StaticExtensionValueMask = 0x2000;
        #endregion Data
    }
 
    //
    // BamlPropertyCustomWriteInfoRecord is for DependencyProperty values that support
    // custom Avalon serialization. The property value objects write directly onto
    // the BAML stream in whatever format they understand. This record is used only
    // during BAML write time.
    //
    internal class BamlPropertyCustomWriteInfoRecord : BamlPropertyCustomRecord
    {
        internal override void WriteRecordData(BinaryWriter bamlBinaryWriter)
        {
            int writePositionStart = (int)bamlBinaryWriter.Seek(0, SeekOrigin.Current);
            short serializerTypeId = SerializerTypeId;
 
            bamlBinaryWriter.Write(AttributeId);
            if (serializerTypeId == (short)KnownElements.DependencyPropertyConverter)
            {
                // There is no need to actually use a real Converter here since we already have the
                // DP value as an AttributeInfoId.
 
                // if ValueMemberName exists then remember that the ValueId is a TypeId of the
                // type that declares ValueMemberName, so that it can be resolved correctly at
                // load time.
                if (ValueMemberName != null)
                {
                    bamlBinaryWriter.Write((short)(serializerTypeId | TypeIdValueMask));
                }
                else
                {
                    bamlBinaryWriter.Write(serializerTypeId);
                }
 
                // if ValueMemberName does not exist, ValueId is a KnownProperty Id
                // else it is a TypeId of the declaring type.
                bamlBinaryWriter.Write(ValueId);
 
                // Write out the ValueMemberName if it exists
                if (ValueMemberName != null)
                {
                    bamlBinaryWriter.Write(ValueMemberName);
                }
 
                return;
            }
 
            bamlBinaryWriter.Write(serializerTypeId);
 
            bool converted = false;
 
            // If we have an enum or a bool, do conversion to custom binary data here,
            // since we do not have a serializer associated with these types.
            if (ValueType != null && ValueType.IsEnum)
            {
                uint uintValue = 0;
                string [] enumValues = Value.Split(',');
 
                // if the Enum is a flag, then resolve each flag value in the enum value string.
                foreach (string enumValue in enumValues)
                {
                    FieldInfo enumField = ValueType.GetField(enumValue.Trim(), BindingFlags.Static | BindingFlags.Public | BindingFlags.IgnoreCase);
                    if (enumField != null)
                    {
                        // get the raw va;ue of the enum field and convert to a uint.
                        object rawEnumValue = enumField.GetRawConstantValue();
                        uintValue += (uint)Convert.ChangeType(rawEnumValue, typeof(uint), TypeConverterHelper.InvariantEnglishUS);
                        converted = true;
                    }
                    else
                    {
                        converted = false;
                        break;
                    }
                }
 
                if (converted)
                {
                    bamlBinaryWriter.Write(uintValue);
                }
            }
            else if (ValueType == typeof(Boolean))
            {
                TypeConverter boolConverter = TypeDescriptor.GetConverter(typeof(Boolean));
                object convertedValue = boolConverter.ConvertFromString(TypeContext, TypeConverterHelper.InvariantEnglishUS, Value);
                bamlBinaryWriter.Write((byte)Convert.ChangeType(convertedValue, typeof(byte), TypeConverterHelper.InvariantEnglishUS));
                converted = true;
            }
            else if (SerializerType == typeof(XamlBrushSerializer))
            {
                XamlSerializer serializer = new XamlBrushSerializer();
 
                // If we custom serialize this particular value at this point, then see
                // if it can convert.
                // NOTE:  This is sensitive to changes in the BamlRecordWriter and
                //        BamlRecordManager code and must be kept in sync with them...
                converted = serializer.ConvertStringToCustomBinary(bamlBinaryWriter, Value);
            }
            else if (SerializerType == typeof(XamlPoint3DCollectionSerializer))
            {
                XamlSerializer serializer = new XamlPoint3DCollectionSerializer();
 
                // If we custom serialize this particular value at this point, then see
                // if it can convert.
                // NOTE:  This is sensitive to changes in the BamlRecordWriter and
                //        BamlRecordManager code and must be kept in sync with them...
                converted = serializer.ConvertStringToCustomBinary(bamlBinaryWriter, Value);
            }
            else if (SerializerType == typeof(XamlVector3DCollectionSerializer))
            {
                XamlSerializer serializer = new XamlVector3DCollectionSerializer();
 
                // If we custom serialize this particular value at this point, then see
                // if it can convert.
                // NOTE:  This is sensitive to changes in the BamlRecordWriter and
                //        BamlRecordManager code and must be kept in sync with them...
                converted = serializer.ConvertStringToCustomBinary(bamlBinaryWriter, Value);
            }
            else if (SerializerType == typeof(XamlPointCollectionSerializer))
            {
                XamlSerializer serializer = new XamlPointCollectionSerializer();
 
                // If we custom serialize this particular value at this point, then see
                // if it can convert.
                // NOTE:  This is sensitive to changes in the BamlRecordWriter and
                //        BamlRecordManager code and must be kept in sync with them...
                converted = serializer.ConvertStringToCustomBinary(bamlBinaryWriter, Value);
            }
            else if (SerializerType == typeof(XamlInt32CollectionSerializer))
            {
                XamlSerializer serializer = new XamlInt32CollectionSerializer();
 
                // If we custom serialize this particular value at this point, then see
                // if it can convert.
                // NOTE:  This is sensitive to changes in the BamlRecordWriter and
                //        BamlRecordManager code and must be kept in sync with them...
                converted = serializer.ConvertStringToCustomBinary(bamlBinaryWriter, Value);
            }
            else if (SerializerType == typeof(XamlPathDataSerializer))
            {
                XamlSerializer serializer = new XamlPathDataSerializer();
 
                // If we custom serialize this particular value at this point, then see
                // if it can convert.
                // NOTE:  This is sensitive to changes in the BamlRecordWriter and
                //        BamlRecordManager code and must be kept in sync with them...
                converted = serializer.ConvertStringToCustomBinary(bamlBinaryWriter, Value);
            }
 
            if (!converted)
            {
                throw new XamlParseException(SR.Format(SR.ParserBadString, Value, ValueType.Name));
            }
        }
 
#if !PBTCOMPILER
        internal override void Copy(BamlRecord record)
        {
            base.Copy(record);
 
            BamlPropertyCustomWriteInfoRecord newRecord = (BamlPropertyCustomWriteInfoRecord)record;
            newRecord._valueId = _valueId;
            newRecord._valueType = _valueType;
            newRecord._value = _value;
            newRecord._valueMemberName = _valueMemberName;
            newRecord._serializerType = _serializerType;
            newRecord._typeContext = _typeContext;
        }
#endif
 
        // The KnownProperty Id of the Value, if it is a property and can be converted into one,
        // or the TypeId of the owner of the property value
        internal short ValueId
        {
            get { return _valueId; }
            set { _valueId = value; }
        }
 
        // If ValueId is a TypeId, then this holds the name of the member.
        internal string ValueMemberName
        {
            get { return _valueMemberName; }
            set { _valueMemberName = value; }
        }
 
        // The following properties are NOT written to the BAML stream.
 
        // Type of this property
        internal Type ValueType
        {
            get { return _valueType; }
            set { _valueType = value; }
        }
 
        // The string Value of the property.
        internal string Value
        {
            get { return _value; }
            set { _value = value; }
        }
 
        // Type of the XamlSerializer associated with this property.  Null
        // if this type is custom serialized by the parser itself.
        internal Type SerializerType
        {
            get { return _serializerType; }
            set { _serializerType = value; }
        }
 
        // Context used for type conversion of built in types.
        internal ITypeDescriptorContext TypeContext
        {
            get { return _typeContext; }
            set { _typeContext = value; }
        }
 
        short                  _valueId;
        Type                   _valueType;
        string                 _value;
        string                 _valueMemberName;
        Type                   _serializerType;
        ITypeDescriptorContext _typeContext;
    }
 
    //
    // BamlPropertyCustomRecord is for DependencyProperty values that support
    // custom Avalon serialization. This record is used only during BAML load.
    // The property value objects are read directly from the BAML stream by the
    // custom binary serializer for the property.
    //
    internal class BamlPropertyCustomRecord : BamlVariableSizedRecord
    {
#region Methods
 
#if !PBTCOMPILER
        internal override void  LoadRecordData(BinaryReader bamlBinaryReader)
        {
            AttributeId      = bamlBinaryReader.ReadInt16();
            short serializerTypeId = bamlBinaryReader.ReadInt16();
 
            IsValueTypeId = (serializerTypeId & TypeIdValueMask) == TypeIdValueMask;
            if (IsValueTypeId)
            {
                serializerTypeId &= (short)(~TypeIdValueMask);
            }
 
            SerializerTypeId = serializerTypeId;
 
            ValueObjectSet  = false;
            IsRawEnumValueSet = false;
            _valueObject = null;
 
            // ValueObject and ValueObject are not set until BamlRecordReader.ReadPropertyCustomRecord
            // because the Mapper is needed for custom DPs
 
            // NOTE: above may no longer true, so this could be potentially changed to be in sync with
            // other record. Needs more investigation.
        }
 
        // Read the binary data using the passed reader and use that to set the ValueObject.
        internal object GetCustomValue(BinaryReader reader, Type propertyType, short serializerId, BamlRecordReader bamlRecordReader)
        {
            Debug.Assert(!ValueObjectSet);
 
            // Handle enums and bools here directly.
            // Otherwise call the known custom serializers directly.
            switch (serializerId)
            {
                case (short)KnownElements.EnumConverter:
 
                    uint enumBits;
                    if (_valueObject == null)
                    {
                        // if no raw value has been read in yet, read it now
                        // from the baml stream.
                        enumBits = reader.ReadUInt32();
                    }
                    else
                    {
                        // raw value has been read in earlier, so try to resolve into
                        // an actual enum value now.
                        enumBits = (uint)_valueObject;
                    }
 
                    if (propertyType.IsEnum)
                    {
                        // property Type is an enum, so raw value can be resolved now.
                        _valueObject = Enum.ToObject(propertyType, enumBits);
                        ValueObjectSet = true;
                        IsRawEnumValueSet = false;
                    }
                    else
                    {
                        // property Type is not available yet, so raw value cannot
                        // be resolved now. Store it and try later.
                        _valueObject = enumBits;
                        ValueObjectSet = false;
                        IsRawEnumValueSet = true;
                    }
 
                    return _valueObject;
 
                case (short)KnownElements.BooleanConverter:
 
                    byte boolByte = reader.ReadByte();
                    _valueObject = boolByte == 1;
                    break;
 
                case (short)KnownElements.XamlBrushSerializer:
 
                    // Don't bother creating a XamlBrushSerializer instance & calling ConvertCustomBinaryToObject
                    // on it since that just calls SCB directly liek below. This saves big on perf.
                    _valueObject = SolidColorBrush.DeserializeFrom(reader, bamlRecordReader.TypeConvertContext);
                    break;
 
                case (short)KnownElements.XamlPathDataSerializer:
 
                    _valueObject = XamlPathDataSerializer.StaticConvertCustomBinaryToObject(reader);
                    break;
 
                case (short)KnownElements.XamlPoint3DCollectionSerializer:
 
                    _valueObject = XamlPoint3DCollectionSerializer.StaticConvertCustomBinaryToObject(reader);
                    break;
 
                case (short)KnownElements.XamlVector3DCollectionSerializer:
 
                    _valueObject = XamlVector3DCollectionSerializer.StaticConvertCustomBinaryToObject(reader);
                    break;
 
                case (short)KnownElements.XamlPointCollectionSerializer:
 
                    _valueObject = XamlPointCollectionSerializer.StaticConvertCustomBinaryToObject(reader);
                    break;
 
                case (short)KnownElements.XamlInt32CollectionSerializer:
 
                    _valueObject = XamlInt32CollectionSerializer.StaticConvertCustomBinaryToObject(reader);
                    break;
 
                default:
                    Debug.Assert (false, "Unknown custom serializer");
                    return null;
            }
 
            ValueObjectSet = true;
            return _valueObject;
        }
 
        internal override void Copy(BamlRecord record)
        {
            base.Copy(record);
 
            BamlPropertyCustomRecord newRecord = (BamlPropertyCustomRecord)record;
            newRecord._valueObject = _valueObject;
            newRecord._attributeId = _attributeId;
            newRecord._serializerTypeId = _serializerTypeId;
        }
 
#endif
 
#endregion Methods
 
#region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.PropertyCustom; }
        }
 
        internal short AttributeId
        {
            get { return _attributeId; }
            set { _attributeId = value; }
        }
 
        // ID of this serializer type.  Referenced in other baml records where a
        // Type is needed.
        internal short SerializerTypeId
        {
            get { return _serializerTypeId; }
            set { _serializerTypeId = value; }
        }
 
        // The following properties are NOT written to the BAML stream.
 
#if !PBTCOMPILER
        // Value of the converted object.
        internal object ValueObject
        {
            get { return _valueObject; }
            set { _valueObject = value; }
        }
 
        // Return true if GetCustomValue has been called, indicating that
        // a conversion from binary custom data to a ValueObject has occurred.
        internal bool ValueObjectSet
        {
            get { return _flags[_isValueSetSection] == 1 ? true : false; }
            set { _flags[_isValueSetSection] = value ? 1 : 0; }
        }
 
        internal bool IsValueTypeId
        {
            get { return _flags[_isValueTypeIdSection] == 1 ? true : false; }
            set { _flags[_isValueTypeIdSection] = value ? 1 : 0; }
        }
 
        // true if only the raw value of enum has been read as it cannot yet be
        // converted into an enum as the Type is not available yet.
        internal bool IsRawEnumValueSet
        {
            get { return _flags[_isRawEnumValueSetSection] == 1 ? true : false; }
            set { _flags[_isRawEnumValueSetSection] = value ? 1 : 0; }
        }
 
        object _valueObject;
 
        // Allocate space in _flags.
        private static BitVector32.Section _isValueSetSection
            = BitVector32.CreateSection(1, BamlVariableSizedRecord.LastFlagsSection);
 
        // Allocate space in _flags.
        private static BitVector32.Section _isValueTypeIdSection
            = BitVector32.CreateSection(1, _isValueSetSection);
 
        // Allocate space in _flags.
        private static BitVector32.Section _isRawEnumValueSetSection
            = BitVector32.CreateSection(1, _isValueTypeIdSection);
 
        // This provides subclasses with a referece section to create their own section.
        internal new static BitVector32.Section LastFlagsSection
        {
            get { return _isRawEnumValueSetSection; }
        }
#endif
 
#endregion Properties
 
#region Data
 
        internal static readonly short TypeIdValueMask = 0x4000;
 
        short                  _attributeId = 0;
        short                  _serializerTypeId = 0;
 
#endregion Data
    }
 
    internal class BamlPropertyArrayEndRecord : BamlRecord
    {
#region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.PropertyArrayEnd; }
        }
 
#endregion Properties
    }
 
    internal class BamlConstructorParametersStartRecord : BamlRecord
    {
#region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.ConstructorParametersStart; }
        }
 
#endregion Properties
    }
 
    internal class BamlConstructorParametersEndRecord : BamlRecord
    {
#region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.ConstructorParametersEnd; }
        }
 
#endregion Properties
    }
 
    internal class BamlConstructorParameterTypeRecord : BamlRecord
    {
        #region Methods
 
#if !PBTCOMPILER
        internal override void LoadRecordData(BinaryReader bamlBinaryReader)
        {
            TypeId  = bamlBinaryReader.ReadInt16();
        }
#endif
 
        internal override void WriteRecordData(BinaryWriter bamlBinaryWriter)
        {
            bamlBinaryWriter.Write(TypeId);
        }
 
#if !PBTCOMPILER
        internal override void Copy(BamlRecord record)
        {
            base.Copy(record);
 
            BamlConstructorParameterTypeRecord newRecord = (BamlConstructorParameterTypeRecord)record;
            newRecord._typeId = _typeId;
        }
#endif
 
        #endregion Methods
 
        #region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.ConstructorParameterType; }
        }
 
        internal short TypeId
        {
            get { return _typeId; }
            set { _typeId = value; }
        }
 
        internal override Int32 RecordSize
        {
            get { return 2; }
            set { Debug.Assert (value == -1, "Wrong size set for complex prop record"); }
        }
 
        #endregion Properties
 
        #region Data
        short _typeId = 0;
        #endregion Data
    }
 
    internal class BamlPropertyIListEndRecord : BamlRecord
    {
#region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.PropertyIListEnd; }
        }
 
#endregion Properties
    }
 
    internal class BamlPropertyIDictionaryEndRecord : BamlRecord
    {
#region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.PropertyIDictionaryEnd; }
        }
 
#endregion Properties
    }
 
    internal class BamlPropertyComplexEndRecord : BamlRecord
    {
#region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.PropertyComplexEnd; }
        }
 
#endregion Properties
    }
 
 
    internal class BamlPropertyArrayStartRecord : BamlPropertyComplexStartRecord
    {
#region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.PropertyArrayStart; }
        }
 
#endregion Properties
    }
 
    internal class BamlPropertyIListStartRecord : BamlPropertyComplexStartRecord
    {
#region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.PropertyIListStart; }
        }
 
#endregion Properties
    }
 
    internal class BamlPropertyIDictionaryStartRecord : BamlPropertyComplexStartRecord
    {
#region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.PropertyIDictionaryStart; }
        }
 
#endregion Properties
    }
 
    internal class BamlRoutedEventRecord : BamlStringValueRecord
    {
#region Methods
 
#if !PBTCOMPILER
        internal override void  LoadRecordData(BinaryReader bamlBinaryReader)
        {
            AttributeId   = bamlBinaryReader.ReadInt16();
            Value         = bamlBinaryReader.ReadString();
        }
#endif
 
        internal override void WriteRecordData(BinaryWriter bamlBinaryWriter)
        {
            bamlBinaryWriter.Write(AttributeId);
            bamlBinaryWriter.Write(Value);
        }
 
#if !PBTCOMPILER
        internal override void Copy(BamlRecord record)
        {
            base.Copy(record);
 
            BamlRoutedEventRecord newRecord = (BamlRoutedEventRecord)record;
            newRecord._attributeId = _attributeId;
        }
#endif
 
#endregion Methods
 
#region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.RoutedEvent; }
        }
 
        internal short AttributeId
        {
            get { return _attributeId; }
#if !PBTCOMPILER
            set { _attributeId = value; }
#endif
        }
 
#endregion Properties
 
#region Data
 
        short _attributeId = -1;
 
#endregion Data
    }
 
 
    // A section of literal content.
    internal class BamlLiteralContentRecord : BamlStringValueRecord
    {
#region Methods
 
#if !PBTCOMPILER
        internal override void  LoadRecordData(BinaryReader bamlBinaryReader)
        {
            Value  =  bamlBinaryReader.ReadString();
 
            Int32 _lineNumber = bamlBinaryReader.ReadInt32();
            Int32 _linePosition = bamlBinaryReader.ReadInt32();
        }
#endif
 
        internal override void WriteRecordData(BinaryWriter bamlBinaryWriter)
        {
            bamlBinaryWriter.Write(Value);
 
            bamlBinaryWriter.Write((Int32)0);
            bamlBinaryWriter.Write((Int32)0);
        }
 
#endregion Methods
 
#region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.LiteralContent; }
        }
 
#endregion Properties
     }
 
    // An record for the connection id that the (Style)BamlRecordReader uses to
    // hookup an ID or event on any element in the object tree or Style visual tree.
    internal class BamlConnectionIdRecord : BamlRecord
    {
#if !PBTCOMPILER
        internal override void LoadRecordData(BinaryReader bamlBinaryReader)
        {
            ConnectionId = bamlBinaryReader.ReadInt32();
        }
#endif
 
        internal override void WriteRecordData(BinaryWriter bamlBinaryWriter)
        {
            bamlBinaryWriter.Write(ConnectionId);
        }
 
#if !PBTCOMPILER
        internal override void Copy(BamlRecord record)
        {
            base.Copy(record);
 
            BamlConnectionIdRecord newRecord = (BamlConnectionIdRecord)record;
            newRecord._connectionId = _connectionId;
        }
#endif
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.ConnectionId; }
        }
 
        // Id of the type of this object
        internal Int32 ConnectionId
        {
            get { return _connectionId; }
            set { _connectionId = value; }
        }
 
        internal override Int32 RecordSize
        {
            get { return 4; }
            set { Debug.Assert(value == -1, "Wrong size set for element record"); }
        }
 
        Int32 _connectionId = -1;
    }
 
    // An object record in the object tree.  This can be a CLR
    // object or a DependencyObject.
    internal class BamlElementStartRecord : BamlRecord
    {
#region Methods
 
#if !PBTCOMPILER
        internal override void  LoadRecordData(BinaryReader bamlBinaryReader)
        {
            TypeId = bamlBinaryReader.ReadInt16();
            byte flags = bamlBinaryReader.ReadByte();
            CreateUsingTypeConverter = (flags & 1) != 0;
            IsInjected = (flags & 2) != 0;
        }
#endif
 
        internal override void WriteRecordData(BinaryWriter bamlBinaryWriter)
        {
            bamlBinaryWriter.Write(TypeId);
            byte flags = (byte)((CreateUsingTypeConverter ? 1 : 0) | (IsInjected ? 2 : 0));
            bamlBinaryWriter.Write(flags);
        }
 
#endregion Methods
 
#region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.ElementStart; }
        }
 
        // Id of the type of this object
        internal short TypeId
        {
            get
            {
                short value = (short) _flags[_typeIdLowSection];
                value |= (short) (_flags[_typeIdHighSection] << 8);
 
                return value;
            }
 
            set
            {
                _flags[_typeIdLowSection] = (short)  (value & 0xff);
                _flags[_typeIdHighSection] = (short) ((value & 0xff00) >> 8);
            }
        }
 
        // Whether this object instance is expected to be created via TypeConverter
        internal bool CreateUsingTypeConverter
        {
            get
            {
                return _flags[_useTypeConverter] == 1 ? true : false;
            }
 
            set
            {
                _flags[_useTypeConverter] = value ? 1 : 0;
            }
        }
 
        // Whether this element start record is just an injected tag that should not be processed
        internal bool IsInjected
        {
            get
            {
                return _flags[_isInjected] == 1 ? true : false;
            }
 
            set
            {
                _flags[_isInjected] = value ? 1 : 0;
            }
        }
 
        internal override Int32 RecordSize
        {
            get { return 3; }
            set { Debug.Assert(value == -1, "Wrong size set for element record"); }
        }
 
#endregion Properties
 
#if !PBTCOMPILER
        public override string ToString()
        {
            return string.Create(CultureInfo.InvariantCulture, $"{RecordType} typeId={GetTypeName(TypeId)}");
        }
#endif
 
 
        // Allocate space in _flags.
        // BitVector32 doesn't support 16 bit sections, so we have to break
        // it up into 2 sections.
 
        private static BitVector32.Section _typeIdLowSection
            = BitVector32.CreateSection( (short)0xff, BamlRecord.LastFlagsSection );
 
        private static BitVector32.Section _typeIdHighSection
            = BitVector32.CreateSection( (short)0xff, _typeIdLowSection );
 
        private static BitVector32.Section _useTypeConverter
            = BitVector32.CreateSection( 1, _typeIdHighSection );
 
        private static BitVector32.Section _isInjected
            = BitVector32.CreateSection( 1, _useTypeConverter );
 
 
        // This provides subclasses with a referece section to create their own section.
        internal new static BitVector32.Section LastFlagsSection
        {
            get { return _isInjected; }
        }
    }
 
 
 
    //+----------------------------------------------------------------------------------------------------------------
    //
    //  BamlNamedElementStartRecord
    //
    //  This is a BamlElementStartRecord that also carries an element name.
    //
    //  This is currently internal, used only for templates.  The original intent for this record was that
    //  it become the new design for named objects; any object with an x:Name set, would have that name
    //  incorporated into the element start record.  But that design did not happen, instead the
    //  property attribute are re-ordered such that the name always immediately follows the element
    //  start record.  So this should be removed, and the template code updated accordingly.  (And in fact,
    //  the template design should be updated so as not to be reliant on naming, as that is too fragile.)
    //
    //+----------------------------------------------------------------------------------------------------------------
#if !PBTCOMPILER
    internal class BamlNamedElementStartRecord : BamlElementStartRecord
    {
#region Methods
 
        #if !PBTCOMPILER
        internal override void  LoadRecordData(BinaryReader bamlBinaryReader)
        {
            TypeId = bamlBinaryReader.ReadInt16();
            RuntimeName = bamlBinaryReader.ReadString();
        }
        #endif
 
        internal override void WriteRecordData(BinaryWriter bamlBinaryWriter)
        {
            bamlBinaryWriter.Write(TypeId);
 
            if( RuntimeName != null )
            {
                bamlBinaryWriter.Write(RuntimeName);
            }
        }
 
#if !PBTCOMPILER
        internal override void Copy(BamlRecord record)
        {
            base.Copy(record);
 
            BamlNamedElementStartRecord newRecord = (BamlNamedElementStartRecord)record;
            newRecord._isTemplateChild = _isTemplateChild;
            newRecord._runtimeName = _runtimeName;
        }
#endif
 
#endregion Methods
 
#region Properties
 
        internal string RuntimeName
        {
            get { return _runtimeName; }
            set { _runtimeName = value; }
        }
 
        // This flag is used by templates to indicate that an ElementStart
        // record is for an object that will be a template child.  We had to add
        // this to allow some validation during template application.  This isn't
        // a good solution, because we shouldn't have this record understanding
        // template children.  But the long-term plan is to break the template design
        // away from a dependence on names, at which point this whole BamlNamedElementStartRecord
        // will go away.
        private bool _isTemplateChild = false;
        internal bool IsTemplateChild
        {
            get { return _isTemplateChild; }
            set { _isTemplateChild = value; }
        }
 
#endregion Properties
 
 
#region Data
 
        // Id of the type of this object
        string _runtimeName = null;
 
#endregion Data
    }
#endif
 
    // Marks a block that has deferable content.  This record contains the size
    // of the deferable section, excluding the start and end records themselves.
    internal class BamlDeferableContentStartRecord : BamlRecord
    {
#region Methods
 
#if !PBTCOMPILER
        internal override void  LoadRecordData(BinaryReader bamlBinaryReader)
        {
            ContentSize = bamlBinaryReader.ReadInt32();
        }
#endif
 
        internal override void WriteRecordData(BinaryWriter bamlBinaryWriter)
        {
            _contentSizePosition = bamlBinaryWriter.Seek(0, SeekOrigin.Current);
            bamlBinaryWriter.Write(ContentSize);
        }
 
        // Update the size of the content contained between the end of the start
        // record and the beginning of the end record.  The size of the content is
        // usually not known when the start record is written out.
        internal void UpdateContentSize(
            Int32         contentSize,
            BinaryWriter  bamlBinaryWriter)
        {
            Debug.Assert(_contentSizePosition != -1,
                    "Must call WriteRecordData before updating content size");
 
            // Use relative positions to reduce the possibility of truncation,
            // since Seek takes a 32 bit int, but position is a 64 bit int.
            Int64 existingPosition = bamlBinaryWriter.Seek(0, SeekOrigin.Current);
            Int32 deltaPosition = (Int32)(_contentSizePosition-existingPosition);
 
            bamlBinaryWriter.Seek(deltaPosition, SeekOrigin.Current);
            bamlBinaryWriter.Write(contentSize);
            bamlBinaryWriter.Seek((int)(-ContentSizeSize-deltaPosition), SeekOrigin.Current);
        }
 
#if !PBTCOMPILER
        internal override void Copy(BamlRecord record)
        {
            base.Copy(record);
 
            BamlDeferableContentStartRecord newRecord = (BamlDeferableContentStartRecord)record;
            newRecord._contentSize = _contentSize;
            newRecord._contentSizePosition = _contentSizePosition;
            newRecord._valuesBuffer = _valuesBuffer;
        }
#endif
 
#endregion Methods
 
#region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.DeferableContentStart; }
        }
 
        internal Int32 ContentSize
        {
            get { return _contentSize; }
#if !PBTCOMPILER
            set { _contentSize = value; }
#endif
        }
 
        internal override Int32 RecordSize
        {
            get { return 4; }
            set { Debug.Assert(value == -1, "Wrong size set for element record"); }
        }
 
#if !PBTCOMPILER
 
        /// <summary>
        /// For the case of a ResourceDictionary inside template content, we read
        /// the dictionary values into a byte array while creating the template
        /// content. Later during template instantiation when the dictionary instance
        /// is created we use this buffer to create a memory stream so that the
        /// ResourceDictionary can use it to RealizeDeferredContent. This is required
        /// because at template instantiation time we do not have a stream to work with.
        /// The reader operates on a linked list of BamlRecords.
        /// </summary>
        internal byte[] ValuesBuffer
        {
            get { return _valuesBuffer; }
            set { _valuesBuffer = value; }
        }
#endif
 
#endregion Properties
 
 
#region Data
 
        // Size of the ContentSize field written out to the baml stream.  This
        // must be kept in sync with the size of the _contentSize field.
        const Int64 ContentSizeSize = 4;
 
        // Size of the content between the end of the start record and the
        // beginning of the end record for this element.
        Int32 _contentSize = - 1;
 
        // Absolute position in the stream where ContentSize is written.
        Int64 _contentSizePosition = -1;
 
#if !PBTCOMPILER
 
        byte[] _valuesBuffer;
 
#endif
 
#endregion Data
    }
 
    //+----------------------------------------------------------------------------------------------------------------
    //
    //  BamlStaticResourceStartRecord
    //
    //  This record marks the start of a StaticResourceExtension within the header for a deferred section.
    //
    //+----------------------------------------------------------------------------------------------------------------
 
    internal class BamlStaticResourceStartRecord : BamlElementStartRecord
    {
#region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.StaticResourceStart; }
        }
 
#endregion Properties
    }
 
    //+----------------------------------------------------------------------------------------------------------------
    //
    //  BamlStaticResourceEndRecord
    //
    //  This record marks the end of a StaticResourceExtension within the header for a deferred section.
    //
    //+----------------------------------------------------------------------------------------------------------------
 
    internal class BamlStaticResourceEndRecord : BamlElementEndRecord
    {
#region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.StaticResourceEnd; }
        }
 
#endregion Properties
    }
 
    //+----------------------------------------------------------------------------------------------------------------
    //
    //  BamlOptimizedStaticResourceRecord
    //
    //  This record represents an optimized StaticResourceExtension within the header for a deferred section.
    //
    //+----------------------------------------------------------------------------------------------------------------
 
    internal class BamlOptimizedStaticResourceRecord : BamlRecord, IOptimizedMarkupExtension
    {
#region Methods
 
#if !PBTCOMPILER
        internal override void LoadRecordData(BinaryReader bamlBinaryReader)
        {
            byte flags = bamlBinaryReader.ReadByte();
            ValueId = bamlBinaryReader.ReadInt16();
 
            IsValueTypeExtension = (flags & TypeExtensionValueMask) != 0;
            IsValueStaticExtension = (flags & StaticExtensionValueMask) != 0;
        }
#endif
 
        internal override void WriteRecordData(BinaryWriter bamlBinaryWriter)
        {
            byte flags = 0;
            if (IsValueTypeExtension)
            {
                flags |= TypeExtensionValueMask;
            }
            else if (IsValueStaticExtension)
            {
                flags |= StaticExtensionValueMask;
            }
            bamlBinaryWriter.Write(flags);
            bamlBinaryWriter.Write(ValueId);
        }
 
#if !PBTCOMPILER
        internal override void Copy(BamlRecord record)
        {
            base.Copy(record);
 
            BamlOptimizedStaticResourceRecord newRecord = (BamlOptimizedStaticResourceRecord)record;
            newRecord._valueId = _valueId;
        }
#endif
 
#endregion Methods
 
#region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.OptimizedStaticResource; }
        }
 
        public short ExtensionTypeId
        {
            get { return (short)KnownElements.StaticResourceExtension; }
        }
 
        // StringId if the value is a string
        // TypeId if the value is a TypeExtension
        // AttributeId of the member if the value is a StaticExtension
        public short ValueId
        {
            get { return _valueId; }
            set { _valueId = value; }
        }
 
        internal override Int32 RecordSize
        {
            get { return 3; }
            set { Debug.Assert(value == -1, "Wrong size set for complex prop record"); }
        }
 
        // If the value is itself a simple TypeExtension
        public bool IsValueTypeExtension
        {
            get { return _flags[_isValueTypeExtensionSection] == 1 ? true : false; }
            set { _flags[_isValueTypeExtensionSection] = value ? 1 : 0; }
        }
 
        // If the value is itself a simple StaticExtension
        public bool IsValueStaticExtension
        {
            get { return _flags[_isValueStaticExtensionSection] == 1 ? true : false; }
            set { _flags[_isValueStaticExtensionSection] = value ? 1 : 0; }
        }
 
#endregion Properties
 
#region Data
 
        short _valueId = 0;
 
        private static readonly byte TypeExtensionValueMask = 0x01;
        private static readonly byte StaticExtensionValueMask = 0x02;
 
        // Allocate space in _flags.
        private static BitVector32.Section _isValueTypeExtensionSection
            = BitVector32.CreateSection(1, BamlRecord.LastFlagsSection);
 
        private static BitVector32.Section _isValueStaticExtensionSection
            = BitVector32.CreateSection(1, _isValueTypeExtensionSection);
 
        // This provides subclasses with a referece section to create their own section.
        internal new static BitVector32.Section LastFlagsSection
        {
            get { return _isValueStaticExtensionSection; }
        }
 
#if !PBTCOMPILER
        public override string ToString()
        {
            return string.Create(CultureInfo.InvariantCulture,
                $"{RecordType} extn(StaticResourceExtension) valueId({_valueId})");
        }
#endif
 
#endregion Data
 
 
    }
 
    //+----------------------------------------------------------------------------------------------------------------
    //
    //  BamlStaticResourceIdRecord
    //
    //  This BamlRecord is an identifier for a StaticResourceExtension within the header for a deferred section.
    //
    //+----------------------------------------------------------------------------------------------------------------
 
    internal class BamlStaticResourceIdRecord : BamlRecord
    {
#region Methods
 
#if !PBTCOMPILER
        internal override void  LoadRecordData(BinaryReader bamlBinaryReader)
        {
            StaticResourceId = bamlBinaryReader.ReadInt16();
        }
#endif
 
        internal override void WriteRecordData(BinaryWriter bamlBinaryWriter)
        {
            bamlBinaryWriter.Write(StaticResourceId);
        }
 
#if !PBTCOMPILER
        internal override void Copy(BamlRecord record)
        {
            base.Copy(record);
 
            BamlStaticResourceIdRecord newRecord = (BamlStaticResourceIdRecord)record;
            newRecord._staticResourceId = _staticResourceId;
        }
#endif
 
#endregion Methods
 
#region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.StaticResourceId; }
        }
 
        internal override Int32 RecordSize
        {
            get { return 2; }
            set { Debug.Assert(value == -1, "Wrong size set for complex prop record"); }
        }
 
        internal short StaticResourceId
        {
            get { return _staticResourceId; }
            set { _staticResourceId = value; }
        }
 
#endregion Properties
 
 
#region Data
 
        short _staticResourceId = -1;
 
#if !PBTCOMPILER
        public override string ToString()
        {
            return string.Create(CultureInfo.InvariantCulture,
                $"{RecordType} staticResourceId({StaticResourceId})");
        }
#endif
 
 
#endregion Data
 
    }
 
    //+----------------------------------------------------------------------------------------------------------------
    //
    //  BamlPropertyWithStaticResourceIdRecord
    //
    //  This BamlRecord represents a BamlPropertyRecord with a StaticResourceId as place holder for
    //  a StaticResourceExtension within a deferred section.
    //
    //+----------------------------------------------------------------------------------------------------------------
 
    internal class BamlPropertyWithStaticResourceIdRecord : BamlStaticResourceIdRecord
    {
#region Methods
 
#if !PBTCOMPILER
        internal override void  LoadRecordData(BinaryReader bamlBinaryReader)
        {
            AttributeId = bamlBinaryReader.ReadInt16();
            StaticResourceId = bamlBinaryReader.ReadInt16();
        }
#endif
 
        internal override void WriteRecordData(BinaryWriter bamlBinaryWriter)
        {
            bamlBinaryWriter.Write(AttributeId);
            bamlBinaryWriter.Write(StaticResourceId);
        }
 
#if !PBTCOMPILER
        internal override void Copy(BamlRecord record)
        {
            base.Copy(record);
 
            BamlPropertyWithStaticResourceIdRecord newRecord = (BamlPropertyWithStaticResourceIdRecord)record;
            newRecord._attributeId = _attributeId;
        }
#endif
 
#endregion Methods
 
#region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.PropertyWithStaticResourceId; }
        }
 
        internal override Int32 RecordSize
        {
            get { return 4; }
            set { Debug.Assert(value == -1, "Wrong size set for complex prop record"); }
        }
 
        // Id of the property whose value is the simple SR
        internal short AttributeId
        {
            get { return _attributeId; }
            set { _attributeId = value; }
        }
 
#endregion Properties
 
#region Data
 
        short _attributeId = -1;
 
#if !PBTCOMPILER
        public override string ToString()
        {
            return string.Create(CultureInfo.InvariantCulture,
                $"{RecordType} attr({AttributeId}) staticResourceId({StaticResourceId})");
        }
#endif
 
#endregion Data
 
    }
 
 
    // Text content between the begin and end tag of an element.
    internal class BamlTextRecord : BamlStringValueRecord
    {
#region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.Text; }
        }
 
#endregion Properties
    }
 
    // This is a text record within a [Static/Dynamic]ResourceExtension.
    internal class BamlTextWithIdRecord : BamlTextRecord
    {
#region Methods
 
#if !PBTCOMPILER
        internal override void  LoadRecordData(BinaryReader bamlBinaryReader)
        {
            ValueId  =  bamlBinaryReader.ReadInt16();
        }
#endif
 
        internal override void WriteRecordData(BinaryWriter bamlBinaryWriter)
        {
            bamlBinaryWriter.Write(ValueId);
        }
 
#if !PBTCOMPILER
        internal override void Copy(BamlRecord record)
        {
            base.Copy(record);
 
            BamlTextWithIdRecord newRecord = (BamlTextWithIdRecord)record;
            newRecord._valueId = _valueId;
        }
#endif
 
#endregion Methods
 
#region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.TextWithId; }
        }
 
        internal Int16 ValueId
        {
            get { return _valueId; }
            set { _valueId = value; }
        }
 
#endregion Properties
 
#region Data
        Int16 _valueId;
#endregion Data
    }
 
    // Text content between the begin and end tag of an element that will be parsed using a type converter.
    internal class BamlTextWithConverterRecord : BamlTextRecord
    {
#region Methods
 
#if !PBTCOMPILER
        internal override void LoadRecordData(BinaryReader bamlBinaryReader)
        {
            base.LoadRecordData(bamlBinaryReader);
            ConverterTypeId  = bamlBinaryReader.ReadInt16();
        }
#endif
 
        internal override void WriteRecordData(BinaryWriter bamlBinaryWriter)
        {
            base.WriteRecordData(bamlBinaryWriter);
            bamlBinaryWriter.Write(ConverterTypeId);
        }
 
#if !PBTCOMPILER
        internal override void Copy(BamlRecord record)
        {
            base.Copy(record);
 
            BamlTextWithConverterRecord newRecord = (BamlTextWithConverterRecord)record;
            newRecord._converterTypeId = _converterTypeId;
        }
#endif
 
#endregion Methods
 
#region Properties
 
        // The following are stored in the baml stream
 
        // ID of this type converter.  Referenced in other baml records where a
        // Type is needed.
        internal short ConverterTypeId
        {
            get { return _converterTypeId; }
            set { _converterTypeId = value; }
        }
 
        // Additional properties not stored in the baml stream
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.TextWithConverter; }
        }
 
#endregion Properties
 
#region Data
 
        short _converterTypeId = 0;
 
#endregion Data
    }
 
    // Marks the start of a Baml document.  This must always be the first
    // record in a BAML stream.   It contains version information, and other
    // document wide directives.
    internal class BamlDocumentStartRecord : BamlRecord
    {
#region Methods
 
        // Writes data at the current position.  The seek pointer points
        // to byte after the end of record when done.
        internal override void Write(BinaryWriter bamlBinaryWriter)
        {
            // Remember the file location of this baml record.  This
            // is needed if we have to come back later to update the sync mode.
            if (FilePos == -1 && bamlBinaryWriter != null)
            {
                FilePos = bamlBinaryWriter.Seek(0,SeekOrigin.Current);
            }
 
            base.Write(bamlBinaryWriter);
        }
 
        // Adjust seeks pointer to this Record and updates the data.
        // Then sets seek pointer pack to original.
        // NOTE:  This will ONLY work for file sizes under 2 gig.  This is
        //        not a problem for current useage, since this is mostly used
        //        when updating LoadAsync attribute on the DocumentStart record,
        //        which is usually set on the first element in the xaml file.
        internal virtual void UpdateWrite(BinaryWriter bamlBinaryWriter)
        {
            // default implementation, class should override if
            // wants to optimize to only update dirty data.
            long currentPosiition = bamlBinaryWriter.Seek(0,SeekOrigin.Current);
 
            // seek to original record position.
 
            Debug.Assert(FilePos != -1,"UpdateWrite called but Write Never was");
 
            // Note: This only works for files up to 2 gig in length.
            //       This is not a new restriction, but it should be
            //       fixed to work with larger files...
            bamlBinaryWriter.Seek((int)FilePos,SeekOrigin.Begin);
            Write(bamlBinaryWriter);
            bamlBinaryWriter.Seek( (int) currentPosiition,SeekOrigin.Begin);
        }
 
#if !PBTCOMPILER
        internal override void  LoadRecordData(BinaryReader bamlBinaryReader)
        {
            LoadAsync =  bamlBinaryReader.ReadBoolean();
            MaxAsyncRecords =  bamlBinaryReader.ReadInt32();
            DebugBaml = bamlBinaryReader.ReadBoolean();
        }
#endif
 
        internal override void WriteRecordData(BinaryWriter bamlBinaryWriter)
        {
            bamlBinaryWriter.Write(LoadAsync);
            bamlBinaryWriter.Write(MaxAsyncRecords);
            bamlBinaryWriter.Write(DebugBaml);
        }
 
#if !PBTCOMPILER
        internal override void Copy(BamlRecord record)
        {
            base.Copy(record);
 
            BamlDocumentStartRecord newRecord = (BamlDocumentStartRecord)record;
            newRecord._maxAsyncRecords = _maxAsyncRecords;
            newRecord._loadAsync = _loadAsync;
            newRecord._filePos = _filePos;
            newRecord._debugBaml = _debugBaml;
        }
#endif
 
#endregion Methods
 
#region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.DocumentStart; }
        }
 
        internal bool LoadAsync
        {
            get { return _loadAsync; }
#if !PBTCOMPILER
            set { _loadAsync = value; }
#endif
        }
 
        internal int MaxAsyncRecords
        {
            get { return _maxAsyncRecords; }
            set { _maxAsyncRecords = value; }
        }
 
        // Position in the baml file stream
        internal long FilePos
        {
            get { return _filePos; }
            set { _filePos  = value; }
        }
 
        // Are there Debug Baml Records in this Baml Stream
        internal bool DebugBaml
        {
            get { return _debugBaml; }
            set { _debugBaml  = value; }
        }
 
#endregion Properties
 
#region Data
        int         _maxAsyncRecords  = -1;
        bool        _loadAsync = false;
        long        _filePos = -1;
        bool        _debugBaml = false;
#endregion Data
    }
 
    // This marks the end tag of an element
    internal class BamlElementEndRecord : BamlRecord
    {
#region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.ElementEnd; }
        }
 
#endregion Properties
    }
 
    // This marks the start tag of an element being used as the key for an IDictionary
    internal class BamlKeyElementStartRecord : BamlDefAttributeKeyTypeRecord, IBamlDictionaryKey
    {
        internal BamlKeyElementStartRecord()
        {
            Pin(); // Don't allow this record to be recycled in the read cache.
        }
 
#region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.KeyElementStart; }
        }
 
#endregion Properties
    }
 
    // This marks the end tag of an element being used as the key for an IDictionary
    internal class BamlKeyElementEndRecord : BamlElementEndRecord
    {
#region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.KeyElementEnd; }
        }
 
#endregion Properties
    }
 
    // This marks the end of the baml stream, or document.
    internal class BamlDocumentEndRecord : BamlRecord
    {
#region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.DocumentEnd; }
        }
 
#endregion Properties
    }
 
    // The following records are used internally in the baml stream to
    // define attribute (eg - property), type and assembly information
    // for records that follow later on in the stream.  They are never
    // publically exposed
 
    // Information about an assembly where a type is defined
    internal class BamlAssemblyInfoRecord : BamlVariableSizedRecord
    {
        internal BamlAssemblyInfoRecord()
        {
            Pin(); // Don't allow this record to be recycled in the read cache.
            AssemblyId = -1;
        }
 
#region Methods
 
#if !PBTCOMPILER
        // LoadRecord specific data
        internal override void  LoadRecordData(BinaryReader bamlBinaryReader)
        {
            AssemblyId       =  bamlBinaryReader.ReadInt16();
            AssemblyFullName =  bamlBinaryReader.ReadString();
        }
#endif
 
        // write record specific Data.
        internal override void WriteRecordData(BinaryWriter bamlBinaryWriter)
        {
            // write out an int for record size but we'll go back and fill
            bamlBinaryWriter.Write(AssemblyId);
            bamlBinaryWriter.Write(AssemblyFullName);
        }
 
#if !PBTCOMPILER
        internal override void Copy(BamlRecord record)
        {
            base.Copy(record);
 
            BamlAssemblyInfoRecord newRecord = (BamlAssemblyInfoRecord)record;
            newRecord._assemblyFullName = _assemblyFullName;
            newRecord._assembly = _assembly;
        }
#endif
 
#endregion Methods
 
#region Properties
 
        // The following are stored in the baml stream
 
        // ID of this assembly
        internal short AssemblyId
        {
            get
            {
                short value = (short) _flags[_assemblyIdLowSection];
                value |= (short) (_flags[_assemblyIdHighSection] << 8);
 
                return value;
            }
 
            set
            {
                _flags[_assemblyIdLowSection] = (short)  (value & 0xff);
                _flags[_assemblyIdHighSection] = (short) ((value & 0xff00) >> 8);
            }
        }
 
        // Allocate space in _flags.
        // BitVector32 doesn't support 16 bit sections, so we have to break
        // it up into 2 sections.
 
        private static BitVector32.Section _assemblyIdLowSection
            = BitVector32.CreateSection( (short)0xff, BamlVariableSizedRecord.LastFlagsSection );
 
        private static BitVector32.Section _assemblyIdHighSection
            = BitVector32.CreateSection( (short)0xff, _assemblyIdLowSection );
 
#if !PBTCOMPILER
        // This provides subclasses with a referece section to create their own section.
        internal new static BitVector32.Section LastFlagsSection
        {
            get { return _assemblyIdHighSection; }
        }
#endif
 
        // Full name of this assembly, excluding any suffix.  This has
        // the format "AssemblyName, Version, Culture, PublicKeyToken" when we
        // have a true full name.  Sometimes we aren't given the full assembly
        // name, in which case the full name is the same as the short name.
        internal string AssemblyFullName
        {
            get { return _assemblyFullName; }
            set { _assemblyFullName = value; }
        }
 
        // The following are not part of the BAML stream
 
        // Identify type of record
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.AssemblyInfo; }
        }
 
        // The actual loaded assembly
        internal Assembly Assembly
        {
            get { return _assembly; }
            set { _assembly = value; }
        }
 
 
#endregion Properties
 
 
#region Data
 
        string   _assemblyFullName;
        Assembly _assembly;
 
#endregion Data
    }
 
    // Information about a type for an element, object or property
    internal class BamlTypeInfoRecord : BamlVariableSizedRecord
    {
        internal BamlTypeInfoRecord()
        {
            Pin(); // Don't allow this record to be recycled in the read cache.
            TypeId = -1;
        }
 
#region Methods
 
#if !PBTCOMPILER
        // LoadRecord specific data
        internal override void  LoadRecordData(BinaryReader bamlBinaryReader)
        {
            TypeId       =   bamlBinaryReader.ReadInt16();
            AssemblyId   =   bamlBinaryReader.ReadInt16();
            TypeFullName =   bamlBinaryReader.ReadString();
 
            // Note that the upper 4 bits of the AssemblyId are used for flags
            _typeInfoFlags = (TypeInfoFlags)(AssemblyId >> 12);
            _assemblyId &= 0x0FFF;
        }
#endif
 
        // write record specific Data.
        internal override void WriteRecordData(BinaryWriter bamlBinaryWriter)
        {
            // write out an int for record size but we'll go back and fill
            bamlBinaryWriter.Write(TypeId);
            // Note that the upper 4 bits of the AssemblyId are used for flags
            bamlBinaryWriter.Write((short)(((ushort)AssemblyId) | (((ushort)_typeInfoFlags) << 12)));
            bamlBinaryWriter.Write(TypeFullName);
        }
 
#if !PBTCOMPILER
        internal override void Copy(BamlRecord record)
        {
            base.Copy(record);
 
            BamlTypeInfoRecord newRecord = (BamlTypeInfoRecord)record;
            newRecord._typeInfoFlags = _typeInfoFlags;
            newRecord._assemblyId = _assemblyId;
            newRecord._typeFullName = _typeFullName;
            newRecord._type = _type;
        }
#endif
 
#endregion Methods
 
#region Properties
 
        // The following are stored in the baml stream
 
        // ID of this type.  Refenced in other baml records where a
        // Type is needed.
        internal short TypeId
        {
            get
            {
                short value = (short) _flags[_typeIdLowSection];
                value |= (short) (_flags[_typeIdHighSection] << 8);
 
                return value;
            }
 
            set
            {
                _flags[_typeIdLowSection] = (short)  (value & 0xff);
                _flags[_typeIdHighSection] = (short) ((value & 0xff00) >> 8);
            }
        }
 
        // Assembly id of the assembly where this type is defined.
        // NOTE:  This is always positive in BAML files, but can be set
        //        to -1 for known types when created programmatically.
        internal short AssemblyId
        {
            get { return _assemblyId; }
            set
            {
                // Make sure we don't intrude on the Flags portion of the assembly ID
                if (_assemblyId > 0x0FFF)
                {
                    throw new XamlParseException(SR.ParserTooManyAssemblies);
                }
                _assemblyId = value;
            }
        }
 
        // Fully qualified name of type, including namespace
        internal string TypeFullName
        {
            get { return _typeFullName; }
            set { _typeFullName = value; }
        }
 
        // Additional properties not stored in the baml stream
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.TypeInfo; }
        }
 
#if !PBTCOMPILER
        // Actual type.  Filled in here when xaml is used to create
        // a tree, and the token reader knows the type
        internal Type Type
        {
            get { return _type; }
            set { _type = value; }
        }
 
        // Extract the namespace from the type full name and return
        // it.  We are assuming here that the type full name has a single
        // classname at the end and we are not refering to a nested class...
        internal string ClrNamespace
        {
            get
            {
                int periodIndex = _typeFullName.LastIndexOf('.');
                return periodIndex > 0 ?
                            _typeFullName.Substring(0, periodIndex) :
                            string.Empty;
            }
        }
#endif
 
        // True if there is a serializer associated with this type
        internal virtual bool HasSerializer
        {
            get { return false; }
        }
 
        internal bool IsInternalType
        {
#if !PBTCOMPILER
            get
            {
                return ((_typeInfoFlags & TypeInfoFlags.Internal) == TypeInfoFlags.Internal);
            }
#endif
 
            set
            {
                // Don't allow resetting to false (i.e. converting back top public if
                // it becomes non-public, for added safety.
                if (value)
                {
                    _typeInfoFlags |= TypeInfoFlags.Internal;
                }
            }
        }
 
#endregion Properties
 
#region Data
 
        // Allocate space in _flags.
        // BitVector32 doesn't support 16 bit sections, so we have to break
        // it up into 2 sections.
 
        private static BitVector32.Section _typeIdLowSection
            = BitVector32.CreateSection( (short)0xff, BamlVariableSizedRecord.LastFlagsSection );
 
        private static BitVector32.Section _typeIdHighSection
            = BitVector32.CreateSection( (short)0xff, _typeIdLowSection );
 
#if !PBTCOMPILER
        // This provides subclasses with a referece section to create their own section.
        internal new static BitVector32.Section LastFlagsSection
        {
            get { return _typeIdHighSection; }
        }
#endif
 
 
        // Flags contained in TypeInfo that give additional information
        // about the type that is determined at compile time.
        [Flags]
        private enum TypeInfoFlags : byte
        {
            Internal             = 0x1,
            UnusedTwo            = 0x2,
            UnusedThree          = 0x4,
        }
 
        TypeInfoFlags _typeInfoFlags = 0;
        short         _assemblyId = -1;
        string        _typeFullName;
#if !PBTCOMPILER
        Type          _type;
#endif
 
#endregion Data
 
 
    }
 
    // Type info record for a type that has a custom serializer associated with it.
    // This gives the serializer type that will be used when deserializing this type
    internal class BamlTypeInfoWithSerializerRecord : BamlTypeInfoRecord
    {
        internal BamlTypeInfoWithSerializerRecord()
        {
            Pin(); // Don't allow this record to be recycled in the read cache.
        }
 
#region Methods
 
#if !PBTCOMPILER
        // LoadRecord specific data
        internal override void  LoadRecordData(BinaryReader bamlBinaryReader)
        {
            base.LoadRecordData(bamlBinaryReader);
            SerializerTypeId  =   bamlBinaryReader.ReadInt16();
        }
#endif
 
        // write record specific Data.
        internal override void WriteRecordData(BinaryWriter bamlBinaryWriter)
        {
            base.WriteRecordData(bamlBinaryWriter);
            bamlBinaryWriter.Write(SerializerTypeId);
        }
 
#if !PBTCOMPILER
        internal override void Copy(BamlRecord record)
        {
            base.Copy(record);
 
            BamlTypeInfoWithSerializerRecord newRecord = (BamlTypeInfoWithSerializerRecord)record;
            newRecord._serializerTypeId = _serializerTypeId;
            newRecord._serializerType = _serializerType;
        }
#endif
 
#endregion Methods
 
#region Properties
 
        // The following are stored in the baml stream
 
        // ID of this type.  Refenced in other baml records where a
        // Type is needed.
        internal short SerializerTypeId
        {
            get { return _serializerTypeId; }
            set { _serializerTypeId = value; }
        }
 
        // Additional properties not stored in the baml stream
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.TypeSerializerInfo; }
        }
 
#if !PBTCOMPILER
        // Actual type of associated serializer.  Filled in here when xaml is used to create
        // a tree, and the token reader knows the type of the serializer, or
        // when we are reading the baml file and have determined the
        // serializer type.
        internal Type SerializerType
        {
            get { return _serializerType; }
            set { _serializerType = value; }
        }
#endif
 
        // True if there is a serializer associated with this type.  A serializer
        // will never be the first type object in a baml file, so its type ID will
        // never be 0.  Any other ID indicates we have a serializer.
        internal override bool HasSerializer
        {
            get
            {
                Debug.Assert( SerializerTypeId != 0 );
                return true;
            }
        }
 
#endregion Properties
 
#region Data
 
        short _serializerTypeId = 0;
#if !PBTCOMPILER
        Type _serializerType;
#endif
 
#endregion Data
 
    }
 
    // Used for mapping properties and events to an owner type, given the
    // name of the attribute.  Note that Attribute is used for historical
    // reasons and for similarities to Xml attributes.  For us attributes
    // are just properties and events.
    internal class BamlAttributeInfoRecord : BamlVariableSizedRecord
    {
        internal BamlAttributeInfoRecord()
        {
            Pin(); // Don't allow this record to be recycled in the read cache.
            AttributeUsage = BamlAttributeUsage.Default;
        }
 
#region Methods
 
#if !PBTCOMPILER
        // LoadRecord specific data
        internal override void  LoadRecordData(BinaryReader bamlBinaryReader)
        {
            AttributeId  =   bamlBinaryReader.ReadInt16();
            OwnerTypeId  =   bamlBinaryReader.ReadInt16();
            AttributeUsage = (BamlAttributeUsage)bamlBinaryReader.ReadByte();
            Name  =          bamlBinaryReader.ReadString();
        }
#endif
 
        // write record specific Data.
        internal override void WriteRecordData(BinaryWriter bamlBinaryWriter)
        {
            // write out an int for record size but we'll go back and fill
            bamlBinaryWriter.Write(AttributeId);
            bamlBinaryWriter.Write(OwnerTypeId);
            bamlBinaryWriter.Write((Byte)AttributeUsage);
            bamlBinaryWriter.Write(Name);
        }
 
#if !PBTCOMPILER
        internal override void Copy(BamlRecord record)
        {
            base.Copy(record);
 
            BamlAttributeInfoRecord newRecord = (BamlAttributeInfoRecord)record;
            newRecord._ownerId = _ownerId;
            newRecord._attributeId = _attributeId;
            newRecord._name = _name;
            newRecord._ownerType = _ownerType;
            newRecord._Event = _Event;
            newRecord._dp = _dp;
            newRecord._ei = _ei;
            newRecord._pi = _pi;
            newRecord._smi = _smi;
            newRecord._gmi = _gmi;
            newRecord._dpOrMiOrPi = _dpOrMiOrPi;
        }
#endif
 
#endregion Methods
 
#region Properties
 
        // The following 3 properties are stored in the Baml file and are read and
        // written by the BamlRecordReader and BamlXamlNodeWriter
 
        internal short OwnerTypeId
        {
            get { return _ownerId; }
            set { _ownerId = value; }
        }
 
        internal short AttributeId
        {
            set { _attributeId = value; }
            get { return _attributeId; }
        }
 
        internal string Name
        {
            get { return _name; }
            set { _name = value; }
        }
 
        // The following properties are derived at runtime from the above 3 properties using
        // the Mapper.  Which are set depends on the attribute and the context in which it is
        // used.
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.AttributeInfo; }
        }
 
#if !PBTCOMPILER
        // Return type of property.  Note that this uses the same logic as
        // Mapper.GetPropertyType but uses the cached values of DP, PropInfo
        // and AttachedPropertySetter.
        internal Type GetPropertyType()
        {
            Type validType = null;
            DependencyProperty dp = DP;
            if (dp == null)
            {
                MethodInfo methodInfo = AttachedPropertySetter;
                if (methodInfo == null)
                {
                    PropertyInfo propInfo = PropInfo;
                    validType = propInfo.PropertyType;
                }
                else
                {
                    ParameterInfo[] paramInfo = methodInfo.GetParameters();
                    validType = paramInfo[1].ParameterType;
                }
            }
            else
            {
                validType = dp.PropertyType;
            }
            return validType;
        }
#endif
 
        /// <summary>
        /// Set the PropertyMember, which can is assumed to be a MethodInfo for
        /// the static setter method for a DP or a PropertyInfo for the clr property
        /// </summary>
        /// <remarks>
        /// The possibility of having multiple member info cached for an attribute is when a
        /// dependency property that does not belong to the default namespace is used in once
        /// in a once with a namespace prefix and once without it. When it has a namespace
        /// prefix we correctly find the dependency property for it. However when it does not
        /// have a namespace prefix it the parser tries to look it up in the default namespace
        /// and falls back to using the clr wrapper's property info for it instead. Another
        /// scenario that requires caching more than one property info is when a dependency
        /// property has both a static settor and a clr wrapper.
        /// </remarks>
        internal void SetPropertyMember (object propertyMember)
        {
            Debug.Assert((propertyMember is MethodInfo) || (propertyMember is PropertyInfo)
                        || (KnownTypes.Types[(int)KnownElements.DependencyProperty].IsAssignableFrom(propertyMember.GetType())),
                "Cache can hold either a MethodInfo and/or a PropertyInfo and/or a DependencyProperty for a given attribute");
 
            if (PropertyMember == null)
            {
                PropertyMember = propertyMember;
            }
            else
            {
                // Cache a additional MemberInfo for the given attribute
                object[] arr = PropertyMember as object[];
                if (arr == null)
                {
                    arr = new object[3];
                    arr[0] = PropertyMember;
                    arr[1] = propertyMember;
                }
                else
                {
                    Debug.Assert(arr.Length == 3 && arr[0] != null && arr[1] != null);
                    arr[2] = propertyMember;
                }
            }
        }
 
        /// <summary>
        /// Return the PropertyMember, which can is assumed to be a MethodInfo for
        /// the static setter method for a DP or a PropertyInfo for the clr property
        /// </summary>
        /// <remarks>
        /// The possibility of having multiple member info cached for an attribute is when a
        /// dependency property that does not belong to the default namespace is used in once
        /// in a once with a namespace prefix and once without it. When it has a namespace
        /// prefix we correctly find the dependency property for it. However when it does not
        /// have a namespace prefix it the parser tries to look it up in the default namespace
        /// and falls back to using the clr wrapper's property info for it instead. Another
        /// scenario that requires caching more than one property info is when a dependency
        /// property has both a static settor and a clr wrapper.
        /// </remarks>
        internal object GetPropertyMember(bool onlyPropInfo)
        {
            if (PropertyMember == null ||
                PropertyMember is MemberInfo ||
                KnownTypes.Types[(int)KnownElements.DependencyProperty].IsAssignableFrom(PropertyMember.GetType( )) )
            {
                if (onlyPropInfo)
                {
#if PBTCOMPILER
                    return PropertyMember as PropertyInfo;
#else
                    return PropInfo;
#endif
                }
                else
                {
                    return PropertyMember;
                }
            }
            else
            {
                // The attribute has multiple member info. Choose which one to return.
                object[] arr = (object[])PropertyMember;
                Debug.Assert(arr.Length == 3 && arr[0] != null && arr[1] != null);
 
                // If someone queries any MemberInfo for the given attribute then we return the
                // first member info cached for it. If they are looking specifically for a
                // PropertyInfo we try and find them one.
                if (onlyPropInfo)
                {
                    if (arr[0] is PropertyInfo)
                    {
                        return (PropertyInfo)arr[0];
                    }
                    else if (arr[1] is PropertyInfo)
                    {
                        return (PropertyInfo)arr[1];
                    }
                    else
                    {
                        return arr[2] as PropertyInfo;
                    }
                }
                else
                {
                    return arr[0];
                }
            }
        }
 
        // Cached value of the DependencyProperty, MethodInfo for the static setter
        // method, or the PropertyInfo for a given property.  If this is an
        // event, then this is null.
        internal object PropertyMember
        {
            get { return _dpOrMiOrPi; }
            set { _dpOrMiOrPi = value; }
        }
 
#if !PBTCOMPILER
 
        // The cached type of the owner or declarer of this property
        internal Type OwnerType
        {
            get { return _ownerType; }
            set { _ownerType = value; }
        }
 
        // Cached value of the routed event id, if this attribute is for a
        // routed event.  If not a routed event, this is null.
        internal RoutedEvent Event
        {
            get {  return _Event; }
            set { _Event = value; }
        }
 
        // Cached value of DP, if available
        internal DependencyProperty DP
        {
            get
            {
                if (null != _dp)
                    return _dp;
                else
                    return _dpOrMiOrPi as DependencyProperty;
            }
            set
            {
                _dp = value;
                if (_dp != null)
                {
                    // Release the other copy of the string
                    _name = _dp.Name;
                }
            }
        }
 
        // Cached value of static property setter method info, if available
        internal MethodInfo AttachedPropertySetter
        {
            get
            {
                return _smi;
            }
 
            set
            {
                _smi = value;
            }
        }
 
        // Cached value of static property getter method info, if available
        internal MethodInfo AttachedPropertyGetter
        {
            get
            {
                return _gmi;
            }
 
            set
            {
                _gmi = value;
            }
        }
 
        // Cached value of EventInfo, if available
        internal EventInfo EventInfo
        {
            get { return _ei; }
            set { _ei = value; }
        }
 
        // Cached value of PropertyInfo, if available
        internal PropertyInfo PropInfo
        {
            get
            {
                return _pi;
            }
            set { _pi = value; }
        }
 
        internal bool IsInternal
        {
            get
            {
                return _flags[_isInternalSection] == 1 ? true : false;
            }
 
            set
            {
                _flags[_isInternalSection] = value ? 1 : 0;
            }
        }
#endif
 
        // Some attributes have special usage, such as setting the XmlLang and XmlSpace
        // strings in the parser context.  This is flagged with this property
        internal BamlAttributeUsage AttributeUsage
        {
            get
            {
                return (BamlAttributeUsage) _flags[_attributeUsageSection];
            }
 
            set
            {
                _flags[_attributeUsageSection] = (int) value;
            }
        }
 
 
        // Allocate space in _flags.
 
        private static BitVector32.Section _isInternalSection
            = BitVector32.CreateSection( 1, BamlVariableSizedRecord.LastFlagsSection );
 
        private static BitVector32.Section _attributeUsageSection
            = BitVector32.CreateSection( 3, _isInternalSection );
 
#if !PBTCOMPILER
        // This provides subclasses with a referece section to create their own section.
        internal new static BitVector32.Section LastFlagsSection
        {
            get { return _attributeUsageSection; }
        }
#endif
 
#endregion Properties
 
#if !PBTCOMPILER
        public override string ToString()
        {
            return string.Create(CultureInfo.InvariantCulture,
                                 $"{RecordType} owner={GetTypeName(OwnerTypeId)} attr({AttributeId}) is '{_name}'");
        }
#endif
 
#region Data
 
        short _ownerId;
        short _attributeId;
        string _name;
 
#if !PBTCOMPILER
        Type               _ownerType = null;
        RoutedEvent        _Event = null;
        DependencyProperty _dp = null;
        EventInfo          _ei = null;
        PropertyInfo       _pi = null;
        MethodInfo         _smi = null;
        MethodInfo         _gmi = null;
#endif
 
        object             _dpOrMiOrPi = null;   // MethodInfo, PropertyInfo or DependencyProperty
 
#endregion Data
    }
 
    // Information about a String that is an entry in the String table.
    internal class BamlStringInfoRecord : BamlVariableSizedRecord
    {
        internal BamlStringInfoRecord()
        {
            Pin(); // Don't allow this record to be recycled in the read cache.
            StringId = -1;
        }
 
#region Methods
 
#if !PBTCOMPILER
        // LoadRecord specific data
        internal override void LoadRecordData(BinaryReader bamlBinaryReader)
        {
            StringId = bamlBinaryReader.ReadInt16();
            Value    = bamlBinaryReader.ReadString();
        }
#endif
 
        // write record specific Data.
        internal override void WriteRecordData(BinaryWriter bamlBinaryWriter)
        {
            // write out an int for string Id
            bamlBinaryWriter.Write(StringId);
            bamlBinaryWriter.Write(Value);
        }
 
#if !PBTCOMPILER
        internal override void Copy(BamlRecord record)
        {
            base.Copy(record);
 
            BamlStringInfoRecord newRecord = (BamlStringInfoRecord)record;
            newRecord._value = _value;
        }
#endif
 
#endregion Methods
 
#region Properties
        // Resource Identifier pointing to the StringTable Entry
        internal short StringId
        {
            get
            {
                short value = (short) _flags[_stringIdLowSection];
                value |= (short) (_flags[_stringIdHighSection] << 8);
 
                return value;
            }
 
            set
            {
                _flags[_stringIdLowSection] = (short)  (value & 0xff);
                _flags[_stringIdHighSection] = (short) ((value & 0xff00) >> 8);
            }
        }
 
        // Resource String
        internal string Value
        {
            get { return _value; }
            set { _value = value; }
        }
 
        // Additional properties not stored in the baml stream
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.StringInfo; }
        }
 
        // True if there is a serializer associated with this type
        internal virtual bool HasSerializer
        {
            get { return false; }
        }
#endregion Properties
 
#if !PBTCOMPILER
        public override string ToString()
        {
            return string.Create(CultureInfo.InvariantCulture,
                                 $"{RecordType} stringId({StringId}='{_value}'");
        }
#endif
 
#region Data
 
 
        // Allocate space in _flags.
        // BitVector32 doesn't support 16 bit sections, so we have to break
        // it up into 2 sections.
 
        private static BitVector32.Section _stringIdLowSection
            = BitVector32.CreateSection( (short)0xff, BamlVariableSizedRecord.LastFlagsSection );
 
        private static BitVector32.Section _stringIdHighSection
            = BitVector32.CreateSection( (short)0xff, _stringIdLowSection );
 
#if !PBTCOMPILER
        // This provides subclasses with a referece section to create their own section.
        internal new static BitVector32.Section LastFlagsSection
        {
            get { return _stringIdHighSection; }
        }
#endif
 
        string _value ;
#endregion Data
    }
 
    // Sets the content property context for an element
    internal class BamlContentPropertyRecord : BamlRecord
    {
        #region Methods
 
#if !PBTCOMPILER
        // LoadRecord specific data
        internal override void LoadRecordData(BinaryReader bamlBinaryReader)
        {
            AttributeId = bamlBinaryReader.ReadInt16();
        }
#endif
 
        // write record specific Data.
        internal override void WriteRecordData(BinaryWriter bamlBinaryWriter)
        {
            // write out an int for attribute Id
            bamlBinaryWriter.Write(AttributeId);
        }
 
#if !PBTCOMPILER
        internal override void Copy(BamlRecord record)
        {
            base.Copy(record);
 
            BamlContentPropertyRecord newRecord = (BamlContentPropertyRecord)record;
            newRecord._attributeId = _attributeId;
        }
#endif
 
        #endregion Methods
 
        #region Properties
        // Id of the property being set as the context
        internal short AttributeId
        {
            get { return _attributeId; }
            set { _attributeId = value; }
        }
 
        // Additional properties not stored in the baml stream
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.ContentProperty; }
        }
 
        // True if there is a serializer associated with this type
        internal virtual bool HasSerializer
        {
            get { return false; }
        }
        #endregion Properties
 
        #region Data
        short _attributeId = -1;
        #endregion Data
    }
 
 
    // Debugging Linenumber record.  Linenumber from the XAML
    internal class BamlLineAndPositionRecord : BamlRecord
    {
#region Methods
 
#if !PBTCOMPILER
        internal override void  LoadRecordData(BinaryReader bamlBinaryReader)
        {
            LineNumber = (uint) bamlBinaryReader.ReadInt32();
            LinePosition = (uint) bamlBinaryReader.ReadInt32();
        }
#endif
 
        internal override void WriteRecordData(BinaryWriter bamlBinaryWriter)
        {
            bamlBinaryWriter.Write(LineNumber);
            bamlBinaryWriter.Write(LinePosition);
        }
 
#if !PBTCOMPILER
        internal override void Copy(BamlRecord record)
        {
            base.Copy(record);
 
            BamlLineAndPositionRecord newRecord = (BamlLineAndPositionRecord)record;
            newRecord._lineNumber = _lineNumber;
            newRecord._linePosition = _linePosition;
        }
#endif
 
#endregion Methods
 
#region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.LineNumberAndPosition; }
        }
 
        // Id of the type of this object
        internal uint LineNumber
        {
            get { return _lineNumber; }
            set { _lineNumber = value; }
        }
 
        internal uint LinePosition
        {
            get { return _linePosition; }
            set { _linePosition = value; }
        }
 
        internal override Int32 RecordSize
        {
            get { return 8; }
        }
 
        uint _lineNumber;
        uint _linePosition;
 
#endregion Properties
 
#if !PBTCOMPILER
        public override string ToString()
        {
            return string.Create(CultureInfo.InvariantCulture,
                $"{RecordType} LineNum={LineNumber} Pos={LinePosition}");
        }
#endif
    }
 
 
    // Debugging Line Position record.  Line Position from the XAML
    internal class BamlLinePositionRecord : BamlRecord
    {
#region Methods
 
#if !PBTCOMPILER
        internal override void  LoadRecordData(BinaryReader bamlBinaryReader)
        {
            LinePosition = (uint) bamlBinaryReader.ReadInt32();
        }
#endif
 
        internal override void WriteRecordData(BinaryWriter bamlBinaryWriter)
        {
            bamlBinaryWriter.Write(LinePosition);
        }
 
#if !PBTCOMPILER
        internal override void Copy(BamlRecord record)
        {
            base.Copy(record);
 
            BamlLinePositionRecord newRecord = (BamlLinePositionRecord)record;
            newRecord._linePosition = _linePosition;
        }
#endif
 
#endregion Methods
 
#region Properties
 
        internal override BamlRecordType RecordType
        {
            get { return BamlRecordType.LinePosition; }
        }
 
        internal uint LinePosition
        {
            get { return _linePosition; }
            set { _linePosition = value; }
        }
 
        internal override Int32 RecordSize
        {
            get { return 4; }
        }
 
        uint _linePosition;
 
#endregion Properties
 
#if !PBTCOMPILER
        public override string ToString()
        {
            return string.Create(CultureInfo.InvariantCulture,
                $"{RecordType} LinePos={LinePosition}");
        }
#endif
    }
}