JsonWriter.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataWeb / Server / System / Data / Services / Serializers / JsonWriter.cs / 1602603 / JsonWriter.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//  
//      Provides a writer implementaion for Json format
//  
// 
// @owner  [....]
//--------------------------------------------------------------------- 

namespace System.Data.Services.Serializers
{
    using System; 
    using System.Collections.Generic;
    using System.Globalization; 
    using System.IO; 
    using System.Text;
    using System.Xml; 

    /// 
    /// Json text writer
    ///  
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable", Justification = "Original writer is disposed of?")]
    internal sealed class JsonWriter 
    { 
        ///  const tick value for caculating tick values
        internal static readonly long DatetimeMinTimeTicks = (new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).Ticks; 

        ///  Json datetime format 
        private const string JsonDateTimeFormat = @"\/Date({0})\/";
 
        /// Text used to start a data object wrapper in JSON.
        private const string JsonDataWrapper = "\"d\" : "; 
 
        /// "results" header for Json data array
        private const string JsonResultName = "results"; 

        ///  Writer to write text into 
        private readonly IndentedTextWriter writer;
 
        ///  scope of the json text - object, array, etc
        private readonly Stack scopes; 
 
        /// 
        /// Creates a new instance of Json writer 
        /// 
        /// writer to which text needs to be written
        public JsonWriter(TextWriter writer)
        { 
            this.writer = new IndentedTextWriter(writer);
            this.scopes = new Stack(); 
        } 

        ///  
        /// Various scope types for Json writer
        /// 
        private enum ScopeType
        { 
            ///  array scope 
            Array = 0, 
 
            ///  object scope
            Object = 1 
        }

        /// 
        /// End the current scope 
        /// 
        public void EndScope() 
        { 
            if (this.scopes.Count == 0)
            { 
                throw new InvalidOperationException("No active scope to end.");
            }

            this.writer.WriteLine(); 
            this.writer.Indent--;
 
            Scope scope = this.scopes.Pop(); 
            if (scope.Type == ScopeType.Array)
            { 
                this.writer.Write("]");
            }
            else
            { 
                this.writer.Write("}");
            } 
        } 

        ///  
        /// Start the array scope
        /// 
        public void StartArrayScope()
        { 
            this.StartScope(ScopeType.Array);
        } 
 
        /// 
        /// Write the "d" wrapper text 
        /// 
        public void WriteDataWrapper()
        {
            this.writer.Write(JsonDataWrapper); 
        }
 
        ///  
        /// Write the "results" header for the data array
        ///  
        public void WriteDataArrayName()
        {
            this.WriteName(JsonResultName);
        } 

        ///  
        /// Start the object scope 
        /// 
        public void StartObjectScope() 
        {
            this.StartScope(ScopeType.Object);
        }
 
        /// 
        /// Write the name for the object property 
        ///  
        /// name of the object property 
        public void WriteName(string name) 
        {
            if (String.IsNullOrEmpty(name))
            {
                throw new ArgumentNullException("name"); 
            }
 
            if (this.scopes.Count == 0) 
            {
                throw new InvalidOperationException("No active scope to write into."); 
            }

            if (this.scopes.Peek().Type != ScopeType.Object)
            { 
                throw new InvalidOperationException("Names can only be written into Object Scopes.");
            } 
 
            Scope currentScope = this.scopes.Peek();
            if (currentScope.Type == ScopeType.Object) 
            {
                if (currentScope.ObjectCount != 0)
                {
                    this.writer.WriteTrimmed(", "); 
                }
 
                currentScope.ObjectCount++; 
            }
 
            this.WriteCore(QuoteJScriptString(name), true /*quotes*/);
            this.writer.WriteTrimmed(": ");
        }
 
        /// 
        /// Write the bool value 
        ///  
        /// bool value to be written
        public void WriteValue(bool value) 
        {
            this.WriteCore(value ? XmlConstants.XmlTrueLiteral : XmlConstants.XmlFalseLiteral, /* quotes */ false);
        }
 
        /// 
        /// Write the int value 
        ///  
        /// int value to be written
        public void WriteValue(int value) 
        {
            this.WriteCore(value.ToString(CultureInfo.InvariantCulture), /* quotes */ false);
        }
 
