LOSFormatter.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 / LOSFormatter.cs / 1 / LOSFormatter.cs

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

#if OBJECTSTATEFORMATTER 
 
namespace System.Web.UI {
    using System; 
    using System.IO;
    using System.Security.Permissions;
    using System.Text;
 

    ///  
    /// Serializes Web Froms view state. The limited object serialization (LOS) 
    /// formatter is designed for ASCII format serialization. This class
    /// supports serializing any object graph, but is optimized for those containing 
    /// strings, arrays, and hashtables. It offers second order optimization for many of
    /// the .NET primitive types.
    /// This class has been replaced with a more optimal serialization mechanism implemented
    /// in LosSerializer. LosFormatter itself uses LosSerialization as part of its 
    /// implementation to benefit from the highly compact serialization when possible.
    ///  
    [AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)] 
    public sealed class LosFormatter {
 
        private const int InitialBufferSize = 24;

        private ObjectStateFormatter _formatter;
        private bool _enableMac; 

 
        ///  
        ///    Creates a LosFormatter object.
        ///  
        public LosFormatter() : this(false, (byte[])null) {
        }

 
        /// 
        ///    Creates a LosFormatter object, specifying whether view state mac should be 
        ///         enabled.  If it is, use macKeyModifier to modify the mac key. 
        /// 
        public LosFormatter(bool enableMac, string macKeyModifier): this (enableMac, GetBytes(macKeyModifier)) { 
        }

        public LosFormatter(bool enableMac, byte[] macKeyModifier) {
            _enableMac = enableMac; 
            if (enableMac) {
                _formatter = new ObjectStateFormatter(macKeyModifier); 
            } 
            else {
                _formatter = new ObjectStateFormatter(); 
            }
        }

        private static byte[] GetBytes(string s) { 
            if (s != null && s.Length != 0)
                return Encoding.Unicode.GetBytes(s); 
            else 
                return null;
        } 


        /// 
        ///  Deserializes a LOS-formatted object from a  object. 
        /// 
        public object Deserialize(Stream stream) { 
            TextReader input = null; 
            input = new StreamReader(stream);
            return Deserialize(input); 
        }


        ///  
        /// Deserializes a LOS-formatted object from a  object.
        ///  
        public object Deserialize(TextReader input) { 
            char[] data = new char[128];
            int read = 0; 
            int current = 0;
            int blockSize = InitialBufferSize;
            do {
                read = input.Read(data, current, blockSize); 
                current += read;
                if (current > data.Length - blockSize) { 
                    char[] bigger = new char[data.Length * 2]; 
                    Array.Copy(data, bigger, data.Length);
                    data = bigger; 
                }
            } while (read == blockSize);

            return Deserialize(new String(data, 0, current)); 
        }
 
 
        /// 
        ///    Deserializes a LOS formatted object from a string. 
        /// 
        public object Deserialize(string input) {
            return _formatter.Deserialize(input);
        } 

 
        ///  
        ///    Serializes the Web Forms view state value into
        ///       a  object. 
        /// 
        public void Serialize(Stream stream, object value) {
            TextWriter output = new StreamWriter(stream);
            SerializeInternal(output, value); 
            output.Flush();
        } 
 

        ///  
        /// Serializes the view state value into a  object.
        /// 
        public void Serialize(TextWriter output, object value) {
            SerializeInternal(output, value); 
        }
 
 
        /// 
        ///     Serialized value into the writer. 
        /// 
        private void SerializeInternal(TextWriter output, object value) {
            string data = _formatter.Serialize(value);
            output.Write(data); 
        }
    } 
} 

#else // !OBJECTSTATEFORMATTER 

// uncomment for "human readable" debugging output - no base64 encoding.
//#define NO_BASE64
 
namespace System.Web.UI {
    using System.Runtime.Serialization.Formatters.Binary; 
    using System.Runtime.Serialization; 
    using System;
    using System.IO; 
    using System.Security.Principal;
    using System.Collections;
    using System.Collections.Specialized;
    using System.Diagnostics; 
    using System.ComponentModel;
    using System.Globalization; 
    using System.Threading; 
    using System.Text;
    using System.Web.Configuration; 
    using System.Security.Permissions;


