##// END OF EJS Templates
mono
mono

File last commit:

r55:c0bf853aa04f default
r67:b4c2454d208e default
Show More
JSONWriter.cs
227 lines | 7.1 KiB | text/x-csharp | CSharpLexer
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 ));
}
}
}