Mercurial > pub > ImplabNet
diff Implab/JSON/JSONWriter.cs @ 55:c0bf853aa04f
Added initial JSON support
+JSONParser
+JSONWriter
author | cin |
---|---|
date | Sun, 15 Jun 2014 19:39:11 +0400 |
parents | |
children | d67b95eddaf4 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Implab/JSON/JSONWriter.cs Sun Jun 15 19:39:11 2014 +0400 @@ -0,0 +1,227 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Implab.JSON { + public class JSONWriter { + struct Context { + public bool needComma; + public JSONElementContext element; + } + Stack<Context> m_contextStack = new Stack<Context>(); + Context m_context; + + TextWriter m_writer; + bool m_indent; + + static readonly char [] _escapeBKS, + _escapeFWD, + _escapeCR, + _escapeNL, + _escapeTAB, + _escapeSLASH, + _escapeBSLASH, + _escapeQ; + + static JSONWriter() { + _escapeBKS = "\\b".ToCharArray(); + _escapeFWD = "\\f".ToCharArray(); + _escapeCR = "\\r".ToCharArray(); + _escapeNL = "\\n".ToCharArray(); + _escapeTAB = "\\t".ToCharArray(); + _escapeBSLASH = "\\\\".ToCharArray(); + _escapeSLASH = "\\/".ToCharArray(); + _escapeQ = "\\\"".ToCharArray(); + } + + public JSONWriter(TextWriter writer) { + Safe.ArgumentNotNull(writer, "writer"); + + m_writer = writer; + } + + void WriteMemberName(string name) { + Safe.ArgumentNotEmpty(name, "name"); + if (m_context.element != JSONElementContext.Object) + OperationNotApplicable("WriteMember"); + if (m_context.needComma) + m_writer.Write(", "); + // TODO indent + m_context.needComma = true; + Write(name); + m_writer.Write(" : "); + } + + public void WriteValue(string name, string value) { + WriteMemberName(name); + Write(value); + } + + public void WriteValue(string name, bool value) { + WriteMemberName(name); + Write(value); + } + + public void WriteValue(string name, double value) { + WriteMemberName(name); + Write(value); + } + + + + public void WriteValue(string value) { + if (m_context.element != JSONElementContext.Array) + OperationNotApplicable("WriteValue"); + if (m_context.needComma) + m_writer.Write(", "); + m_context.needComma = true; + + Write(value); + } + + public void WriteValue(bool value) { + if (m_context.element != JSONElementContext.Array) + OperationNotApplicable("WriteValue"); + if (m_context.needComma) + m_writer.Write(", "); + m_context.needComma = true; + + Write(value); + } + + public void WriteValue(double value) { + if (m_context.element != JSONElementContext.Array) + OperationNotApplicable("WriteValue"); + if (m_context.needComma) + m_writer.Write(", "); + m_context.needComma = true; + + Write(value); + } + + public void BeginObject() { + if (m_context.element != JSONElementContext.None && m_context.element != JSONElementContext.Array) + OperationNotApplicable("BeginObject"); + if (m_context.needComma) + m_writer.Write(", "); + m_context.needComma = true; + + m_contextStack.Push(m_context); + + m_context = new Context { element = JSONElementContext.Object, needComma = false }; + m_writer.Write("{ "); + } + + public void BeginObject(string name) { + WriteMemberName(name); + + m_contextStack.Push(m_context); + + m_context = new Context { element = JSONElementContext.Object, needComma = false }; + m_writer.Write("{ "); + } + + public void EndObject() { + if (m_context.element != JSONElementContext.Object) + OperationNotApplicable("EndArray"); + + m_writer.Write(" }"); + m_context = m_contextStack.Pop(); + } + + public void BeginArray() { + if (m_context.element != JSONElementContext.None && m_context.element != JSONElementContext.Array) + throw new InvalidOperationException(); + if (m_context.needComma) + m_writer.Write(", "); + m_context.needComma = true; + + m_contextStack.Push(m_context); + + m_context = new Context { element = JSONElementContext.Array, needComma = false }; + m_writer.Write("[ "); + } + + public void BeginArray(string name) { + WriteMemberName(name); + + m_contextStack.Push(m_context); + + m_context = new Context { element = JSONElementContext.Array, needComma = false }; + m_writer.Write("[ "); + } + + public void EndArray() { + if (m_context.element != JSONElementContext.Array) + OperationNotApplicable("EndArray"); + + m_writer.Write(" ]"); + m_context = m_contextStack.Pop(); + } + + void Write(bool value) { + m_writer.Write(value ? "true" : "false"); + } + + + void Write(string value) { + if (value == null) + m_writer.Write("null"); + + var chars = value.ToCharArray(); + m_writer.Write('"'); + + for (int i = 0; i < chars.Length; i++) { + var ch = chars[i]; + + switch (ch) { + case '\b': + m_writer.Write(_escapeBKS); + break; + case '\f': + m_writer.Write(_escapeFWD); + break; + case '\r': + m_writer.Write(_escapeCR); + break; + case '\n': + m_writer.Write(_escapeNL); + break; + case '\t': + m_writer.Write(_escapeTAB); + break; + case '\\': + m_writer.Write(_escapeBSLASH); + break; + case '/': + m_writer.Write(_escapeSLASH); + break; + case '"': + m_writer.Write(_escapeQ); + break; + default: + if (ch < 0x20) { + m_writer.Write("\\u00{0:x2}",(int)ch); + } else { + m_writer.Write(ch); + } + break; + } + } + + m_writer.Write('"'); + } + + void Write(double value) { + m_writer.Write(value); + } + + void OperationNotApplicable(string opName) { + throw new InvalidOperationException(String.Format("The operation '{0}' isn't applicable in the context of '{1}'", opName, m_context.element )); + } + + } +}