2
// http://code.google.com/p/servicestack/wiki/TypeSerializer
3
// ServiceStack.Text: .NET C# POCO Type Text Serializer.
6
// Demis Bellot (demis.bellot@gmail.com)
8
// Copyright 2011 Liquidbit Ltd.
10
// Licensed under the same terms of ServiceStack: new BSD license.
14
using System.Globalization;
17
using ServiceStack.Text.Common;
19
namespace ServiceStack.Text.Json
21
internal class JsonTypeSerializer
24
public static ITypeSerializer Instance = new JsonTypeSerializer();
26
public string TypeAttrInObject { get { return "{\"__type\":"; } }
28
public static readonly bool[] WhiteSpaceFlags = new bool[(int)' ' + 1];
30
static JsonTypeSerializer()
32
WhiteSpaceFlags[(int)' '] = true;
33
WhiteSpaceFlags[(int)'\t'] = true;
34
WhiteSpaceFlags[(int)'\r'] = true;
35
WhiteSpaceFlags[(int)'\n'] = true;
38
public WriteObjectDelegate GetWriteFn<T>()
40
return JsonWriter<T>.WriteFn();
43
public WriteObjectDelegate GetWriteFn(Type type)
45
return JsonWriter.GetWriteFn(type);
48
public TypeInfo GetTypeInfo(Type type)
50
return JsonWriter.GetTypeInfo(type);
54
/// Shortcut escape when we're sure value doesn't contain any escaped chars
56
/// <param name="writer"></param>
57
/// <param name="value"></param>
58
public void WriteRawString(TextWriter writer, string value)
60
writer.Write(JsWriter.QuoteChar);
62
writer.Write(JsWriter.QuoteChar);
65
public void WritePropertyName(TextWriter writer, string value)
67
if (JsState.WritingKeyCount > 0)
69
writer.Write(JsWriter.EscapedQuoteString);
71
writer.Write(JsWriter.EscapedQuoteString);
75
WriteRawString(writer, value);
79
public void WriteString(TextWriter writer, string value)
81
JsonUtils.WriteString(writer, value);
84
public void WriteBuiltIn(TextWriter writer, object value)
86
if (JsState.WritingKeyCount > 0 && !JsState.IsWritingValue) writer.Write(JsonUtils.QuoteChar);
88
WriteRawString(writer, value.ToString());
90
if (JsState.WritingKeyCount > 0 && !JsState.IsWritingValue) writer.Write(JsonUtils.QuoteChar);
93
public void WriteObjectString(TextWriter writer, object value)
95
JsonUtils.WriteString(writer, value != null ? value.ToString() : null);
98
public void WriteException(TextWriter writer, object value)
100
WriteString(writer, ((Exception)value).Message);
103
public void WriteDateTime(TextWriter writer, object oDateTime)
105
WriteRawString(writer, DateTimeSerializer.ToWcfJsonDate((DateTime)oDateTime));
108
public void WriteNullableDateTime(TextWriter writer, object dateTime)
110
if (dateTime == null)
111
writer.Write( JsonUtils.Null );
113
WriteDateTime(writer, dateTime);
116
public void WriteGuid(TextWriter writer, object oValue)
118
WriteRawString(writer, ((Guid)oValue).ToString("N"));
121
public void WriteNullableGuid(TextWriter writer, object oValue)
123
if (oValue == null) return;
124
WriteRawString(writer, ((Guid)oValue).ToString("N"));
127
public void WriteBytes(TextWriter writer, object oByteValue)
129
if (oByteValue == null) return;
130
WriteRawString(writer, Convert.ToBase64String((byte[])oByteValue));
133
public void WriteChar(TextWriter writer, object charValue)
135
if (charValue == null)
136
writer.Write(JsonUtils.Null);
138
WriteRawString(writer, ((char)charValue).ToString(CultureInfo.InvariantCulture));
141
public void WriteByte(TextWriter writer, object byteValue)
143
if (byteValue == null)
144
writer.Write(JsonUtils.Null);
146
writer.Write((byte)byteValue);
149
public void WriteInt16(TextWriter writer, object intValue)
151
if (intValue == null)
152
writer.Write(JsonUtils.Null);
154
writer.Write((short)intValue);
157
public void WriteUInt16(TextWriter writer, object intValue)
159
if (intValue == null)
160
writer.Write(JsonUtils.Null);
162
writer.Write((ushort)intValue);
165
public void WriteInt32(TextWriter writer, object intValue)
167
if (intValue == null)
168
writer.Write(JsonUtils.Null);
170
writer.Write((int)intValue);
173
public void WriteUInt32(TextWriter writer, object uintValue)
175
if (uintValue == null)
176
writer.Write(JsonUtils.Null);
178
writer.Write((uint)uintValue);
181
public void WriteInt64(TextWriter writer, object integerValue)
183
if (integerValue == null)
184
writer.Write(JsonUtils.Null);
186
writer.Write((long)integerValue);
189
public void WriteUInt64(TextWriter writer, object ulongValue)
191
if (ulongValue == null)
193
writer.Write(JsonUtils.Null);
196
writer.Write((ulong)ulongValue);
199
public void WriteBool(TextWriter writer, object boolValue)
201
if (boolValue == null)
202
writer.Write(JsonUtils.Null);
204
writer.Write(((bool)boolValue) ? JsonUtils.True : JsonUtils.False);
207
public void WriteFloat(TextWriter writer, object floatValue)
209
if (floatValue == null)
210
writer.Write(JsonUtils.Null);
213
var floatVal = (float)floatValue;
214
if (Equals(floatVal, float.MaxValue) || Equals(floatVal, float.MinValue))
215
writer.Write(floatVal.ToString("r", CultureInfo.InvariantCulture));
217
writer.Write(floatVal.ToString(CultureInfo.InvariantCulture));
221
public void WriteDouble(TextWriter writer, object doubleValue)
223
if (doubleValue == null)
224
writer.Write(JsonUtils.Null);
227
var doubleVal = (double)doubleValue;
228
if (Equals(doubleVal, double.MaxValue) || Equals(doubleVal, double.MinValue))
229
writer.Write(doubleVal.ToString("r", CultureInfo.InvariantCulture));
231
writer.Write(doubleVal.ToString(CultureInfo.InvariantCulture));
235
public void WriteDecimal(TextWriter writer, object decimalValue)
237
if (decimalValue == null)
238
writer.Write(JsonUtils.Null);
240
writer.Write(((decimal)decimalValue).ToString(CultureInfo.InvariantCulture));
243
public void WriteEnum(TextWriter writer, object enumValue)
245
if (enumValue == null) return;
246
WriteRawString(writer, enumValue.ToString());
249
public void WriteEnumFlags(TextWriter writer, object enumFlagValue)
251
if (enumFlagValue == null) return;
252
var intVal = (int)enumFlagValue;
253
writer.Write(intVal);
256
public void WriteLinqBinary(TextWriter writer, object linqBinaryValue)
258
#if !MONOTOUCH && !SILVERLIGHT && !XBOX
259
WriteRawString(writer, Convert.ToBase64String(((System.Data.Linq.Binary)linqBinaryValue).ToArray()));
263
public ParseStringDelegate GetParseFn<T>()
265
return JsonReader.Instance.GetParseFn<T>();
268
public ParseStringDelegate GetParseFn(Type type)
270
return JsonReader.GetParseFn(type);
273
public string ParseRawString(string value)
275
if (String.IsNullOrEmpty(value)) return value;
277
return value[0] == JsonUtils.QuoteChar
278
? value.Substring(1, value.Length - 2)
282
public string ParseString(string value)
284
return string.IsNullOrEmpty(value) ? value : ParseRawString(value);
287
static readonly char[] IsSafeJsonChars = new[] { JsonUtils.QuoteChar, JsonUtils.EscapeChar };
289
internal static string ParseJsonString(string json, ref int index)
291
var jsonLength = json.Length;
293
for (; index < json.Length; index++) { var ch = json[index]; if (ch >= WhiteSpaceFlags.Length || !WhiteSpaceFlags[ch]) break; } //Whitespace inline
295
if (json[index] == JsonUtils.QuoteChar)
299
//MicroOp: See if we can short-circuit evaluation (to avoid StringBuilder)
300
var strEndPos = json.IndexOfAny(IsSafeJsonChars, index);
301
if (strEndPos == -1) return json.Substring(index, jsonLength - index);
302
if (json[strEndPos] == JsonUtils.QuoteChar)
304
var potentialValue = json.Substring(index, strEndPos - index);
305
index = strEndPos + 1;
306
return potentialValue;
310
var sb = new StringBuilder(jsonLength);
315
if (index == jsonLength) break;
318
if (c == JsonUtils.QuoteChar) break;
323
if (index == jsonLength)
355
var remainingLength = jsonLength - index;
356
if (remainingLength >= 4)
358
var unicodeString = json.Substring(index, 4);
359
var unicodeIntVal = UInt32.Parse(unicodeString, NumberStyles.HexNumber);
360
sb.Append(ConvertFromUtf32((int)unicodeIntVal));
376
var strValue = sb.ToString();
377
return strValue == JsonUtils.Null ? null : strValue;
381
/// Since Silverlight doesn't have char.ConvertFromUtf32() so putting Mono's implemenation inline.
383
/// <param name="utf32"></param>
384
/// <returns></returns>
385
private static string ConvertFromUtf32(int utf32)
387
if (utf32 < 0 || utf32 > 0x10FFFF)
388
throw new ArgumentOutOfRangeException("utf32", "The argument must be from 0 to 0x10FFFF.");
389
if (0xD800 <= utf32 && utf32 <= 0xDFFF)
390
throw new ArgumentOutOfRangeException("utf32", "The argument must not be in surrogate pair range.");
392
return new string((char)utf32, 1);
394
return new string(new[] {(char) ((utf32 >> 10) + 0xD800),
395
(char) (utf32 % 0x0400 + 0xDC00)});
398
private static void EatWhitespace(string json, ref int index)
401
for (; index < json.Length; index++)
404
if (c >= WhiteSpaceFlags.Length || !WhiteSpaceFlags[c])
411
public string EatTypeValue(string value, ref int i)
413
return EatValue(value, ref i);
416
public bool EatMapStartChar(string value, ref int i)
418
for (; i < value.Length; i++) { var c = value[i]; if (c >= WhiteSpaceFlags.Length || !WhiteSpaceFlags[c]) break; } //Whitespace inline
419
return value[i++] == JsWriter.MapStartChar;
422
public string EatMapKey(string value, ref int i)
424
return ParseJsonString(value, ref i);
427
public bool EatMapKeySeperator(string value, ref int i)
429
for (; i < value.Length; i++) { var c = value[i]; if (c >= WhiteSpaceFlags.Length || !WhiteSpaceFlags[c]) break; } //Whitespace inline
430
if (value.Length == i) return false;
431
return value[i++] == JsWriter.MapKeySeperator;
434
public bool EatItemSeperatorOrMapEndChar(string value, ref int i)
436
for (; i < value.Length; i++) { var c = value[i]; if (c >= WhiteSpaceFlags.Length || !WhiteSpaceFlags[c]) break; } //Whitespace inline
438
if (i == value.Length) return false;
440
var success = value[i] == JsWriter.ItemSeperator
441
|| value[i] == JsWriter.MapEndChar;
447
for (; i < value.Length; i++) { var c = value[i]; if (c >= WhiteSpaceFlags.Length || !WhiteSpaceFlags[c]) break; } //Whitespace inline
453
public string EatValue(string value, ref int i)
455
var valueLength = value.Length;
456
if (i == valueLength) return null;
458
for (; i < value.Length; i++) { var c = value[i]; if (c >= WhiteSpaceFlags.Length || !WhiteSpaceFlags[c]) break; } //Whitespace inline
460
var tokenStartPos = i;
461
var valueChar = value[i];
462
var withinQuotes = false;
467
//If we are at the end, return.
468
case JsWriter.ItemSeperator:
469
case JsWriter.MapEndChar:
472
//Is Within Quotes, i.e. "..."
473
case JsWriter.QuoteChar:
474
return ParseJsonString(value, ref i);
476
//Is Type/Map, i.e. {...}
477
case JsWriter.MapStartChar:
478
while (++i < valueLength && endsToEat > 0)
480
valueChar = value[i];
482
if (valueChar == JsWriter.QuoteChar
483
&& value[i - 1] != JsonUtils.EscapeChar)
484
withinQuotes = !withinQuotes;
489
if (valueChar == JsWriter.MapStartChar)
492
if (valueChar == JsWriter.MapEndChar)
495
return value.Substring(tokenStartPos, i - tokenStartPos);
497
//Is List, i.e. [...]
498
case JsWriter.ListStartChar:
499
while (++i < valueLength && endsToEat > 0)
501
valueChar = value[i];
503
if (valueChar == JsWriter.QuoteChar
504
&& value[i - 1] != JsonUtils.EscapeChar)
505
withinQuotes = !withinQuotes;
510
if (valueChar == JsWriter.ListStartChar)
513
if (valueChar == JsWriter.ListEndChar)
516
return value.Substring(tokenStartPos, i - tokenStartPos);
520
while (++i < valueLength)
522
valueChar = value[i];
524
if (valueChar == JsWriter.ItemSeperator
525
|| valueChar == JsWriter.MapEndChar
526
//If it doesn't have quotes it's either a keyword or number so also has a ws boundary
527
|| (valueChar < WhiteSpaceFlags.Length && WhiteSpaceFlags[valueChar])
534
var strValue = value.Substring(tokenStartPos, i - tokenStartPos);
535
return strValue == JsonUtils.Null ? null : strValue;
b'\\ No newline at end of file'