    ///  
    ///    Serializes Web Froms view state. The limited object serialization (LOS)
    ///       formatter is designed for highly compact ASCII format serialization. This class 
    ///       supports serializing any object graph, but is optimized for those containing 
    ///       strings, arrays, and hashtables. It offers second order optimization for many of
    ///       the .NET primitive types. 
    /// 
    [AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)]
    public sealed class LosFormatter : IStateFormatter {
 
        // NOTE : This formatter is not very fault tolerant, by design. I want
        //      : to avoid a bunch of reduntant checking... Since the format 
        //      : is short lived we shouldn't have to worry about it. 
        //
 
        // NOTE : Although hex encoding of numbers would be more effecient, it
        //      : would make it much harder to determine what are numbers vs.
        //      : names & types. Unless this becomes a problem, I suggest we
        //      : keep encoding in decimal. 
        //
 
        // Known Types. There can only be 50 of these... The order shouldn't 
        // matter, we store and index into this array... although there is a
        // slight perf advantage being at the top of the list... 
        //
        private static readonly Type[] knownTypes = new Type[]
        {
            typeof(object), 
            typeof(System.Web.UI.WebControls.Unit),
            typeof(System.Drawing.Color), 
            typeof(System.Int16), 
            typeof(System.Int64),
        }; 

        static readonly Encoding EncodingInstance = new UTF8Encoding(false);
        static readonly NumberFormatInfo NumberFormat = NumberFormatInfo.InvariantInfo;
 
        private const int UntypedTypeId = -1;
        private const int NoTypeId = -2; 
        private const int InitialBufferSize = 24; 
        private const int BufferGrowth = 48;
 

        // Constant chars and strings... you can change these and all references to the
        // begin, end, and delimiter chars are fixed up
        private const char leftAngleBracketChar = '<'; 
        private const char rightAngleBracketChar = '>';
        private const char valueDelimiterChar = ';'; 
 
        private static readonly char[] escapedCharacters = { leftAngleBracketChar, rightAngleBracketChar, valueDelimiterChar, '\\' };
        private static CharBufferAllocator _charBufferAllocator = new CharBufferAllocator(256, 16); 

        // reusable Temp buffer used for constructing strings from char arrays... this is
        // more performant than using a StringBuilder.
        // 
        private char[] _builder;
        private bool _recyclable; 
 
        // Tables used to build up the type and name tables during
        // serialization. Not used during deserilization. 
        private IDictionary _typeTable;

        // Deserialization variables. Not used during serialization.
        private ArrayList       _deserializedTypeTable; 
        private ListDictionary  _deserializedConverterTable;
        private char[]          _deserializationData; 
        private int             _current; 

        // MAC authentication 
        private bool _enableViewStateMac;
        private bool EnableViewStateMac {
            get { return _enableViewStateMac; }
        } 

        private byte [] _macKey = null; 
 

        ///  
        ///    Creates a LosFormatter object.
        /// 
        public LosFormatter() {}
 

        ///  
        ///    Creates a LosFormatter object, specifying whether view state mac should be 
        ///         enabled.  If it is, use macKeyModifier to modify the mac key.
        ///  
        public LosFormatter(bool enableMac, string macKeyModifier) {
            _enableViewStateMac = enableMac;

            if (macKeyModifier != null) 
                _macKey = Encoding.Unicode.GetBytes(macKeyModifier);
        } 
 

        ///  
        ///  Deserializes a LOS-formatted object from a  object.
        /// 
        public object Deserialize(Stream stream) {
            TextReader input = null; 
            input = new StreamReader(stream);
            return Deserialize(input); 
        } 

 
        /// 
        /// Deserializes a LOS-formatted object from a  object.
        /// 
        public object Deserialize(TextReader input) { 
            char[] data = new char[128];
            int read = 0; 
            int current = 0; 
            int blockSize = InitialBufferSize;
            do { 
                read = input.Read(data, current, blockSize);
                current += read;
                if (current > data.Length - blockSize) {
                    char[] bigger = new char[data.Length * 2]; 
                    Array.Copy(data, bigger, data.Length);
                    data = bigger; 
                } 
            } while (read == blockSize);
 
            return Deserialize(new String(data, 0, current));
        }

 
        /// 
        ///    Deserializes a LOS formatted object from a string. 
        ///  
        public object Deserialize(string input) {
 
#if NO_BASE64
            char[] data = input.ToCharArray();
#else
            byte[] dataBytes = Convert.FromBase64String(input); 

            int dataLength = -1; 
            if (EnableViewStateMac) { 

                try { 
                    dataBytes = MachineKeySection.GetDecodedData(dataBytes, _macKey, 0, dataBytes.Length, ref dataLength);
                }
                catch (Exception e) {
                    PerfCounters.IncrementCounter(AppPerfCounter.VIEWSTATE_MAC_FAIL); 
                    ViewStateException.ThrowMacValidationError(e, input);
                } 
            } 

            if (dataLength == -1) { 
                dataLength = dataBytes.Length;
            }

            char[] data = EncodingInstance.GetChars(dataBytes, 0, dataLength); 
#endif
 
 
            // clear or allocate name and type tables.
            // 
            if (_deserializedTypeTable == null) {
                _deserializedTypeTable = new ArrayList();
                _deserializedConverterTable = new ListDictionary();
            } 
            else {
                _deserializedTypeTable.Clear(); 
                _deserializedConverterTable.Clear(); 
            }
 
            _builder = (char[])  _charBufferAllocator.GetBuffer();
            _recyclable = true;

            // DeserializeValueInternal is recursive, so we just kick this off 
            // starting at 0
            _current = 0; 
            _deserializationData = data; 
            object ret = DeserializeValueInternal();
 
            if (_recyclable)
                _charBufferAllocator.ReuseBuffer(_builder);

            return ret; 
        }
 
 
        /// 
        ///     Deserializes a value from tokens, starting at current. When this 
        ///     function returns, current will be left at the next token.
        ///
        ///     This function is recursive.
        ///  
        private object DeserializeValueInternal() {
            // Determine the data type... possible combinations are: 
            // 
            //   @<...>     == array of strings
            //   @T<...>    == array of (typeref T) 
            //   b<...>     == base64 encoded value
            //   h<...>     == hashtable
            //   l<...>     == arraylist
            //   p<...>     == pair 
            //   t<...>     == triplet
            //   i<...>     == int 
            //   o     == boolean true/false 
            //   T<...>     == (typeref T)
            //   ...        == string 
            //

            object value = null;
 
            string token = ConsumeOneToken();
 
            if (_current >= _deserializationData.Length || _deserializationData[_current] != leftAngleBracketChar) { 
                // just a string - next token is not a left angle bracket
                // we can shortcut here and just return the string 
                //_current++; //consume right angle bracket or delimiter
                return token;
            }
 
            _current++; // consume left angle bracket
 
            // otherwise, we have typeref followed by value 
            if (token.Length == 1) {
                // simple type we recognize 
                char ch = token[0];
                if (ch == 'p') {
                    Pair p = new Pair();
 
                    if (_deserializationData[_current] != valueDelimiterChar) {
                        p.First = DeserializeValueInternal(); 
                    } 
                    _current++; // consume delimeter
                    if (_deserializationData[_current] != rightAngleBracketChar) { 
                        p.Second = DeserializeValueInternal();
                    }
                    value = p;
                } 
                else if (ch == 't') {
                    Triplet t = new Triplet(); 
 
                    if (_deserializationData[_current] != valueDelimiterChar) {
                        t.First = DeserializeValueInternal(); 
                    }
                    _current++; // consume delimeter
                    if (_deserializationData[_current] != valueDelimiterChar) {
                        t.Second = DeserializeValueInternal(); 
                    }
                    _current++; // consume delimeter 
                    if (_deserializationData[_current] != rightAngleBracketChar) { 
                        t.Third = DeserializeValueInternal();
                    } 
                    value = t;
                }

                // Parse int32... 
                else if (ch == 'i') {
                    value = Int32.Parse(ConsumeOneToken(), NumberFormat); 
                } 

                else if (ch == 'o') { 
                    value = _deserializationData[_current] == 't';
                    _current++;  // consume t or f
                }
 
                // Parse arrayList...
                // 
                else if (ch == 'l') { 
                    ArrayList data = new ArrayList();
 
                    while (_deserializationData[_current] != rightAngleBracketChar) {
                        object itemValue = null;
                        if (_deserializationData[_current] != valueDelimiterChar) {
                            itemValue = DeserializeValueInternal(); 
                        }
                        data.Add(itemValue); 
                        _current++; //consume the delimiter 
                    }
 
                    value = data;
                }
                else if (ch == '@') {
                    // if we're here, length == 1 so this is a string array 
                    value = ConsumeStringArray();
                } 
 
                // Parse hashtable...
                // 
                else if (ch == 'h') {
                    Hashtable data = new Hashtable();

                    while (_deserializationData[_current] != rightAngleBracketChar) { 
                        object key;
                        key = DeserializeValueInternal();   // hashtable key cannot be null 
 
                        _current++; // consume delimiter
                        if (_deserializationData[_current] != valueDelimiterChar) { 
                            data[key] = DeserializeValueInternal();
                        }
                        else {
                            data[key] = null; 
                        }
 
                        _current++; // consume delimiter 
                    }
 
                    value = data;
                }

                // base64 encoded... 
                //
                else if (ch == 'b') { 
                    string text = ConsumeOneToken(); 
                    byte[] serializedData;
                    serializedData = Convert.FromBase64String(text); 

                    if (!String.IsNullOrEmpty(serializedData)) {
                        System.Runtime.Serialization.IFormatter formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
                        value = formatter.Deserialize(new MemoryStream(serializedData)); 
                    }
                } 
 
                // Parse typeconverter value ...
                // 
                else {
                    // we have a typeref which is only one character long
                    value = ConsumeTypeConverterValue(token);
                } 

 
            } 
            else {
                // length > 1 

                // Parse array...
                //
                if (token[0] == '@') { 
                    // if we're here, length > 1 so we must have a type ref after the @
                    Type creatableType = TypeFromTypeRef(token.Substring(1)); 
                    value = ConsumeArray(creatableType); 
                }
 
                // Parse typeconverter value ...
                //
                else {
                    // we have a typeref which is more than one character long 
                    value = ConsumeTypeConverterValue(token);
                } 
            } 

            _current++; //consume right angle bracket 
            return value;
        }

 

        private string ConsumeOneToken() { 
            int locInBuilder = 0; 

            while (_current < _deserializationData.Length) 
            {
                switch (_deserializationData[_current]) {
                    case '\\':
                        _current++; // skip slash 
                        if (_deserializationData[_current] == 'e') {
                            _current++; 
                            return String.Empty; 
                        }
                        _builder[locInBuilder] = _deserializationData[_current]; 
                        locInBuilder++;
                        break;
                    case valueDelimiterChar:
                    case leftAngleBracketChar: 
                    case rightAngleBracketChar:
                        return new string(_builder, 0, locInBuilder); 
 
                    default:
                        _builder[locInBuilder] = _deserializationData[_current]; 
                        locInBuilder++;
                        break;
                }
 
                _current++;
 
                // Alloc _builder always 2 greater than locInBuilder to make sure 
                // we can do nested/escape parsing without error...
                // 
                if (locInBuilder >= _builder.Length) {
                    char[] bigger = new char[_builder.Length + BufferGrowth];
                    Array.Copy(_builder, bigger, _builder.Length);
                    _builder = bigger; 
                    _recyclable = false;
                } 
            } 
            return new string(_builder, 0, locInBuilder);
        } 

        private object ConsumeStringArray() {
            ArrayList data = new ArrayList();
            while (_deserializationData[_current] != rightAngleBracketChar) { 
                object itemValue = null;
                if (_deserializationData[_current] != valueDelimiterChar) { 
                    itemValue = ConsumeOneToken(); 
                }
                data.Add(itemValue); 
                _current++; //consume the delimiter
            }

            return data.ToArray(typeof(string)); 
        }
 
        private object ConsumeArray(Type creatableType) { 
            ArrayList data = new ArrayList();
            while (_deserializationData[_current] != rightAngleBracketChar) { 
                object itemValue = null;
                if (_deserializationData[_current] != valueDelimiterChar) {
                    itemValue = DeserializeValueInternal();
                } 
                data.Add(itemValue);
                _current++; //consume the delimiter 
            } 

            return data.ToArray(creatableType); 
        }

        private object ConsumeTypeConverterValue(string token) {
            int typeref = ParseNumericString(token); 
            TypeConverter tc;
 
            if (typeref != -1) { 
                // token is the string representation of the number here
                tc = (TypeConverter) _deserializedConverterTable[token]; 
                if (tc == null) {
                    // wasn't in the converter table, add it now
                    // we need this case because arrays can add types but not typeconverters
                    Type t = TypeFromTypeCode(typeref); 
                    tc = TypeDescriptor.GetConverter(t);
                    _deserializedConverterTable[token] = tc; 
                } 
            }
            else { 
                // it's just a name, lookup type and add to type table
                Type t = Type.GetType(token);
                tc = TypeDescriptor.GetConverter(t);
 
                // add to type table and converter table.
                _deserializedConverterTable[(_deserializedTypeTable.Count + 50).ToString(NumberFormat)] = tc; 
                _deserializedTypeTable.Add(t); 
            }
            string text = ConsumeOneToken(); 
            return tc.ConvertFrom(null, CultureInfo.InvariantCulture, text);
        }

 
        /// 
        ///    Serializes the Web Forms view state value into 
        ///       a  object. 
        /// 
        public void Serialize(Stream stream, object value) { 
            TextWriter output = new StreamWriter(stream);
            SerializeInternal(output, value);
            output.Flush();
        } 

 
        ///  
        /// Serializes the view state value into a  object.
        ///  
        public void Serialize(TextWriter output, object value) {
            SerializeInternal(output, value);
        }
 

        ///  
        ///     Serialized value into the writer. 
        /// 
        private void SerializeInternal(TextWriter output, object value) { 
            if (value == null)
                return;

            if (_typeTable == null) 
                _typeTable = new HybridDictionary();
            else 
                _typeTable.Clear(); 

#if NO_BASE64 
            SerializeValue(output, value);
#else

            LosWriter writer = new LosWriter(); 

            SerializeValue(writer, value); 
 
            writer.CompleteTransforms(output, EnableViewStateMac, _macKey);
            writer.Dispose(); 
#endif

        }
 

        ///  
        ///     Recursively serializes value into the writer. 
        /// 
        private void SerializeValue(TextWriter output, object value) { 
            if (value == null)
                return;

            // First determine the type... either typeless (string), array, 
            // typed array, hashtable, pair, triplet, knowntype, typetable reference, or
            // type... 
            // 

            // serialize string... 
            //
            if (value is string) {
                WriteEscapedString(output, (string)value);
            } 

            // serialize Int32... 
            // 
            else if (value is Int32) {
                output.Write('i'); 
                output.Write(leftAngleBracketChar);
                output.Write(((Int32)value).ToString(NumberFormat));
                output.Write(rightAngleBracketChar);
            } 
            else if (value is Boolean) {
                output.Write('o'); 
                output.Write(leftAngleBracketChar); 
                output.Write( ((bool) value) ? 't' : 'f');
                output.Write(rightAngleBracketChar); 
            }

            // serialize arraylist...
            // 
            else if (value is ArrayList) {
                output.Write('l'); 
                output.Write(leftAngleBracketChar); 

                ArrayList ar = (ArrayList)value; 
                int c = ar.Count;
                for (int i=0; i 
        ///     Takes a typeRef, and converts it to a Type. Either by returning
        ///     Type.GetType(typeRef), or looking it up. 
        /// 
        private Type TypeFromTypeRef(string typeRef) {

            int number = ParseNumericString(typeRef); 

            Type t = TypeFromTypeCode(number); 
 
            if (t != null)
                return t; 

            // it's just a name, lookup type and add to type table
            t = Type.GetType(typeRef);
            _deserializedTypeTable.Add(t); 
            return t;
 
        } 

        private Type TypeFromTypeCode(int number) { 
            if (number != -1) {
                // it is a type id, either in the known table or in our type table
                if (number <= 49)
                    return knownTypes[number]; 

                return (Type) _deserializedTypeTable[number - 50]; 
 
            }
            return null; 
        }


        // Note : We have to determine if "typeRef" is a number. The easiest 
        //      : and fastest way to do this is to walk the string. While
        //      : we are doing this, lets build up the number... after 
        //      : all this is much faster than Int32.Parse 
        //
        private int ParseNumericString(string num) { 
            int number = 0;
            int len = num.Length;

            for (int i=0; i
        ///     Escapes and writes the escaped value of str into the writer.
        ///  
        private void WriteEscapedString(TextWriter output, string str) {
 
            if (str == null) 
                return;
 
            // need to "escape" the empty string to distinguish it
            // from a null value
            if (str.Length == 0) {
                output.Write('\\'); 
                output.Write('e');
                return; 
            } 

            int first = str.IndexOfAny(escapedCharacters); 
            if (first == -1) {
                output.Write(str);
            }
            else { 
                char[] strData = str.ToCharArray();
                output.Write(strData, 0, first); 
                int len = strData.Length; 

                for (int i=first; i
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

#if OBJECTSTATEFORMATTER 
 
namespace System.Web.UI {
    using System; 
    using System.IO;
    using System.Security.Permissions;
    using System.Text;
 

    ///  
    /// Serializes Web Froms view state. The limited object serialization (LOS) 
    /// formatter is designed for ASCII format serialization. This class
    /// supports serializing any object graph, but is optimized for those containing 
    /// strings, arrays, and hashtables. It offers second order optimization for many of
    /// the .NET primitive types.
    /// This class has been replaced with a more optimal serialization mechanism implemented
    /// in LosSerializer. LosFormatter itself uses LosSerialization as part of its 
    /// implementation to benefit from the highly compact serialization when possible.
    ///  
    [AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)] 
    public sealed class LosFormatter {
 
        private const int InitialBufferSize = 24;

        private ObjectStateFormatter _formatter;
        private bool _enableMac; 

 
        ///  
        ///    Creates a LosFormatter object.
        ///  
        public LosFormatter() : this(false, (byte[])null) {
        }

 
        /// 
        ///    Creates a LosFormatter object, specifying whether view state mac should be 
        ///         enabled.  If it is, use macKeyModifier to modify the mac key. 
        /// 
        public LosFormatter(bool enableMac, string macKeyModifier): this (enableMac, GetBytes(macKeyModifier)) { 
        }

        public LosFormatter(bool enableMac, byte[] macKeyModifier) {
            _enableMac = enableMac; 
            if (enableMac) {
                _formatter = new ObjectStateFormatter(macKeyModifier); 
            } 
            else {
                _formatter = new ObjectStateFormatter(); 
            }
        }

        private static byte[] GetBytes(string s) { 
            if (s != null && s.Length != 0)
                return Encoding.Unicode.GetBytes(s); 
            else 
                return null;
        } 


        /// 
        ///  Deserializes a LOS-formatted object from a  object. 
        /// 
        public object Deserialize(Stream stream) { 
            TextReader input = null; 
            input = new StreamReader(stream);
            return Deserialize(input); 
        }


        ///  
        /// Deserializes a LOS-formatted object from a  object.
        ///  
        public object Deserialize(TextReader input) { 
            char[] data = new char[128];
            int read = 0; 
            int current = 0;
            int blockSize = InitialBufferSize;
            do {
                read = input.Read(data, current, blockSize); 
                current += read;
                if (current > data.Length - blockSize) { 
                    char[] bigger = new char[data.Length * 2]; 
                    Array.Copy(data, bigger, data.Length);
                    data = bigger; 
                }
            } while (read == blockSize);

            return Deserialize(new String(data, 0, current)); 
        }
 
 
        /// 
        ///    Deserializes a LOS formatted object from a string. 
        /// 
        public object Deserialize(string input) {
            return _formatter.Deserialize(input);
        } 

 
        ///  
        ///    Serializes the Web Forms view state value into
        ///       a  object. 
        /// 
        public void Serialize(Stream stream, object value) {
            TextWriter output = new StreamWriter(stream);
            SerializeInternal(output, value); 
            output.Flush();
        } 
 

        ///  
        /// Serializes the view state value into a  object.
        /// 
        public void Serialize(TextWriter output, object value) {
            SerializeInternal(output, value); 
        }
 
 
        /// 
        ///     Serialized value into the writer. 
        /// 
        private void SerializeInternal(TextWriter output, object value) {
            string data = _formatter.Serialize(value);
            output.Write(data); 
        }
    } 
} 

#else // !OBJECTSTATEFORMATTER 

// uncomment for "human readable" debugging output - no base64 encoding.
//#define NO_BASE64
 
namespace System.Web.UI {
    using System.Runtime.Serialization.Formatters.Binary; 
    using System.Runtime.Serialization; 
    using System;
    using System.IO; 
    using System.Security.Principal;
    using System.Collections;
    using System.Collections.Specialized;
    using System.Diagnostics; 
    using System.ComponentModel;
    using System.Globalization; 
    using System.Threading; 
    using System.Text;
    using System.Web.Configuration; 
    using System.Security.Permissions;


    ///  
    ///    Serializes Web Froms view state. The limited object serialization (LOS)
    ///       formatter is designed for highly compact ASCII format serialization. This class 
    ///       supports serializing any object graph, but is optimized for those containing 
    ///       strings, arrays, and hashtables. It offers second order optimization for many of
    ///       the .NET primitive types. 
    /// 
    [AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)]
    public sealed class LosFormatter : IStateFormatter {
 
        // NOTE : This formatter is not very fault tolerant, by design. I want
        //      : to avoid a bunch of reduntant checking... Since the format 
        //      : is short lived we shouldn't have to worry about it. 
        //
 
        // NOTE : Although hex encoding of numbers would be more effecient, it
        //      : would make it much harder to determine what are numbers vs.
        //      : names & types. Unless this becomes a problem, I suggest we
        //      : keep encoding in decimal. 
        //
 
        // Known Types. There can only be 50 of these... The order shouldn't 
        // matter, we store and index into this array... although there is a
        // slight perf advantage being at the top of the list... 
        //
        private static readonly Type[] knownTypes = new Type[]
        {
            typeof(object), 
            typeof(System.Web.UI.WebControls.Unit),
            typeof(System.Drawing.Color), 
            typeof(System.Int16), 
            typeof(System.Int64),
        }; 

        static readonly Encoding EncodingInstance = new UTF8Encoding(false);
        static readonly NumberFormatInfo NumberFormat = NumberFormatInfo.InvariantInfo;
 
        private const int UntypedTypeId = -1;
        private const int NoTypeId = -2; 
        private const int InitialBufferSize = 24; 
        private const int BufferGrowth = 48;
 

        // Constant chars and strings... you can change these and all references to the
        // begin, end, and delimiter chars are fixed up
        private const char leftAngleBracketChar = '<'; 
        private const char rightAngleBracketChar = '>';
        private const char valueDelimiterChar = ';'; 
 
        private static readonly char[] escapedCharacters = { leftAngleBracketChar, rightAngleBracketChar, valueDelimiterChar, '\\' };
        private static CharBufferAllocator _charBufferAllocator = new CharBufferAllocator(256, 16); 

        // reusable Temp buffer used for constructing strings from char arrays... this is
        // more performant than using a StringBuilder.
        // 
        private char[] _builder;
        private bool _recyclable; 
 
        // Tables used to build up the type and name tables during
        // serialization. Not used during deserilization. 
        private IDictionary _typeTable;

        // Deserialization variables. Not used during serialization.
        private ArrayList       _deserializedTypeTable; 
        private ListDictionary  _deserializedConverterTable;
        private char[]          _deserializationData; 
        private int             _current; 

        // MAC authentication 
        private bool _enableViewStateMac;
        private bool EnableViewStateMac {
            get { return _enableViewStateMac; }
        } 

        private byte [] _macKey = null; 
 

        ///  
        ///    Creates a LosFormatter object.
        /// 
        public LosFormatter() {}
 

        ///  
        ///    Creates a LosFormatter object, specifying whether view state mac should be 
        ///         enabled.  If it is, use macKeyModifier to modify the mac key.
        ///  
        public LosFormatter(bool enableMac, string macKeyModifier) {
            _enableViewStateMac = enableMac;

            if (macKeyModifier != null) 
                _macKey = Encoding.Unicode.GetBytes(macKeyModifier);
        } 
 

        ///  
        ///  Deserializes a LOS-formatted object from a  object.
        /// 
        public object Deserialize(Stream stream) {
            TextReader input = null; 
            input = new StreamReader(stream);
            return Deserialize(input); 
        } 

 
        /// 
        /// Deserializes a LOS-formatted object from a  object.
        /// 
        public object Deserialize(TextReader input) { 
            char[] data = new char[128];
            int read = 0; 
            int current = 0; 
            int blockSize = InitialBufferSize;
            do { 
                read = input.Read(data, current, blockSize);
                current += read;
                if (current > data.Length - blockSize) {
                    char[] bigger = new char[data.Length * 2]; 
                    Array.Copy(data, bigger, data.Length);
                    data = bigger; 
                } 
            } while (read == blockSize);
 
            return Deserialize(new String(data, 0, current));
        }

 
        /// 
        ///    Deserializes a LOS formatted object from a string. 
        ///  
        public object Deserialize(string input) {
 
#if NO_BASE64
            char[] data = input.ToCharArray();
#else
            byte[] dataBytes = Convert.FromBase64String(input); 

            int dataLength = -1; 
            if (EnableViewStateMac) { 

                try { 
                    dataBytes = MachineKeySection.GetDecodedData(dataBytes, _macKey, 0, dataBytes.Length, ref dataLength);
                }
                catch (Exception e) {
                    PerfCounters.IncrementCounter(AppPerfCounter.VIEWSTATE_MAC_FAIL); 
                    ViewStateException.ThrowMacValidationError(e, input);
                } 
            } 

            if (dataLength == -1) { 
                dataLength = dataBytes.Length;
            }

            char[] data = EncodingInstance.GetChars(dataBytes, 0, dataLength); 
#endif
 
 
            // clear or allocate name and type tables.
            // 
            if (_deserializedTypeTable == null) {
                _deserializedTypeTable = new ArrayList();
                _deserializedConverterTable = new ListDictionary();
            } 
            else {
                _deserializedTypeTable.Clear(); 
                _deserializedConverterTable.Clear(); 
            }
 
            _builder = (char[])  _charBufferAllocator.GetBuffer();
            _recyclable = true;

            // DeserializeValueInternal is recursive, so we just kick this off 
            // starting at 0
            _current = 0; 
            _deserializationData = data; 
            object ret = DeserializeValueInternal();
 
            if (_recyclable)
                _charBufferAllocator.ReuseBuffer(_builder);

            return ret; 
        }
 
 
        /// 
        ///     Deserializes a value from tokens, starting at current. When this 
        ///     function returns, current will be left at the next token.
        ///
        ///     This function is recursive.
        ///  
        private object DeserializeValueInternal() {
            // Determine the data type... possible combinations are: 
            // 
            //   @<...>     == array of strings
            //   @T<...>    == array of (typeref T) 
            //   b<...>     == base64 encoded value
            //   h<...>     == hashtable
            //   l<...>     == arraylist
            //   p<...>     == pair 
            //   t<...>     == triplet
            //   i<...>     == int 
            //   o     == boolean true/false 
            //   T<...>     == (typeref T)
            //   ...        == string 
            //

            object value = null;
 
            string token = ConsumeOneToken();
 
            if (_current >= _deserializationData.Length || _deserializationData[_current] != leftAngleBracketChar) { 
                // just a string - next token is not a left angle bracket
                // we can shortcut here and just return the string 
                //_current++; //consume right angle bracket or delimiter
                return token;
            }
 
            _current++; // consume left angle bracket
 
            // otherwise, we have typeref followed by value 
            if (token.Length == 1) {
                // simple type we recognize 
                char ch = token[0];
                if (ch == 'p') {
                    Pair p = new Pair();
 
                    if (_deserializationData[_current] != valueDelimiterChar) {
                        p.First = DeserializeValueInternal(); 
                    } 
                    _current++; // consume delimeter
                    if (_deserializationData[_current] != rightAngleBracketChar) { 
                        p.Second = DeserializeValueInternal();
                    }
                    value = p;
                } 
                else if (ch == 't') {
                    Triplet t = new Triplet(); 
 
                    if (_deserializationData[_current] != valueDelimiterChar) {
                        t.First = DeserializeValueInternal(); 
                    }
                    _current++; // consume delimeter
                    if (_deserializationData[_current] != valueDelimiterChar) {
                        t.Second = DeserializeValueInternal(); 
                    }
                    _current++; // consume delimeter 
                    if (_deserializationData[_current] != rightAngleBracketChar) { 
                        t.Third = DeserializeValueInternal();
                    } 
                    value = t;
                }

                // Parse int32... 
                else if (ch == 'i') {
                    value = Int32.Parse(ConsumeOneToken(), NumberFormat); 
                } 

                else if (ch == 'o') { 
                    value = _deserializationData[_current] == 't';
                    _current++;  // consume t or f
                }
 
                // Parse arrayList...
                // 
                else if (ch == 'l') { 
                    ArrayList data = new ArrayList();
 
                    while (_deserializationData[_current] != rightAngleBracketChar) {
                        object itemValue = null;
                        if (_deserializationData[_current] != valueDelimiterChar) {
                            itemValue = DeserializeValueInternal(); 
                        }
                        data.Add(itemValue); 
                        _current++; //consume the delimiter 
                    }
 
                    value = data;
                }
                else if (ch == '@') {
                    // if we're here, length == 1 so this is a string array 
                    value = ConsumeStringArray();
                } 
 
                // Parse hashtable...
                // 
                else if (ch == 'h') {
                    Hashtable data = new Hashtable();

                    while (_deserializationData[_current] != rightAngleBracketChar) { 
                        object key;
                        key = DeserializeValueInternal();   // hashtable key cannot be null 
 
                        _current++; // consume delimiter
                        if (_deserializationData[_current] != valueDelimiterChar) { 
                            data[key] = DeserializeValueInternal();
                        }
                        else {
                            data[key] = null; 
                        }
 
                        _current++; // consume delimiter 
                    }
 
                    value = data;
                }

                // base64 encoded... 
                //
                else if (ch == 'b') { 
                    string text = ConsumeOneToken(); 
                    byte[] serializedData;
                    serializedData = Convert.FromBase64String(text); 

                    if (!String.IsNullOrEmpty(serializedData)) {
                        System.Runtime.Serialization.IFormatter formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
                        value = formatter.Deserialize(new MemoryStream(serializedData)); 
                    }
                } 
 
                // Parse typeconverter value ...
                // 
                else {
                    // we have a typeref which is only one character long
                    value = ConsumeTypeConverterValue(token);
                } 

 
            } 
            else {
                // length > 1 

                // Parse array...
                //
                if (token[0] == '@') { 
                    // if we're here, length > 1 so we must have a type ref after the @
                    Type creatableType = TypeFromTypeRef(token.Substring(1)); 
                    value = ConsumeArray(creatableType); 
                }
 
                // Parse typeconverter value ...
                //
                else {
                    // we have a typeref which is more than one character long 
                    value = ConsumeTypeConverterValue(token);
                } 
            } 

            _current++; //consume right angle bracket 
            return value;
        }

 

        private string ConsumeOneToken() { 
            int locInBuilder = 0; 

            while (_current < _deserializationData.Length) 
            {
                switch (_deserializationData[_current]) {
                    case '\\':
                        _current++; // skip slash 
                        if (_deserializationData[_current] == 'e') {
                            _current++; 
                            return String.Empty; 
                        }
                        _builder[locInBuilder] = _deserializationData[_current]; 
                        locInBuilder++;
                        break;
                    case valueDelimiterChar:
                    case leftAngleBracketChar: 
                    case rightAngleBracketChar:
                        return new string(_builder, 0, locInBuilder); 
 
                    default:
                        _builder[locInBuilder] = _deserializationData[_current]; 
                        locInBuilder++;
                        break;
                }
 
                _current++;
 
                // Alloc _builder always 2 greater than locInBuilder to make sure 
                // we can do nested/escape parsing without error...
                // 
                if (locInBuilder >= _builder.Length) {
                    char[] bigger = new char[_builder.Length + BufferGrowth];
                    Array.Copy(_builder, bigger, _builder.Length);
                    _builder = bigger; 
                    _recyclable = false;
                } 
            } 
            return new string(_builder, 0, locInBuilder);
        } 

        private object ConsumeStringArray() {
            ArrayList data = new ArrayList();
            while (_deserializationData[_current] != rightAngleBracketChar) { 
                object itemValue = null;
                if (_deserializationData[_current] != valueDelimiterChar) { 
                    itemValue = ConsumeOneToken(); 
                }
                data.Add(itemValue); 
                _current++; //consume the delimiter
            }

            return data.ToArray(typeof(string)); 
        }
 
        private object ConsumeArray(Type creatableType) { 
            ArrayList data = new ArrayList();
            while (_deserializationData[_current] != rightAngleBracketChar) { 
                object itemValue = null;
                if (_deserializationData[_current] != valueDelimiterChar) {
                    itemValue = DeserializeValueInternal();
                } 
                data.Add(itemValue);
                _current++; //consume the delimiter 
            } 

            return data.ToArray(creatableType); 
        }

        private object ConsumeTypeConverterValue(string token) {
            int typeref = ParseNumericString(token); 
            TypeConverter tc;
 
            if (typeref != -1) { 
                // token is the string representation of the number here
                tc = (TypeConverter) _deserializedConverterTable[token]; 
                if (tc == null) {
                    // wasn't in the converter table, add it now
                    // we need this case because arrays can add types but not typeconverters
                    Type t = TypeFromTypeCode(typeref); 
                    tc = TypeDescriptor.GetConverter(t);
                    _deserializedConverterTable[token] = tc; 
                } 
            }
            else { 
                // it's just a name, lookup type and add to type table
                Type t = Type.GetType(token);
                tc = TypeDescriptor.GetConverter(t);
 
                // add to type table and converter table.
                _deserializedConverterTable[(_deserializedTypeTable.Count + 50).ToString(NumberFormat)] = tc; 
                _deserializedTypeTable.Add(t); 
            }
            string text = ConsumeOneToken(); 
            return tc.ConvertFrom(null, CultureInfo.InvariantCulture, text);
        }

 
        /// 
        ///    Serializes the Web Forms view state value into 
        ///       a  object. 
        /// 
        public void Serialize(Stream stream, object value) { 
            TextWriter output = new StreamWriter(stream);
            SerializeInternal(output, value);
            output.Flush();
        } 

 
        ///  
        /// Serializes the view state value into a  object.
        ///  
        public void Serialize(TextWriter output, object value) {
            SerializeInternal(output, value);
        }
 

        ///  
        ///     Serialized value into the writer. 
        /// 
        private void SerializeInternal(TextWriter output, object value) { 
            if (value == null)
                return;

            if (_typeTable == null) 
                _typeTable = new HybridDictionary();
            else 
                _typeTable.Clear(); 

#if NO_BASE64 
            SerializeValue(output, value);
#else

            LosWriter writer = new LosWriter(); 

            SerializeValue(writer, value); 
 
            writer.CompleteTransforms(output, EnableViewStateMac, _macKey);
            writer.Dispose(); 
#endif

        }
 

        ///  
        ///     Recursively serializes value into the writer. 
        /// 
        private void SerializeValue(TextWriter output, object value) { 
            if (value == null)
                return;

            // First determine the type... either typeless (string), array, 
            // typed array, hashtable, pair, triplet, knowntype, typetable reference, or
            // type... 
            // 

            // serialize string... 
            //
            if (value is string) {
                WriteEscapedString(output, (string)value);
            } 

            // serialize Int32... 
            // 
            else if (value is Int32) {
                output.Write('i'); 
                output.Write(leftAngleBracketChar);
                output.Write(((Int32)value).ToString(NumberFormat));
                output.Write(rightAngleBracketChar);
            } 
            else if (value is Boolean) {
                output.Write('o'); 
                output.Write(leftAngleBracketChar); 
                output.Write( ((bool) value) ? 't' : 'f');
                output.Write(rightAngleBracketChar); 
            }

            // serialize arraylist...
            // 
            else if (value is ArrayList) {
                output.Write('l'); 
                output.Write(leftAngleBracketChar); 

                ArrayList ar = (ArrayList)value; 
                int c = ar.Count;
                for (int i=0; i 
        ///     Takes a typeRef, and converts it to a Type. Either by returning
        ///     Type.GetType(typeRef), or looking it up. 
        /// 
        private Type TypeFromTypeRef(string typeRef) {

            int number = ParseNumericString(typeRef); 

            Type t = TypeFromTypeCode(number); 
 
            if (t != null)
                return t; 

            // it's just a name, lookup type and add to type table
            t = Type.GetType(typeRef);
            _deserializedTypeTable.Add(t); 
            return t;
 
        } 

        private Type TypeFromTypeCode(int number) { 
            if (number != -1) {
                // it is a type id, either in the known table or in our type table
                if (number <= 49)
                    return knownTypes[number]; 

                return (Type) _deserializedTypeTable[number - 50]; 
 
            }
            return null; 
        }


        // Note : We have to determine if "typeRef" is a number. The easiest 
        //      : and fastest way to do this is to walk the string. While
        //      : we are doing this, lets build up the number... after 
        //      : all this is much faster than Int32.Parse 
        //
        private int ParseNumericString(string num) { 
            int number = 0;
            int len = num.Length;

            for (int i=0; i
        ///     Escapes and writes the escaped value of str into the writer.
        ///  
        private void WriteEscapedString(TextWriter output, string str) {
 
            if (str == null) 
                return;
 
            // need to "escape" the empty string to distinguish it
            // from a null value
            if (str.Length == 0) {
                output.Write('\\'); 
                output.Write('e');
                return; 
            } 

            int first = str.IndexOfAny(escapedCharacters); 
            if (first == -1) {
                output.Write(str);
            }
            else { 
                char[] strData = str.ToCharArray();
                output.Write(strData, 0, first); 
                int len = strData.Length; 

                for (int i=first; i

                        

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