blob: 15e08e0522a9d8f90f11a9233a3942192bcb0728 [file] [log] [blame]
csharptest60fd7732011-09-09 12:18:16 -05001using System;
csharptest74c5e0c2011-07-14 13:06:22 -05002using System.Collections;
csharptestafe844b2011-06-10 16:03:22 -05003using System.Collections.Generic;
4using System.IO;
csharptest7fc785c2011-06-10 23:54:53 -05005using System.Text;
csharptestafe844b2011-06-10 16:03:22 -05006using Google.ProtocolBuffers.Descriptors;
7
8namespace Google.ProtocolBuffers.Serialization
9{
10 /// <summary>
11 /// JsonFormatWriter is a .NET 2.0 friendly json formatter for proto buffer messages. For .NET 3.5
12 /// you may also use the XmlFormatWriter with an XmlWriter created by the
13 /// <see cref="System.Runtime.Serialization.Json.JsonReaderWriterFactory">JsonReaderWriterFactory</see>.
14 /// </summary>
csharptest7fc785c2011-06-10 23:54:53 -050015 public abstract class JsonFormatWriter : AbstractTextWriter
csharptestafe844b2011-06-10 16:03:22 -050016 {
csharptest7fc785c2011-06-10 23:54:53 -050017 #region buffering implementations
csharptest74c5e0c2011-07-14 13:06:22 -050018
csharptest7fc785c2011-06-10 23:54:53 -050019 private class JsonTextWriter : JsonFormatWriter
csharptestafe844b2011-06-10 16:03:22 -050020 {
csharptest7fc785c2011-06-10 23:54:53 -050021 private readonly char[] _buffer;
22 private TextWriter _output;
csharptest74c5e0c2011-07-14 13:06:22 -050023 private int _bufferPos;
csharptestafe844b2011-06-10 16:03:22 -050024
csharptest7fc785c2011-06-10 23:54:53 -050025 public JsonTextWriter(TextWriter output)
csharptestafe844b2011-06-10 16:03:22 -050026 {
csharptest7fc785c2011-06-10 23:54:53 -050027 _buffer = new char[4096];
28 _bufferPos = 0;
29 _output = output;
30 _counter.Add(0);
31 }
32
33 /// <summary>
34 /// Returns the output of TextWriter.ToString() where TextWriter is the ctor argument.
35 /// </summary>
36 public override string ToString()
37 {
38 Flush();
39
40 if (_output != null)
csharptest74c5e0c2011-07-14 13:06:22 -050041 {
csharptest7fc785c2011-06-10 23:54:53 -050042 return _output.ToString();
csharptest74c5e0c2011-07-14 13:06:22 -050043 }
csharptest7fc785c2011-06-10 23:54:53 -050044
45 return new String(_buffer, 0, _bufferPos);
46 }
47
48 protected override void WriteToOutput(char[] chars, int offset, int len)
49 {
50 if (_bufferPos + len >= _buffer.Length)
csharptestafe844b2011-06-10 16:03:22 -050051 {
csharptest7fc785c2011-06-10 23:54:53 -050052 if (_output == null)
csharptest74c5e0c2011-07-14 13:06:22 -050053 {
54 _output = new StringWriter(new StringBuilder(_buffer.Length*2 + len));
55 }
csharptest7fc785c2011-06-10 23:54:53 -050056 Flush();
57 }
58
59 if (len < _buffer.Length)
60 {
61 if (len <= 12)
62 {
63 int stop = offset + len;
64 for (int i = offset; i < stop; i++)
csharptest74c5e0c2011-07-14 13:06:22 -050065 {
csharptest7fc785c2011-06-10 23:54:53 -050066 _buffer[_bufferPos++] = chars[i];
csharptest74c5e0c2011-07-14 13:06:22 -050067 }
csharptest7fc785c2011-06-10 23:54:53 -050068 }
69 else
70 {
71 Buffer.BlockCopy(chars, offset << 1, _buffer, _bufferPos << 1, len << 1);
72 _bufferPos += len;
73 }
74 }
75 else
csharptest74c5e0c2011-07-14 13:06:22 -050076 {
csharptest7fc785c2011-06-10 23:54:53 -050077 _output.Write(chars, offset, len);
csharptest74c5e0c2011-07-14 13:06:22 -050078 }
csharptest7fc785c2011-06-10 23:54:53 -050079 }
80
81 protected override void WriteToOutput(char ch)
82 {
83 if (_bufferPos >= _buffer.Length)
csharptest74c5e0c2011-07-14 13:06:22 -050084 {
csharptest7fc785c2011-06-10 23:54:53 -050085 Flush();
csharptest74c5e0c2011-07-14 13:06:22 -050086 }
csharptest7fc785c2011-06-10 23:54:53 -050087 _buffer[_bufferPos++] = ch;
88 }
89
90 public override void Flush()
91 {
92 if (_bufferPos > 0 && _output != null)
93 {
94 _output.Write(_buffer, 0, _bufferPos);
95 _bufferPos = 0;
96 }
97 base.Flush();
98 }
99 }
csharptest74c5e0c2011-07-14 13:06:22 -0500100
csharptest7fc785c2011-06-10 23:54:53 -0500101 private class JsonStreamWriter : JsonFormatWriter
102 {
103#if SILVERLIGHT2 || COMPACT_FRAMEWORK_35
csharptest60fd7732011-09-09 12:18:16 -0500104 static readonly Encoding Encoding = new UTF8Encoding(false);
csharptest7fc785c2011-06-10 23:54:53 -0500105#else
csharptest74c5e0c2011-07-14 13:06:22 -0500106 private static readonly Encoding Encoding = Encoding.ASCII;
csharptest7fc785c2011-06-10 23:54:53 -0500107#endif
108 private readonly byte[] _buffer;
109 private Stream _output;
csharptest74c5e0c2011-07-14 13:06:22 -0500110 private int _bufferPos;
csharptest7fc785c2011-06-10 23:54:53 -0500111
112 public JsonStreamWriter(Stream output)
113 {
114 _buffer = new byte[8192];
115 _bufferPos = 0;
116 _output = output;
117 _counter.Add(0);
118 }
119
120 protected override void WriteToOutput(char[] chars, int offset, int len)
121 {
122 if (_bufferPos + len >= _buffer.Length)
csharptest74c5e0c2011-07-14 13:06:22 -0500123 {
csharptest7fc785c2011-06-10 23:54:53 -0500124 Flush();
csharptest74c5e0c2011-07-14 13:06:22 -0500125 }
csharptest7fc785c2011-06-10 23:54:53 -0500126
127 if (len < _buffer.Length)
128 {
129 if (len <= 12)
130 {
131 int stop = offset + len;
132 for (int i = offset; i < stop; i++)
csharptest74c5e0c2011-07-14 13:06:22 -0500133 {
134 _buffer[_bufferPos++] = (byte) chars[i];
135 }
csharptest7fc785c2011-06-10 23:54:53 -0500136 }
137 else
138 {
139 _bufferPos += Encoding.GetBytes(chars, offset, len, _buffer, _bufferPos);
140 }
csharptestafe844b2011-06-10 16:03:22 -0500141 }
142 else
143 {
csharptest7fc785c2011-06-10 23:54:53 -0500144 byte[] temp = Encoding.GetBytes(chars, offset, len);
145 _output.Write(temp, 0, temp.Length);
csharptestafe844b2011-06-10 16:03:22 -0500146 }
147 }
csharptestafe844b2011-06-10 16:03:22 -0500148
csharptest7fc785c2011-06-10 23:54:53 -0500149 protected override void WriteToOutput(char ch)
csharptestafe844b2011-06-10 16:03:22 -0500150 {
csharptest7fc785c2011-06-10 23:54:53 -0500151 if (_bufferPos >= _buffer.Length)
csharptest74c5e0c2011-07-14 13:06:22 -0500152 {
csharptest7fc785c2011-06-10 23:54:53 -0500153 Flush();
csharptest74c5e0c2011-07-14 13:06:22 -0500154 }
155 _buffer[_bufferPos++] = (byte) ch;
csharptestafe844b2011-06-10 16:03:22 -0500156 }
csharptest7fc785c2011-06-10 23:54:53 -0500157
158 public override void Flush()
159 {
160 if (_bufferPos > 0 && _output != null)
161 {
162 _output.Write(_buffer, 0, _bufferPos);
163 _bufferPos = 0;
164 }
165 base.Flush();
166 }
167 }
csharptest74c5e0c2011-07-14 13:06:22 -0500168
csharptest7fc785c2011-06-10 23:54:53 -0500169 #endregion
170
171 private readonly List<int> _counter;
172 private bool _isArray;
csharptest74c5e0c2011-07-14 13:06:22 -0500173
csharptest7fc785c2011-06-10 23:54:53 -0500174 /// <summary>
175 /// Constructs a JsonFormatWriter, use the ToString() member to extract the final Json on completion.
176 /// </summary>
177 protected JsonFormatWriter()
178 {
179 _counter = new List<int>();
csharptestafe844b2011-06-10 16:03:22 -0500180 }
181
182 /// <summary>
csharptest7fc785c2011-06-10 23:54:53 -0500183 /// Constructs a JsonFormatWriter, use ToString() to extract the final output
csharptestafe844b2011-06-10 16:03:22 -0500184 /// </summary>
csharptest74c5e0c2011-07-14 13:06:22 -0500185 public static JsonFormatWriter CreateInstance()
186 {
187 return new JsonTextWriter(null);
188 }
189
csharptest7fc785c2011-06-10 23:54:53 -0500190 /// <summary>
191 /// Constructs a JsonFormatWriter to output to the given text writer
192 /// </summary>
csharptest74c5e0c2011-07-14 13:06:22 -0500193 public static JsonFormatWriter CreateInstance(TextWriter output)
194 {
195 return new JsonTextWriter(output);
196 }
csharptest7fc785c2011-06-10 23:54:53 -0500197
198 /// <summary>
199 /// Constructs a JsonFormatWriter to output to the given stream
200 /// </summary>
csharptest74c5e0c2011-07-14 13:06:22 -0500201 public static JsonFormatWriter CreateInstance(Stream output)
202 {
203 return new JsonStreamWriter(output);
204 }
csharptest7fc785c2011-06-10 23:54:53 -0500205
206 /// <summary> Write to the output stream </summary>
207 protected void WriteToOutput(string format, params object[] args)
csharptest74c5e0c2011-07-14 13:06:22 -0500208 {
209 WriteToOutput(String.Format(format, args));
210 }
211
csharptest7fc785c2011-06-10 23:54:53 -0500212 /// <summary> Write to the output stream </summary>
213 protected void WriteToOutput(string text)
csharptest74c5e0c2011-07-14 13:06:22 -0500214 {
215 WriteToOutput(text.ToCharArray(), 0, text.Length);
216 }
217
csharptest7fc785c2011-06-10 23:54:53 -0500218 /// <summary> Write to the output stream </summary>
219 protected abstract void WriteToOutput(char ch);
csharptest74c5e0c2011-07-14 13:06:22 -0500220
csharptest7fc785c2011-06-10 23:54:53 -0500221 /// <summary> Write to the output stream </summary>
222 protected abstract void WriteToOutput(char[] chars, int offset, int len);
csharptestafe844b2011-06-10 16:03:22 -0500223
224 /// <summary> Sets the output formatting to use Environment.NewLine with 4-character indentions </summary>
225 public JsonFormatWriter Formatted()
226 {
227 NewLine = Environment.NewLine;
228 Indent = " ";
229 Whitespace = " ";
230 return this;
231 }
232
233 /// <summary> Gets or sets the characters to use for the new-line, default = empty </summary>
234 public string NewLine { get; set; }
csharptest74c5e0c2011-07-14 13:06:22 -0500235
csharptestafe844b2011-06-10 16:03:22 -0500236 /// <summary> Gets or sets the text to use for indenting, default = empty </summary>
237 public string Indent { get; set; }
csharptest74c5e0c2011-07-14 13:06:22 -0500238
csharptestafe844b2011-06-10 16:03:22 -0500239 /// <summary> Gets or sets the whitespace to use to separate the text, default = empty </summary>
240 public string Whitespace { get; set; }
241
csharptest819b7152011-09-08 20:28:22 -0500242 /// <summary>
243 /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
244 /// </summary>
245 protected override void Dispose(bool disposing)
246 {
csharptest60fd7732011-09-09 12:18:16 -0500247 if (disposing)
csharptest819b7152011-09-08 20:28:22 -0500248 {
csharptestc86b5042011-09-09 22:16:08 -0500249 while (_counter.Count > 1)
250 {
csharptest60fd7732011-09-09 12:18:16 -0500251 WriteMessageEnd();
csharptestc86b5042011-09-09 22:16:08 -0500252 }
csharptest819b7152011-09-08 20:28:22 -0500253 }
254
255 base.Dispose(disposing);
256 }
257
csharptestafe844b2011-06-10 16:03:22 -0500258 private void Seperator()
259 {
260 if (_counter.Count == 0)
csharptest74c5e0c2011-07-14 13:06:22 -0500261 {
csharptestafe844b2011-06-10 16:03:22 -0500262 throw new InvalidOperationException("Missmatched open/close in Json writer.");
csharptest74c5e0c2011-07-14 13:06:22 -0500263 }
csharptestafe844b2011-06-10 16:03:22 -0500264
265 int index = _counter.Count - 1;
266 if (_counter[index] > 0)
csharptest74c5e0c2011-07-14 13:06:22 -0500267 {
csharptestafe844b2011-06-10 16:03:22 -0500268 WriteToOutput(',');
csharptest74c5e0c2011-07-14 13:06:22 -0500269 }
csharptestafe844b2011-06-10 16:03:22 -0500270
271 WriteLine(String.Empty);
272 _counter[index] = _counter[index] + 1;
273 }
274
275 private void WriteLine(string content)
276 {
277 if (!String.IsNullOrEmpty(NewLine))
278 {
279 WriteToOutput(NewLine);
280 for (int i = 1; i < _counter.Count; i++)
csharptest74c5e0c2011-07-14 13:06:22 -0500281 {
csharptestafe844b2011-06-10 16:03:22 -0500282 WriteToOutput(Indent);
csharptest74c5e0c2011-07-14 13:06:22 -0500283 }
csharptestafe844b2011-06-10 16:03:22 -0500284 }
csharptest74c5e0c2011-07-14 13:06:22 -0500285 else if (!String.IsNullOrEmpty(Whitespace))
286 {
csharptestafe844b2011-06-10 16:03:22 -0500287 WriteToOutput(Whitespace);
csharptest74c5e0c2011-07-14 13:06:22 -0500288 }
csharptestafe844b2011-06-10 16:03:22 -0500289
290 WriteToOutput(content);
291 }
292
293 private void WriteName(string field)
294 {
295 Seperator();
296 if (!String.IsNullOrEmpty(field))
297 {
298 WriteToOutput('"');
299 WriteToOutput(field);
300 WriteToOutput('"');
301 WriteToOutput(':');
302 if (!String.IsNullOrEmpty(Whitespace))
csharptest74c5e0c2011-07-14 13:06:22 -0500303 {
csharptestafe844b2011-06-10 16:03:22 -0500304 WriteToOutput(Whitespace);
csharptest74c5e0c2011-07-14 13:06:22 -0500305 }
csharptestafe844b2011-06-10 16:03:22 -0500306 }
307 }
308
309 private void EncodeText(string value)
310 {
311 char[] text = value.ToCharArray();
312 int len = text.Length;
313 int pos = 0;
314
315 while (pos < len)
316 {
317 int next = pos;
csharptest74c5e0c2011-07-14 13:06:22 -0500318 while (next < len && text[next] >= 32 && text[next] < 127 && text[next] != '\\' && text[next] != '/' &&
319 text[next] != '"')
320 {
csharptestafe844b2011-06-10 16:03:22 -0500321 next++;
csharptest74c5e0c2011-07-14 13:06:22 -0500322 }
csharptestafe844b2011-06-10 16:03:22 -0500323 WriteToOutput(text, pos, next - pos);
324 if (next < len)
325 {
326 switch (text[next])
327 {
csharptest74c5e0c2011-07-14 13:06:22 -0500328 case '"':
329 WriteToOutput(@"\""");
330 break;
331 case '\\':
332 WriteToOutput(@"\\");
333 break;
334 //odd at best to escape '/', most Json implementations don't, but it is defined in the rfc-4627
335 case '/':
336 WriteToOutput(@"\/");
337 break;
338 case '\b':
339 WriteToOutput(@"\b");
340 break;
341 case '\f':
342 WriteToOutput(@"\f");
343 break;
344 case '\n':
345 WriteToOutput(@"\n");
346 break;
347 case '\r':
348 WriteToOutput(@"\r");
349 break;
350 case '\t':
351 WriteToOutput(@"\t");
352 break;
353 default:
354 WriteToOutput(@"\u{0:x4}", (int) text[next]);
355 break;
csharptestafe844b2011-06-10 16:03:22 -0500356 }
357 next++;
358 }
359 pos = next;
360 }
361 }
362
363 /// <summary>
364 /// Writes a String value
365 /// </summary>
366 protected override void WriteAsText(string field, string textValue, object typedValue)
367 {
368 WriteName(field);
csharptest74c5e0c2011-07-14 13:06:22 -0500369 if (typedValue is bool || typedValue is int || typedValue is uint || typedValue is long ||
370 typedValue is ulong || typedValue is double || typedValue is float)
371 {
csharptestafe844b2011-06-10 16:03:22 -0500372 WriteToOutput(textValue);
csharptest74c5e0c2011-07-14 13:06:22 -0500373 }
csharptestafe844b2011-06-10 16:03:22 -0500374 else
375 {
376 WriteToOutput('"');
377 if (typedValue is string)
csharptest74c5e0c2011-07-14 13:06:22 -0500378 {
csharptestafe844b2011-06-10 16:03:22 -0500379 EncodeText(textValue);
csharptest74c5e0c2011-07-14 13:06:22 -0500380 }
csharptestafe844b2011-06-10 16:03:22 -0500381 else
csharptest74c5e0c2011-07-14 13:06:22 -0500382 {
csharptestafe844b2011-06-10 16:03:22 -0500383 WriteToOutput(textValue);
csharptest74c5e0c2011-07-14 13:06:22 -0500384 }
csharptestafe844b2011-06-10 16:03:22 -0500385 WriteToOutput('"');
386 }
387 }
388
389 /// <summary>
390 /// Writes a Double value
391 /// </summary>
392 protected override void Write(string field, double value)
393 {
394 if (double.IsNaN(value) || double.IsNegativeInfinity(value) || double.IsPositiveInfinity(value))
csharptest74c5e0c2011-07-14 13:06:22 -0500395 {
csharptestafe844b2011-06-10 16:03:22 -0500396 throw new InvalidOperationException("This format does not support NaN, Infinity, or -Infinity");
csharptest74c5e0c2011-07-14 13:06:22 -0500397 }
csharptestafe844b2011-06-10 16:03:22 -0500398 base.Write(field, value);
399 }
400
401 /// <summary>
402 /// Writes a Single value
403 /// </summary>
404 protected override void Write(string field, float value)
405 {
406 if (float.IsNaN(value) || float.IsNegativeInfinity(value) || float.IsPositiveInfinity(value))
csharptest74c5e0c2011-07-14 13:06:22 -0500407 {
csharptestafe844b2011-06-10 16:03:22 -0500408 throw new InvalidOperationException("This format does not support NaN, Infinity, or -Infinity");
csharptest74c5e0c2011-07-14 13:06:22 -0500409 }
csharptestafe844b2011-06-10 16:03:22 -0500410 base.Write(field, value);
411 }
412
413 // Treat enum as string
414 protected override void WriteEnum(string field, int number, string name)
415 {
416 Write(field, name);
417 }
418
419 /// <summary>
420 /// Writes an array of field values
421 /// </summary>
csharptest74c5e0c2011-07-14 13:06:22 -0500422 protected override void WriteArray(FieldType type, string field, IEnumerable items)
csharptestafe844b2011-06-10 16:03:22 -0500423 {
csharptest74c5e0c2011-07-14 13:06:22 -0500424 IEnumerator enumerator = items.GetEnumerator();
425 try
426 {
427 if (!enumerator.MoveNext())
428 {
429 return;
430 }
431 }
432 finally
433 {
434 if (enumerator is IDisposable)
435 {
436 ((IDisposable) enumerator).Dispose();
437 }
438 }
csharptestafe844b2011-06-10 16:03:22 -0500439
440 WriteName(field);
441 WriteToOutput("[");
442 _counter.Add(0);
443
444 base.WriteArray(type, String.Empty, items);
445
446 _counter.RemoveAt(_counter.Count - 1);
447 WriteLine("]");
448 }
449
450 /// <summary>
451 /// Writes a message
452 /// </summary>
453 protected override void WriteMessageOrGroup(string field, IMessageLite message)
454 {
455 WriteName(field);
456 WriteMessage(message);
457 }
458
459 /// <summary>
460 /// Writes the message to the the formatted stream.
461 /// </summary>
462 public override void WriteMessage(IMessageLite message)
463 {
csharptest60fd7732011-09-09 12:18:16 -0500464 WriteMessageStart();
csharptestc2d2c1a2011-09-08 20:02:11 -0500465 message.WriteTo(this);
csharptest60fd7732011-09-09 12:18:16 -0500466 WriteMessageEnd();
csharptestc2d2c1a2011-09-08 20:02:11 -0500467 }
468
469 /// <summary>
470 /// Used to write the root-message preamble, in json this is the left-curly brace '{'.
471 /// After this call you can call IMessageLite.MergeTo(...) and complete the message with
csharptest60fd7732011-09-09 12:18:16 -0500472 /// a call to WriteMessageEnd().
csharptestc2d2c1a2011-09-08 20:02:11 -0500473 /// </summary>
csharptest60fd7732011-09-09 12:18:16 -0500474 public override void WriteMessageStart()
csharptestc2d2c1a2011-09-08 20:02:11 -0500475 {
csharptest74c5e0c2011-07-14 13:06:22 -0500476 if (_isArray)
477 {
478 Seperator();
479 }
csharptestafe844b2011-06-10 16:03:22 -0500480 WriteToOutput("{");
481 _counter.Add(0);
csharptestc2d2c1a2011-09-08 20:02:11 -0500482 }
483
484 /// <summary>
csharptest60fd7732011-09-09 12:18:16 -0500485 /// Used to complete a root-message previously started with a call to WriteMessageStart()
csharptestc2d2c1a2011-09-08 20:02:11 -0500486 /// </summary>
csharptest60fd7732011-09-09 12:18:16 -0500487 public override void WriteMessageEnd()
csharptestc2d2c1a2011-09-08 20:02:11 -0500488 {
csharptestafe844b2011-06-10 16:03:22 -0500489 _counter.RemoveAt(_counter.Count - 1);
490 WriteLine("}");
491 Flush();
492 }
493
494 /// <summary>
csharptestafe844b2011-06-10 16:03:22 -0500495 /// Used in streaming arrays of objects to the writer
496 /// </summary>
497 /// <example>
498 /// <code>
499 /// using(writer.StartArray())
500 /// foreach(IMessageLite m in messages)
501 /// writer.WriteMessage(m);
502 /// </code>
503 /// </example>
csharptest74c5e0c2011-07-14 13:06:22 -0500504 public sealed class JsonArray : IDisposable
csharptestafe844b2011-06-10 16:03:22 -0500505 {
csharptest74c5e0c2011-07-14 13:06:22 -0500506 private JsonFormatWriter _writer;
507
csharptestafe844b2011-06-10 16:03:22 -0500508 internal JsonArray(JsonFormatWriter writer)
509 {
510 _writer = writer;
511 _writer.WriteToOutput("[");
512 _writer._counter.Add(0);
513 }
514
515 /// <summary>
516 /// Causes the end of the array character to be written.
517 /// </summary>
csharptest74c5e0c2011-07-14 13:06:22 -0500518 private void EndArray()
csharptestafe844b2011-06-10 16:03:22 -0500519 {
520 if (_writer != null)
521 {
522 _writer._counter.RemoveAt(_writer._counter.Count - 1);
523 _writer.WriteLine("]");
524 _writer.Flush();
525 }
csharptest74c5e0c2011-07-14 13:06:22 -0500526 _writer = null;
csharptestafe844b2011-06-10 16:03:22 -0500527 }
csharptest74c5e0c2011-07-14 13:06:22 -0500528
529 void IDisposable.Dispose()
530 {
531 EndArray();
532 }
csharptestafe844b2011-06-10 16:03:22 -0500533 }
534
535 /// <summary>
536 /// Used to write an array of messages as the output rather than a single message.
537 /// </summary>
538 /// <example>
539 /// <code>
540 /// using(writer.StartArray())
541 /// foreach(IMessageLite m in messages)
542 /// writer.WriteMessage(m);
543 /// </code>
544 /// </example>
545 public JsonArray StartArray()
546 {
csharptest74c5e0c2011-07-14 13:06:22 -0500547 if (_isArray)
548 {
549 Seperator();
550 }
csharptestafe844b2011-06-10 16:03:22 -0500551 _isArray = true;
552 return new JsonArray(this);
553 }
554 }
555}