comparison 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
comparison
equal deleted inserted replaced
51:2c332a9c64c0 55:c0bf853aa04f
1 using System;
2 using System.Collections.Generic;
3 using System.IO;
4 using System.Linq;
5 using System.Text;
6 using System.Threading.Tasks;
7
8 namespace Implab.JSON {
9 public class JSONWriter {
10 struct Context {
11 public bool needComma;
12 public JSONElementContext element;
13 }
14 Stack<Context> m_contextStack = new Stack<Context>();
15 Context m_context;
16
17 TextWriter m_writer;
18 bool m_indent;
19
20 static readonly char [] _escapeBKS,
21 _escapeFWD,
22 _escapeCR,
23 _escapeNL,
24 _escapeTAB,
25 _escapeSLASH,
26 _escapeBSLASH,
27 _escapeQ;
28
29 static JSONWriter() {
30 _escapeBKS = "\\b".ToCharArray();
31 _escapeFWD = "\\f".ToCharArray();
32 _escapeCR = "\\r".ToCharArray();
33 _escapeNL = "\\n".ToCharArray();
34 _escapeTAB = "\\t".ToCharArray();
35 _escapeBSLASH = "\\\\".ToCharArray();
36 _escapeSLASH = "\\/".ToCharArray();
37 _escapeQ = "\\\"".ToCharArray();
38 }
39
40 public JSONWriter(TextWriter writer) {
41 Safe.ArgumentNotNull(writer, "writer");
42
43 m_writer = writer;
44 }
45
46 void WriteMemberName(string name) {
47 Safe.ArgumentNotEmpty(name, "name");
48 if (m_context.element != JSONElementContext.Object)
49 OperationNotApplicable("WriteMember");
50 if (m_context.needComma)
51 m_writer.Write(", ");
52 // TODO indent
53 m_context.needComma = true;
54 Write(name);
55 m_writer.Write(" : ");
56 }
57
58 public void WriteValue(string name, string value) {
59 WriteMemberName(name);
60 Write(value);
61 }
62
63 public void WriteValue(string name, bool value) {
64 WriteMemberName(name);
65 Write(value);
66 }
67
68 public void WriteValue(string name, double value) {
69 WriteMemberName(name);
70 Write(value);
71 }
72
73
74
75 public void WriteValue(string value) {
76 if (m_context.element != JSONElementContext.Array)
77 OperationNotApplicable("WriteValue");
78 if (m_context.needComma)
79 m_writer.Write(", ");
80 m_context.needComma = true;
81
82 Write(value);
83 }
84
85 public void WriteValue(bool value) {
86 if (m_context.element != JSONElementContext.Array)
87 OperationNotApplicable("WriteValue");
88 if (m_context.needComma)
89 m_writer.Write(", ");
90 m_context.needComma = true;
91
92 Write(value);
93 }
94
95 public void WriteValue(double value) {
96 if (m_context.element != JSONElementContext.Array)
97 OperationNotApplicable("WriteValue");
98 if (m_context.needComma)
99 m_writer.Write(", ");
100 m_context.needComma = true;
101
102 Write(value);
103 }
104
105 public void BeginObject() {
106 if (m_context.element != JSONElementContext.None && m_context.element != JSONElementContext.Array)
107 OperationNotApplicable("BeginObject");
108 if (m_context.needComma)
109 m_writer.Write(", ");
110 m_context.needComma = true;
111
112 m_contextStack.Push(m_context);
113
114 m_context = new Context { element = JSONElementContext.Object, needComma = false };
115 m_writer.Write("{ ");
116 }
117
118 public void BeginObject(string name) {
119 WriteMemberName(name);
120
121 m_contextStack.Push(m_context);
122
123 m_context = new Context { element = JSONElementContext.Object, needComma = false };
124 m_writer.Write("{ ");
125 }
126
127 public void EndObject() {
128 if (m_context.element != JSONElementContext.Object)
129 OperationNotApplicable("EndArray");
130
131 m_writer.Write(" }");
132 m_context = m_contextStack.Pop();
133 }
134
135 public void BeginArray() {
136 if (m_context.element != JSONElementContext.None && m_context.element != JSONElementContext.Array)
137 throw new InvalidOperationException();
138 if (m_context.needComma)
139 m_writer.Write(", ");
140 m_context.needComma = true;
141
142 m_contextStack.Push(m_context);
143
144 m_context = new Context { element = JSONElementContext.Array, needComma = false };
145 m_writer.Write("[ ");
146 }
147
148 public void BeginArray(string name) {
149 WriteMemberName(name);
150
151 m_contextStack.Push(m_context);
152
153 m_context = new Context { element = JSONElementContext.Array, needComma = false };
154 m_writer.Write("[ ");
155 }
156
157 public void EndArray() {
158 if (m_context.element != JSONElementContext.Array)
159 OperationNotApplicable("EndArray");
160
161 m_writer.Write(" ]");
162 m_context = m_contextStack.Pop();
163 }
164
165 void Write(bool value) {
166 m_writer.Write(value ? "true" : "false");
167 }
168
169
170 void Write(string value) {
171 if (value == null)
172 m_writer.Write("null");
173
174 var chars = value.ToCharArray();
175 m_writer.Write('"');
176
177 for (int i = 0; i < chars.Length; i++) {
178 var ch = chars[i];
179
180 switch (ch) {
181 case '\b':
182 m_writer.Write(_escapeBKS);
183 break;
184 case '\f':
185 m_writer.Write(_escapeFWD);
186 break;
187 case '\r':
188 m_writer.Write(_escapeCR);
189 break;
190 case '\n':
191 m_writer.Write(_escapeNL);
192 break;
193 case '\t':
194 m_writer.Write(_escapeTAB);
195 break;
196 case '\\':
197 m_writer.Write(_escapeBSLASH);
198 break;
199 case '/':
200 m_writer.Write(_escapeSLASH);
201 break;
202 case '"':
203 m_writer.Write(_escapeQ);
204 break;
205 default:
206 if (ch < 0x20) {
207 m_writer.Write("\\u00{0:x2}",(int)ch);
208 } else {
209 m_writer.Write(ch);
210 }
211 break;
212 }
213 }
214
215 m_writer.Write('"');
216 }
217
218 void Write(double value) {
219 m_writer.Write(value);
220 }
221
222 void OperationNotApplicable(string opName) {
223 throw new InvalidOperationException(String.Format("The operation '{0}' isn't applicable in the context of '{1}'", opName, m_context.element ));
224 }
225
226 }
227 }