##// END OF EJS Templates
sync
sync

File last commit:

r150:3258399cba83 v2
r157:948c015a9011 v2
Show More
JSONWriter.cs
319 lines | 10.4 KiB | text/x-csharp | CSharpLexer
cin
Added initial JSON support...
r55 using System;
using System.Collections.Generic;
using System.IO;
cin
fixed JSONWriter handling Infinity, NaN and locale aware number formatting
r142 using System.Globalization;
cin
JSONWriter improvements
r150 using System.Diagnostics;
cin
Added initial JSON support...
r55
namespace Implab.JSON {
public class JSONWriter {
struct Context {
public bool needComma;
public JSONElementContext element;
}
Stack<Context> m_contextStack = new Stack<Context>();
Context m_context;
cin
JSONWriter improvements
r150 const int BUFFER_SIZE = 64;
cin
Added initial JSON support...
r55 TextWriter m_writer;
cin
promises refactoring
r72 readonly bool m_indent = true;
readonly int m_indentSize = 4;
cin
JSONWriter improvements
r150 readonly char[] m_buffer = new char[BUFFER_SIZE];
int m_bufferPos;
cin
Added initial JSON support...
r55
cin
JSONWriter improvements
r150 static readonly char [] _hex = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
cin
Added initial JSON support...
r55 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;
}
cin
promises refactoring
r72 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(' ');
}
}
cin
Added initial JSON support...
r55 void WriteMemberName(string name) {
Safe.ArgumentNotEmpty(name, "name");
if (m_context.element != JSONElementContext.Object)
OperationNotApplicable("WriteMember");
if (m_context.needComma)
cin
promises refactoring
r72 m_writer.Write(",");
WriteIndent();
cin
Added initial JSON support...
r55 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) {
cin
fixed JSON writer
r141 if (m_context.element == JSONElementContext.Array) {
if (m_context.needComma)
m_writer.Write(",");
WriteIndent();
m_context.needComma = true;
Write(value);
} else if (m_context.element == JSONElementContext.None) {
Write(value);
m_context.element = JSONElementContext.Closed;
} else {
cin
Added initial JSON support...
r55 OperationNotApplicable("WriteValue");
cin
fixed JSON writer
r141 }
cin
Added initial JSON support...
r55 }
public void WriteValue(bool value) {
cin
fixed JSON writer
r141 if (m_context.element == JSONElementContext.Array) {
if (m_context.needComma)
m_writer.Write(",");
WriteIndent();
m_context.needComma = true;
Write(value);
} else if (m_context.element == JSONElementContext.None) {
Write(value);
m_context.element = JSONElementContext.Closed;
} else {
cin
Added initial JSON support...
r55 OperationNotApplicable("WriteValue");
cin
fixed JSON writer
r141 }
cin
Added initial JSON support...
r55 }
public void WriteValue(double value) {
cin
fixed JSON writer
r141 if (m_context.element == JSONElementContext.Array) {
if (m_context.needComma)
m_writer.Write(",");
WriteIndent();
m_context.needComma = true;
Write(value);
} else if (m_context.element == JSONElementContext.None) {
Write(value);
m_context.element = JSONElementContext.Closed;
} else {
cin
Added initial JSON support...
r55 OperationNotApplicable("WriteValue");
cin
fixed JSON writer
r141 }
cin
Added initial JSON support...
r55 }
public void BeginObject() {
if (m_context.element != JSONElementContext.None && m_context.element != JSONElementContext.Array)
OperationNotApplicable("BeginObject");
if (m_context.needComma)
cin
promises refactoring
r72 m_writer.Write(",");
WriteIndent();
cin
Added initial JSON support...
r55 m_context.needComma = true;
m_contextStack.Push(m_context);
m_context = new Context { element = JSONElementContext.Object, needComma = false };
cin
promises refactoring
r72 m_writer.Write("{");
cin
Added initial JSON support...
r55 }
public void BeginObject(string name) {
WriteMemberName(name);
m_contextStack.Push(m_context);
m_context = new Context { element = JSONElementContext.Object, needComma = false };
cin
promises refactoring
r72 m_writer.Write("{");
cin
Added initial JSON support...
r55 }
public void EndObject() {
if (m_context.element != JSONElementContext.Object)
cin
fixed JSON writer
r141 OperationNotApplicable("EndObject");
cin
promises refactoring
r72
cin
Added initial JSON support...
r55 m_context = m_contextStack.Pop();
cin
fixed JSON writer
r141 if (m_contextStack.Count == 0)
m_context.element = JSONElementContext.Closed;
cin
promises refactoring
r72 WriteIndent();
m_writer.Write("}");
cin
Added initial JSON support...
r55 }
public void BeginArray() {
if (m_context.element != JSONElementContext.None && m_context.element != JSONElementContext.Array)
throw new InvalidOperationException();
cin
promises refactoring
r72 if (m_context.needComma) {
m_writer.Write(",");
}
cin
Added initial JSON support...
r55 m_context.needComma = true;
cin
promises refactoring
r72 WriteIndent();
cin
Added initial JSON support...
r55 m_contextStack.Push(m_context);
m_context = new Context { element = JSONElementContext.Array, needComma = false };
cin
promises refactoring
r72 m_writer.Write("[");
cin
Added initial JSON support...
r55 }
public void BeginArray(string name) {
WriteMemberName(name);
m_contextStack.Push(m_context);
m_context = new Context { element = JSONElementContext.Array, needComma = false };
cin
promises refactoring
r72 m_writer.Write("[");
cin
Added initial JSON support...
r55 }
public void EndArray() {
if (m_context.element != JSONElementContext.Array)
OperationNotApplicable("EndArray");
m_context = m_contextStack.Pop();
cin
fixed JSON writer
r141 if (m_contextStack.Count == 0)
m_context.element = JSONElementContext.Closed;
cin
promises refactoring
r72 WriteIndent();
m_writer.Write("]");
cin
Added initial JSON support...
r55 }
void Write(bool value) {
m_writer.Write(value ? "true" : "false");
}
cin
JSONWriter improvements
r150
void FlushBuffer() {
if (m_bufferPos > 0) {
m_writer.Write(m_buffer, 0, m_bufferPos);
m_bufferPos = 0;
}
}
cin
Added initial JSON support...
r55
void Write(string value) {
cin
fixed JSON writer
r115 if (value == null) {
cin
Added initial JSON support...
r55 m_writer.Write("null");
cin
fixed JSON writer
r115 return;
}
cin
Added initial JSON support...
r55
cin
JSONWriter improvements
r150 Debug.Assert(m_bufferPos == 0);
cin
Added initial JSON support...
r55 var chars = value.ToCharArray();
cin
JSONWriter improvements
r150 m_buffer[m_bufferPos++] = '"';
cin
Promises rewritten, added improved version of AsyncQueue
r119 // Analysis disable once ForCanBeConvertedToForeach
cin
Added initial JSON support...
r55 for (int i = 0; i < chars.Length; i++) {
var ch = chars[i];
cin
JSONWriter improvements
r150 char[] escapeSeq;
cin
Added initial JSON support...
r55 switch (ch) {
case '\b':
cin
JSONWriter improvements
r150 escapeSeq = _escapeBKS;
cin
Added initial JSON support...
r55 break;
case '\f':
cin
JSONWriter improvements
r150 escapeSeq = _escapeFWD;
cin
Added initial JSON support...
r55 break;
case '\r':
cin
JSONWriter improvements
r150 escapeSeq = _escapeCR;
cin
Added initial JSON support...
r55 break;
case '\n':
cin
JSONWriter improvements
r150 escapeSeq = _escapeNL;
cin
Added initial JSON support...
r55 break;
case '\t':
cin
JSONWriter improvements
r150 escapeSeq = _escapeTAB;
cin
Added initial JSON support...
r55 break;
case '\\':
cin
JSONWriter improvements
r150 escapeSeq = _escapeBSLASH;
cin
Added initial JSON support...
r55 break;
case '"':
cin
JSONWriter improvements
r150 escapeSeq = _escapeQ;
cin
Added initial JSON support...
r55 break;
default:
if (ch < 0x20) {
cin
JSONWriter improvements
r150 if (m_bufferPos + 6 > BUFFER_SIZE)
FlushBuffer();
m_buffer[m_bufferPos++] = '\\';
m_buffer[m_bufferPos++] = 'u';
m_buffer[m_bufferPos++] = '0';
m_buffer[m_bufferPos++] = '0';
m_buffer[m_bufferPos++] = _hex[ch >> 4 & 0xf];
m_buffer[m_bufferPos++] = _hex[ch & 0xf];
cin
Added initial JSON support...
r55 } else {
cin
JSONWriter improvements
r150 if (m_bufferPos >= BUFFER_SIZE)
FlushBuffer();
m_buffer[m_bufferPos++] = ch;
cin
Added initial JSON support...
r55 }
cin
JSONWriter improvements
r150 continue;
cin
Added initial JSON support...
r55 }
cin
JSONWriter improvements
r150
if (m_bufferPos + escapeSeq.Length > BUFFER_SIZE)
FlushBuffer();
Array.Copy(escapeSeq, 0, m_buffer, m_bufferPos, escapeSeq.Length);
m_bufferPos += escapeSeq.Length;
cin
Added initial JSON support...
r55 }
cin
JSONWriter improvements
r150 if (m_bufferPos >= BUFFER_SIZE)
FlushBuffer();
m_buffer[m_bufferPos++] = '"';
FlushBuffer();
cin
Added initial JSON support...
r55 }
void Write(double value) {
cin
fixed JSONWriter handling Infinity, NaN and locale aware number formatting
r142 if (double.IsNaN(value))
Write("NaN");
else if (double.IsNegativeInfinity(value))
Write("-Infinity");
else if (double.IsPositiveInfinity(value))
Write("Infinity");
else
m_writer.Write(value.ToString(CultureInfo.InvariantCulture));
cin
Added initial JSON support...
r55 }
void OperationNotApplicable(string opName) {
throw new InvalidOperationException(String.Format("The operation '{0}' isn't applicable in the context of '{1}'", opName, m_context.element ));
}
}
}