-JsonTextReader, BsonReader performance
-Fix dictionary key encoding when serializing -Fix WrappedDictionary being set to a property when deserializing -Fix Silverlight serialization security error
This commit is contained in:
@@ -97,7 +97,11 @@ namespace Newtonsoft.Json.Tests.Converters
|
||||
[Test]
|
||||
public void SerializeCustomFormattedDateTime()
|
||||
{
|
||||
IsoDateTimeConverter converter = new IsoDateTimeConverter() { DateTimeFormat = "dd/MM/yyyy" };
|
||||
IsoDateTimeConverter converter = new IsoDateTimeConverter
|
||||
{
|
||||
DateTimeFormat = "dd/MM/yyyy",
|
||||
Culture = CultureInfo.InvariantCulture
|
||||
};
|
||||
|
||||
string json = @"""09/12/2006""";
|
||||
|
||||
|
||||
@@ -152,6 +152,9 @@ now brown cow?", '"', true);
|
||||
|
||||
result = JavaScriptUtils.ToEscapedJavaScriptString(@"Fred's ""cat"".", '\'', true);
|
||||
Assert.AreEqual(result, @"'Fred\'s ""cat"".'");
|
||||
|
||||
result = JavaScriptUtils.ToEscapedJavaScriptString("\u001farray\u003caddress");
|
||||
Assert.AreEqual(result, @"""\u001farray<address""");
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace Newtonsoft.Json.Tests
|
||||
,{""t"":""CSCO"", ""n"":""Cisco Systems, Inc."", ""e"":""NASDAQ"", ""id"":""99624""}
|
||||
,{""t"":""CVX"", ""n"":""Chevron Corporation"", ""e"":""NYSE"", ""id"":""667226""}
|
||||
,{""t"":""TM"", ""n"":""Toyota Motor Corporation (ADR)"", ""e"":""NYSE"", ""id"":""655880""}
|
||||
,{""t"":""JPM"", ""n"":""JPMorgan Chase \x26 Co."", ""e"":""NYSE"", ""id"":""665639""}
|
||||
,{""t"":""JPM"", ""n"":""JPMorgan Chase \\x26 Co."", ""e"":""NYSE"", ""id"":""665639""}
|
||||
,{""t"":""COP"", ""n"":""ConocoPhillips"", ""e"":""NYSE"", ""id"":""1691168""}
|
||||
,{""t"":""LFC"", ""n"":""China Life Insurance Company Ltd. (ADR)"", ""e"":""NYSE"", ""id"":""688679""}
|
||||
,{""t"":""NOK"", ""n"":""Nokia Corporation (ADR)"", ""e"":""NYSE"", ""id"":""657729""}
|
||||
@@ -138,6 +138,8 @@ namespace Newtonsoft.Json.Tests
|
||||
Assert.AreEqual(jsonReader.TokenType, JsonToken.EndObject);
|
||||
Assert.AreEqual(7, jsonReader.LineNumber);
|
||||
Assert.AreEqual(1, jsonReader.LinePosition);
|
||||
|
||||
Assert.IsFalse(jsonReader.Read());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,10 +178,12 @@ namespace Newtonsoft.Json.Tests
|
||||
|
||||
jsonReader.Read();
|
||||
Assert.AreEqual(jsonReader.TokenType, JsonToken.Integer);
|
||||
Assert.AreEqual(1, jsonReader.Value);
|
||||
Assert.AreEqual(3, jsonReader.Depth);
|
||||
|
||||
jsonReader.Read();
|
||||
Assert.AreEqual(jsonReader.TokenType, JsonToken.Integer);
|
||||
Assert.AreEqual(2, jsonReader.Value);
|
||||
Assert.AreEqual(3, jsonReader.Depth);
|
||||
|
||||
jsonReader.Read();
|
||||
@@ -192,6 +196,140 @@ namespace Newtonsoft.Json.Tests
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(ArgumentNullException), ExpectedMessage = @"Value cannot be null.
|
||||
Parameter name: reader")]
|
||||
public void NullTextReader()
|
||||
{
|
||||
new JsonTextReader(null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Unterminated string. Expected delimiter: '. Line 1, position 3.")]
|
||||
public void UnexpectedEndOfString()
|
||||
{
|
||||
JsonReader reader = new JsonTextReader(new StringReader("'hi"));
|
||||
reader.Read();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReadNullTerminatorStrings()
|
||||
{
|
||||
JsonReader reader = new JsonTextReader(new StringReader("'h\0i'"));
|
||||
Assert.IsTrue(reader.Read());
|
||||
|
||||
Assert.AreEqual("h\0i", reader.Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Unexpected end while parsing unicode character. Line 1, position 7.")]
|
||||
public void UnexpectedEndOfHex()
|
||||
{
|
||||
JsonReader reader = new JsonTextReader(new StringReader(@"'h\u006"));
|
||||
reader.Read();
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Unterminated string. Expected delimiter: '. Line 1, position 3.")]
|
||||
public void UnexpectedEndOfControlCharacter()
|
||||
{
|
||||
JsonReader reader = new JsonTextReader(new StringReader(@"'h\"));
|
||||
reader.Read();
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Unexpected character encountered while parsing value: t. Line 1, position 1.")]
|
||||
public void ReadBytesWithBadCharacter()
|
||||
{
|
||||
JsonReader reader = new JsonTextReader(new StringReader(@"true"));
|
||||
reader.ReadAsBytes();
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Unterminated string. Expected delimiter: '. Line 1, position 17.")]
|
||||
public void ReadBytesWithUnexpectedEnd()
|
||||
{
|
||||
string helloWorld = "Hello world!";
|
||||
byte[] helloWorldData = Encoding.UTF8.GetBytes(helloWorld);
|
||||
|
||||
JsonReader reader = new JsonTextReader(new StringReader(@"'" + Convert.ToBase64String(helloWorldData)));
|
||||
reader.ReadAsBytes();
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Unexpected end when reading bytes: Line 1, position 3.")]
|
||||
public void ReadBytesNoStartWithUnexpectedEnd()
|
||||
{
|
||||
JsonReader reader = new JsonTextReader(new StringReader(@"[ "));
|
||||
Assert.IsTrue(reader.Read());
|
||||
reader.ReadAsBytes();
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(JsonReaderException), ExpectedMessage = "Unexpected end when parsing unquoted property name. Line 1, position 4.")]
|
||||
public void UnexpectedEndWhenParsingUnquotedProperty()
|
||||
{
|
||||
JsonReader reader = new JsonTextReader(new StringReader(@"{aww"));
|
||||
Assert.IsTrue(reader.Read());
|
||||
reader.Read();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParsingQuotedPropertyWithControlCharacters()
|
||||
{
|
||||
JsonReader reader = new JsonTextReader(new StringReader(@"{'hi\r\nbye':1}"));
|
||||
Assert.IsTrue(reader.Read());
|
||||
Assert.IsTrue(reader.Read());
|
||||
Assert.AreEqual(JsonToken.PropertyName, reader.TokenType);
|
||||
Assert.AreEqual(@"hi
|
||||
bye", reader.Value);
|
||||
Assert.IsTrue(reader.Read());
|
||||
Assert.IsTrue(reader.Read());
|
||||
Assert.IsFalse(reader.Read());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReadBytesFollowingNumberInArray()
|
||||
{
|
||||
string helloWorld = "Hello world!";
|
||||
byte[] helloWorldData = Encoding.UTF8.GetBytes(helloWorld);
|
||||
|
||||
JsonReader reader = new JsonTextReader(new StringReader(@"[1,'" + Convert.ToBase64String(helloWorldData) + @"']"));
|
||||
Assert.IsTrue(reader.Read());
|
||||
Assert.AreEqual(JsonToken.StartArray, reader.TokenType);
|
||||
Assert.IsTrue(reader.Read());
|
||||
Assert.AreEqual(JsonToken.Integer, reader.TokenType);
|
||||
byte[] data = reader.ReadAsBytes();
|
||||
Assert.AreEqual(helloWorldData, data);
|
||||
Assert.AreEqual(JsonToken.Bytes, reader.TokenType);
|
||||
Assert.IsTrue(reader.Read());
|
||||
Assert.AreEqual(JsonToken.EndArray, reader.TokenType);
|
||||
|
||||
Assert.IsFalse(reader.Read());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReadBytesFollowingNumberInObject()
|
||||
{
|
||||
string helloWorld = "Hello world!";
|
||||
byte[] helloWorldData = Encoding.UTF8.GetBytes(helloWorld);
|
||||
|
||||
JsonReader reader = new JsonTextReader(new StringReader(@"{num:1,data:'" + Convert.ToBase64String(helloWorldData) + @"'}"));
|
||||
Assert.IsTrue(reader.Read());
|
||||
Assert.AreEqual(JsonToken.StartObject, reader.TokenType);
|
||||
Assert.IsTrue(reader.Read());
|
||||
Assert.IsTrue(reader.Read());
|
||||
Assert.AreEqual(JsonToken.Integer, reader.TokenType);
|
||||
Assert.IsTrue(reader.Read());
|
||||
byte[] data = reader.ReadAsBytes();
|
||||
Assert.AreEqual(helloWorldData, data);
|
||||
Assert.AreEqual(JsonToken.Bytes, reader.TokenType);
|
||||
Assert.IsTrue(reader.Read());
|
||||
Assert.AreEqual(JsonToken.EndObject, reader.TokenType);
|
||||
|
||||
Assert.IsFalse(reader.Read());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReadingEscapedStrings()
|
||||
{
|
||||
|
||||
@@ -527,7 +527,7 @@ namespace Newtonsoft.Json.Tests
|
||||
|
||||
Assert.IsTrue(reader.Read());
|
||||
Assert.AreEqual(JsonToken.Null, reader.TokenType);
|
||||
Assert.AreEqual(@"Value null is not defined in enum. Line 1, position 6.", validationEventArgs.Message);
|
||||
Assert.AreEqual(@"Value null is not defined in enum. Line 1, position 5.", validationEventArgs.Message);
|
||||
|
||||
Assert.IsTrue(reader.Read());
|
||||
Assert.AreEqual(JsonToken.EndArray, reader.TokenType);
|
||||
@@ -564,7 +564,7 @@ namespace Newtonsoft.Json.Tests
|
||||
|
||||
Assert.IsTrue(reader.Read());
|
||||
Assert.AreEqual(JsonToken.Boolean, reader.TokenType);
|
||||
Assert.AreEqual(@"Value false is not defined in enum. Line 1, position 12.", validationEventArgs.Message);
|
||||
Assert.AreEqual(@"Value false is not defined in enum. Line 1, position 11.", validationEventArgs.Message);
|
||||
|
||||
Assert.IsTrue(reader.Read());
|
||||
Assert.AreEqual(JsonToken.EndArray, reader.TokenType);
|
||||
@@ -1005,7 +1005,7 @@ namespace Newtonsoft.Json.Tests
|
||||
|
||||
Assert.IsTrue(reader.Read());
|
||||
Assert.AreEqual(JsonToken.Null, reader.TokenType);
|
||||
Assert.AreEqual("Index 3 has not been defined and the schema does not allow additional items. Line 1, position 14.", validationEventArgs.Message);
|
||||
Assert.AreEqual("Index 3 has not been defined and the schema does not allow additional items. Line 1, position 13.", validationEventArgs.Message);
|
||||
|
||||
Assert.IsTrue(reader.Read());
|
||||
Assert.AreEqual(JsonToken.EndArray, reader.TokenType);
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -27,6 +27,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
#if !SILVERLIGHT && !PocketPC && !NET20
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Web.Script.Serialization;
|
||||
#endif
|
||||
using System.Text;
|
||||
using NUnit.Framework;
|
||||
@@ -131,12 +132,21 @@ namespace Newtonsoft.Json.Tests.Serialization
|
||||
[Test]
|
||||
public void DeserializeJavaScriptDate()
|
||||
{
|
||||
DateTime dateValue = new DateTime(2000, 3, 30);
|
||||
DateTime dateValue = new DateTime(2010, 3, 30);
|
||||
Dictionary<string, object> testDictionary = new Dictionary<string, object>();
|
||||
testDictionary["date"] = dateValue;
|
||||
|
||||
string jsonText = JsonConvert.SerializeObject(testDictionary);
|
||||
|
||||
#if !PocketPC && !NET20
|
||||
MemoryStream ms = new MemoryStream();
|
||||
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(Dictionary<string, object>));
|
||||
serializer.WriteObject(ms, testDictionary);
|
||||
|
||||
byte[] data = ms.ToArray();
|
||||
string output = Encoding.UTF8.GetString(data, 0, data.Length);
|
||||
#endif
|
||||
|
||||
Dictionary<string, object> deserializedDictionary = (Dictionary<string, object>)JsonConvert.DeserializeObject(jsonText, typeof(Dictionary<string, object>));
|
||||
DateTime deserializedDate = (DateTime)deserializedDictionary["date"];
|
||||
|
||||
@@ -403,6 +413,37 @@ keyword such as type of business.""
|
||||
Assert.AreEqual(dataContractResult[0], jsonNetResult[0]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BackslashEqivilence()
|
||||
{
|
||||
string json = @"[""vvv\/vvv\tvvv\""vvv\bvvv\nvvv\rvvv\\vvv\fvvv""]";
|
||||
|
||||
#if !SILVERLIGHT
|
||||
JavaScriptSerializer javaScriptSerializer = new JavaScriptSerializer();
|
||||
List<string> javaScriptSerializerResult = javaScriptSerializer.Deserialize<List<string>>(json);
|
||||
#endif
|
||||
|
||||
DataContractJsonSerializer s = new DataContractJsonSerializer(typeof(List<string>));
|
||||
List<string> dataContractResult = (List<string>)s.ReadObject(new MemoryStream(Encoding.UTF8.GetBytes(json)));
|
||||
|
||||
List<string> jsonNetResult = JsonConvert.DeserializeObject<List<string>>(json);
|
||||
|
||||
Assert.AreEqual(1, jsonNetResult.Count);
|
||||
Assert.AreEqual(dataContractResult[0], jsonNetResult[0]);
|
||||
#if !SILVERLIGHT
|
||||
Assert.AreEqual(javaScriptSerializerResult[0], jsonNetResult[0]);
|
||||
#endif
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException(typeof(JsonReaderException), ExpectedMessage = @"Bad JSON escape sequence: \j. Line 1, position 7.")]
|
||||
public void InvalidBackslash()
|
||||
{
|
||||
string json = @"[""vvv\jvvv""]";
|
||||
|
||||
JsonConvert.DeserializeObject<List<string>>(json);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DateTimeTest()
|
||||
{
|
||||
@@ -1068,9 +1109,6 @@ keyword such as type of business.""
|
||||
]
|
||||
}";
|
||||
|
||||
//JavaScriptSerializer serializer = new JavaScriptSerializer();
|
||||
//GoogleMapGeocoderStructure jsonGoogleMapGeocoder = serializer.Deserialize<GoogleMapGeocoderStructure>(json);
|
||||
|
||||
GoogleMapGeocoderStructure jsonGoogleMapGeocoder = JsonConvert.DeserializeObject<GoogleMapGeocoderStructure>(json);
|
||||
}
|
||||
|
||||
@@ -2051,5 +2089,39 @@ keyword such as type of business.""
|
||||
PersonPropertyClass newPersonPropertyClass = JsonConvert.DeserializeObject<PersonPropertyClass>(json);
|
||||
Assert.AreEqual(wagePerson.HourlyWage, ((WagePerson) newPersonPropertyClass.Person).HourlyWage);
|
||||
}
|
||||
|
||||
public class ExistingValueClass
|
||||
{
|
||||
public Dictionary<string, string> Dictionary { get; set; }
|
||||
public List<string> List { get; set; }
|
||||
|
||||
public ExistingValueClass()
|
||||
{
|
||||
Dictionary = new Dictionary<string, string>
|
||||
{
|
||||
{"existing", "yup"}
|
||||
};
|
||||
List = new List<string>
|
||||
{
|
||||
"existing"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DeserializePopulateDictionaryAndList()
|
||||
{
|
||||
ExistingValueClass d = JsonConvert.DeserializeObject<ExistingValueClass>(@"{'Dictionary':{appended:'appended',existing:'new'}}");
|
||||
|
||||
Assert.IsNotNull(d);
|
||||
Assert.IsNotNull(d.Dictionary);
|
||||
Assert.AreEqual(typeof(Dictionary<string, string>), d.Dictionary.GetType());
|
||||
Assert.AreEqual(typeof(List<string>), d.List.GetType());
|
||||
Assert.AreEqual(2, d.Dictionary.Count);
|
||||
Assert.AreEqual("new", d.Dictionary["existing"]);
|
||||
Assert.AreEqual("appended", d.Dictionary["appended"]);
|
||||
Assert.AreEqual(1, d.List.Count);
|
||||
Assert.AreEqual("existing", d.List[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,6 +46,8 @@ namespace Newtonsoft.Json.Bson
|
||||
private char[] _charBuffer;
|
||||
private BsonType _currentElementType;
|
||||
private BsonReaderState _bsonReaderState;
|
||||
private ContainerContext _currentContext;
|
||||
|
||||
private const int MaxCharBytesSize = 128;
|
||||
|
||||
private enum BsonReaderState
|
||||
@@ -63,20 +65,9 @@ namespace Newtonsoft.Json.Bson
|
||||
|
||||
private class ContainerContext
|
||||
{
|
||||
public JTokenType Type { get; private set; }
|
||||
public int Length { get; set; }
|
||||
private int _position;
|
||||
public int Position
|
||||
{
|
||||
get { return _position; }
|
||||
set
|
||||
{
|
||||
if (value > Length && Length != 0)
|
||||
throw new JsonReaderException("Read past end of current container context.");
|
||||
|
||||
_position = value;
|
||||
}
|
||||
}
|
||||
public readonly JTokenType Type;
|
||||
public int Length;
|
||||
public int Position;
|
||||
|
||||
public ContainerContext(JTokenType type)
|
||||
{
|
||||
@@ -188,7 +179,7 @@ namespace Newtonsoft.Json.Bson
|
||||
_bsonReaderState = BsonReaderState.CodeWScopeScopeObject;
|
||||
|
||||
ContainerContext newContext = new ContainerContext(JTokenType.Object);
|
||||
_stack.Add(newContext);
|
||||
PushContext(newContext);
|
||||
newContext.Length = ReadInt32();
|
||||
|
||||
return true;
|
||||
@@ -270,7 +261,7 @@ namespace Newtonsoft.Json.Bson
|
||||
|
||||
SetToken(token);
|
||||
ContainerContext newContext = new ContainerContext(type);
|
||||
_stack.Add(newContext);
|
||||
PushContext(newContext);
|
||||
newContext.Length = ReadInt32();
|
||||
return true;
|
||||
}
|
||||
@@ -292,7 +283,7 @@ namespace Newtonsoft.Json.Bson
|
||||
ReadType(_currentElementType);
|
||||
return true;
|
||||
case State.PostValue:
|
||||
ContainerContext context = GetCurrentContext();
|
||||
ContainerContext context = _currentContext;
|
||||
if (context == null)
|
||||
return false;
|
||||
|
||||
@@ -317,8 +308,8 @@ namespace Newtonsoft.Json.Bson
|
||||
if (ReadByte() != 0)
|
||||
throw new JsonReaderException("Unexpected end of object byte value.");
|
||||
|
||||
_stack.RemoveAt(_stack.Count - 1);
|
||||
if (_stack.Count != 0)
|
||||
PopContext();
|
||||
if (_currentContext != null)
|
||||
MovePosition(context.Length);
|
||||
|
||||
JsonToken endToken = (context.Type == JTokenType.Object) ? JsonToken.EndObject : JsonToken.EndArray;
|
||||
@@ -344,6 +335,21 @@ namespace Newtonsoft.Json.Bson
|
||||
return false;
|
||||
}
|
||||
|
||||
private void PopContext()
|
||||
{
|
||||
_stack.RemoveAt(_stack.Count - 1);
|
||||
if (_stack.Count == 0)
|
||||
_currentContext = null;
|
||||
else
|
||||
_currentContext = _stack[_stack.Count - 1];
|
||||
}
|
||||
|
||||
private void PushContext(ContainerContext newContext)
|
||||
{
|
||||
_stack.Add(newContext);
|
||||
_currentContext = newContext;
|
||||
}
|
||||
|
||||
private byte ReadByte()
|
||||
{
|
||||
MovePosition(1);
|
||||
@@ -366,7 +372,7 @@ namespace Newtonsoft.Json.Bson
|
||||
SetToken(JsonToken.StartObject);
|
||||
|
||||
ContainerContext newContext = new ContainerContext(JTokenType.Object);
|
||||
_stack.Add(newContext);
|
||||
PushContext(newContext);
|
||||
newContext.Length = ReadInt32();
|
||||
break;
|
||||
}
|
||||
@@ -375,7 +381,7 @@ namespace Newtonsoft.Json.Bson
|
||||
SetToken(JsonToken.StartArray);
|
||||
|
||||
ContainerContext newContext = new ContainerContext(JTokenType.Array);
|
||||
_stack.Add(newContext);
|
||||
PushContext(newContext);
|
||||
newContext.Length = ReadInt32();
|
||||
break;
|
||||
}
|
||||
@@ -561,19 +567,9 @@ namespace Newtonsoft.Json.Bson
|
||||
return (BsonType)_reader.ReadSByte();
|
||||
}
|
||||
|
||||
private ContainerContext GetCurrentContext()
|
||||
{
|
||||
int count = _stack.Count;
|
||||
if (count == 0)
|
||||
return null;
|
||||
|
||||
return _stack[count - 1];
|
||||
}
|
||||
|
||||
private void MovePosition(int count)
|
||||
{
|
||||
ContainerContext context = GetCurrentContext();
|
||||
context.Position += count;
|
||||
_currentContext.Position += count;
|
||||
}
|
||||
|
||||
private byte[] ReadBytes(int count)
|
||||
|
||||
@@ -29,6 +29,7 @@ using System.Globalization;
|
||||
using Newtonsoft.Json.Utilities;
|
||||
using System.Xml;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using System.Text;
|
||||
|
||||
namespace Newtonsoft.Json
|
||||
{
|
||||
@@ -96,14 +97,11 @@ namespace Newtonsoft.Json
|
||||
/// <returns>A JSON string representation of the <see cref="DateTime"/>.</returns>
|
||||
public static string ToString(DateTime value)
|
||||
{
|
||||
TimeSpan utcOffset;
|
||||
#if !PocketPC && !NET20
|
||||
utcOffset = TimeZoneInfo.Local.GetUtcOffset(value);
|
||||
#else
|
||||
utcOffset = TimeZone.CurrentTimeZone.GetUtcOffset(value);
|
||||
#endif
|
||||
|
||||
return ToStringInternal(value, utcOffset, value.Kind);
|
||||
using (StringWriter writer = StringUtils.CreateStringWriter(64))
|
||||
{
|
||||
WriteDateTimeString(writer, value, GetUtcOffset(value), value.Kind);
|
||||
return writer.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
#if !PocketPC && !NET20
|
||||
@@ -114,33 +112,95 @@ namespace Newtonsoft.Json
|
||||
/// <returns>A JSON string representation of the <see cref="DateTimeOffset"/>.</returns>
|
||||
public static string ToString(DateTimeOffset value)
|
||||
{
|
||||
return ToStringInternal(value.UtcDateTime, value.Offset, DateTimeKind.Local);
|
||||
using (StringWriter writer = StringUtils.CreateStringWriter(64))
|
||||
{
|
||||
WriteDateTimeString(writer, value.UtcDateTime, value.Offset, DateTimeKind.Local);
|
||||
return writer.ToString();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
internal static string ToStringInternal(DateTime value, TimeSpan offset, DateTimeKind kind)
|
||||
private static TimeSpan GetUtcOffset(DateTime dateTime)
|
||||
{
|
||||
long javaScriptTicks = ConvertDateTimeToJavaScriptTicks(value);
|
||||
#if SILVERLIGHT
|
||||
return TimeZoneInfo.Local.GetUtcOffset(dateTime);
|
||||
#else
|
||||
return TimeZone.CurrentTimeZone.GetUtcOffset(dateTime);
|
||||
#endif
|
||||
}
|
||||
|
||||
string timezoneOffset;
|
||||
internal static void WriteDateTimeString(TextWriter writer, DateTime value)
|
||||
{
|
||||
WriteDateTimeString(writer, value, GetUtcOffset(value), value.Kind);
|
||||
}
|
||||
|
||||
internal static void WriteDateTimeString(TextWriter writer, DateTime value, TimeSpan offset, DateTimeKind kind)
|
||||
{
|
||||
long javaScriptTicks = ConvertDateTimeToJavaScriptTicks(value, offset);
|
||||
|
||||
writer.Write(@"""\/Date(");
|
||||
writer.Write(javaScriptTicks);
|
||||
|
||||
switch (kind)
|
||||
{
|
||||
case DateTimeKind.Local:
|
||||
case DateTimeKind.Unspecified:
|
||||
timezoneOffset = offset.Hours.ToString("+00;-00", CultureInfo.InvariantCulture) + offset.Minutes.ToString("00;00", CultureInfo.InvariantCulture);
|
||||
break;
|
||||
default:
|
||||
timezoneOffset = string.Empty;
|
||||
writer.Write((offset.Ticks >= 0L) ? "+" : "-");
|
||||
|
||||
int absHours = Math.Abs(offset.Hours);
|
||||
if (absHours < 10)
|
||||
writer.Write(0);
|
||||
writer.Write(absHours);
|
||||
int absMinutes = Math.Abs(offset.Minutes);
|
||||
if (absMinutes < 10)
|
||||
writer.Write(0);
|
||||
writer.Write(absMinutes);
|
||||
break;
|
||||
}
|
||||
return @"""\/Date(" + javaScriptTicks.ToString(CultureInfo.InvariantCulture) + timezoneOffset + @")\/""";
|
||||
|
||||
writer.Write(@")\/""");
|
||||
}
|
||||
|
||||
private static long ToUniversalTicks(DateTime dateTime)
|
||||
{
|
||||
if (dateTime.Kind == DateTimeKind.Utc)
|
||||
return dateTime.Ticks;
|
||||
|
||||
return ToUniversalTicks(dateTime, GetUtcOffset(dateTime));
|
||||
}
|
||||
|
||||
private static long ToUniversalTicks(DateTime dateTime, TimeSpan offset)
|
||||
{
|
||||
if (dateTime.Kind == DateTimeKind.Utc)
|
||||
return dateTime.Ticks;
|
||||
|
||||
long ticks = dateTime.Ticks - offset.Ticks;
|
||||
if (ticks > 3155378975999999999L)
|
||||
return 3155378975999999999L;
|
||||
|
||||
if (ticks < 0L)
|
||||
return 0L;
|
||||
|
||||
return ticks;
|
||||
}
|
||||
|
||||
internal static long ConvertDateTimeToJavaScriptTicks(DateTime dateTime, TimeSpan offset)
|
||||
{
|
||||
long universialTicks = ToUniversalTicks(dateTime, offset);
|
||||
|
||||
return UniversialTicksToJavaScriptTicks(universialTicks);
|
||||
}
|
||||
|
||||
internal static long ConvertDateTimeToJavaScriptTicks(DateTime dateTime)
|
||||
{
|
||||
DateTime utcDateTime = dateTime.ToUniversalTime();
|
||||
long universialTicks = ToUniversalTicks(dateTime);
|
||||
|
||||
long javaScriptTicks = (utcDateTime.Ticks - InitialJavaScriptDateTicks) / 10000;
|
||||
return UniversialTicksToJavaScriptTicks(universialTicks);
|
||||
}
|
||||
|
||||
private static long UniversialTicksToJavaScriptTicks(long universialTicks)
|
||||
{
|
||||
long javaScriptTicks = (universialTicks - InitialJavaScriptDateTicks) / 10000;
|
||||
|
||||
return javaScriptTicks;
|
||||
}
|
||||
@@ -524,7 +584,8 @@ namespace Newtonsoft.Json
|
||||
{
|
||||
JsonSerializer jsonSerializer = JsonSerializer.Create(settings);
|
||||
|
||||
StringWriter sw = new StringWriter(CultureInfo.InvariantCulture);
|
||||
StringBuilder sb = new StringBuilder(128);
|
||||
StringWriter sw = new StringWriter(sb, CultureInfo.InvariantCulture);
|
||||
using (JsonTextWriter jsonWriter = new JsonTextWriter(sw))
|
||||
{
|
||||
jsonWriter.Formatting = formatting;
|
||||
|
||||
@@ -102,6 +102,7 @@ namespace Newtonsoft.Json
|
||||
private Type _valueType;
|
||||
private char _quoteChar;
|
||||
private State _currentState;
|
||||
private JTokenType _currentTypeContext;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current reader state.
|
||||
@@ -182,6 +183,7 @@ namespace Newtonsoft.Json
|
||||
{
|
||||
_stack.Add(value);
|
||||
_top++;
|
||||
_currentTypeContext = value;
|
||||
}
|
||||
|
||||
private JTokenType Pop()
|
||||
@@ -189,13 +191,14 @@ namespace Newtonsoft.Json
|
||||
JTokenType value = Peek();
|
||||
_stack.RemoveAt(_stack.Count - 1);
|
||||
_top--;
|
||||
_currentTypeContext = _stack[_top - 1];
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private JTokenType Peek()
|
||||
{
|
||||
return _stack[_top - 1];
|
||||
return _currentTypeContext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -418,16 +418,6 @@ namespace Newtonsoft.Json
|
||||
serializerWriter.Serialize(jsonWriter, value);
|
||||
}
|
||||
|
||||
internal bool HasClassConverter(JsonContract contract, out JsonConverter converter)
|
||||
{
|
||||
if (contract == null)
|
||||
throw new ArgumentNullException("contract");
|
||||
|
||||
converter = contract.Converter;
|
||||
|
||||
return (converter != null);
|
||||
}
|
||||
|
||||
internal bool HasMatchingConverter(Type type, out JsonConverter matchingConverter)
|
||||
{
|
||||
if (HasMatchingConverter(_converters, type, out matchingConverter))
|
||||
|
||||
@@ -40,10 +40,10 @@ namespace Newtonsoft.Json
|
||||
{
|
||||
private readonly TextReader _reader;
|
||||
private readonly StringBuffer _buffer;
|
||||
private char _currentChar;
|
||||
private char? _lastChar;
|
||||
private int _currentLinePosition;
|
||||
private int _currentLineNumber;
|
||||
private bool _currentCharCarriageReturn;
|
||||
private bool _end;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="JsonReader"/> class with the specified <see cref="TextReader"/>.
|
||||
@@ -61,7 +61,7 @@ namespace Newtonsoft.Json
|
||||
|
||||
private void ParseString(char quote)
|
||||
{
|
||||
ReadStringIntoBuffer(quote, null);
|
||||
ReadStringIntoBuffer(quote);
|
||||
|
||||
string text = _buffer.ToString();
|
||||
_buffer.Position = 0;
|
||||
@@ -77,23 +77,24 @@ namespace Newtonsoft.Json
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadStringIntoBuffer(char quote, int? untilPosition)
|
||||
private void ReadStringIntoBuffer(char quote)
|
||||
{
|
||||
bool stringTerminated = false;
|
||||
bool hexNumber = false;
|
||||
int hexCount = 0;
|
||||
|
||||
while (!stringTerminated && (untilPosition == null || _buffer.Position < untilPosition) && MoveNext())
|
||||
while (true)
|
||||
{
|
||||
if (hexNumber)
|
||||
hexCount++;
|
||||
char currentChar = MoveNext();
|
||||
|
||||
switch (_currentChar)
|
||||
switch (currentChar)
|
||||
{
|
||||
case '\0':
|
||||
if (_end)
|
||||
throw CreateJsonReaderException("Unterminated string. Expected delimiter: {0}. Line {1}, position {2}.", quote, _currentLineNumber, _currentLinePosition);
|
||||
|
||||
_buffer.Append('\0');
|
||||
break;
|
||||
case '\\':
|
||||
if (MoveNext())
|
||||
if ((currentChar = MoveNext()) != '\0' || !_end)
|
||||
{
|
||||
switch (_currentChar)
|
||||
switch (currentChar)
|
||||
{
|
||||
case 'b':
|
||||
_buffer.Append('\b');
|
||||
@@ -110,13 +111,29 @@ namespace Newtonsoft.Json
|
||||
case 'r':
|
||||
_buffer.Append('\r');
|
||||
break;
|
||||
case '\\':
|
||||
_buffer.Append('\\');
|
||||
break;
|
||||
case '"':
|
||||
case '\'':
|
||||
case '/':
|
||||
_buffer.Append(currentChar);
|
||||
break;
|
||||
case 'u':
|
||||
// note the start of a hex character
|
||||
hexNumber = true;
|
||||
char[] hexValues = new char[4];
|
||||
for (int i = 0; i < hexValues.Length; i++)
|
||||
{
|
||||
if ((currentChar = MoveNext()) != '\0' || !_end)
|
||||
hexValues[i] = currentChar;
|
||||
else
|
||||
throw CreateJsonReaderException("Unexpected end while parsing unicode character. Line {0}, position {1}.", _currentLineNumber, _currentLinePosition);
|
||||
}
|
||||
|
||||
char hexChar = Convert.ToChar(int.Parse(new string(hexValues), NumberStyles.HexNumber, NumberFormatInfo.InvariantInfo));
|
||||
_buffer.Append(hexChar);
|
||||
break;
|
||||
default:
|
||||
_buffer.Append(_currentChar);
|
||||
break;
|
||||
throw CreateJsonReaderException("Bad JSON escape sequence: {0}. Line {1}, position {2}.", @"\" + currentChar, _currentLineNumber, _currentLinePosition);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -126,34 +143,20 @@ namespace Newtonsoft.Json
|
||||
break;
|
||||
case '"':
|
||||
case '\'':
|
||||
if (_currentChar == quote)
|
||||
stringTerminated = true;
|
||||
if (currentChar == quote)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
goto default;
|
||||
{
|
||||
_buffer.Append(currentChar);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
_buffer.Append(_currentChar);
|
||||
_buffer.Append(currentChar);
|
||||
break;
|
||||
}
|
||||
|
||||
if (hexCount == 4)
|
||||
{
|
||||
// remove hex characters from buffer, convert to char and then add
|
||||
string hexString = _buffer.ToString(_buffer.Position - 4, 4);
|
||||
char hexChar = Convert.ToChar(int.Parse(hexString, NumberStyles.HexNumber, NumberFormatInfo.InvariantInfo));
|
||||
|
||||
_buffer.Position = _buffer.Position - 4;
|
||||
_buffer.Append(hexChar);
|
||||
|
||||
hexNumber = false;
|
||||
hexCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!stringTerminated)
|
||||
throw CreateJsonReaderException("Unterminated string. Expected delimiter: {0}. Line {1}, position {2}.", quote, _currentLineNumber, _currentLinePosition);
|
||||
|
||||
ClearCurrentChar();
|
||||
}
|
||||
|
||||
private JsonReaderException CreateJsonReaderException(string format, params object[] args)
|
||||
@@ -162,41 +165,6 @@ namespace Newtonsoft.Json
|
||||
return new JsonReaderException(message, null, _currentLineNumber, _currentLinePosition);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the current token and value.
|
||||
/// </summary>
|
||||
/// <param name="newToken">The new token.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
protected override void SetToken(JsonToken newToken, object value)
|
||||
{
|
||||
base.SetToken(newToken, value);
|
||||
|
||||
switch (newToken)
|
||||
{
|
||||
case JsonToken.StartObject:
|
||||
ClearCurrentChar();
|
||||
break;
|
||||
case JsonToken.StartArray:
|
||||
ClearCurrentChar();
|
||||
break;
|
||||
case JsonToken.StartConstructor:
|
||||
ClearCurrentChar();
|
||||
break;
|
||||
case JsonToken.EndObject:
|
||||
ClearCurrentChar();
|
||||
break;
|
||||
case JsonToken.EndArray:
|
||||
ClearCurrentChar();
|
||||
break;
|
||||
case JsonToken.EndConstructor:
|
||||
ClearCurrentChar();
|
||||
break;
|
||||
case JsonToken.PropertyName:
|
||||
ClearCurrentChar();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void ParseDate(string text)
|
||||
{
|
||||
string value = text.Substring(6, text.Length - 8);
|
||||
@@ -236,34 +204,32 @@ namespace Newtonsoft.Json
|
||||
private const int LineFeedValue = StringUtils.LineFeed;
|
||||
private const int CarriageReturnValue = StringUtils.CarriageReturn;
|
||||
|
||||
private bool MoveNext()
|
||||
private char MoveNext()
|
||||
{
|
||||
int value = _reader.Read();
|
||||
|
||||
switch (value)
|
||||
{
|
||||
case -1:
|
||||
return false;
|
||||
_end = true;
|
||||
return '\0';
|
||||
case CarriageReturnValue:
|
||||
if (_reader.Peek() == LineFeedValue)
|
||||
_reader.Read();
|
||||
|
||||
_currentLineNumber++;
|
||||
_currentLinePosition = 0;
|
||||
_currentCharCarriageReturn = true;
|
||||
break;
|
||||
case LineFeedValue:
|
||||
if (!_currentCharCarriageReturn)
|
||||
_currentLineNumber++;
|
||||
|
||||
_currentLineNumber++;
|
||||
_currentLinePosition = 0;
|
||||
_currentCharCarriageReturn = false;
|
||||
break;
|
||||
default:
|
||||
_currentLinePosition++;
|
||||
_currentCharCarriageReturn = false;
|
||||
break;
|
||||
}
|
||||
|
||||
_currentChar = (char)value;
|
||||
return true;
|
||||
return (char)value;
|
||||
}
|
||||
|
||||
private bool HasNext()
|
||||
@@ -271,14 +237,9 @@ namespace Newtonsoft.Json
|
||||
return (_reader.Peek() != -1);
|
||||
}
|
||||
|
||||
private char PeekNext()
|
||||
private int PeekNext()
|
||||
{
|
||||
return (char)_reader.Peek();
|
||||
}
|
||||
|
||||
private void ClearCurrentChar()
|
||||
{
|
||||
_currentChar = '\0';
|
||||
return _reader.Peek();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -291,11 +252,19 @@ namespace Newtonsoft.Json
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (_currentChar == '\0')
|
||||
char currentChar;
|
||||
if (_lastChar != null)
|
||||
{
|
||||
if (!MoveNext())
|
||||
return false;
|
||||
currentChar = _lastChar.Value;
|
||||
_lastChar = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentChar = MoveNext();
|
||||
}
|
||||
|
||||
if (currentChar == '\0' && _end)
|
||||
return false;
|
||||
|
||||
switch (CurrentState)
|
||||
{
|
||||
@@ -305,16 +274,16 @@ namespace Newtonsoft.Json
|
||||
case State.ArrayStart:
|
||||
case State.Constructor:
|
||||
case State.ConstructorStart:
|
||||
return ParseValue();
|
||||
return ParseValue(currentChar);
|
||||
case State.Complete:
|
||||
break;
|
||||
case State.Object:
|
||||
case State.ObjectStart:
|
||||
return ParseObject();
|
||||
return ParseObject(currentChar);
|
||||
case State.PostValue:
|
||||
// returns true if it hits
|
||||
// end of object or array
|
||||
if (ParsePostValue())
|
||||
if (ParsePostValue(currentChar))
|
||||
return true;
|
||||
break;
|
||||
case State.Closed:
|
||||
@@ -337,14 +306,23 @@ namespace Newtonsoft.Json
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (_currentChar == '\0')
|
||||
char currentChar;
|
||||
if (_lastChar != null)
|
||||
{
|
||||
if (!MoveNext())
|
||||
throw CreateJsonReaderException("Unexpected end: Line {0}, position {1}.", _currentLineNumber, _currentLinePosition);
|
||||
currentChar = _lastChar.Value;
|
||||
_lastChar = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentChar = MoveNext();
|
||||
}
|
||||
|
||||
if (currentChar == '\0' && _end)
|
||||
throw CreateJsonReaderException("Unexpected end when reading bytes: Line {0}, position {1}.", _currentLineNumber, _currentLinePosition);
|
||||
|
||||
switch (CurrentState)
|
||||
{
|
||||
case State.PostValue:
|
||||
case State.Start:
|
||||
case State.Property:
|
||||
case State.Array:
|
||||
@@ -353,11 +331,11 @@ namespace Newtonsoft.Json
|
||||
case State.ConstructorStart:
|
||||
do
|
||||
{
|
||||
switch (_currentChar)
|
||||
switch (currentChar)
|
||||
{
|
||||
case '"':
|
||||
case '\'':
|
||||
ReadStringIntoBuffer(_currentChar, null);
|
||||
ReadStringIntoBuffer(currentChar);
|
||||
|
||||
byte[] data = Convert.FromBase64CharArray(_buffer.GetInternalBuffer(), 0, _buffer.Position);
|
||||
_buffer.Position = 0;
|
||||
@@ -368,19 +346,27 @@ namespace Newtonsoft.Json
|
||||
case 'n':
|
||||
ParseNull();
|
||||
return null;
|
||||
case ' ':
|
||||
case StringUtils.Tab:
|
||||
case StringUtils.LineFeed:
|
||||
case StringUtils.CarriageReturn:
|
||||
// eat
|
||||
break;
|
||||
case ',':
|
||||
SetStateBasedOnCurrent();
|
||||
break;
|
||||
default:
|
||||
if (char.IsWhiteSpace(_currentChar))
|
||||
if (char.IsWhiteSpace(currentChar))
|
||||
{
|
||||
// eat
|
||||
}
|
||||
else
|
||||
{
|
||||
throw CreateJsonReaderException("Unexpected character encountered while parsing value: {0}. Line {1}, position {2}.", _currentChar, _currentLineNumber, _currentLinePosition);
|
||||
throw CreateJsonReaderException("Unexpected character encountered while parsing value: {0}. Line {1}, position {2}.", currentChar, _currentLineNumber, _currentLinePosition);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} while (MoveNext());
|
||||
ParseValue();
|
||||
} while ((currentChar = MoveNext()) != '\0' || !_end);
|
||||
break;
|
||||
default:
|
||||
throw CreateJsonReaderException("Unexpected state: {0}. Line {1}, position {2}.", CurrentState, _currentLineNumber, _currentLinePosition);
|
||||
@@ -388,115 +374,114 @@ namespace Newtonsoft.Json
|
||||
}
|
||||
}
|
||||
|
||||
private bool ParsePostValue()
|
||||
private bool ParsePostValue(char currentChar)
|
||||
{
|
||||
do
|
||||
{
|
||||
switch (_currentChar)
|
||||
switch (currentChar)
|
||||
{
|
||||
case '}':
|
||||
SetToken(JsonToken.EndObject);
|
||||
ClearCurrentChar();
|
||||
return true;
|
||||
case ']':
|
||||
SetToken(JsonToken.EndArray);
|
||||
ClearCurrentChar();
|
||||
return true;
|
||||
case ')':
|
||||
SetToken(JsonToken.EndConstructor);
|
||||
ClearCurrentChar();
|
||||
return true;
|
||||
case '/':
|
||||
ParseComment();
|
||||
return true;
|
||||
case ',':
|
||||
// finished paring
|
||||
// finished parsing
|
||||
SetStateBasedOnCurrent();
|
||||
ClearCurrentChar();
|
||||
return false;
|
||||
case ' ':
|
||||
// eat whitespace
|
||||
ClearCurrentChar();
|
||||
break;
|
||||
default:
|
||||
if (char.IsWhiteSpace(_currentChar))
|
||||
{
|
||||
// eat whitespace
|
||||
ClearCurrentChar();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw CreateJsonReaderException("After parsing a value an unexpected character was encoutered: {0}. Line {1}, position {2}.", _currentChar, _currentLineNumber, _currentLinePosition);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} while (MoveNext());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool ParseObject()
|
||||
{
|
||||
do
|
||||
{
|
||||
switch (_currentChar)
|
||||
{
|
||||
case '}':
|
||||
SetToken(JsonToken.EndObject);
|
||||
return true;
|
||||
case '/':
|
||||
ParseComment();
|
||||
return true;
|
||||
case ',':
|
||||
SetToken(JsonToken.Undefined);
|
||||
return true;
|
||||
case ' ':
|
||||
case StringUtils.Tab:
|
||||
case StringUtils.LineFeed:
|
||||
case StringUtils.CarriageReturn:
|
||||
// eat
|
||||
break;
|
||||
default:
|
||||
if (char.IsWhiteSpace(_currentChar))
|
||||
if (char.IsWhiteSpace(currentChar))
|
||||
{
|
||||
// eat
|
||||
}
|
||||
else
|
||||
{
|
||||
return ParseProperty();
|
||||
throw CreateJsonReaderException("After parsing a value an unexpected character was encoutered: {0}. Line {1}, position {2}.", currentChar, _currentLineNumber, _currentLinePosition);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} while (MoveNext());
|
||||
} while ((currentChar = MoveNext()) != '\0' || !_end);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool ParseProperty()
|
||||
private bool ParseObject(char currentChar)
|
||||
{
|
||||
do
|
||||
{
|
||||
switch (currentChar)
|
||||
{
|
||||
case '}':
|
||||
SetToken(JsonToken.EndObject);
|
||||
return true;
|
||||
case '/':
|
||||
ParseComment();
|
||||
return true;
|
||||
case ' ':
|
||||
case StringUtils.Tab:
|
||||
case StringUtils.LineFeed:
|
||||
case StringUtils.CarriageReturn:
|
||||
// eat
|
||||
break;
|
||||
default:
|
||||
if (char.IsWhiteSpace(currentChar))
|
||||
{
|
||||
// eat
|
||||
}
|
||||
else
|
||||
{
|
||||
return ParseProperty(currentChar);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} while ((currentChar = MoveNext()) != '\0' || !_end);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool ParseProperty(char firstChar)
|
||||
{
|
||||
char currentChar = firstChar;
|
||||
char quoteChar;
|
||||
|
||||
if (ValidIdentifierChar(_currentChar))
|
||||
if (ValidIdentifierChar(currentChar))
|
||||
{
|
||||
quoteChar = '\0';
|
||||
ParseUnquotedProperty();
|
||||
currentChar = ParseUnquotedProperty(currentChar);
|
||||
}
|
||||
else if (_currentChar == '"' || _currentChar == '\'')
|
||||
else if (currentChar == '"' || currentChar == '\'')
|
||||
{
|
||||
quoteChar = _currentChar;
|
||||
ParseQuotedProperty(_currentChar);
|
||||
quoteChar = currentChar;
|
||||
ReadStringIntoBuffer(quoteChar);
|
||||
currentChar = MoveNext();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw CreateJsonReaderException("Invalid property identifier character: {0}. Line {1}, position {2}.", _currentChar, _currentLineNumber, _currentLinePosition);
|
||||
throw CreateJsonReaderException("Invalid property identifier character: {0}. Line {1}, position {2}.", currentChar, _currentLineNumber, _currentLinePosition);
|
||||
}
|
||||
|
||||
if (_currentChar != ':')
|
||||
if (currentChar != ':')
|
||||
{
|
||||
MoveNext();
|
||||
currentChar = MoveNext();
|
||||
|
||||
// finished property. skip any whitespace and move to colon
|
||||
EatWhitespace(false);
|
||||
EatWhitespace(currentChar, false, out currentChar);
|
||||
|
||||
if (_currentChar != ':')
|
||||
throw CreateJsonReaderException("Invalid character after parsing property name. Expected ':' but got: {0}. Line {1}, position {2}.", _currentChar, _currentLineNumber, _currentLinePosition);
|
||||
if (currentChar != ':')
|
||||
throw CreateJsonReaderException("Invalid character after parsing property name. Expected ':' but got: {0}. Line {1}, position {2}.", currentChar, _currentLineNumber, _currentLinePosition);
|
||||
}
|
||||
|
||||
SetToken(JsonToken.PropertyName, _buffer.ToString());
|
||||
@@ -506,60 +491,46 @@ namespace Newtonsoft.Json
|
||||
return true;
|
||||
}
|
||||
|
||||
private void ParseQuotedProperty(char quoteChar)
|
||||
{
|
||||
// parse property name until quoted char is hit
|
||||
while (MoveNext())
|
||||
{
|
||||
if (_currentChar == quoteChar)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
_buffer.Append(_currentChar);
|
||||
}
|
||||
}
|
||||
|
||||
throw CreateJsonReaderException("Unclosed quoted property. Expected: {0}. Line {1}, position {2}.", quoteChar, _currentLineNumber, _currentLinePosition);
|
||||
}
|
||||
|
||||
private bool ValidIdentifierChar(char value)
|
||||
{
|
||||
return (char.IsLetterOrDigit(_currentChar) || _currentChar == '_' || _currentChar == '$');
|
||||
return (char.IsLetterOrDigit(value) || value == '_' || value == '$');
|
||||
}
|
||||
|
||||
private void ParseUnquotedProperty()
|
||||
private char ParseUnquotedProperty(char firstChar)
|
||||
{
|
||||
// parse unquoted property name until whitespace or colon
|
||||
_buffer.Append(_currentChar);
|
||||
_buffer.Append(firstChar);
|
||||
|
||||
while (MoveNext())
|
||||
char currentChar;
|
||||
|
||||
while ((currentChar = MoveNext()) != '\0' || !_end)
|
||||
{
|
||||
if (char.IsWhiteSpace(_currentChar) || _currentChar == ':')
|
||||
if (char.IsWhiteSpace(currentChar) || currentChar == ':')
|
||||
{
|
||||
break;
|
||||
return currentChar;
|
||||
}
|
||||
else if (ValidIdentifierChar(_currentChar))
|
||||
else if (ValidIdentifierChar(currentChar))
|
||||
{
|
||||
_buffer.Append(_currentChar);
|
||||
_buffer.Append(currentChar);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw CreateJsonReaderException("Invalid JavaScript property identifier character: {0}. Line {1}, position {2}.", _currentChar, _currentLineNumber, _currentLinePosition);
|
||||
throw CreateJsonReaderException("Invalid JavaScript property identifier character: {0}. Line {1}, position {2}.", currentChar, _currentLineNumber, _currentLinePosition);
|
||||
}
|
||||
}
|
||||
|
||||
throw CreateJsonReaderException("Unexpected end when parsing unquoted property name. Line {0}, position {1}.", _currentLineNumber, _currentLinePosition);
|
||||
}
|
||||
|
||||
private bool ParseValue()
|
||||
private bool ParseValue(char currentChar)
|
||||
{
|
||||
do
|
||||
{
|
||||
switch (_currentChar)
|
||||
switch (currentChar)
|
||||
{
|
||||
case '"':
|
||||
case '\'':
|
||||
ParseString(_currentChar);
|
||||
ParseString(currentChar);
|
||||
return true;
|
||||
case 't':
|
||||
ParseTrue();
|
||||
@@ -570,14 +541,14 @@ namespace Newtonsoft.Json
|
||||
case 'n':
|
||||
if (HasNext())
|
||||
{
|
||||
char next = PeekNext();
|
||||
char next = (char)PeekNext();
|
||||
|
||||
if (next == 'u')
|
||||
ParseNull();
|
||||
else if (next == 'e')
|
||||
ParseConstructor();
|
||||
else
|
||||
throw CreateJsonReaderException("Unexpected character encountered while parsing value: {0}. Line {1}, position {2}.", _currentChar, _currentLineNumber, _currentLinePosition);
|
||||
throw CreateJsonReaderException("Unexpected character encountered while parsing value: {0}. Line {1}, position {2}.", currentChar, _currentLineNumber, _currentLinePosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -594,7 +565,7 @@ namespace Newtonsoft.Json
|
||||
if (PeekNext() == 'I')
|
||||
ParseNumberNegativeInfinity();
|
||||
else
|
||||
ParseNumber();
|
||||
ParseNumber(currentChar);
|
||||
return true;
|
||||
case '/':
|
||||
ParseComment();
|
||||
@@ -616,63 +587,70 @@ namespace Newtonsoft.Json
|
||||
return true;
|
||||
case ',':
|
||||
SetToken(JsonToken.Undefined);
|
||||
//ClearCurrentChar();
|
||||
return true;
|
||||
case ')':
|
||||
SetToken(JsonToken.EndConstructor);
|
||||
return true;
|
||||
case ' ':
|
||||
case StringUtils.Tab:
|
||||
case StringUtils.LineFeed:
|
||||
case StringUtils.CarriageReturn:
|
||||
// eat
|
||||
break;
|
||||
default:
|
||||
if (char.IsWhiteSpace(_currentChar))
|
||||
if (char.IsWhiteSpace(currentChar))
|
||||
{
|
||||
// eat
|
||||
}
|
||||
else if (char.IsNumber(_currentChar) || _currentChar == '-' || _currentChar == '.')
|
||||
else if (char.IsNumber(currentChar) || currentChar == '-' || currentChar == '.')
|
||||
{
|
||||
ParseNumber();
|
||||
ParseNumber(currentChar);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw CreateJsonReaderException("Unexpected character encountered while parsing value: {0}. Line {1}, position {2}.", _currentChar, _currentLineNumber, _currentLinePosition);
|
||||
throw CreateJsonReaderException("Unexpected character encountered while parsing value: {0}. Line {1}, position {2}.", currentChar, _currentLineNumber, _currentLinePosition);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} while (MoveNext());
|
||||
} while ((currentChar = MoveNext()) != '\0' || !_end);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool EatWhitespace(bool oneOrMore)
|
||||
private bool EatWhitespace(char initialChar, bool oneOrMore, out char finalChar)
|
||||
{
|
||||
bool whitespace = false;
|
||||
while (_currentChar == ' ' || char.IsWhiteSpace(_currentChar))
|
||||
char currentChar = initialChar;
|
||||
while (currentChar == ' ' || char.IsWhiteSpace(currentChar))
|
||||
{
|
||||
whitespace = true;
|
||||
MoveNext();
|
||||
currentChar = MoveNext();
|
||||
}
|
||||
|
||||
finalChar = currentChar;
|
||||
|
||||
return (!oneOrMore || whitespace);
|
||||
}
|
||||
|
||||
private void ParseConstructor()
|
||||
{
|
||||
if (MatchValue("new", true))
|
||||
if (MatchValue('n', "new", true))
|
||||
{
|
||||
if (EatWhitespace(true))
|
||||
char currentChar = MoveNext();
|
||||
|
||||
if (EatWhitespace(currentChar, true, out currentChar))
|
||||
{
|
||||
while (char.IsLetter(_currentChar))
|
||||
while (char.IsLetter(currentChar))
|
||||
{
|
||||
_buffer.Append(_currentChar);
|
||||
MoveNext();
|
||||
_buffer.Append(currentChar);
|
||||
currentChar = MoveNext();
|
||||
}
|
||||
|
||||
EatWhitespace(false);
|
||||
EatWhitespace(currentChar, false, out currentChar);
|
||||
|
||||
if (_currentChar != '(')
|
||||
throw CreateJsonReaderException("Unexpected character while parsing constructor: {0}. Line {1}, position {2}.", _currentChar, _currentLineNumber, _currentLinePosition);
|
||||
if (currentChar != '(')
|
||||
throw CreateJsonReaderException("Unexpected character while parsing constructor: {0}. Line {1}, position {2}.", currentChar, _currentLineNumber, _currentLinePosition);
|
||||
|
||||
string constructorName = _buffer.ToString();
|
||||
_buffer.Position = 0;
|
||||
@@ -682,22 +660,25 @@ namespace Newtonsoft.Json
|
||||
}
|
||||
}
|
||||
|
||||
private void ParseNumber()
|
||||
private void ParseNumber(char firstChar)
|
||||
{
|
||||
char currentChar = firstChar;
|
||||
|
||||
// parse until seperator character or end
|
||||
bool end = false;
|
||||
do
|
||||
{
|
||||
if (CurrentIsSeperator())
|
||||
if (IsSeperator(currentChar))
|
||||
{
|
||||
end = true;
|
||||
_lastChar = currentChar;
|
||||
}
|
||||
else
|
||||
_buffer.Append(_currentChar);
|
||||
{
|
||||
_buffer.Append(currentChar);
|
||||
}
|
||||
|
||||
} while (!end && MoveNext());
|
||||
|
||||
// hit the end of the reader before the number ended. clear the last number value
|
||||
if (!end)
|
||||
ClearCurrentChar();
|
||||
} while (!end && ((currentChar = MoveNext()) != '\0' || !_end));
|
||||
|
||||
string number = _buffer.ToString();
|
||||
object numberValue;
|
||||
@@ -706,12 +687,12 @@ namespace Newtonsoft.Json
|
||||
if (number.IndexOf(".", StringComparison.OrdinalIgnoreCase) == -1
|
||||
&& number.IndexOf("e", StringComparison.OrdinalIgnoreCase) == -1)
|
||||
{
|
||||
numberValue = Convert.ToInt64(_buffer.ToString(), CultureInfo.InvariantCulture);
|
||||
numberValue = Convert.ToInt64(number, CultureInfo.InvariantCulture);
|
||||
numberType = JsonToken.Integer;
|
||||
}
|
||||
else
|
||||
{
|
||||
numberValue = Convert.ToDouble(_buffer.ToString(), CultureInfo.InvariantCulture);
|
||||
numberValue = Convert.ToDouble(number, CultureInfo.InvariantCulture);
|
||||
numberType = JsonToken.Float;
|
||||
}
|
||||
|
||||
@@ -724,30 +705,30 @@ namespace Newtonsoft.Json
|
||||
{
|
||||
// should have already parsed / character before reaching this method
|
||||
|
||||
MoveNext();
|
||||
char currentChar = MoveNext();
|
||||
|
||||
if (_currentChar == '*')
|
||||
if (currentChar == '*')
|
||||
{
|
||||
while (MoveNext())
|
||||
while ((currentChar = MoveNext()) != '\0' || !_end)
|
||||
{
|
||||
if (_currentChar == '*')
|
||||
if (currentChar == '*')
|
||||
{
|
||||
if (MoveNext())
|
||||
if ((currentChar = MoveNext()) != '\0' || !_end)
|
||||
{
|
||||
if (_currentChar == '/')
|
||||
if (currentChar == '/')
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
_buffer.Append('*');
|
||||
_buffer.Append(_currentChar);
|
||||
_buffer.Append(currentChar);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_buffer.Append(_currentChar);
|
||||
_buffer.Append(currentChar);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -759,30 +740,30 @@ namespace Newtonsoft.Json
|
||||
SetToken(JsonToken.Comment, _buffer.ToString());
|
||||
|
||||
_buffer.Position = 0;
|
||||
|
||||
ClearCurrentChar();
|
||||
}
|
||||
|
||||
private bool MatchValue(string value)
|
||||
private bool MatchValue(char firstChar, string value)
|
||||
{
|
||||
char currentChar = firstChar;
|
||||
|
||||
int i = 0;
|
||||
do
|
||||
{
|
||||
if (_currentChar != value[i])
|
||||
if (currentChar != value[i])
|
||||
{
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
while (i < value.Length && MoveNext());
|
||||
while (i < value.Length && ((currentChar = MoveNext()) != '\0' || !_end));
|
||||
|
||||
return (i == value.Length);
|
||||
}
|
||||
|
||||
private bool MatchValue(string value, bool noTrailingNonSeperatorCharacters)
|
||||
private bool MatchValue(char firstChar, string value, bool noTrailingNonSeperatorCharacters)
|
||||
{
|
||||
// will match value and then move to the next character, checking that it is a seperator character
|
||||
bool match = MatchValue(value);
|
||||
bool match = MatchValue(firstChar, value);
|
||||
|
||||
if (!noTrailingNonSeperatorCharacters)
|
||||
{
|
||||
@@ -790,17 +771,17 @@ namespace Newtonsoft.Json
|
||||
}
|
||||
else
|
||||
{
|
||||
bool matchAndNoTrainingNonSeperatorCharacters = (match && (!MoveNext() || CurrentIsSeperator()));
|
||||
if (!CurrentIsSeperator())
|
||||
ClearCurrentChar();
|
||||
int c = PeekNext();
|
||||
char next = (c != -1) ? (char) c : '\0';
|
||||
bool matchAndNoTrainingNonSeperatorCharacters = (match && (next == '\0' || IsSeperator(next)));
|
||||
|
||||
return matchAndNoTrainingNonSeperatorCharacters;
|
||||
}
|
||||
}
|
||||
|
||||
private bool CurrentIsSeperator()
|
||||
private bool IsSeperator(char c)
|
||||
{
|
||||
switch (_currentChar)
|
||||
switch (c)
|
||||
{
|
||||
case '}':
|
||||
case ']':
|
||||
@@ -814,9 +795,12 @@ namespace Newtonsoft.Json
|
||||
return true;
|
||||
break;
|
||||
case ' ':
|
||||
case StringUtils.Tab:
|
||||
case StringUtils.LineFeed:
|
||||
case StringUtils.CarriageReturn:
|
||||
return true;
|
||||
default:
|
||||
if (char.IsWhiteSpace(_currentChar))
|
||||
if (char.IsWhiteSpace(c))
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
@@ -829,7 +813,7 @@ namespace Newtonsoft.Json
|
||||
// check characters equal 'true'
|
||||
// and that it is followed by either a seperator character
|
||||
// or the text ends
|
||||
if (MatchValue(JsonConvert.True, true))
|
||||
if (MatchValue('t', JsonConvert.True, true))
|
||||
{
|
||||
SetToken(JsonToken.Boolean, true);
|
||||
}
|
||||
@@ -841,7 +825,7 @@ namespace Newtonsoft.Json
|
||||
|
||||
private void ParseNull()
|
||||
{
|
||||
if (MatchValue(JsonConvert.Null, true))
|
||||
if (MatchValue('n', JsonConvert.Null, true))
|
||||
{
|
||||
SetToken(JsonToken.Null);
|
||||
}
|
||||
@@ -853,7 +837,7 @@ namespace Newtonsoft.Json
|
||||
|
||||
private void ParseUndefined()
|
||||
{
|
||||
if (MatchValue(JsonConvert.Undefined, true))
|
||||
if (MatchValue('u', JsonConvert.Undefined, true))
|
||||
{
|
||||
SetToken(JsonToken.Undefined);
|
||||
}
|
||||
@@ -865,7 +849,7 @@ namespace Newtonsoft.Json
|
||||
|
||||
private void ParseFalse()
|
||||
{
|
||||
if (MatchValue(JsonConvert.False, true))
|
||||
if (MatchValue('f', JsonConvert.False, true))
|
||||
{
|
||||
SetToken(JsonToken.Boolean, false);
|
||||
}
|
||||
@@ -877,7 +861,7 @@ namespace Newtonsoft.Json
|
||||
|
||||
private void ParseNumberNegativeInfinity()
|
||||
{
|
||||
if (MatchValue(JsonConvert.NegativeInfinity, true))
|
||||
if (MatchValue('-', JsonConvert.NegativeInfinity, true))
|
||||
{
|
||||
SetToken(JsonToken.Float, double.NegativeInfinity);
|
||||
}
|
||||
@@ -889,7 +873,7 @@ namespace Newtonsoft.Json
|
||||
|
||||
private void ParseNumberPositiveInfinity()
|
||||
{
|
||||
if (MatchValue(JsonConvert.PositiveInfinity, true))
|
||||
if (MatchValue('I', JsonConvert.PositiveInfinity, true))
|
||||
{
|
||||
SetToken(JsonToken.Float, double.PositiveInfinity);
|
||||
}
|
||||
@@ -901,7 +885,7 @@ namespace Newtonsoft.Json
|
||||
|
||||
private void ParseNumberNaN()
|
||||
{
|
||||
if (MatchValue(JsonConvert.NaN, true))
|
||||
if (MatchValue('N', JsonConvert.NaN, true))
|
||||
{
|
||||
SetToken(JsonToken.Float, double.NaN);
|
||||
}
|
||||
@@ -964,4 +948,4 @@ namespace Newtonsoft.Json
|
||||
get { return _currentLinePosition; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -288,7 +288,15 @@ namespace Newtonsoft.Json
|
||||
public override void WriteValue(string value)
|
||||
{
|
||||
base.WriteValue(value);
|
||||
WriteValueInternal((value != null) ? JsonConvert.ToString(value, _quoteChar) : JsonConvert.Null, JsonToken.String);
|
||||
if (value == null)
|
||||
WriteValueInternal(JsonConvert.Null, JsonToken.Null);
|
||||
else
|
||||
{
|
||||
JavaScriptUtils.WriteEscapedJavaScriptString(_writer, value, _quoteChar, true);
|
||||
//_writer.Write(JavaScriptUtils.EscapeJavaScriptString(value, _quoteChar, false));
|
||||
//WriteValueInternal(, JsonToken.String);
|
||||
//JavaScriptUtils.WriteEscapedJavaScriptString(_writer, value, _quoteChar, true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -428,7 +436,7 @@ namespace Newtonsoft.Json
|
||||
public override void WriteValue(DateTime value)
|
||||
{
|
||||
base.WriteValue(value);
|
||||
WriteValueInternal(JsonConvert.ToString(value), JsonToken.Date);
|
||||
JsonConvert.WriteDateTimeString(_writer, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -107,17 +107,17 @@ namespace Newtonsoft.Json
|
||||
}
|
||||
|
||||
// array that gives a new state based on the current state an the token being written
|
||||
private static readonly State[,] stateArray = {
|
||||
private static readonly State[][] stateArray = new[] {
|
||||
// Start PropertyName ObjectStart Object ArrayStart Array ConstructorStart Constructor Closed Error
|
||||
//
|
||||
/* None */{ State.Error, State.Error, State.Error, State.Error, State.Error, State.Error, State.Error, State.Error, State.Error, State.Error },
|
||||
/* StartObject */{ State.ObjectStart, State.ObjectStart, State.Error, State.Error, State.ObjectStart, State.ObjectStart, State.ObjectStart, State.ObjectStart, State.Error, State.Error },
|
||||
/* StartArray */{ State.ArrayStart, State.ArrayStart, State.Error, State.Error, State.ArrayStart, State.ArrayStart, State.ArrayStart, State.ArrayStart, State.Error, State.Error },
|
||||
/* StartConstructor */{ State.ConstructorStart, State.ConstructorStart, State.Error, State.Error, State.ConstructorStart, State.ConstructorStart, State.ConstructorStart, State.ConstructorStart, State.Error, State.Error },
|
||||
/* StartProperty */{ State.Property, State.Error, State.Property, State.Property, State.Error, State.Error, State.Error, State.Error, State.Error, State.Error },
|
||||
/* Comment */{ State.Start, State.Property, State.ObjectStart, State.Object, State.ArrayStart, State.Array, State.Constructor, State.Constructor, State.Error, State.Error },
|
||||
/* Raw */{ State.Start, State.Property, State.ObjectStart, State.Object, State.ArrayStart, State.Array, State.Constructor, State.Constructor, State.Error, State.Error },
|
||||
/* Value */{ State.Start, State.Object, State.Error, State.Error, State.Array, State.Array, State.Constructor, State.Constructor, State.Error, State.Error },
|
||||
/* None */new[]{ State.Error, State.Error, State.Error, State.Error, State.Error, State.Error, State.Error, State.Error, State.Error, State.Error },
|
||||
/* StartObject */new[]{ State.ObjectStart, State.ObjectStart, State.Error, State.Error, State.ObjectStart, State.ObjectStart, State.ObjectStart, State.ObjectStart, State.Error, State.Error },
|
||||
/* StartArray */new[]{ State.ArrayStart, State.ArrayStart, State.Error, State.Error, State.ArrayStart, State.ArrayStart, State.ArrayStart, State.ArrayStart, State.Error, State.Error },
|
||||
/* StartConstructor */new[]{ State.ConstructorStart, State.ConstructorStart, State.Error, State.Error, State.ConstructorStart, State.ConstructorStart, State.ConstructorStart, State.ConstructorStart, State.Error, State.Error },
|
||||
/* StartProperty */new[]{ State.Property, State.Error, State.Property, State.Property, State.Error, State.Error, State.Error, State.Error, State.Error, State.Error },
|
||||
/* Comment */new[]{ State.Start, State.Property, State.ObjectStart, State.Object, State.ArrayStart, State.Array, State.Constructor, State.Constructor, State.Error, State.Error },
|
||||
/* Raw */new[]{ State.Start, State.Property, State.ObjectStart, State.Object, State.ArrayStart, State.Array, State.Constructor, State.Constructor, State.Error, State.Error },
|
||||
/* Value */new[]{ State.Start, State.Object, State.Error, State.Error, State.Array, State.Array, State.Constructor, State.Constructor, State.Error, State.Error },
|
||||
};
|
||||
|
||||
private int _top;
|
||||
@@ -586,7 +586,7 @@ namespace Newtonsoft.Json
|
||||
}
|
||||
|
||||
// gets new state based on the current state and what is being written
|
||||
State newState = stateArray[token, (int)_currentState];
|
||||
State newState = stateArray[token][(int)_currentState];
|
||||
|
||||
if (newState == State.Error)
|
||||
throw new JsonWriterException("Token {0} in state {1} would result in an invalid JavaScript object.".FormatWith(CultureInfo.InvariantCulture, tokenBeingWritten.ToString(), _currentState.ToString()));
|
||||
|
||||
@@ -209,7 +209,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
if (ReflectionUtils.HasDefaultConstructor(contract.CreatedType, true)
|
||||
|| contract.CreatedType.IsValueType)
|
||||
{
|
||||
#if !PocketPC
|
||||
#if !PocketPC && !SILVERLIGHT
|
||||
contract.DefaultCreator = LateBoundDelegateFactory.CreateDefaultConstructor(contract.CreatedType);
|
||||
#else
|
||||
ConstructorInfo constructorInfo = ReflectionUtils.GetDefaultConstructor(contract.CreatedType, true);
|
||||
@@ -414,7 +414,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
{
|
||||
JsonProperty property = new JsonProperty();
|
||||
property.PropertyType = ReflectionUtils.GetMemberUnderlyingType(member);
|
||||
#if !PocketPC
|
||||
#if !PocketPC && !SILVERLIGHT
|
||||
property.ValueProvider = new DynamicValueProvider(member);
|
||||
#else
|
||||
property.ValueProvider = new ReflectionValueProvider(member);
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
#endregion
|
||||
|
||||
#if !PocketPC
|
||||
#if !PocketPC && !SILVERLIGHT
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -65,6 +65,20 @@ namespace Newtonsoft.Json.Serialization
|
||||
if (_setter == null)
|
||||
_setter = LateBoundDelegateFactory.CreateSet<object>(_memberInfo);
|
||||
|
||||
#if DEBUG
|
||||
// dynamic method doesn't check whether the type is 'legal' to set
|
||||
// add this check for unit tests
|
||||
if (value == null)
|
||||
{
|
||||
if (!ReflectionUtils.IsNullable(ReflectionUtils.GetMemberUnderlyingType(_memberInfo)))
|
||||
throw new Exception("Incompatible value. Cannot set {0} to null.".FormatWith(CultureInfo.InvariantCulture, _memberInfo));
|
||||
}
|
||||
else if (!ReflectionUtils.GetMemberUnderlyingType(_memberInfo).IsAssignableFrom(value.GetType()))
|
||||
{
|
||||
throw new Exception("Incompatible value. Cannot set {0} to type {1}.".FormatWith(CultureInfo.InvariantCulture, _memberInfo, value.GetType()));
|
||||
}
|
||||
#endif
|
||||
|
||||
_setter(target, value);
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -82,7 +82,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
_genericWrapperType = ReflectionUtils.MakeGenericType(typeof(CollectionWrapper<>), CollectionItemType);
|
||||
|
||||
ConstructorInfo genericWrapperConstructor = _genericWrapperType.GetConstructor(new[] { _genericCollectionDefinitionType });
|
||||
#if !PocketPC
|
||||
#if !PocketPC && !SILVERLIGHT
|
||||
_genericWrapperCreator = LateBoundDelegateFactory.CreateMethodHandler(genericWrapperConstructor);
|
||||
#else
|
||||
_genericWrapperCreator = (target, args) => genericWrapperConstructor.Invoke(new[] { args[0] });
|
||||
|
||||
@@ -85,7 +85,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
_genericWrapperType = ReflectionUtils.MakeGenericType(typeof(DictionaryWrapper<,>), DictionaryKeyType, DictionaryValueType);
|
||||
|
||||
ConstructorInfo genericWrapperConstructor = _genericWrapperType.GetConstructor(new[] { _genericCollectionDefinitionType });
|
||||
#if !PocketPC
|
||||
#if !PocketPC && !SILVERLIGHT
|
||||
_genericWrapperCreator = LateBoundDelegateFactory.CreateMethodHandler(genericWrapperConstructor);
|
||||
#else
|
||||
_genericWrapperCreator = (target, args) => genericWrapperConstructor.Invoke(new[] { args[0] });
|
||||
|
||||
@@ -85,43 +85,38 @@ namespace Newtonsoft.Json.Serialization
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get the closest matching <see cref="JsonProperty"/> object.
|
||||
/// Gets the closest matching <see cref="JsonProperty"/> object.
|
||||
/// First attempts to get an exact case match of propertyName and then
|
||||
/// a case insensitive match.
|
||||
/// </summary>
|
||||
/// <param name="propertyName">Name of the property.</param>
|
||||
/// <param name="property">A matching property if found.</param>
|
||||
/// <returns>A flag indicating whether a match was found.</returns>
|
||||
public bool TryGetClosestMatchProperty(string propertyName, out JsonProperty property)
|
||||
/// <returns>A matching property if found.</returns>
|
||||
public JsonProperty GetClosestMatchProperty(string propertyName)
|
||||
{
|
||||
if (TryGetProperty(propertyName, StringComparison.Ordinal, out property))
|
||||
return true;
|
||||
if (TryGetProperty(propertyName, StringComparison.OrdinalIgnoreCase, out property))
|
||||
return true;
|
||||
JsonProperty property = GetProperty(propertyName, StringComparison.Ordinal);
|
||||
if (property == null)
|
||||
property = GetProperty(propertyName, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
return false;
|
||||
return property;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get a property by property name.
|
||||
/// Gets a property by property name.
|
||||
/// </summary>
|
||||
/// <param name="propertyName">The name of the property to get.</param>
|
||||
/// <param name="comparisonType">Type property name string comparison.</param>
|
||||
/// <param name="matchingProperty">A matching property if found.</param>
|
||||
/// <returns>A flag indicating whether a match was found.</returns>
|
||||
public bool TryGetProperty(string propertyName, StringComparison comparisonType, out JsonProperty matchingProperty)
|
||||
/// <returns>A matching property if found.</returns>
|
||||
public JsonProperty GetProperty(string propertyName, StringComparison comparisonType)
|
||||
{
|
||||
foreach (JsonProperty property in this)
|
||||
{
|
||||
if (string.Compare(propertyName, property.PropertyName, comparisonType) == 0)
|
||||
if (string.Equals(propertyName, property.PropertyName, comparisonType))
|
||||
{
|
||||
matchingProperty = property;
|
||||
return true;
|
||||
return property;
|
||||
}
|
||||
}
|
||||
|
||||
matchingProperty = default(JsonProperty);
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -171,8 +171,8 @@ namespace Newtonsoft.Json.Serialization
|
||||
if (memberConverter != null)
|
||||
return memberConverter.ReadJson(reader, objectType, GetInternalSerializer());
|
||||
|
||||
if (objectType != null && Serializer.HasClassConverter(contract, out converter))
|
||||
return converter.ReadJson(reader, objectType, GetInternalSerializer());
|
||||
if (contract != null && contract.Converter != null)
|
||||
return contract.Converter.ReadJson(reader, objectType, GetInternalSerializer());
|
||||
|
||||
if (objectType != null && Serializer.HasMatchingConverter(objectType, out converter))
|
||||
return converter.ReadJson(reader, objectType, GetInternalSerializer());
|
||||
@@ -472,7 +472,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
return dictionary.UnderlyingDictionary;
|
||||
}
|
||||
|
||||
private IDictionary PopulateDictionary(IWrappedDictionary dictionary, JsonReader reader, JsonDictionaryContract contract, string id)
|
||||
private object PopulateDictionary(IWrappedDictionary dictionary, JsonReader reader, JsonDictionaryContract contract, string id)
|
||||
{
|
||||
if (id != null)
|
||||
Serializer.ReferenceResolver.AddReference(id, dictionary.UnderlyingDictionary);
|
||||
@@ -491,7 +491,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
|
||||
try
|
||||
{
|
||||
dictionary.Add(keyValue, CreateValue(reader, contract.DictionaryValueType, GetContractSafe(contract.DictionaryValueType), null, null));
|
||||
dictionary[keyValue] = CreateValue(reader, contract.DictionaryValueType, GetContractSafe(contract.DictionaryValueType), null, null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -504,7 +504,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
case JsonToken.EndObject:
|
||||
contract.InvokeOnDeserialized(dictionary.UnderlyingDictionary);
|
||||
|
||||
return dictionary;
|
||||
return dictionary.UnderlyingDictionary;
|
||||
default:
|
||||
throw new JsonSerializationException("Unexpected token when deserializing object: " + reader.TokenType);
|
||||
}
|
||||
@@ -615,10 +615,11 @@ namespace Newtonsoft.Json.Serialization
|
||||
if (!reader.Read())
|
||||
throw new JsonSerializationException("Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName));
|
||||
|
||||
JsonProperty property;
|
||||
// attempt exact case match first
|
||||
// then try match ignoring case
|
||||
if (contract.Properties.TryGetClosestMatchProperty(memberName, out property))
|
||||
JsonProperty property = contract.Properties.GetClosestMatchProperty(memberName);
|
||||
|
||||
if (property != null)
|
||||
{
|
||||
if (!property.Ignored)
|
||||
{
|
||||
@@ -693,10 +694,11 @@ namespace Newtonsoft.Json.Serialization
|
||||
case JsonToken.PropertyName:
|
||||
string memberName = reader.Value.ToString();
|
||||
|
||||
JsonProperty property;
|
||||
// attempt exact case match first
|
||||
// then try match ignoring case
|
||||
if (!contract.Properties.TryGetClosestMatchProperty(memberName, out property))
|
||||
JsonProperty property = contract.Properties.GetClosestMatchProperty(memberName);
|
||||
|
||||
if (property == null)
|
||||
{
|
||||
if (Serializer.MissingMemberHandling == MissingMemberHandling.Error)
|
||||
throw new JsonSerializationException("Could not find member '{0}' on object of type '{1}'".FormatWith(CultureInfo.InvariantCulture, memberName, contract.UnderlyingType.Name));
|
||||
|
||||
@@ -91,7 +91,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
}
|
||||
|
||||
if (converter != null
|
||||
|| Serializer.HasClassConverter(contract, out converter)
|
||||
|| ((converter = contract.Converter) != null)
|
||||
|| Serializer.HasMatchingConverter(contract.UnderlyingType, out converter))
|
||||
{
|
||||
SerializeConvertable(writer, converter, value, contract);
|
||||
@@ -165,7 +165,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
return Serializer.ReferenceResolver.IsReferenced(value);
|
||||
}
|
||||
|
||||
private void WriteMemberInfoProperty(JsonWriter writer, object value, object memberValue, JsonProperty property, JsonContract contract)
|
||||
private void WriteMemberInfoProperty(JsonWriter writer, object memberValue, JsonProperty property, JsonContract contract)
|
||||
{
|
||||
string propertyName = property.PropertyName;
|
||||
JsonConverter memberConverter = property.MemberConverter;
|
||||
@@ -295,7 +295,7 @@ namespace Newtonsoft.Json.Serialization
|
||||
object memberValue = property.ValueProvider.GetValue(value);
|
||||
JsonContract memberContract = GetContractSafe(memberValue);
|
||||
|
||||
WriteMemberInfoProperty(writer, value, memberValue, property, memberContract);
|
||||
WriteMemberInfoProperty(writer, memberValue, property, memberContract);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -314,6 +314,10 @@ namespace Newtonsoft.Json.Utilities
|
||||
public static object ConvertOrCast(object initialValue, CultureInfo culture, Type targetType)
|
||||
{
|
||||
object convertedValue;
|
||||
|
||||
if (initialValue == null && ReflectionUtils.IsNullable(targetType))
|
||||
return null;
|
||||
|
||||
if (TryConvert(initialValue, culture, targetType, out convertedValue))
|
||||
return convertedValue;
|
||||
|
||||
|
||||
@@ -35,68 +35,100 @@ namespace Newtonsoft.Json.Utilities
|
||||
{
|
||||
internal static class JavaScriptUtils
|
||||
{
|
||||
public static void WriteEscapedJavaScriptString(StringBuilder writer, string value, char delimiter, bool appendDelimiters)
|
||||
public static void WriteEscapedJavaScriptString(TextWriter writer, string value, char delimiter, bool appendDelimiters)
|
||||
{
|
||||
// leading delimiter
|
||||
if (appendDelimiters)
|
||||
writer.Append(delimiter);
|
||||
writer.Write(delimiter);
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
int lastWritePosition = 0;
|
||||
int skipped = 0;
|
||||
char[] chars = null;
|
||||
|
||||
for (int i = 0; i < value.Length; i++)
|
||||
{
|
||||
char c = value[i];
|
||||
string escapedValue;
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case '\t':
|
||||
writer.Append(@"\t");
|
||||
escapedValue = @"\t";
|
||||
break;
|
||||
case '\n':
|
||||
writer.Append(@"\n");
|
||||
escapedValue = @"\n";
|
||||
break;
|
||||
case '\r':
|
||||
writer.Append(@"\r");
|
||||
escapedValue = @"\r";
|
||||
break;
|
||||
case '\f':
|
||||
writer.Append(@"\f");
|
||||
escapedValue = @"\f";
|
||||
break;
|
||||
case '\b':
|
||||
writer.Append(@"\b");
|
||||
escapedValue = @"\b";
|
||||
break;
|
||||
case '\\':
|
||||
writer.Append(@"\\");
|
||||
escapedValue = @"\\";
|
||||
break;
|
||||
case '\u0085': // Next Line
|
||||
writer.Append(@"\u0085");
|
||||
escapedValue = @"\u0085";
|
||||
break;
|
||||
case '\u2028': // Line Separator
|
||||
writer.Append(@"\u2028");
|
||||
escapedValue = @"\u2028";
|
||||
break;
|
||||
case '\u2029': // Paragraph Separator
|
||||
writer.Append(@"\u2029");
|
||||
escapedValue = @"\u2029";
|
||||
break;
|
||||
case '\'':
|
||||
// only escape if this charater is being used as the delimiter
|
||||
writer.Append((delimiter == '\'') ? @"\'" : @"'");
|
||||
escapedValue = (delimiter == '\'') ? @"\'" : null;
|
||||
break;
|
||||
case '"':
|
||||
// only escape if this charater is being used as the delimiter
|
||||
writer.Append((delimiter == '"') ? "\\\"" : @"""");
|
||||
escapedValue = (delimiter == '"') ? "\\\"" : null;
|
||||
break;
|
||||
default:
|
||||
if (c > '\u001f')
|
||||
writer.Append(c);
|
||||
else
|
||||
StringUtils.WriteCharAsUnicode(writer, c);
|
||||
escapedValue = (c <= '\u001f') ? StringUtils.ToCharAsUnicode(c) : null;
|
||||
break;
|
||||
}
|
||||
|
||||
if (escapedValue != null)
|
||||
{
|
||||
if (chars == null)
|
||||
chars = value.ToCharArray();
|
||||
|
||||
// write skipped text
|
||||
if (skipped > 0)
|
||||
{
|
||||
writer.Write(chars, lastWritePosition, skipped);
|
||||
skipped = 0;
|
||||
}
|
||||
|
||||
// write escaped value and note position
|
||||
writer.Write(escapedValue);
|
||||
lastWritePosition = i + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
skipped++;
|
||||
}
|
||||
}
|
||||
|
||||
// write any remaining skipped text
|
||||
if (skipped > 0)
|
||||
{
|
||||
if (lastWritePosition == 0)
|
||||
writer.Write(value);
|
||||
else
|
||||
writer.Write(chars, lastWritePosition, skipped);
|
||||
}
|
||||
}
|
||||
|
||||
// trailing delimiter
|
||||
if (appendDelimiters)
|
||||
writer.Append(delimiter);
|
||||
writer.Write(delimiter);
|
||||
}
|
||||
|
||||
public static string ToEscapedJavaScriptString(string value)
|
||||
@@ -106,14 +138,11 @@ namespace Newtonsoft.Json.Utilities
|
||||
|
||||
public static string ToEscapedJavaScriptString(string value, char delimiter, bool appendDelimiters)
|
||||
{
|
||||
int length = value.Length;
|
||||
if (appendDelimiters)
|
||||
length += 2;
|
||||
|
||||
StringBuilder builder = new StringBuilder(length);
|
||||
|
||||
WriteEscapedJavaScriptString(builder, value, delimiter, appendDelimiters);
|
||||
return builder.ToString();
|
||||
using (StringWriter w = StringUtils.CreateStringWriter(StringUtils.GetLength(value) ?? 16))
|
||||
{
|
||||
WriteEscapedJavaScriptString(w, value, delimiter, appendDelimiters);
|
||||
return w.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,29 @@
|
||||
#if !PocketPC
|
||||
#region License
|
||||
// Copyright (c) 2007 James Newton-King
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
// restriction, including without limitation the rights to use,
|
||||
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following
|
||||
// conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
#endregion
|
||||
|
||||
#if !PocketPC && !SILVERLIGHT
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace Newtonsoft.Json.Utilities
|
||||
public void Append(char value)
|
||||
{
|
||||
// test if the buffer array is large enough to take the value
|
||||
if (_position + 1 > _buffer.Length)
|
||||
if (_position == _buffer.Length)
|
||||
{
|
||||
EnsureSize(1);
|
||||
}
|
||||
|
||||
@@ -325,13 +325,15 @@ namespace Newtonsoft.Json.Utilities
|
||||
|
||||
public static string ToCharAsUnicode(char c)
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
WriteCharAsUnicode(builder, c);
|
||||
char h1 = MathUtils.IntToHex((c >> 12) & '\x000f');
|
||||
char h2 = MathUtils.IntToHex((c >> 8) & '\x000f');
|
||||
char h3 = MathUtils.IntToHex((c >> 4) & '\x000f');
|
||||
char h4 = MathUtils.IntToHex(c & '\x000f');
|
||||
|
||||
return builder.ToString();
|
||||
return new string(new[] { '\\', 'u', h1, h2, h3, h4 });
|
||||
}
|
||||
|
||||
public static void WriteCharAsUnicode(StringBuilder writer, char c)
|
||||
public static void WriteCharAsUnicode(TextWriter writer, char c)
|
||||
{
|
||||
ValidationUtils.ArgumentNotNull(writer, "writer");
|
||||
|
||||
@@ -340,12 +342,12 @@ namespace Newtonsoft.Json.Utilities
|
||||
char h3 = MathUtils.IntToHex((c >> 4) & '\x000f');
|
||||
char h4 = MathUtils.IntToHex(c & '\x000f');
|
||||
|
||||
writer.Append('\\');
|
||||
writer.Append('u');
|
||||
writer.Append(h1);
|
||||
writer.Append(h2);
|
||||
writer.Append(h3);
|
||||
writer.Append(h4);
|
||||
writer.Write('\\');
|
||||
writer.Write('u');
|
||||
writer.Write(h1);
|
||||
writer.Write(h2);
|
||||
writer.Write(h3);
|
||||
writer.Write(h4);
|
||||
}
|
||||
|
||||
public static TSource ForgivingCaseSensitiveFind<TSource>(this IEnumerable<TSource> source, Func<TSource, string> valueSelector, string testValue)
|
||||
|
||||
Reference in New Issue
Block a user