##// END OF EJS Templates
fixed JSON writer
cin -
r141:0fa293bb1351 v2
parent child
Show More
@@ -1,11 +1,8
1 using System;
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5
2
6 namespace Implab {
3 namespace Implab {
7 public interface ICancellable {
4 public interface ICancellable {
8 void Cancel();
5 void Cancel();
9 void Cancel(Exception reason);
6 void Cancel(Exception reason);
10 }
7 }
11 }
8 }
@@ -1,16 +1,17
1 using System;
1 using System;
2 using System.Collections.Generic;
2 using System.Collections.Generic;
3 using System.Linq;
3 using System.Linq;
4 using System.Text;
4 using System.Text;
5 using System.Threading.Tasks;
5 using System.Threading.Tasks;
6
6
7 namespace Implab.JSON {
7 namespace Implab.JSON {
8 /// <summary>
8 /// <summary>
9 /// internal
9 /// internal
10 /// </summary>
10 /// </summary>
11 public enum JSONElementContext {
11 public enum JSONElementContext {
12 None,
12 None,
13 Object,
13 Object,
14 Array
14 Array,
15 Closed
15 }
16 }
16 }
17 }
@@ -1,251 +1,273
1 using System;
1 using System;
2 using System.Collections.Generic;
2 using System.Collections.Generic;
3 using System.IO;
3 using System.IO;
4
4
5 namespace Implab.JSON {
5 namespace Implab.JSON {
6 public class JSONWriter {
6 public class JSONWriter {
7 struct Context {
7 struct Context {
8 public bool needComma;
8 public bool needComma;
9 public JSONElementContext element;
9 public JSONElementContext element;
10 }
10 }
11 Stack<Context> m_contextStack = new Stack<Context>();
11 Stack<Context> m_contextStack = new Stack<Context>();
12 Context m_context;
12 Context m_context;
13
13
14 TextWriter m_writer;
14 TextWriter m_writer;
15 readonly bool m_indent = true;
15 readonly bool m_indent = true;
16 readonly int m_indentSize = 4;
16 readonly int m_indentSize = 4;
17
17
18 static readonly char [] _escapeBKS,
18 static readonly char [] _escapeBKS,
19 _escapeFWD,
19 _escapeFWD,
20 _escapeCR,
20 _escapeCR,
21 _escapeNL,
21 _escapeNL,
22 _escapeTAB,
22 _escapeTAB,
23 _escapeBSLASH,
23 _escapeBSLASH,
24 _escapeQ;
24 _escapeQ;
25
25
26 static JSONWriter() {
26 static JSONWriter() {
27 _escapeBKS = "\\b".ToCharArray();
27 _escapeBKS = "\\b".ToCharArray();
28 _escapeFWD = "\\f".ToCharArray();
28 _escapeFWD = "\\f".ToCharArray();
29 _escapeCR = "\\r".ToCharArray();
29 _escapeCR = "\\r".ToCharArray();
30 _escapeNL = "\\n".ToCharArray();
30 _escapeNL = "\\n".ToCharArray();
31 _escapeTAB = "\\t".ToCharArray();
31 _escapeTAB = "\\t".ToCharArray();
32 _escapeBSLASH = "\\\\".ToCharArray();
32 _escapeBSLASH = "\\\\".ToCharArray();
33 _escapeQ = "\\\"".ToCharArray();
33 _escapeQ = "\\\"".ToCharArray();
34 }
34 }
35
35
36 public JSONWriter(TextWriter writer) {
36 public JSONWriter(TextWriter writer) {
37 Safe.ArgumentNotNull(writer, "writer");
37 Safe.ArgumentNotNull(writer, "writer");
38
38
39 m_writer = writer;
39 m_writer = writer;
40 }
40 }
41
41
42 public JSONWriter(TextWriter writer, bool indent) {
42 public JSONWriter(TextWriter writer, bool indent) {
43 Safe.ArgumentNotNull(writer, "writer");
43 Safe.ArgumentNotNull(writer, "writer");
44
44
45 m_writer = writer;
45 m_writer = writer;
46 m_indent = indent;
46 m_indent = indent;
47 }
47 }
48
48
49 void WriteIndent() {
49 void WriteIndent() {
50 if (m_indent) {
50 if (m_indent) {
51 var indent = new char[m_contextStack.Count * m_indentSize + 1];
51 var indent = new char[m_contextStack.Count * m_indentSize + 1];
52 indent[0] = '\n';
52 indent[0] = '\n';
53 for (int i = 1; i < indent.Length; i++)
53 for (int i = 1; i < indent.Length; i++)
54 indent[i] = ' ';
54 indent[i] = ' ';
55 m_writer.Write(new String(indent));
55 m_writer.Write(new String(indent));
56 } else {
56 } else {
57 m_writer.Write(' ');
57 m_writer.Write(' ');
58 }
58 }
59 }
59 }
60
60
61 void WriteMemberName(string name) {
61 void WriteMemberName(string name) {
62 Safe.ArgumentNotEmpty(name, "name");
62 Safe.ArgumentNotEmpty(name, "name");
63 if (m_context.element != JSONElementContext.Object)
63 if (m_context.element != JSONElementContext.Object)
64 OperationNotApplicable("WriteMember");
64 OperationNotApplicable("WriteMember");
65 if (m_context.needComma)
65 if (m_context.needComma)
66 m_writer.Write(",");
66 m_writer.Write(",");
67
67
68 WriteIndent();
68 WriteIndent();
69 m_context.needComma = true;
69 m_context.needComma = true;
70 Write(name);
70 Write(name);
71 m_writer.Write(" : ");
71 m_writer.Write(" : ");
72 }
72 }
73
73
74 public void WriteValue(string name, string value) {
74 public void WriteValue(string name, string value) {
75 WriteMemberName(name);
75 WriteMemberName(name);
76 Write(value);
76 Write(value);
77 }
77 }
78
78
79 public void WriteValue(string name, bool value) {
79 public void WriteValue(string name, bool value) {
80 WriteMemberName(name);
80 WriteMemberName(name);
81 Write(value);
81 Write(value);
82 }
82 }
83
83
84 public void WriteValue(string name, double value) {
84 public void WriteValue(string name, double value) {
85 WriteMemberName(name);
85 WriteMemberName(name);
86 Write(value);
86 Write(value);
87 }
87 }
88
88
89 public void WriteValue(string value) {
89 public void WriteValue(string value) {
90 if (m_context.element != JSONElementContext.Array)
90 if (m_context.element == JSONElementContext.Array) {
91
92 if (m_context.needComma)
93 m_writer.Write(",");
94 WriteIndent();
95 m_context.needComma = true;
96
97 Write(value);
98 } else if (m_context.element == JSONElementContext.None) {
99 Write(value);
100 m_context.element = JSONElementContext.Closed;
101 } else {
91 OperationNotApplicable("WriteValue");
102 OperationNotApplicable("WriteValue");
92 if (m_context.needComma)
103 }
93 m_writer.Write(",");
94 WriteIndent();
95 m_context.needComma = true;
96
97 Write(value);
98 }
104 }
99
105
100 public void WriteValue(bool value) {
106 public void WriteValue(bool value) {
101 if (m_context.element != JSONElementContext.Array)
107 if (m_context.element == JSONElementContext.Array) {
108
109 if (m_context.needComma)
110 m_writer.Write(",");
111 WriteIndent();
112 m_context.needComma = true;
113
114 Write(value);
115 } else if (m_context.element == JSONElementContext.None) {
116 Write(value);
117 m_context.element = JSONElementContext.Closed;
118 } else {
102 OperationNotApplicable("WriteValue");
119 OperationNotApplicable("WriteValue");
103 if (m_context.needComma)
120 }
104 m_writer.Write(",");
105 m_context.needComma = true;
106
107 WriteIndent();
108 Write(value);
109 }
121 }
110
122
111 public void WriteValue(double value) {
123 public void WriteValue(double value) {
112 if (m_context.element != JSONElementContext.Array)
124 if (m_context.element == JSONElementContext.Array) {
125
126 if (m_context.needComma)
127 m_writer.Write(",");
128 WriteIndent();
129 m_context.needComma = true;
130
131 Write(value);
132 } else if (m_context.element == JSONElementContext.None) {
133 Write(value);
134 m_context.element = JSONElementContext.Closed;
135 } else {
113 OperationNotApplicable("WriteValue");
136 OperationNotApplicable("WriteValue");
114 if (m_context.needComma)
137 }
115 m_writer.Write(",");
116 m_context.needComma = true;
117
118 WriteIndent();
119 Write(value);
120 }
138 }
121
139
122 public void BeginObject() {
140 public void BeginObject() {
123 if (m_context.element != JSONElementContext.None && m_context.element != JSONElementContext.Array)
141 if (m_context.element != JSONElementContext.None && m_context.element != JSONElementContext.Array)
124 OperationNotApplicable("BeginObject");
142 OperationNotApplicable("BeginObject");
125 if (m_context.needComma)
143 if (m_context.needComma)
126 m_writer.Write(",");
144 m_writer.Write(",");
127
145
128 WriteIndent();
146 WriteIndent();
129
147
130 m_context.needComma = true;
148 m_context.needComma = true;
131
149
132 m_contextStack.Push(m_context);
150 m_contextStack.Push(m_context);
133
151
134 m_context = new Context { element = JSONElementContext.Object, needComma = false };
152 m_context = new Context { element = JSONElementContext.Object, needComma = false };
135 m_writer.Write("{");
153 m_writer.Write("{");
136 }
154 }
137
155
138 public void BeginObject(string name) {
156 public void BeginObject(string name) {
139 WriteMemberName(name);
157 WriteMemberName(name);
140
158
141 m_contextStack.Push(m_context);
159 m_contextStack.Push(m_context);
142
160
143 m_context = new Context { element = JSONElementContext.Object, needComma = false };
161 m_context = new Context { element = JSONElementContext.Object, needComma = false };
144 m_writer.Write("{");
162 m_writer.Write("{");
145 }
163 }
146
164
147 public void EndObject() {
165 public void EndObject() {
148 if (m_context.element != JSONElementContext.Object)
166 if (m_context.element != JSONElementContext.Object)
149 OperationNotApplicable("EndArray");
167 OperationNotApplicable("EndObject");
150
168
151 m_context = m_contextStack.Pop();
169 m_context = m_contextStack.Pop();
170 if (m_contextStack.Count == 0)
171 m_context.element = JSONElementContext.Closed;
152 WriteIndent();
172 WriteIndent();
153 m_writer.Write("}");
173 m_writer.Write("}");
154 }
174 }
155
175
156 public void BeginArray() {
176 public void BeginArray() {
157 if (m_context.element != JSONElementContext.None && m_context.element != JSONElementContext.Array)
177 if (m_context.element != JSONElementContext.None && m_context.element != JSONElementContext.Array)
158 throw new InvalidOperationException();
178 throw new InvalidOperationException();
159 if (m_context.needComma) {
179 if (m_context.needComma) {
160 m_writer.Write(",");
180 m_writer.Write(",");
161
181
162 }
182 }
163 m_context.needComma = true;
183 m_context.needComma = true;
164
184
165 WriteIndent();
185 WriteIndent();
166 m_contextStack.Push(m_context);
186 m_contextStack.Push(m_context);
167 m_context = new Context { element = JSONElementContext.Array, needComma = false };
187 m_context = new Context { element = JSONElementContext.Array, needComma = false };
168 m_writer.Write("[");
188 m_writer.Write("[");
169 }
189 }
170
190
171 public void BeginArray(string name) {
191 public void BeginArray(string name) {
172 WriteMemberName(name);
192 WriteMemberName(name);
173
193
174 m_contextStack.Push(m_context);
194 m_contextStack.Push(m_context);
175
195
176 m_context = new Context { element = JSONElementContext.Array, needComma = false };
196 m_context = new Context { element = JSONElementContext.Array, needComma = false };
177 m_writer.Write("[");
197 m_writer.Write("[");
178 }
198 }
179
199
180 public void EndArray() {
200 public void EndArray() {
181 if (m_context.element != JSONElementContext.Array)
201 if (m_context.element != JSONElementContext.Array)
182 OperationNotApplicable("EndArray");
202 OperationNotApplicable("EndArray");
183
203
184 m_context = m_contextStack.Pop();
204 m_context = m_contextStack.Pop();
205 if (m_contextStack.Count == 0)
206 m_context.element = JSONElementContext.Closed;
185 WriteIndent();
207 WriteIndent();
186 m_writer.Write("]");
208 m_writer.Write("]");
187 }
209 }
188
210
189 void Write(bool value) {
211 void Write(bool value) {
190 m_writer.Write(value ? "true" : "false");
212 m_writer.Write(value ? "true" : "false");
191 }
213 }
192
214
193
215
194 void Write(string value) {
216 void Write(string value) {
195 if (value == null) {
217 if (value == null) {
196 m_writer.Write("null");
218 m_writer.Write("null");
197 return;
219 return;
198 }
220 }
199
221
200 var chars = value.ToCharArray();
222 var chars = value.ToCharArray();
201 m_writer.Write('"');
223 m_writer.Write('"');
202
224
203 // Analysis disable once ForCanBeConvertedToForeach
225 // Analysis disable once ForCanBeConvertedToForeach
204 for (int i = 0; i < chars.Length; i++) {
226 for (int i = 0; i < chars.Length; i++) {
205 var ch = chars[i];
227 var ch = chars[i];
206
228
207 switch (ch) {
229 switch (ch) {
208 case '\b':
230 case '\b':
209 m_writer.Write(_escapeBKS);
231 m_writer.Write(_escapeBKS);
210 break;
232 break;
211 case '\f':
233 case '\f':
212 m_writer.Write(_escapeFWD);
234 m_writer.Write(_escapeFWD);
213 break;
235 break;
214 case '\r':
236 case '\r':
215 m_writer.Write(_escapeCR);
237 m_writer.Write(_escapeCR);
216 break;
238 break;
217 case '\n':
239 case '\n':
218 m_writer.Write(_escapeNL);
240 m_writer.Write(_escapeNL);
219 break;
241 break;
220 case '\t':
242 case '\t':
221 m_writer.Write(_escapeTAB);
243 m_writer.Write(_escapeTAB);
222 break;
244 break;
223 case '\\':
245 case '\\':
224 m_writer.Write(_escapeBSLASH);
246 m_writer.Write(_escapeBSLASH);
225 break;
247 break;
226 case '"':
248 case '"':
227 m_writer.Write(_escapeQ);
249 m_writer.Write(_escapeQ);
228 break;
250 break;
229 default:
251 default:
230 if (ch < 0x20) {
252 if (ch < 0x20) {
231 m_writer.Write("\\u00{0:x2}",(int)ch);
253 m_writer.Write("\\u00{0:x2}",(int)ch);
232 } else {
254 } else {
233 m_writer.Write(ch);
255 m_writer.Write(ch);
234 }
256 }
235 break;
257 break;
236 }
258 }
237 }
259 }
238
260
239 m_writer.Write('"');
261 m_writer.Write('"');
240 }
262 }
241
263
242 void Write(double value) {
264 void Write(double value) {
243 m_writer.Write(value);
265 m_writer.Write(value);
244 }
266 }
245
267
246 void OperationNotApplicable(string opName) {
268 void OperationNotApplicable(string opName) {
247 throw new InvalidOperationException(String.Format("The operation '{0}' isn't applicable in the context of '{1}'", opName, m_context.element ));
269 throw new InvalidOperationException(String.Format("The operation '{0}' isn't applicable in the context of '{1}'", opName, m_context.element ));
248 }
270 }
249
271
250 }
272 }
251 }
273 }
General Comments 0
You need to be logged in to leave comments. Login now