        /// 
        /// Write the float value 
        ///  
        /// float value to be written
        public void WriteValue(float value) 
        {
            if (double.IsInfinity(value) || double.IsNaN(value))
            {
                this.WriteCore(value.ToString(null, CultureInfo.InvariantCulture), true /*quotes*/); 
            }
            else 
            { 
                // float.ToString() supports a max scale of six,
                // whereas float.MinValue and float.MaxValue have 8 digits scale. Hence we need 
                // to use XmlConvert in all other cases, except infinity
                this.WriteCore(XmlConvert.ToString(value), /* quotes */ false);
            }
        } 

        ///  
        /// Write the short value 
        /// 
        /// short value to be written 
        public void WriteValue(short value)
        {
            this.WriteCore(value.ToString(CultureInfo.InvariantCulture), /* quotes */ false);
        } 

        ///  
        /// Write the long value 
        /// 
        /// long value to be written 
        public void WriteValue(long value)
        {
            // Since Json only supports number, we need to convert long into string to prevent data loss
            this.WriteCore(value.ToString(CultureInfo.InvariantCulture), /* quotes */ true); 
        }
 
        ///  
        /// Write the double value
        ///  
        /// double value to be written
        public void WriteValue(double value)
        {
            if (double.IsInfinity(value) || double.IsNaN(value)) 
            {
                this.WriteCore(value.ToString(null, CultureInfo.InvariantCulture), true /*quotes*/); 
            } 
            else
            { 
                // double.ToString() supports a max scale of 14,
                // whereas float.MinValue and float.MaxValue have 16 digits scale. Hence we need
                // to use XmlConvert in all other cases, except infinity
                this.WriteCore(XmlConvert.ToString(value), /* quotes */ false); 
            }
        } 
 
        /// 
        /// Write the Guid value 
        /// 
        /// double value to be written
        public void WriteValue(Guid value)
        { 
            this.WriteCore(value.ToString(), /* quotes */ true);
        } 
 
        /// 
        /// Write the decimal value 
        /// 
        /// decimal value to be written
        public void WriteValue(decimal value)
        { 
            // Since Json doesn't have decimal support (it only has one data type - number),
            // we need to convert decimal to string to prevent data loss 
            this.WriteCore(value.ToString(CultureInfo.InvariantCulture), /* quotes */ true); 
        }
 
        /// 
        /// Write the DateTime value
        /// 
        /// dateTime value to be written 
        public void WriteValue(DateTime dateTime)
        { 
            // taken from the Atlas serializer 
            // DevDiv 41127: Never confuse atlas serialized strings with dates
            // Serialized date: "\/Date(123)\/" 
            // sb.Append(@"""\/Date(");
            // sb.Append((datetime.ToUniversalTime().Ticks - DatetimeMinTimeTicks) / 10000);
            // sb.Append(@")\/""");
            switch (dateTime.Kind) 
            {
                case DateTimeKind.Local: 
                    dateTime = dateTime.ToUniversalTime(); 
                    break;
                case DateTimeKind.Unspecified: 
                    dateTime = new DateTime(dateTime.Ticks, DateTimeKind.Utc);
                    break;
                case DateTimeKind.Utc:
                    break; 
            }
 
            System.Diagnostics.Debug.Assert(dateTime.Kind == DateTimeKind.Utc, "dateTime.Kind == DateTimeKind.Utc"); 
            this.WriteCore(
                String.Format( 
                    CultureInfo.InvariantCulture,
                    JsonWriter.JsonDateTimeFormat,
                    ((dateTime.Ticks - DatetimeMinTimeTicks) / 10000)),
                true); 
        }
 
        ///  
        /// Write the byte value
        ///  
        /// byte value to be written
        public void WriteValue(byte value)
        {
            this.WriteCore(value.ToString(CultureInfo.InvariantCulture), /* quotes */ false); 
        }
 
        ///  
        /// Write the sbyte value
        ///  
        /// sbyte value to be written
        public void WriteValue(sbyte value)
        {
            this.WriteCore(value.ToString(CultureInfo.InvariantCulture), /* quotes */ false); 
        }
 
        ///  
        /// Write the string value
        ///  
        /// string value to be written
        public void WriteValue(string s)
        {
            if (s == null) 
            {
                this.WriteCore("null", /* quotes */ false); 
            } 
            else
            { 
                this.WriteCore(QuoteJScriptString(s), /* quotes */ true);
            }
        }
 
        /// 
        /// Clears all buffers for the current writer 
        ///  
        public void Flush()
        { 
            this.writer.Flush();
        }

