Mercurial > pub > ImplabNet
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 } |