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 } |