        ///  
        /// Returns the string value with special characters escaped
        ///  
        /// input string value 
        /// Returns the string value with special characters escaped.
        private static string QuoteJScriptString(string s) 
        {
            if (String.IsNullOrEmpty(s))
            {
                return String.Empty; 
            }
 
            StringBuilder b = null; 
            int startIndex = 0;
            int count = 0; 
            for (int i = 0; i < s.Length; i++)
            {
                char c = s[i];
 
                // Append the unhandled characters (that do not require special treament)
                // to the string builder when special characters are detected. 
                if (c == '\r' || c == '\t' || c == '\"' || 
                    c == '\\' || c == '\n' || c < ' ' || c > 0x7F || c == '\b' || c == '\f')
                { 
                    // Flush out the unescaped characters we've built so far.
                    if (b == null)
                    {
                        b = new StringBuilder(s.Length + 6); 
                    }
 
                    if (count > 0) 
                    {
                        b.Append(s, startIndex, count); 
                    }

                    startIndex = i + 1;
                    count = 0; 
                }
 
                switch (c) 
                {
                    case '\r': 
                        b.Append("\\r");
                        break;
                    case '\t':
                        b.Append("\\t"); 
                        break;
                    case '\"': 
                        b.Append("\\\""); 
                        break;
                    case '\\': 
                        b.Append("\\\\");
                        break;
                    case '\n':
                        b.Append("\\n"); 
                        break;
                    case '\b': 
                        b.Append("\\b"); 
                        break;
                    case '\f': 
                        b.Append("\\f");
                        break;
                    default:
                        if ((c < ' ') || (c > 0x7F)) 
                        {
                            b.AppendFormat(CultureInfo.InvariantCulture, "\\u{0:x4}", (int)c); 
                        } 
                        else
                        { 
                            count++;
                        }

                        break; 
                }
            } 
 
            string processedString = s;
            if (b != null) 
            {
                if (count > 0)
                {
                    b.Append(s, startIndex, count); 
                }
 
                processedString = b.ToString(); 
            }
 
            return processedString;
        }

        ///  
        /// Write the string value with/without quotes
        ///  
        /// string value to be written 
        /// put quotes around the value if this value is true
        private void WriteCore(string text, bool quotes) 
        {
            if (this.scopes.Count != 0)
            {
                Scope currentScope = this.scopes.Peek(); 
                if (currentScope.Type == ScopeType.Array)
                { 
                    if (currentScope.ObjectCount != 0) 
                    {
                        this.writer.WriteTrimmed(", "); 
                    }

                    currentScope.ObjectCount++;
                } 
            }
 
            if (quotes) 
            {
                this.writer.Write('"'); 
            }

            this.writer.Write(text);
            if (quotes) 
            {
                this.writer.Write('"'); 
            } 
        }
 
        /// 
        /// Start the scope given the scope type
        /// 
        /// scope type 
        private void StartScope(ScopeType type)
        { 
            if (this.scopes.Count != 0) 
            {
                Scope currentScope = this.scopes.Peek(); 
                if ((currentScope.Type == ScopeType.Array) &&
                    (currentScope.ObjectCount != 0))
                {
                    this.writer.WriteTrimmed(", "); 
                }
 
                currentScope.ObjectCount++; 
            }
 
            Scope scope = new Scope(type);
            this.scopes.Push(scope);

            if (type == ScopeType.Array) 
            {
                this.writer.Write("["); 
            } 
            else
            { 
                this.writer.Write("{");
            }

            this.writer.Indent++; 
            this.writer.WriteLine();
        } 
 
        /// 
        /// class representing scope information 
        /// 
        private sealed class Scope
        {
            ///  keeps the count of the nested scopes  
            private int objectCount;
 
            ///  keeps the type of the scope  
            private ScopeType type;
 
            /// 
            /// Creates a new instance of scope type
            /// 
            /// type of the scope 
            public Scope(ScopeType type)
            { 
                this.type = type; 
            }
 
            /// 
            /// Get/Set the object count for this scope
            /// 
            public int ObjectCount 
            {
                get 
                { 
                    return this.objectCount;
                } 

                set
                {
                    this.objectCount = value; 
                }
            } 
 
            /// 
            /// Gets the scope type for this scope 
            /// 
            public ScopeType Type
            {
                get 
                {
                    return this.type; 
                } 
            }
        } 
    }
}

// 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