##// END OF EJS Templates
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation
added ICancellable.Cancel(Exception) to allow specify the reason of cancellation

File last commit:

r119:2573b562e328 v2
r138:f75cfa58e3d4 v2
Show More
JSONWriter.cs
251 lines | 7.8 KiB | text/x-csharp | CSharpLexer
using System;
using System.Collections.Generic;
using System.IO;
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;
readonly bool m_indent = true;
readonly int m_indentSize = 4;
static readonly char [] _escapeBKS,
_escapeFWD,
_escapeCR,
_escapeNL,
_escapeTAB,
_escapeBSLASH,
_escapeQ;
static JSONWriter() {
_escapeBKS = "\\b".ToCharArray();
_escapeFWD = "\\f".ToCharArray();
_escapeCR = "\\r".ToCharArray();
_escapeNL = "\\n".ToCharArray();
_escapeTAB = "\\t".ToCharArray();
_escapeBSLASH = "\\\\".ToCharArray();
_escapeQ = "\\\"".ToCharArray();
}
public JSONWriter(TextWriter writer) {
Safe.ArgumentNotNull(writer, "writer");
m_writer = writer;
}
public JSONWriter(TextWriter writer, bool indent) {
Safe.ArgumentNotNull(writer, "writer");
m_writer = writer;
m_indent = indent;
}
void WriteIndent() {
if (m_indent) {
var indent = new char[m_contextStack.Count * m_indentSize + 1];
indent[0] = '\n';
for (int i = 1; i < indent.Length; i++)
indent[i] = ' ';
m_writer.Write(new String(indent));
} else {
m_writer.Write(' ');
}
}
void WriteMemberName(string name) {
Safe.ArgumentNotEmpty(name, "name");
if (m_context.element != JSONElementContext.Object)
OperationNotApplicable("WriteMember");
if (m_context.needComma)
m_writer.Write(",");
WriteIndent();
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(",");
WriteIndent();
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;
WriteIndent();
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;
WriteIndent();
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(",");
WriteIndent();
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_context = m_contextStack.Pop();
WriteIndent();
m_writer.Write("}");
}
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;
WriteIndent();
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_context = m_contextStack.Pop();
WriteIndent();
m_writer.Write("]");
}
void Write(bool value) {
m_writer.Write(value ? "true" : "false");
}
void Write(string value) {
if (value == null) {
m_writer.Write("null");
return;
}
var chars = value.ToCharArray();
m_writer.Write('"');
// Analysis disable once ForCanBeConvertedToForeach
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(_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 ));
}
}
}