ObjectStateFormatter.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / whidbey / NetFXspW7 / ndp / fx / src / xsp / System / Web / UI / ObjectStateFormatter.cs / 1 / ObjectStateFormatter.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

namespace System.Web.UI { 
 
    using System;
    using System.Collections; 
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.ComponentModel;
    using System.Drawing; 
    using System.IO;
    using System.Globalization; 
    using System.Reflection; 
    using System.Runtime.Serialization;
    using System.Runtime.Serialization.Formatters.Binary; 
    using System.Security;
    using System.Security.Permissions;
    using System.Text;
    using System.Web.Compilation; 
    using System.Web.Configuration;
    using System.Web.Util; 
    using System.Web.Management; 
    using System.Web.UI.WebControls;
 
    //


 
    /// 
    /// ObjectStateFormatter is designed to efficiently serialize arbitrary object graphs 
    /// that represent the state of an object (decomposed into simpler types) into 
    /// a highly compact binary or ASCII representations.
    /// The formatter contains native support for optimized serialization of a fixed 
    /// set of known types such as ints, shorts, booleans, strings, other primitive types
    /// arrays, Pairs, Triplets, ArrayLists, Hashtables etc. In addition it utilizes
    /// TypeConverters for semi-optimized serialization of custom types. Finally, it uses
    /// binary serialization as a fallback mechanism. The formatter is also able to compress 
    /// IndexedStrings contained in the object graph.
    ///  
    [AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)] 
    public sealed class ObjectStateFormatter : IStateFormatter, IFormatter {
 
        // Optimized type tokens
        private const byte Token_Int16 = 1;
        private const byte Token_Int32 = 2;
        private const byte Token_Byte = 3; 
        private const byte Token_Char = 4;
        private const byte Token_String = 5; 
        private const byte Token_DateTime = 6; 
        private const byte Token_Double = 7;
        private const byte Token_Single = 8; 
        private const byte Token_Color = 9;
        private const byte Token_KnownColor = 10;
        private const byte Token_IntEnum = 11;
        private const byte Token_EmptyColor = 12; 
        private const byte Token_Pair = 15;
        private const byte Token_Triplet = 16; 
        private const byte Token_Array = 20; 
        private const byte Token_StringArray = 21;
        private const byte Token_ArrayList = 22; 
        private const byte Token_Hashtable = 23;
        private const byte Token_HybridDictionary = 24;
        private const byte Token_Type = 25;
        // private const byte Token_Nullable = 26; Removed per DevDiv 165426 
        // Background: Used to support nullables as a special case, CLR added support for this
        // but they forgot to remove the deserialization code when they removed the support 
        // potentially Beta2 customers could have serialized data (WebParts) which have this token. 
        // We removed support since this was broken anyways in RTM.
        private const byte Token_Unit = 27; 
        private const byte Token_EmptyUnit = 28;

        // String-table optimized strings
        private const byte Token_IndexedStringAdd = 30; 
        private const byte Token_IndexedString = 31;
 
        // Semi-optimized (TypeConverter-based) 
        private const byte Token_StringFormatted = 40;
 
        // Semi-optimized (Types)
        private const byte Token_TypeRefAdd = 41;
        private const byte Token_TypeRefAddLocal = 42;
        private const byte Token_TypeRef = 43; 

        // Un-optimized (Binary serialized) types 
        private const byte Token_BinarySerialized = 50; 

        // Optimized for sparse arrays 
        private const byte Token_SparseArray = 60;

        // Constant values
        private const byte Token_Null = 100; 
        private const byte Token_EmptyString = 101;
        private const byte Token_ZeroInt32 = 102; 
        private const byte Token_True = 103; 
        private const byte Token_False = 104;
 
        // Known types for which we generate short type references
        // rather than assembly qualified names
        //
 

        private static readonly Type[] KnownTypes = 
            new Type[] { 
                typeof(object),
                typeof(int), 
                typeof(string),
                typeof(bool)
            };
 
        private static readonly Stack _streams = new Stack();
 
        // Format and Version 
        private const byte Marker_Format = 0xFF;
        private const byte Marker_Version_1 = 0x01; 

        // The size of the string table. At most it can be Byte.MaxValue.
        //
        private const int StringTableSize = Byte.MaxValue; 

        // Used during serialization 
        private IDictionary _typeTable; 
        private IDictionary _stringTable;
 
        // Used during deserialization
        private IList _typeList;

        // Used during both serialization and deserialization 
        private int _stringTableCount;
        private string[] _stringList; 
 
        // Used for performing Mac-encoding when this LosSerializer is used
        // in view state serialization. 
        private byte[] _macKeyBytes;

        // If true, this class will throw an exception if it cannot deserialize a type or value.
        // If false, this class will use insert "null" if it cannot deserialize a type or value. 
        // Default is true, WebParts Personalization sets this to false.
        private bool _throwOnErrorDeserializing; 
 
        // We use page to determine whether to to encrypt or decrypt based on Page.RequiresViewStateEncryptionInternal or Page.ContainsEncryptedViewstate
        private Page _page; 

        /// 
        /// Initializes a new instance of the ObjectStateFormatter.
        ///  
        public ObjectStateFormatter() : this(null) {
        } 
 
        /// 
        ///  
        /// Initializes a new instance of the ObjectStateFormatter. A MAC encoding
        /// key can be specified to have the serialized data encoded for view state
        /// purposes.
        /// NOTE: this constructor is mainly for LOSFormatter's consumption, not used internally 
        /// 
        internal ObjectStateFormatter(byte[] macEncodingKey) : this(null, true) { 
            _macKeyBytes = macEncodingKey; 
        }
 
        /// 
        /// 
        /// Initializes a new instance of the ObjectStateFormatter. A MAC encoding
        /// key can be specified to have the serialized data encoded for view state 
        /// purposes. The Page object is used to determine whether the viewstate will be encrypted
        /// for serialize and deserialize. 
        ///  

        internal ObjectStateFormatter(Page page, bool throwOnErrorDeserializing) { 
            _page = page;
            _throwOnErrorDeserializing = throwOnErrorDeserializing;
        }
 
        // This will return the MacKeyModifier provided in the LOSFormatter constructor or
        // generate one from Page if EnableViewStateMac is true. 
        private byte[] GetMacKeyModifier() { 
            if (_macKeyBytes == null) {
                // Only generate a MacKeyModifier if we have a page 
                if (_page == null) {
                    return null;
                }
 
                // Note: duplicated in MobilePage.cs, keep in [....]
 
                // Use the page's directory and class name as part of the key (ASURT 64044) 
                // We need to make sure that the hash is case insensitive, since the file system
                // is, and strange view state errors could otherwise happen (ASURT 128657) 
                int pageHashCode = StringComparer.InvariantCultureIgnoreCase.GetHashCode(
                    _page.TemplateSourceDirectory);
                pageHashCode += StringComparer.InvariantCultureIgnoreCase.GetHashCode(_page.GetType().Name);
 
                string viewStateUserKey = _page.ViewStateUserKey;
                if (viewStateUserKey != null) { 
                    // Modify the key with the ViewStateUserKey, if any (ASURT 126375) 
                    int count = Encoding.Unicode.GetByteCount(viewStateUserKey);
                    _macKeyBytes = new byte[count + 4]; 
                    Encoding.Unicode.GetBytes(viewStateUserKey, 0, viewStateUserKey.Length, _macKeyBytes, 4);

                }
                else { 
                    _macKeyBytes = new byte[4];
                } 
 
                _macKeyBytes[0] = (byte)pageHashCode;
                _macKeyBytes[1] = (byte)(pageHashCode >> 8); 
                _macKeyBytes[2] = (byte)(pageHashCode >> 16);
                _macKeyBytes[3] = (byte)(pageHashCode >> 24);
            }
            return _macKeyBytes; 
        }
 
        ///  
        /// Adds a string reference during the deserialization process
        /// to support deserialization of IndexedStrings. 
        /// The string is added to the string list on the fly, so it is available
        /// for future reference by index.
        /// 
        private void AddDeserializationStringReference(string s) { 
            Debug.Assert((s != null) && (s.Length != 0));
 
            if (_stringTableCount == StringTableSize) { 
                // loop around to the start of the table
                _stringTableCount = 0; 
            }

            _stringList[_stringTableCount] = s;
            _stringTableCount++; 
        }
 
        ///  
        /// Adds a type reference during the deserialization process,
        /// so that it can be referred to later by its index. 
        /// 
        private void AddDeserializationTypeReference(Type type) {
            // Type may be null, if there is no longer a Type on the system with the saved type name.
            // This is unlikely to happen with a Type stored in ViewState, but more likely with a Type 
            // stored in Personalization.
            _typeList.Add(type); 
        } 

        ///  
        /// Adds a string reference during the serialization process to support
        /// the serialization of IndexedStrings.
        /// The string is added to the string list, as well as to a string table
        /// for quick lookup. 
        /// 
        private void AddSerializationStringReference(string s) { 
            Debug.Assert((s != null) && (s.Length != 0)); 

            if (_stringTableCount == StringTableSize) { 
                // loop around to the start of the table
                _stringTableCount = 0;
            }
 
            string oldString = _stringList[_stringTableCount];
            if (oldString != null) { 
                // it means we're looping around, and the existing table entry 
                // needs to be removed, as a new one will replace it
                Debug.Assert(_stringTable.Contains(oldString)); 
                _stringTable.Remove(oldString);
            }

            _stringTable[s] = _stringTableCount; 
            _stringList[_stringTableCount] = s;
            _stringTableCount++; 
        } 

        ///  
        /// Adds a type reference during the serialization process, so it
        /// can be later referred to by its index.
        /// 
        private void AddSerializationTypeReference(Type type) { 
            Debug.Assert(type != null);
 
            int typeID = _typeTable.Count; 
            _typeTable[type] = typeID;
        } 

        [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.SerializationFormatter)]
        internal object DeserializeWithAssert(Stream inputStream) {
            return Deserialize(inputStream); 
        }
 
        ///  
        /// Deserializes an object graph from its binary serialized form
        /// contained in the specified stream. 
        /// 
        public object Deserialize(Stream inputStream) {
            if (inputStream == null) {
                throw new ArgumentNullException("inputStream"); 
            }
 
            Exception deserializationException = null; 

            InitializeDeserializer(); 

            SerializerBinaryReader reader = new SerializerBinaryReader(inputStream);
            try {
                byte formatMarker = reader.ReadByte(); 

                if (formatMarker == Marker_Format) { 
                    byte versionMarker = reader.ReadByte(); 

                    Debug.Assert(versionMarker == Marker_Version_1); 
                    if (versionMarker == Marker_Version_1) {
                        return DeserializeValue(reader);
                    }
                } 
            }
            catch (Exception e) { 
                deserializationException = e; 
            }
 
            // throw an exception if there was an exception during deserialization
            // or if deserialization was skipped because of invalid format or
            // version data in the stream
 
            throw new ArgumentException(SR.GetString(SR.InvalidSerializedData), deserializationException);
        } 
 

        ///  
        /// Deserializes an object graph from its textual serialized form
        /// contained in the specified string.
        /// 
        public object Deserialize(string inputString) { 
            if (String.IsNullOrEmpty(inputString)) {
                throw new ArgumentNullException("inputString"); 
            } 

            byte[] inputBytes = Convert.FromBase64String(inputString); 
            int length = inputBytes.Length;

#if !FEATURE_PAL // FEATURE_PAL does not enable cryptography
            try { 
                if (_page != null && _page.ContainsEncryptedViewState) {
                    inputBytes = MachineKeySection.EncryptOrDecryptData(false, inputBytes, GetMacKeyModifier(), 0, length); 
                    length = inputBytes.Length; 
                }
                // We need to decode if the page has EnableViewStateMac or we got passed in some mac key string 
                else if ((_page != null && _page.EnableViewStateMac) || _macKeyBytes != null) {
                    inputBytes = MachineKeySection.GetDecodedData(inputBytes, GetMacKeyModifier(), 0, length, ref length);
                }
            } 
            catch (Exception e) {
                PerfCounters.IncrementCounter(AppPerfCounter.VIEWSTATE_MAC_FAIL); 
                ViewStateException.ThrowMacValidationError(e, inputString); 
            }
#endif // !FEATURE_PAL 
            object result = null;
            MemoryStream objectStream = GetMemoryStream();
            try {
                objectStream.Write(inputBytes, 0, length); 
                objectStream.Position = 0;
                result = Deserialize(objectStream); 
            } 
            finally {
                ReleaseMemoryStream(objectStream); 
            }
            return result;
        }
 
        /// 
        /// Deserializes an IndexedString. An IndexedString can either be the string itself (the 
        /// first occurrence), or a reference to it by index into the string table. 
        /// 
        private IndexedString DeserializeIndexedString(SerializerBinaryReader reader, byte token) { 
            Debug.Assert((token == Token_IndexedStringAdd) || (token == Token_IndexedString));

            if (token == Token_IndexedString) {
                // reference to string in the current string table 
                int tableIndex = (int)reader.ReadByte();
 
                Debug.Assert(_stringList[tableIndex] != null); 
                return new IndexedString(_stringList[tableIndex]);
            } 
            else {
                // first occurrence of this indexed string. Read in the string, and add
                // a reference to it, so future references can be resolved.
                string s = reader.ReadString(); 

                AddDeserializationStringReference(s); 
                return new IndexedString(s); 
            }
        } 

        /// 
        /// Deserializes a Type. A Type can either be its name (the first occurrence),
        /// or a reference to it by index into the type table.  If we cannot load the type, 
        /// we throw an exception if _throwOnErrorDeserializing is true, and we return null if
        /// _throwOnErrorDeserializing is false. 
        ///  
        private Type DeserializeType(SerializerBinaryReader reader) {
            byte token = reader.ReadByte(); 
            Debug.Assert((token == Token_TypeRef) ||
                         (token == Token_TypeRefAdd) ||
                         (token == Token_TypeRefAddLocal));
 
            if (token == Token_TypeRef) {
                // reference by index into type table 
                int typeID = reader.ReadEncodedInt32(); 
                return (Type)_typeList[typeID];
            } 
            else {
                // first occurrence of this type. Read in the type, resolve it, and
                // add it to the type table
                string typeName = reader.ReadString(); 

                Type resolvedType = null; 
                try { 
                    if (token == Token_TypeRefAddLocal) {
                        resolvedType = HttpContext.SystemWebAssembly.GetType(typeName, true); 
                    }
                    else {
                        resolvedType = Type.GetType(typeName, true);
                    } 
                }
                catch (Exception exception) { 
                    if (_throwOnErrorDeserializing) { 
                        throw;
                    } 
                    else {
                        // Log error message
                        WebBaseEvent.RaiseSystemEvent(
                            SR.GetString(SR.Webevent_msg_OSF_Deserialization_Type, typeName), 
                            this,
                            WebEventCodes.WebErrorObjectStateFormatterDeserializationError, 
                            WebEventCodes.UndefinedEventDetailCode, 
                            exception);
                    } 
                }

                AddDeserializationTypeReference(resolvedType);
                return resolvedType; 
            }
        } 
 
        /// 
        /// Deserializes a single value from the underlying stream. 
        /// Essentially a token is read, followed by as much data needed to recreate
        /// the single value.
        /// 
        private object DeserializeValue(SerializerBinaryReader reader) { 
            byte token = reader.ReadByte();
 
            // NOTE: Preserve the order here with the order of the logic in 
            //       the SerializeValue method.
 
            switch (token) {
                case Token_Null:
                    return null;
                case Token_EmptyString: 
                    return String.Empty;
                case Token_String: 
                    return reader.ReadString(); 
                case Token_ZeroInt32:
                    return 0; 
                case Token_Int32:
                    return reader.ReadEncodedInt32();
                case Token_Pair:
                    return new Pair(DeserializeValue(reader), 
                                    DeserializeValue(reader));
                case Token_Triplet: 
                    return new Triplet(DeserializeValue(reader), 
                                       DeserializeValue(reader),
                                       DeserializeValue(reader)); 
                case Token_IndexedString:
                case Token_IndexedStringAdd:
                    return DeserializeIndexedString(reader, token);
                case Token_ArrayList: 
                    {
                        int count = reader.ReadEncodedInt32(); 
                        ArrayList list = new ArrayList(count); 
                        for (int i = 0; i < count; i++) {
                            list.Add(DeserializeValue(reader)); 
                        }

                        return list;
                    } 
                case Token_True:
                    return true; 
                case Token_False: 
                    return false;
                case Token_Byte: 
                    return reader.ReadByte();
                case Token_Char:
                    return reader.ReadChar();
                case Token_DateTime: 
                    return DateTime.FromBinary(reader.ReadInt64());
                case Token_Double: 
                    return reader.ReadDouble(); 
                case Token_Int16:
                    return reader.ReadInt16(); 
                case Token_Single:
                    return reader.ReadSingle();
                case Token_Hashtable:
                case Token_HybridDictionary: 
                    {
                        int count = reader.ReadEncodedInt32(); 
 
                        IDictionary table;
                        if (token == Token_Hashtable) { 
                            table = new Hashtable(count);
                        }
                        else {
                            table = new HybridDictionary(count); 
                        }
                        for (int i = 0; i < count; i++) { 
                            table.Add(DeserializeValue(reader), 
                                      DeserializeValue(reader));
                        } 

                        return table;
                    }
                case Token_Type: 
                    return DeserializeType(reader);
                case Token_StringArray: 
                    { 
                        int count = reader.ReadEncodedInt32();
 
                        string[] array = new string[count];
                        for (int i = 0; i < count; i++) {
                            array[i] = reader.ReadString();
                        } 

                        return array; 
                    } 
                case Token_Array:
                    { 
                        Type elementType = DeserializeType(reader);
                        int count = reader.ReadEncodedInt32();

                        Array list = Array.CreateInstance(elementType, count); 
                        for (int i = 0; i < count; i++) {
                            list.SetValue(DeserializeValue(reader), i); 
                        } 

                        return list; 
                    }
                case Token_IntEnum:
                    {
                        Type enumType = DeserializeType(reader); 
                        int enumValue = reader.ReadEncodedInt32();
 
                        return Enum.ToObject(enumType, enumValue); 
                    }
                case Token_Color: 
                    return Color.FromArgb(reader.ReadInt32());
                case Token_EmptyColor:
                    return Color.Empty;
                case Token_KnownColor: 
                    return Color.FromKnownColor((KnownColor)reader.ReadEncodedInt32());
                case Token_Unit: 
                    return new Unit(reader.ReadDouble(), (UnitType)reader.ReadInt32()); 
                case Token_EmptyUnit:
                    return Unit.Empty; 
                case Token_SparseArray:
                    {
                        Type elementType = DeserializeType(reader);
                        int count = reader.ReadEncodedInt32(); 
                        int itemCount = reader.ReadEncodedInt32();
 
                        // Guard against bad data 
                        if (itemCount > count) {
                            throw new InvalidOperationException(SR.GetString(SR.InvalidSerializedData)); 
                        }

                        Array list = Array.CreateInstance(elementType, count);
                        for (int i = 0; i < itemCount; ++i) { 
                            // Data is encoded as 
                            int nextPos = reader.ReadEncodedInt32(); 
 
                            // Guard against bad data (nextPos way too big, or nextPos not increasing)
                            if (nextPos >= count || nextPos < 0) { 
                                throw new InvalidOperationException(SR.GetString(SR.InvalidSerializedData));
                            }
                            list.SetValue(DeserializeValue(reader), nextPos);
                        } 

                        return list; 
                    } 
                case Token_StringFormatted:
                    { 
                        object result = null;

                        Type valueType = DeserializeType(reader);
                        string formattedValue = reader.ReadString(); 

                        if (valueType != null) { 
                            TypeConverter converter = TypeDescriptor.GetConverter(valueType); 
                            // TypeDescriptor.GetConverter() will never return null.  The ref docs
                            // for this method are incorrect. 
                            try {
                                result = converter.ConvertFromInvariantString(formattedValue);
                            }
                            catch (Exception exception) { 
                                if (_throwOnErrorDeserializing) {
                                    throw; 
                                } 
                                else {
                                    WebBaseEvent.RaiseSystemEvent( 
                                        SR.GetString(SR.Webevent_msg_OSF_Deserialization_String, valueType.AssemblyQualifiedName),
                                        this,
                                        WebEventCodes.WebErrorObjectStateFormatterDeserializationError,
                                        WebEventCodes.UndefinedEventDetailCode, 
                                        exception);
                                } 
                            } 
                        }
 
                        return result;
                    }
                case Token_BinarySerialized:
                    { 
                        int length = reader.ReadEncodedInt32();
 
                        byte[] buffer = new byte[length]; 
                        if (length != 0) {
                            reader.Read(buffer, 0, length); 
                        }

                        object result = null;
                        MemoryStream ms = GetMemoryStream(); 
                        try {
                            ms.Write(buffer, 0, length); 
                            ms.Position = 0; 
                            IFormatter formatter = new BinaryFormatter();
 
                            result = formatter.Deserialize(ms);
                        }
                        catch (Exception exception) {
                            if (_throwOnErrorDeserializing) { 
                                throw;
                            } 
                            else { 
                                WebBaseEvent.RaiseSystemEvent(
                                    SR.GetString(SR.Webevent_msg_OSF_Deserialization_Binary), 
                                    this,
                                    WebEventCodes.WebErrorObjectStateFormatterDeserializationError,
                                    WebEventCodes.UndefinedEventDetailCode,
                                    exception); 
                            }
                        } 
                        finally { 
                            ReleaseMemoryStream(ms);
                        } 
                        return result;
                    }
                default:
                    throw new InvalidOperationException(SR.GetString(SR.InvalidSerializedData)); 
            }
        } 
 
        /// 
        /// Retrieves a memory stream from the pool. 
        /// 
        private static MemoryStream GetMemoryStream() {
            MemoryStream stream = null;
            if (_streams.Count > 0) { 
                lock (_streams) {
                    if (_streams.Count > 0) { 
                        stream = (MemoryStream)_streams.Pop(); 
                    }
                } 
            }

            if (stream == null) {
                stream = new MemoryStream(2048); 
            }
            return stream; 
        } 

 
        /// 
        /// Initializes this instance to perform deserialization.
        /// 
        private void InitializeDeserializer() { 
            _typeList = new ArrayList();
 
            for (int i = 0; i < KnownTypes.Length; i++) { 
                AddDeserializationTypeReference(KnownTypes[i]);
            } 

            _stringList = new string[Byte.MaxValue];
            _stringTableCount = 0;
        } 

        ///  
        /// Initializes this instance to perform serialization. 
        /// 
        private void InitializeSerializer() { 
            _typeTable = new HybridDictionary();

            for (int i = 0; i < KnownTypes.Length; i++) {
                AddSerializationTypeReference(KnownTypes[i]); 
            }
 
            _stringList = new string[Byte.MaxValue]; 
            _stringTable = new Hashtable();
            _stringTableCount = 0; 
        }

        /// 
        /// Returns a memory stream back into the pool. 
        /// 
        private static void ReleaseMemoryStream(MemoryStream stream) { 
            Debug.Assert(stream != null); 
            stream.Position = 0;
            stream.SetLength(0); 
            lock (_streams) {
                _streams.Push(stream);
            }
        } 

        ///  
        /// Serializes an object graph into a textual serialized form. 
        /// 
        public string Serialize(object stateGraph) { 
            string result = null;

            MemoryStream ms = GetMemoryStream();
            try { 
                Serialize(ms, stateGraph);
                ms.SetLength(ms.Position); 
 
                byte[] buffer = ms.GetBuffer();
                int length = (int)ms.Length; 

#if !FEATURE_PAL // FEATURE_PAL does not enable cryptography
                // We only support serialization of encrypted or encoded data through our internal Page constructors
                if (_page != null && _page.RequiresViewStateEncryptionInternal) { 
                    buffer = MachineKeySection.EncryptOrDecryptData(true, buffer, GetMacKeyModifier(), 0, length);
                    length = buffer.Length; 
                } 
                // We need to encode if the page has EnableViewStateMac or we got passed in some mac key string
                else if ((_page != null && _page.EnableViewStateMac) || _macKeyBytes != null) { 
                    buffer = MachineKeySection.GetEncodedData(buffer, GetMacKeyModifier(), 0, ref length);
                }

#endif // !FEATURE_PAL 
                result = Convert.ToBase64String(buffer, 0, length);
            } 
            finally { 
                ReleaseMemoryStream(ms);
            } 
            return result;
        }

        [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.SerializationFormatter)] 
        internal void SerializeWithAssert(Stream outputStream, object stateGraph) {
            Serialize(outputStream, stateGraph); 
        } 

        ///  
        /// Serializes an object graph into a binary serialized form within
        /// the specified stream.
        /// 
        public void Serialize(Stream outputStream, object stateGraph) { 
            if (outputStream == null) {
                throw new ArgumentNullException("outputStream"); 
            } 

            InitializeSerializer(); 

            SerializerBinaryWriter writer = new SerializerBinaryWriter(outputStream);
            writer.Write(Marker_Format);
            writer.Write(Marker_Version_1); 
            SerializeValue(writer, stateGraph);
        } 
 
        /// 
        /// Serializes an IndexedString. If this is the first occurrence, it is written 
        /// out to the underlying stream, and is added to the string table for future
        /// reference. Otherwise, a reference by index is written out.
        /// 
        private void SerializeIndexedString(SerializerBinaryWriter writer, string s) { 
            object id = _stringTable[s];
            if (id != null) { 
                writer.Write(Token_IndexedString); 
                writer.Write((byte)(int)id);
                return; 
            }

            AddSerializationStringReference(s);
 
            writer.Write(Token_IndexedStringAdd);
            writer.Write(s); 
        } 

        ///  
        /// Serializes a Type. If this is the first occurrence, the type name is written
        /// out to the underlying stream, and the type is added to the string table for future
        /// reference. Otherwise, a reference by index is written out.
        ///  
        private void SerializeType(SerializerBinaryWriter writer, Type type) {
            object id = _typeTable[type]; 
            if (id != null) { 
                writer.Write(Token_TypeRef);
                writer.WriteEncoded((int)id); 
                return;
            }

            AddSerializationTypeReference(type); 

            if (type.Assembly == HttpContext.SystemWebAssembly) { 
                writer.Write(Token_TypeRefAddLocal); 
                writer.Write(type.FullName);
            } 
            else {
                writer.Write(Token_TypeRefAdd);
                writer.Write(type.AssemblyQualifiedName);
            } 
        }
 
        ///  
        /// Serializes a single value using the specified writer.
        /// Handles exceptions to provide more information about the value being serialized. 
        /// 
        private void SerializeValue(SerializerBinaryWriter writer, object value) {
            try {
 
                Stack objectStack = new Stack();
                objectStack.Push(value); 
 
                do {
                    value = objectStack.Pop(); 

                    if (value == null) {
                        writer.Write(Token_Null);
                        continue; 
                    }
 
                    // NOTE: These are ordered roughly in the order of frequency. 

                    if (value is string) { 
                        string s = (string)value;
                        if (s.Length == 0) {
                            writer.Write(Token_EmptyString);
                        } 
                        else {
                            writer.Write(Token_String); 
                            writer.Write(s); 
                        }
                        continue; 
                    }

                    if (value is int) {
                        int i = (int)value; 
                        if (i == 0) {
                            writer.Write(Token_ZeroInt32); 
                        } 
                        else {
                            writer.Write(Token_Int32); 
                            writer.WriteEncoded(i);
                        }
                        continue;
                    } 

                    if (value is Pair) { 
                        writer.Write(Token_Pair); 

                        Pair p = (Pair)value; 
                        objectStack.Push(p.Second);
                        objectStack.Push(p.First);
                        continue;
                    } 

                    if (value is Triplet) { 
                        writer.Write(Token_Triplet); 

                        Triplet t = (Triplet)value; 
                        objectStack.Push(t.Third);
                        objectStack.Push(t.Second);
                        objectStack.Push(t.First);
                        continue; 
                    }
 
                    if (value is IndexedString) { 
                        Debug.Assert(((IndexedString)value).Value != null);
                        SerializeIndexedString(writer, ((IndexedString)value).Value); 
                        continue;
                    }

                    if (value.GetType() == typeof(ArrayList)) { 
                        writer.Write(Token_ArrayList);
 
                        ArrayList list = (ArrayList)value; 

                        writer.WriteEncoded(list.Count); 
                        for (int i = list.Count - 1; i >= 0; i--) {
                            objectStack.Push(list[i]);
                        }
 
                        continue;
                    } 
 
                    if (value is bool) {
                        if (((bool)value)) { 
                            writer.Write(Token_True);
                        }
                        else {
                            writer.Write(Token_False); 
                        }
                        continue; 
                    } 
                    if (value is byte) {
                        writer.Write(Token_Byte); 
                        writer.Write((byte)value);
                        continue;
                    }
                    if (value is char) { 
                        writer.Write(Token_Char);
                        writer.Write((char)value); 
                        continue; 
                    }
                    if (value is DateTime) { 
                        writer.Write(Token_DateTime);
                        writer.Write(((DateTime)value).ToBinary());
                        continue;
                    } 
                    if (value is double) {
                        writer.Write(Token_Double); 
                        writer.Write((double)value); 
                        continue;
                    } 
                    if (value is short) {
                        writer.Write(Token_Int16);
                        writer.Write((short)value);
                        continue; 
                    }
                    if (value is float) { 
                        writer.Write(Token_Single); 
                        writer.Write((float)value);
                        continue; 
                    }

                    if (value is IDictionary) {
                        bool canSerializeDictionary = false; 

                        if (value.GetType() == typeof(Hashtable)) { 
                            writer.Write(Token_Hashtable); 
                            canSerializeDictionary = true;
                        } 
                        else if (value.GetType() == typeof(HybridDictionary)) {
                            writer.Write(Token_HybridDictionary);
                            canSerializeDictionary = true;
                        } 

                        if (canSerializeDictionary) { 
                            IDictionary table = (IDictionary)value; 

                            writer.WriteEncoded(table.Count); 
                            if (table.Count != 0) {
                                foreach (DictionaryEntry entry in table) {
                                    objectStack.Push(entry.Value);
                                    objectStack.Push(entry.Key); 
                                }
                            } 
 
                            continue;
                        } 
                    }

                    if (value is Type) {
                        writer.Write(Token_Type); 
                        SerializeType(writer, (Type)value);
                        continue; 
                    } 

                    Type valueType = value.GetType(); 

                    if (value is Array) {
                        // We only support Arrays with rank 1 (No multi dimensional arrays
                        if (((Array)value).Rank > 1) { 
                            continue;
                        } 
 
                        Type underlyingType = valueType.GetElementType();
 
                        if (underlyingType == typeof(string)) {
                            string[] strings = (string[])value;
                            bool containsNulls = false;
                            for (int i = 0; i < strings.Length; i++) { 
                                if (strings[i] == null) {
                                    // Will have to treat these as generic arrays since we 
                                    // can't represent nulls in the binary stream, without 
                                    // writing out string token markers.
                                    // Generic array writing includes the token markers. 
                                    containsNulls = true;
                                    break;
                                }
                            } 

                            if (!containsNulls) { 
                                writer.Write(Token_StringArray); 
                                writer.WriteEncoded(strings.Length);
                                for (int i = 0; i < strings.Length; i++) { 
                                    writer.Write(strings[i]);
                                }
                                continue;
                            } 
                        }
 
                        Array values = (Array)value; 

                        // Optimize for sparse arrays, if the array is more than 3/4 nulls 
                        if (values.Length > 3) {
                            int sparseThreshold = (values.Length / 4) + 1;
                            int numValues = 0;
                            List items = new List(sparseThreshold); 
                            for (int i = 0; i < values.Length; ++i) {
                                if (values.GetValue(i) != null) { 
                                    ++numValues; 
                                    if (numValues >= sparseThreshold) {
                                        break; 
                                    }
                                    items.Add(i);
                                }
                            } 

                            // We have enough nulls to use sparse array format  
                            if (numValues < sparseThreshold) { 
                                writer.Write(Token_SparseArray);
                                SerializeType(writer, underlyingType); 

                                writer.WriteEncoded(values.Length);
                                writer.WriteEncoded(numValues);
 
                                // Now we need to just serialize pairs representing the index, and the item
                                foreach (int index in items) { 
                                    writer.WriteEncoded(index); 
                                    SerializeValue(writer, values.GetValue(index));
                                } 

                                continue;
                            }
                        } 

                        writer.Write(Token_Array); 
                        SerializeType(writer, underlyingType); 

                        writer.WriteEncoded(values.Length); 
                        for (int i = values.Length - 1; i >= 0; i--) {
                            objectStack.Push(values.GetValue(i));
                        }
 
                        continue;
                    } 
 
                    if (valueType.IsEnum) {
                        Type underlyingType = Enum.GetUnderlyingType(valueType); 
                        if (underlyingType == typeof(int)) {
                            writer.Write(Token_IntEnum);
                            SerializeType(writer, valueType);
                            writer.WriteEncoded((int)value); 

                            continue; 
                        } 
                    }
 
                    if (valueType == typeof(Color)) {
                        Color c = (Color)value;
                        if (c.IsEmpty) {
                            writer.Write(Token_EmptyColor); 
                            continue;
                        } 
                        if (!c.IsNamedColor) { 
                            writer.Write(Token_Color);
                            writer.Write(c.ToArgb()); 
                            continue;
                        }
                        else {
                            writer.Write(Token_KnownColor); 
                            writer.WriteEncoded((int)c.ToKnownColor());
                            continue; 
                        } 
                    }
 
                    if (value is Unit) {
                        Unit uval = (Unit)value;
                        if (uval.IsEmpty) {
                            writer.Write(Token_EmptyUnit); 
                        }
                        else { 
                            writer.Write(Token_Unit); 
                            writer.Write(uval.Value);
                            writer.Write((int)uval.Type); 
                        }
                        continue;
                    }
 
                    // Handle the remaining types
                    // First try to get a type converter, and then resort to 
                    // binary serialization if all else fails 

                    TypeConverter converter = TypeDescriptor.GetConverter(valueType); 
                    bool canConvert = System.Web.UI.Util.CanConvertToFrom(converter, typeof(string));

                    if (canConvert) {
                        writer.Write(Token_StringFormatted); 
                        SerializeType(writer, valueType);
                        writer.Write(converter.ConvertToInvariantString(null, value)); 
                    } 
                    else {
                        IFormatter formatter = new BinaryFormatter(); 
                        MemoryStream ms = new MemoryStream(256);
                        formatter.Serialize(ms, value);

                        byte[] buffer = ms.GetBuffer(); 
                        int length = (int)ms.Length;
 
                        writer.Write(Token_BinarySerialized); 
                        writer.WriteEncoded(length);
                        if (buffer.Length != 0) { 
                            writer.Write(buffer, 0, (int)length);
                        }
                    }
                } 
                while (objectStack.Count > 0);
            } 
            catch (Exception serializationException) { 
                throw new ArgumentException(SR.GetString(SR.ErrorSerializingValue, value.ToString(), value.GetType().FullName),
                                            serializationException); 
            }
        }

        #region Implementation of IStateFormatter 
        object IStateFormatter.Deserialize(string serializedState) {
            return Deserialize(serializedState); 
        } 

        string IStateFormatter.Serialize(object state) { 
            return Serialize(state);
        }
        #endregion
 
        #region Implementation of IFormatter
 
        ///  
        SerializationBinder IFormatter.Binder {
            get { 
                return null;
            }
            set {
            } 
        }
 
 
        /// 
        StreamingContext IFormatter.Context { 
            get {
                return new StreamingContext(StreamingContextStates.All);
            }
            set { 
            }
        } 
 

        ///  
        ISurrogateSelector IFormatter.SurrogateSelector {
            get {
                return null;
            } 
            set {
            } 
        } 

 
        /// 
        object IFormatter.Deserialize(Stream serializationStream) {
            return Deserialize(serializationStream);
        } 

 
        ///  
        void IFormatter.Serialize(Stream serializationStream, object stateGraph) {
            Serialize(serializationStream, stateGraph); 
        }
        #endregion

        ///  
        /// Custom BinaryReader used during the deserialization.
        ///  
        private sealed class SerializerBinaryReader : BinaryReader { 

            public SerializerBinaryReader(Stream stream) : base(stream) { 
            }

            public int ReadEncodedInt32() {
                return Read7BitEncodedInt(); 
            }
        } 
 

        ///  
        /// Custom BinaryWriter used during the serialization.
        /// 
        private sealed class SerializerBinaryWriter : BinaryWriter {
 
            public SerializerBinaryWriter(Stream stream) : base(stream) {
            } 
 
            public void WriteEncoded(int value) {
                // 

                uint v = (uint)value;
                while (v >= 0x80) {
                    Write((byte)(v | 0x80)); 
                    v >>= 7;
                } 
                Write((byte)v); 
            }
        } 
    }
}


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

namespace System.Web.UI { 
 
    using System;
    using System.Collections; 
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.ComponentModel;
    using System.Drawing; 
    using System.IO;
    using System.Globalization; 
    using System.Reflection; 
    using System.Runtime.Serialization;
    using System.Runtime.Serialization.Formatters.Binary; 
    using System.Security;
    using System.Security.Permissions;
    using System.Text;
    using System.Web.Compilation; 
    using System.Web.Configuration;
    using System.Web.Util; 
    using System.Web.Management; 
    using System.Web.UI.WebControls;
 
    //


 
    /// 
    /// ObjectStateFormatter is designed to efficiently serialize arbitrary object graphs 
    /// that represent the state of an object (decomposed into simpler types) into 
    /// a highly compact binary or ASCII representations.
    /// The formatter contains native support for optimized serialization of a fixed 
    /// set of known types such as ints, shorts, booleans, strings, other primitive types
    /// arrays, Pairs, Triplets, ArrayLists, Hashtables etc. In addition it utilizes
    /// TypeConverters for semi-optimized serialization of custom types. Finally, it uses
    /// binary serialization as a fallback mechanism. The formatter is also able to compress 
    /// IndexedStrings contained in the object graph.
    ///  
    [AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)] 
    public sealed class ObjectStateFormatter : IStateFormatter, IFormatter {
 
        // Optimized type tokens
        private const byte Token_Int16 = 1;
        private const byte Token_Int32 = 2;
        private const byte Token_Byte = 3; 
        private const byte Token_Char = 4;
        private const byte Token_String = 5; 
        private const byte Token_DateTime = 6; 
        private const byte Token_Double = 7;
        private const byte Token_Single = 8; 
        private const byte Token_Color = 9;
        private const byte Token_KnownColor = 10;
        private const byte Token_IntEnum = 11;
        private const byte Token_EmptyColor = 12; 
        private const byte Token_Pair = 15;
        private const byte Token_Triplet = 16; 
        private const byte Token_Array = 20; 
        private const byte Token_StringArray = 21;
        private const byte Token_ArrayList = 22; 
        private const byte Token_Hashtable = 23;
        private const byte Token_HybridDictionary = 24;
        private const byte Token_Type = 25;
        // private const byte Token_Nullable = 26; Removed per DevDiv 165426 
        // Background: Used to support nullables as a special case, CLR added support for this
        // but they forgot to remove the deserialization code when they removed the support 
        // potentially Beta2 customers could have serialized data (WebParts) which have this token. 
        // We removed support since this was broken anyways in RTM.
        private const byte Token_Unit = 27; 
        private const byte Token_EmptyUnit = 28;

        // String-table optimized strings
        private const byte Token_IndexedStringAdd = 30; 
        private const byte Token_IndexedString = 31;
 
        // Semi-optimized (TypeConverter-based) 
        private const byte Token_StringFormatted = 40;
 
        // Semi-optimized (Types)
        private const byte Token_TypeRefAdd = 41;
        private const byte Token_TypeRefAddLocal = 42;
        private const byte Token_TypeRef = 43; 

        // Un-optimized (Binary serialized) types 
        private const byte Token_BinarySerialized = 50; 

        // Optimized for sparse arrays 
        private const byte Token_SparseArray = 60;

        // Constant values
        private const byte Token_Null = 100; 
        private const byte Token_EmptyString = 101;
        private const byte Token_ZeroInt32 = 102; 
        private const byte Token_True = 103; 
        private const byte Token_False = 104;
 
        // Known types for which we generate short type references
        // rather than assembly qualified names
        //
 

        private static readonly Type[] KnownTypes = 
            new Type[] { 
                typeof(object),
                typeof(int), 
                typeof(string),
                typeof(bool)
            };
 
        private static readonly Stack _streams = new Stack();
 
        // Format and Version 
        private const byte Marker_Format = 0xFF;
        private const byte Marker_Version_1 = 0x01; 

        // The size of the string table. At most it can be Byte.MaxValue.
        //
        private const int StringTableSize = Byte.MaxValue; 

        // Used during serialization 
        private IDictionary _typeTable; 
        private IDictionary _stringTable;
 
        // Used during deserialization
        private IList _typeList;

        // Used during both serialization and deserialization 
        private int _stringTableCount;
        private string[] _stringList; 
 
        // Used for performing Mac-encoding when this LosSerializer is used
        // in view state serialization. 
        private byte[] _macKeyBytes;

        // If true, this class will throw an exception if it cannot deserialize a type or value.
        // If false, this class will use insert "null" if it cannot deserialize a type or value. 
        // Default is true, WebParts Personalization sets this to false.
        private bool _throwOnErrorDeserializing; 
 
        // We use page to determine whether to to encrypt or decrypt based on Page.RequiresViewStateEncryptionInternal or Page.ContainsEncryptedViewstate
        private Page _page; 

        /// 
        /// Initializes a new instance of the ObjectStateFormatter.
        ///  
        public ObjectStateFormatter() : this(null) {
        } 
 
        /// 
        ///  
        /// Initializes a new instance of the ObjectStateFormatter. A MAC encoding
        /// key can be specified to have the serialized data encoded for view state
        /// purposes.
        /// NOTE: this constructor is mainly for LOSFormatter's consumption, not used internally 
        /// 
        internal ObjectStateFormatter(byte[] macEncodingKey) : this(null, true) { 
            _macKeyBytes = macEncodingKey; 
        }
 
        /// 
        /// 
        /// Initializes a new instance of the ObjectStateFormatter. A MAC encoding
        /// key can be specified to have the serialized data encoded for view state 
        /// purposes. The Page object is used to determine whether the viewstate will be encrypted
        /// for serialize and deserialize. 
        ///  

        internal ObjectStateFormatter(Page page, bool throwOnErrorDeserializing) { 
            _page = page;
            _throwOnErrorDeserializing = throwOnErrorDeserializing;
        }
 
        // This will return the MacKeyModifier provided in the LOSFormatter constructor or
        // generate one from Page if EnableViewStateMac is true. 
        private byte[] GetMacKeyModifier() { 
            if (_macKeyBytes == null) {
                // Only generate a MacKeyModifier if we have a page 
                if (_page == null) {
                    return null;
                }
 
                // Note: duplicated in MobilePage.cs, keep in [....]
 
                // Use the page's directory and class name as part of the key (ASURT 64044) 
                // We need to make sure that the hash is case insensitive, since the file system
                // is, and strange view state errors could otherwise happen (ASURT 128657) 
                int pageHashCode = StringComparer.InvariantCultureIgnoreCase.GetHashCode(
                    _page.TemplateSourceDirectory);
                pageHashCode += StringComparer.InvariantCultureIgnoreCase.GetHashCode(_page.GetType().Name);
 
                string viewStateUserKey = _page.ViewStateUserKey;
                if (viewStateUserKey != null) { 
                    // Modify the key with the ViewStateUserKey, if any (ASURT 126375) 
                    int count = Encoding.Unicode.GetByteCount(viewStateUserKey);
                    _macKeyBytes = new byte[count + 4]; 
                    Encoding.Unicode.GetBytes(viewStateUserKey, 0, viewStateUserKey.Length, _macKeyBytes, 4);

                }
                else { 
                    _macKeyBytes = new byte[4];
                } 
 
                _macKeyBytes[0] = (byte)pageHashCode;
                _macKeyBytes[1] = (byte)(pageHashCode >> 8); 
                _macKeyBytes[2] = (byte)(pageHashCode >> 16);
                _macKeyBytes[3] = (byte)(pageHashCode >> 24);
            }
            return _macKeyBytes; 
        }
 
        ///  
        /// Adds a string reference during the deserialization process
        /// to support deserialization of IndexedStrings. 
        /// The string is added to the string list on the fly, so it is available
        /// for future reference by index.
        /// 
        private void AddDeserializationStringReference(string s) { 
            Debug.Assert((s != null) && (s.Length != 0));
 
            if (_stringTableCount == StringTableSize) { 
                // loop around to the start of the table
                _stringTableCount = 0; 
            }

            _stringList[_stringTableCount] = s;
            _stringTableCount++; 
        }
 
        ///  
        /// Adds a type reference during the deserialization process,
        /// so that it can be referred to later by its index. 
        /// 
        private void AddDeserializationTypeReference(Type type) {
            // Type may be null, if there is no longer a Type on the system with the saved type name.
            // This is unlikely to happen with a Type stored in ViewState, but more likely with a Type 
            // stored in Personalization.
            _typeList.Add(type); 
        } 

        ///  
        /// Adds a string reference during the serialization process to support
        /// the serialization of IndexedStrings.
        /// The string is added to the string list, as well as to a string table
        /// for quick lookup. 
        /// 
        private void AddSerializationStringReference(string s) { 
            Debug.Assert((s != null) && (s.Length != 0)); 

            if (_stringTableCount == StringTableSize) { 
                // loop around to the start of the table
                _stringTableCount = 0;
            }
 
            string oldString = _stringList[_stringTableCount];
            if (oldString != null) { 
                // it means we're looping around, and the existing table entry 
                // needs to be removed, as a new one will replace it
                Debug.Assert(_stringTable.Contains(oldString)); 
                _stringTable.Remove(oldString);
            }

            _stringTable[s] = _stringTableCount; 
            _stringList[_stringTableCount] = s;
            _stringTableCount++; 
        } 

        ///  
        /// Adds a type reference during the serialization process, so it
        /// can be later referred to by its index.
        /// 
        private void AddSerializationTypeReference(Type type) { 
            Debug.Assert(type != null);
 
            int typeID = _typeTable.Count; 
            _typeTable[type] = typeID;
        } 

        [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.SerializationFormatter)]
        internal object DeserializeWithAssert(Stream inputStream) {
            return Deserialize(inputStream); 
        }
 
        ///  
        /// Deserializes an object graph from its binary serialized form
        /// contained in the specified stream. 
        /// 
        public object Deserialize(Stream inputStream) {
            if (inputStream == null) {
                throw new ArgumentNullException("inputStream"); 
            }
 
            Exception deserializationException = null; 

            InitializeDeserializer(); 

            SerializerBinaryReader reader = new SerializerBinaryReader(inputStream);
            try {
                byte formatMarker = reader.ReadByte(); 

                if (formatMarker == Marker_Format) { 
                    byte versionMarker = reader.ReadByte(); 

                    Debug.Assert(versionMarker == Marker_Version_1); 
                    if (versionMarker == Marker_Version_1) {
                        return DeserializeValue(reader);
                    }
                } 
            }
            catch (Exception e) { 
                deserializationException = e; 
            }
 
            // throw an exception if there was an exception during deserialization
            // or if deserialization was skipped because of invalid format or
            // version data in the stream
 
            throw new ArgumentException(SR.GetString(SR.InvalidSerializedData), deserializationException);
        } 
 

        ///  
        /// Deserializes an object graph from its textual serialized form
        /// contained in the specified string.
        /// 
        public object Deserialize(string inputString) { 
            if (String.IsNullOrEmpty(inputString)) {
                throw new ArgumentNullException("inputString"); 
            } 

            byte[] inputBytes = Convert.FromBase64String(inputString); 
            int length = inputBytes.Length;

#if !FEATURE_PAL // FEATURE_PAL does not enable cryptography
            try { 
                if (_page != null && _page.ContainsEncryptedViewState) {
                    inputBytes = MachineKeySection.EncryptOrDecryptData(false, inputBytes, GetMacKeyModifier(), 0, length); 
                    length = inputBytes.Length; 
                }
                // We need to decode if the page has EnableViewStateMac or we got passed in some mac key string 
                else if ((_page != null && _page.EnableViewStateMac) || _macKeyBytes != null) {
                    inputBytes = MachineKeySection.GetDecodedData(inputBytes, GetMacKeyModifier(), 0, length, ref length);
                }
            } 
            catch (Exception e) {
                PerfCounters.IncrementCounter(AppPerfCounter.VIEWSTATE_MAC_FAIL); 
                ViewStateException.ThrowMacValidationError(e, inputString); 
            }
#endif // !FEATURE_PAL 
            object result = null;
            MemoryStream objectStream = GetMemoryStream();
            try {
                objectStream.Write(inputBytes, 0, length); 
                objectStream.Position = 0;
                result = Deserialize(objectStream); 
            } 
            finally {
                ReleaseMemoryStream(objectStream); 
            }
            return result;
        }
 
        /// 
        /// Deserializes an IndexedString. An IndexedString can either be the string itself (the 
        /// first occurrence), or a reference to it by index into the string table. 
        /// 
        private IndexedString DeserializeIndexedString(SerializerBinaryReader reader, byte token) { 
            Debug.Assert((token == Token_IndexedStringAdd) || (token == Token_IndexedString));

            if (token == Token_IndexedString) {
                // reference to string in the current string table 
                int tableIndex = (int)reader.ReadByte();
 
                Debug.Assert(_stringList[tableIndex] != null); 
                return new IndexedString(_stringList[tableIndex]);
            } 
            else {
                // first occurrence of this indexed string. Read in the string, and add
                // a reference to it, so future references can be resolved.
                string s = reader.ReadString(); 

                AddDeserializationStringReference(s); 
                return new IndexedString(s); 
            }
        } 

        /// 
        /// Deserializes a Type. A Type can either be its name (the first occurrence),
        /// or a reference to it by index into the type table.  If we cannot load the type, 
        /// we throw an exception if _throwOnErrorDeserializing is true, and we return null if
        /// _throwOnErrorDeserializing is false. 
        ///  
        private Type DeserializeType(SerializerBinaryReader reader) {
            byte token = reader.ReadByte(); 
            Debug.Assert((token == Token_TypeRef) ||
                         (token == Token_TypeRefAdd) ||
                         (token == Token_TypeRefAddLocal));
 
            if (token == Token_TypeRef) {
                // reference by index into type table 
                int typeID = reader.ReadEncodedInt32(); 
                return (Type)_typeList[typeID];
            } 
            else {
                // first occurrence of this type. Read in the type, resolve it, and
                // add it to the type table
                string typeName = reader.ReadString(); 

                Type resolvedType = null; 
                try { 
                    if (token == Token_TypeRefAddLocal) {
                        resolvedType = HttpContext.SystemWebAssembly.GetType(typeName, true); 
                    }
                    else {
                        resolvedType = Type.GetType(typeName, true);
                    } 
                }
                catch (Exception exception) { 
                    if (_throwOnErrorDeserializing) { 
                        throw;
                    } 
                    else {
                        // Log error message
                        WebBaseEvent.RaiseSystemEvent(
                            SR.GetString(SR.Webevent_msg_OSF_Deserialization_Type, typeName), 
                            this,
                            WebEventCodes.WebErrorObjectStateFormatterDeserializationError, 
                            WebEventCodes.UndefinedEventDetailCode, 
                            exception);
                    } 
                }

                AddDeserializationTypeReference(resolvedType);
                return resolvedType; 
            }
        } 
 
        /// 
        /// Deserializes a single value from the underlying stream. 
        /// Essentially a token is read, followed by as much data needed to recreate
        /// the single value.
        /// 
        private object DeserializeValue(SerializerBinaryReader reader) { 
            byte token = reader.ReadByte();
 
            // NOTE: Preserve the order here with the order of the logic in 
            //       the SerializeValue method.
 
            switch (token) {
                case Token_Null:
                    return null;
                case Token_EmptyString: 
                    return String.Empty;
                case Token_String: 
                    return reader.ReadString(); 
                case Token_ZeroInt32:
                    return 0; 
                case Token_Int32:
                    return reader.ReadEncodedInt32();
                case Token_Pair:
                    return new Pair(DeserializeValue(reader), 
                                    DeserializeValue(reader));
                case Token_Triplet: 
                    return new Triplet(DeserializeValue(reader), 
                                       DeserializeValue(reader),
                                       DeserializeValue(reader)); 
                case Token_IndexedString:
                case Token_IndexedStringAdd:
                    return DeserializeIndexedString(reader, token);
                case Token_ArrayList: 
                    {
                        int count = reader.ReadEncodedInt32(); 
                        ArrayList list = new ArrayList(count); 
                        for (int i = 0; i < count; i++) {
                            list.Add(DeserializeValue(reader)); 
                        }

                        return list;
                    } 
                case Token_True:
                    return true; 
                case Token_False: 
                    return false;
                case Token_Byte: 
                    return reader.ReadByte();
                case Token_Char:
                    return reader.ReadChar();
                case Token_DateTime: 
                    return DateTime.FromBinary(reader.ReadInt64());
                case Token_Double: 
                    return reader.ReadDouble(); 
                case Token_Int16:
                    return reader.ReadInt16(); 
                case Token_Single:
                    return reader.ReadSingle();
                case Token_Hashtable:
                case Token_HybridDictionary: 
                    {
                        int count = reader.ReadEncodedInt32(); 
 
                        IDictionary table;
                        if (token == Token_Hashtable) { 
                            table = new Hashtable(count);
                        }
                        else {
                            table = new HybridDictionary(count); 
                        }
                        for (int i = 0; i < count; i++) { 
                            table.Add(DeserializeValue(reader), 
                                      DeserializeValue(reader));
                        } 

                        return table;
                    }
                case Token_Type: 
                    return DeserializeType(reader);
                case Token_StringArray: 
                    { 
                        int count = reader.ReadEncodedInt32();
 
                        string[] array = new string[count];
                        for (int i = 0; i < count; i++) {
                            array[i] = reader.ReadString();
                        } 

                        return array; 
                    } 
                case Token_Array:
                    { 
                        Type elementType = DeserializeType(reader);
                        int count = reader.ReadEncodedInt32();

                        Array list = Array.CreateInstance(elementType, count); 
                        for (int i = 0; i < count; i++) {
                            list.SetValue(DeserializeValue(reader), i); 
                        } 

                        return list; 
                    }
                case Token_IntEnum:
                    {
                        Type enumType = DeserializeType(reader); 
                        int enumValue = reader.ReadEncodedInt32();
 
                        return Enum.ToObject(enumType, enumValue); 
                    }
                case Token_Color: 
                    return Color.FromArgb(reader.ReadInt32());
                case Token_EmptyColor:
                    return Color.Empty;
                case Token_KnownColor: 
                    return Color.FromKnownColor((KnownColor)reader.ReadEncodedInt32());
                case Token_Unit: 
                    return new Unit(reader.ReadDouble(), (UnitType)reader.ReadInt32()); 
                case Token_EmptyUnit:
                    return Unit.Empty; 
                case Token_SparseArray:
                    {
                        Type elementType = DeserializeType(reader);
                        int count = reader.ReadEncodedInt32(); 
                        int itemCount = reader.ReadEncodedInt32();
 
                        // Guard against bad data 
                        if (itemCount > count) {
                            throw new InvalidOperationException(SR.GetString(SR.InvalidSerializedData)); 
                        }

                        Array list = Array.CreateInstance(elementType, count);
                        for (int i = 0; i < itemCount; ++i) { 
                            // Data is encoded as 
                            int nextPos = reader.ReadEncodedInt32(); 
 
                            // Guard against bad data (nextPos way too big, or nextPos not increasing)
                            if (nextPos >= count || nextPos < 0) { 
                                throw new InvalidOperationException(SR.GetString(SR.InvalidSerializedData));
                            }
                            list.SetValue(DeserializeValue(reader), nextPos);
                        } 

                        return list; 
                    } 
                case Token_StringFormatted:
                    { 
                        object result = null;

                        Type valueType = DeserializeType(reader);
                        string formattedValue = reader.ReadString(); 

                        if (valueType != null) { 
                            TypeConverter converter = TypeDescriptor.GetConverter(valueType); 
                            // TypeDescriptor.GetConverter() will never return null.  The ref docs
                            // for this method are incorrect. 
                            try {
                                result = converter.ConvertFromInvariantString(formattedValue);
                            }
                            catch (Exception exception) { 
                                if (_throwOnErrorDeserializing) {
                                    throw; 
                                } 
                                else {
                                    WebBaseEvent.RaiseSystemEvent( 
                                        SR.GetString(SR.Webevent_msg_OSF_Deserialization_String, valueType.AssemblyQualifiedName),
                                        this,
                                        WebEventCodes.WebErrorObjectStateFormatterDeserializationError,
                                        WebEventCodes.UndefinedEventDetailCode, 
                                        exception);
                                } 
                            } 
                        }
 
                        return result;
                    }
                case Token_BinarySerialized:
                    { 
                        int length = reader.ReadEncodedInt32();
 
                        byte[] buffer = new byte[length]; 
                        if (length != 0) {
                            reader.Read(buffer, 0, length); 
                        }

                        object result = null;
                        MemoryStream ms = GetMemoryStream(); 
                        try {
                            ms.Write(buffer, 0, length); 
                            ms.Position = 0; 
                            IFormatter formatter = new BinaryFormatter();
 
                            result = formatter.Deserialize(ms);
                        }
                        catch (Exception exception) {
                            if (_throwOnErrorDeserializing) { 
                                throw;
                            } 
                            else { 
                                WebBaseEvent.RaiseSystemEvent(
                                    SR.GetString(SR.Webevent_msg_OSF_Deserialization_Binary), 
                                    this,
                                    WebEventCodes.WebErrorObjectStateFormatterDeserializationError,
                                    WebEventCodes.UndefinedEventDetailCode,
                                    exception); 
                            }
                        } 
                        finally { 
                            ReleaseMemoryStream(ms);
                        } 
                        return result;
                    }
                default:
                    throw new InvalidOperationException(SR.GetString(SR.InvalidSerializedData)); 
            }
        } 
 
        /// 
        /// Retrieves a memory stream from the pool. 
        /// 
        private static MemoryStream GetMemoryStream() {
            MemoryStream stream = null;
            if (_streams.Count > 0) { 
                lock (_streams) {
                    if (_streams.Count > 0) { 
                        stream = (MemoryStream)_streams.Pop(); 
                    }
                } 
            }

            if (stream == null) {
                stream = new MemoryStream(2048); 
            }
            return stream; 
        } 

 
        /// 
        /// Initializes this instance to perform deserialization.
        /// 
        private void InitializeDeserializer() { 
            _typeList = new ArrayList();
 
            for (int i = 0; i < KnownTypes.Length; i++) { 
                AddDeserializationTypeReference(KnownTypes[i]);
            } 

            _stringList = new string[Byte.MaxValue];
            _stringTableCount = 0;
        } 

        ///  
        /// Initializes this instance to perform serialization. 
        /// 
        private void InitializeSerializer() { 
            _typeTable = new HybridDictionary();

            for (int i = 0; i < KnownTypes.Length; i++) {
                AddSerializationTypeReference(KnownTypes[i]); 
            }
 
            _stringList = new string[Byte.MaxValue]; 
            _stringTable = new Hashtable();
            _stringTableCount = 0; 
        }

        /// 
        /// Returns a memory stream back into the pool. 
        /// 
        private static void ReleaseMemoryStream(MemoryStream stream) { 
            Debug.Assert(stream != null); 
            stream.Position = 0;
            stream.SetLength(0); 
            lock (_streams) {
                _streams.Push(stream);
            }
        } 

        ///  
        /// Serializes an object graph into a textual serialized form. 
        /// 
        public string Serialize(object stateGraph) { 
            string result = null;

            MemoryStream ms = GetMemoryStream();
            try { 
                Serialize(ms, stateGraph);
                ms.SetLength(ms.Position); 
 
                byte[] buffer = ms.GetBuffer();
                int length = (int)ms.Length; 

#if !FEATURE_PAL // FEATURE_PAL does not enable cryptography
                // We only support serialization of encrypted or encoded data through our internal Page constructors
                if (_page != null && _page.RequiresViewStateEncryptionInternal) { 
                    buffer = MachineKeySection.EncryptOrDecryptData(true, buffer, GetMacKeyModifier(), 0, length);
                    length = buffer.Length; 
                } 
                // We need to encode if the page has EnableViewStateMac or we got passed in some mac key string
                else if ((_page != null && _page.EnableViewStateMac) || _macKeyBytes != null) { 
                    buffer = MachineKeySection.GetEncodedData(buffer, GetMacKeyModifier(), 0, ref length);
                }

#endif // !FEATURE_PAL 
                result = Convert.ToBase64String(buffer, 0, length);
            } 
            finally { 
                ReleaseMemoryStream(ms);
            } 
            return result;
        }

        [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.SerializationFormatter)] 
        internal void SerializeWithAssert(Stream outputStream, object stateGraph) {
            Serialize(outputStream, stateGraph); 
        } 

        ///  
        /// Serializes an object graph into a binary serialized form within
        /// the specified stream.
        /// 
        public void Serialize(Stream outputStream, object stateGraph) { 
            if (outputStream == null) {
                throw new ArgumentNullException("outputStream"); 
            } 

            InitializeSerializer(); 

            SerializerBinaryWriter writer = new SerializerBinaryWriter(outputStream);
            writer.Write(Marker_Format);
            writer.Write(Marker_Version_1); 
            SerializeValue(writer, stateGraph);
        } 
 
        /// 
        /// Serializes an IndexedString. If this is the first occurrence, it is written 
        /// out to the underlying stream, and is added to the string table for future
        /// reference. Otherwise, a reference by index is written out.
        /// 
        private void SerializeIndexedString(SerializerBinaryWriter writer, string s) { 
            object id = _stringTable[s];
            if (id != null) { 
                writer.Write(Token_IndexedString); 
                writer.Write((byte)(int)id);
                return; 
            }

            AddSerializationStringReference(s);
 
            writer.Write(Token_IndexedStringAdd);
            writer.Write(s); 
        } 

        ///  
        /// Serializes a Type. If this is the first occurrence, the type name is written
        /// out to the underlying stream, and the type is added to the string table for future
        /// reference. Otherwise, a reference by index is written out.
        ///  
        private void SerializeType(SerializerBinaryWriter writer, Type type) {
            object id = _typeTable[type]; 
            if (id != null) { 
                writer.Write(Token_TypeRef);
                writer.WriteEncoded((int)id); 
                return;
            }

            AddSerializationTypeReference(type); 

            if (type.Assembly == HttpContext.SystemWebAssembly) { 
                writer.Write(Token_TypeRefAddLocal); 
                writer.Write(type.FullName);
            } 
            else {
                writer.Write(Token_TypeRefAdd);
                writer.Write(type.AssemblyQualifiedName);
            } 
        }
 
        ///  
        /// Serializes a single value using the specified writer.
        /// Handles exceptions to provide more information about the value being serialized. 
        /// 
        private void SerializeValue(SerializerBinaryWriter writer, object value) {
            try {
 
                Stack objectStack = new Stack();
                objectStack.Push(value); 
 
                do {
                    value = objectStack.Pop(); 

                    if (value == null) {
                        writer.Write(Token_Null);
                        continue; 
                    }
 
                    // NOTE: These are ordered roughly in the order of frequency. 

                    if (value is string) { 
                        string s = (string)value;
                        if (s.Length == 0) {
                            writer.Write(Token_EmptyString);
                        } 
                        else {
                            writer.Write(Token_String); 
                            writer.Write(s); 
                        }
                        continue; 
                    }

                    if (value is int) {
                        int i = (int)value; 
                        if (i == 0) {
                            writer.Write(Token_ZeroInt32); 
                        } 
                        else {
                            writer.Write(Token_Int32); 
                            writer.WriteEncoded(i);
                        }
                        continue;
                    } 

                    if (value is Pair) { 
                        writer.Write(Token_Pair); 

                        Pair p = (Pair)value; 
                        objectStack.Push(p.Second);
                        objectStack.Push(p.First);
                        continue;
                    } 

                    if (value is Triplet) { 
                        writer.Write(Token_Triplet); 

                        Triplet t = (Triplet)value; 
                        objectStack.Push(t.Third);
                        objectStack.Push(t.Second);
                        objectStack.Push(t.First);
                        continue; 
                    }
 
                    if (value is IndexedString) { 
                        Debug.Assert(((IndexedString)value).Value != null);
                        SerializeIndexedString(writer, ((IndexedString)value).Value); 
                        continue;
                    }

                    if (value.GetType() == typeof(ArrayList)) { 
                        writer.Write(Token_ArrayList);
 
                        ArrayList list = (ArrayList)value; 

                        writer.WriteEncoded(list.Count); 
                        for (int i = list.Count - 1; i >= 0; i--) {
                            objectStack.Push(list[i]);
                        }
 
                        continue;
                    } 
 
                    if (value is bool) {
                        if (((bool)value)) { 
                            writer.Write(Token_True);
                        }
                        else {
                            writer.Write(Token_False); 
                        }
                        continue; 
                    } 
                    if (value is byte) {
                        writer.Write(Token_Byte); 
                        writer.Write((byte)value);
                        continue;
                    }
                    if (value is char) { 
                        writer.Write(Token_Char);
                        writer.Write((char)value); 
                        continue; 
                    }
                    if (value is DateTime) { 
                        writer.Write(Token_DateTime);
                        writer.Write(((DateTime)value).ToBinary());
                        continue;
                    } 
                    if (value is double) {
                        writer.Write(Token_Double); 
                        writer.Write((double)value); 
                        continue;
                    } 
                    if (value is short) {
                        writer.Write(Token_Int16);
                        writer.Write((short)value);
                        continue; 
                    }
                    if (value is float) { 
                        writer.Write(Token_Single); 
                        writer.Write((float)value);
                        continue; 
                    }

                    if (value is IDictionary) {
                        bool canSerializeDictionary = false; 

                        if (value.GetType() == typeof(Hashtable)) { 
                            writer.Write(Token_Hashtable); 
                            canSerializeDictionary = true;
                        } 
                        else if (value.GetType() == typeof(HybridDictionary)) {
                            writer.Write(Token_HybridDictionary);
                            canSerializeDictionary = true;
                        } 

                        if (canSerializeDictionary) { 
                            IDictionary table = (IDictionary)value; 

                            writer.WriteEncoded(table.Count); 
                            if (table.Count != 0) {
                                foreach (DictionaryEntry entry in table) {
                                    objectStack.Push(entry.Value);
                                    objectStack.Push(entry.Key); 
                                }
                            } 
 
                            continue;
                        } 
                    }

                    if (value is Type) {
                        writer.Write(Token_Type); 
                        SerializeType(writer, (Type)value);
                        continue; 
                    } 

                    Type valueType = value.GetType(); 

                    if (value is Array) {
                        // We only support Arrays with rank 1 (No multi dimensional arrays
                        if (((Array)value).Rank > 1) { 
                            continue;
                        } 
 
                        Type underlyingType = valueType.GetElementType();
 
                        if (underlyingType == typeof(string)) {
                            string[] strings = (string[])value;
                            bool containsNulls = false;
                            for (int i = 0; i < strings.Length; i++) { 
                                if (strings[i] == null) {
                                    // Will have to treat these as generic arrays since we 
                                    // can't represent nulls in the binary stream, without 
                                    // writing out string token markers.
                                    // Generic array writing includes the token markers. 
                                    containsNulls = true;
                                    break;
                                }
                            } 

                            if (!containsNulls) { 
                                writer.Write(Token_StringArray); 
                                writer.WriteEncoded(strings.Length);
                                for (int i = 0; i < strings.Length; i++) { 
                                    writer.Write(strings[i]);
                                }
                                continue;
                            } 
                        }
 
                        Array values = (Array)value; 

                        // Optimize for sparse arrays, if the array is more than 3/4 nulls 
                        if (values.Length > 3) {
                            int sparseThreshold = (values.Length / 4) + 1;
                            int numValues = 0;
                            List items = new List(sparseThreshold); 
                            for (int i = 0; i < values.Length; ++i) {
                                if (values.GetValue(i) != null) { 
                                    ++numValues; 
                                    if (numValues >= sparseThreshold) {
                                        break; 
                                    }
                                    items.Add(i);
                                }
                            } 

                            // We have enough nulls to use sparse array format  
                            if (numValues < sparseThreshold) { 
                                writer.Write(Token_SparseArray);
                                SerializeType(writer, underlyingType); 

                                writer.WriteEncoded(values.Length);
                                writer.WriteEncoded(numValues);
 
                                // Now we need to just serialize pairs representing the index, and the item
                                foreach (int index in items) { 
                                    writer.WriteEncoded(index); 
                                    SerializeValue(writer, values.GetValue(index));
                                } 

                                continue;
                            }
                        } 

                        writer.Write(Token_Array); 
                        SerializeType(writer, underlyingType); 

                        writer.WriteEncoded(values.Length); 
                        for (int i = values.Length - 1; i >= 0; i--) {
                            objectStack.Push(values.GetValue(i));
                        }
 
                        continue;
                    } 
 
                    if (valueType.IsEnum) {
                        Type underlyingType = Enum.GetUnderlyingType(valueType); 
                        if (underlyingType == typeof(int)) {
                            writer.Write(Token_IntEnum);
                            SerializeType(writer, valueType);
                            writer.WriteEncoded((int)value); 

                            continue; 
                        } 
                    }
 
                    if (valueType == typeof(Color)) {
                        Color c = (Color)value;
                        if (c.IsEmpty) {
                            writer.Write(Token_EmptyColor); 
                            continue;
                        } 
                        if (!c.IsNamedColor) { 
                            writer.Write(Token_Color);
                            writer.Write(c.ToArgb()); 
                            continue;
                        }
                        else {
                            writer.Write(Token_KnownColor); 
                            writer.WriteEncoded((int)c.ToKnownColor());
                            continue; 
                        } 
                    }
 
                    if (value is Unit) {
                        Unit uval = (Unit)value;
                        if (uval.IsEmpty) {
                            writer.Write(Token_EmptyUnit); 
                        }
                        else { 
                            writer.Write(Token_Unit); 
                            writer.Write(uval.Value);
                            writer.Write((int)uval.Type); 
                        }
                        continue;
                    }
 
                    // Handle the remaining types
                    // First try to get a type converter, and then resort to 
                    // binary serialization if all else fails 

                    TypeConverter converter = TypeDescriptor.GetConverter(valueType); 
                    bool canConvert = System.Web.UI.Util.CanConvertToFrom(converter, typeof(string));

                    if (canConvert) {
                        writer.Write(Token_StringFormatted); 
                        SerializeType(writer, valueType);
                        writer.Write(converter.ConvertToInvariantString(null, value)); 
                    } 
                    else {
                        IFormatter formatter = new BinaryFormatter(); 
                        MemoryStream ms = new MemoryStream(256);
                        formatter.Serialize(ms, value);

                        byte[] buffer = ms.GetBuffer(); 
                        int length = (int)ms.Length;
 
                        writer.Write(Token_BinarySerialized); 
                        writer.WriteEncoded(length);
                        if (buffer.Length != 0) { 
                            writer.Write(buffer, 0, (int)length);
                        }
                    }
                } 
                while (objectStack.Count > 0);
            } 
            catch (Exception serializationException) { 
                throw new ArgumentException(SR.GetString(SR.ErrorSerializingValue, value.ToString(), value.GetType().FullName),
                                            serializationException); 
            }
        }

        #region Implementation of IStateFormatter 
        object IStateFormatter.Deserialize(string serializedState) {
            return Deserialize(serializedState); 
        } 

        string IStateFormatter.Serialize(object state) { 
            return Serialize(state);
        }
        #endregion
 
        #region Implementation of IFormatter
 
        ///  
        SerializationBinder IFormatter.Binder {
            get { 
                return null;
            }
            set {
            } 
        }
 
 
        /// 
        StreamingContext IFormatter.Context { 
            get {
                return new StreamingContext(StreamingContextStates.All);
            }
            set { 
            }
        } 
 

        ///  
        ISurrogateSelector IFormatter.SurrogateSelector {
            get {
                return null;
            } 
            set {
            } 
        } 

 
        /// 
        object IFormatter.Deserialize(Stream serializationStream) {
            return Deserialize(serializationStream);
        } 

 
        ///  
        void IFormatter.Serialize(Stream serializationStream, object stateGraph) {
            Serialize(serializationStream, stateGraph); 
        }
        #endregion

        ///  
        /// Custom BinaryReader used during the deserialization.
        ///  
        private sealed class SerializerBinaryReader : BinaryReader { 

            public SerializerBinaryReader(Stream stream) : base(stream) { 
            }

            public int ReadEncodedInt32() {
                return Read7BitEncodedInt(); 
            }
        } 
 

        ///  
        /// Custom BinaryWriter used during the serialization.
        /// 
        private sealed class SerializerBinaryWriter : BinaryWriter {
 
            public SerializerBinaryWriter(Stream stream) : base(stream) {
            } 
 
            public void WriteEncoded(int value) {
                // 

                uint v = (uint)value;
                while (v >= 0x80) {
                    Write((byte)(v | 0x80)); 
                    v >>= 7;
                } 
                Write((byte)v); 
            }
        } 
    }
}


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK