diff --git a/Src/Newtonsoft.Json.Tests/Linq/JArrayTests.cs b/Src/Newtonsoft.Json.Tests/Linq/JArrayTests.cs index f88846c8..2746a738 100644 --- a/Src/Newtonsoft.Json.Tests/Linq/JArrayTests.cs +++ b/Src/Newtonsoft.Json.Tests/Linq/JArrayTests.cs @@ -560,5 +560,21 @@ Parameter name: index"); Assert.AreEqual(2, (int)a[1]); Assert.AreEqual(3, (int)a[2]); } + + [Test] + public void Parse_LineInfo() + { + string json = "[1,2,3]"; + + JArray a = JArray.Parse(json, new JsonLoadSettings + { + LineInfoHandling = LineInfoHandling.Load + }); + + Assert.AreEqual(false, ((IJsonLineInfo)a).HasLineInfo()); + Assert.AreEqual(false, ((IJsonLineInfo)a[0]).HasLineInfo()); + Assert.AreEqual(false, ((IJsonLineInfo)a[1]).HasLineInfo()); + Assert.AreEqual(false, ((IJsonLineInfo)a[2]).HasLineInfo()); + } } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net40.project.json b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net40.project.json index bd003f1b..32527e95 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net40.project.json +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Net40.project.json @@ -1,7 +1,7 @@ { "dependencies": { "NUnit": "2.6.2", - "FSharp.Core": "4.0.0" + "FSharp.Core": "4.0.0.1" }, "frameworks": { "net40": {} diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable.project.json b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable.project.json index 7d49c971..cc0e4b7f 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable.project.json +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable.project.json @@ -1,6 +1,6 @@ { "dependencies": { - "FSharp.Core": "4.0.0", + "FSharp.Core": "4.0.0.1", "NUnit": "2.6.2", "System.Collections.Immutable": "1.1.36" }, diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable40.project.json b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable40.project.json index fa254618..dee49009 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable40.project.json +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.Portable40.project.json @@ -1,6 +1,6 @@ { "dependencies": { - "FSharp.Core": "4.0.0", + "FSharp.Core": "4.0.0.1", "NUnit": "2.6.2" }, "frameworks": { diff --git a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.project.json b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.project.json index e59325de..fc81f703 100644 --- a/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.project.json +++ b/Src/Newtonsoft.Json.Tests/Newtonsoft.Json.Tests.project.json @@ -1,7 +1,7 @@ { "dependencies": { "Autofac": "4.0.0-beta7-130", - "FSharp.Core": "4.0.0", + "FSharp.Core": "4.0.0.1", "NUnit": "2.6.2", "System.Collections.Immutable": "1.1.36" }, diff --git a/Src/Newtonsoft.Json/JsonPosition.cs b/Src/Newtonsoft.Json/JsonPosition.cs index fd8deef4..57cf04ed 100644 --- a/Src/Newtonsoft.Json/JsonPosition.cs +++ b/Src/Newtonsoft.Json/JsonPosition.cs @@ -56,6 +56,20 @@ namespace Newtonsoft.Json PropertyName = null; } + internal int CalculateLength() + { + switch (Type) + { + case JsonContainerType.Object: + return PropertyName.Length + 5; + case JsonContainerType.Array: + case JsonContainerType.Constructor: + return MathUtils.IntLength((ulong)Position) + 2; + default: + throw new ArgumentOutOfRangeException("Type"); + } + } + internal void WriteTo(StringBuilder sb) { switch (Type) @@ -71,7 +85,9 @@ namespace Newtonsoft.Json else { if (sb.Length > 0) + { sb.Append('.'); + } sb.Append(propertyName); } @@ -90,13 +106,32 @@ namespace Newtonsoft.Json return (type == JsonContainerType.Array || type == JsonContainerType.Constructor); } - internal static string BuildPath(IEnumerable positions) + internal static string BuildPath(List positions, JsonPosition? currentPosition) { - StringBuilder sb = new StringBuilder(); - - foreach (JsonPosition state in positions) + int capacity = 0; + if (positions != null) { - state.WriteTo(sb); + for (int i = 0; i < positions.Count; i++) + { + capacity += positions[i].CalculateLength(); + } + } + if (currentPosition != null) + { + capacity += currentPosition.Value.CalculateLength(); + } + + StringBuilder sb = new StringBuilder(capacity); + if (positions != null) + { + foreach (JsonPosition state in positions) + { + state.WriteTo(sb); + } + } + if (currentPosition != null) + { + currentPosition.Value.WriteTo(sb); } return sb.ToString(); diff --git a/Src/Newtonsoft.Json/JsonReader.cs b/Src/Newtonsoft.Json/JsonReader.cs index bab1d2f3..25e58ec7 100644 --- a/Src/Newtonsoft.Json/JsonReader.cs +++ b/Src/Newtonsoft.Json/JsonReader.cs @@ -128,7 +128,7 @@ namespace Newtonsoft.Json internal DateParseHandling _dateParseHandling; internal FloatParseHandling _floatParseHandling; private string _dateFormatString; - private readonly List _stack; + private List _stack; /// /// Gets the current reader state. @@ -280,11 +280,15 @@ namespace Newtonsoft.Json { get { - int depth = _stack.Count; + int depth = (_stack != null) ? _stack.Count : 0; if (JsonTokenUtils.IsStartToken(TokenType) || _currentPosition.Type == JsonContainerType.None) + { return depth; + } else + { return depth + 1; + } } } @@ -302,11 +306,9 @@ namespace Newtonsoft.Json && _currentState != State.ConstructorStart && _currentState != State.ObjectStart); - IEnumerable positions = (!insideContainer) - ? _stack - : _stack.Concat(new[] { _currentPosition }); + JsonPosition? current = insideContainer ? (JsonPosition?)_currentPosition : null; - return JsonPosition.BuildPath(positions); + return JsonPosition.BuildPath(_stack, current); } } @@ -321,8 +323,10 @@ namespace Newtonsoft.Json internal JsonPosition GetPosition(int depth) { - if (depth < _stack.Count) + if (_stack != null && depth < _stack.Count) + { return _stack[depth]; + } return _currentPosition; } @@ -333,7 +337,6 @@ namespace Newtonsoft.Json protected JsonReader() { _currentState = State.Start; - _stack = new List(4); _dateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind; _dateParseHandling = DateParseHandling.DateTime; _floatParseHandling = FloatParseHandling.Double; @@ -351,6 +354,11 @@ namespace Newtonsoft.Json } else { + if (_stack == null) + { + _stack = new List(); + } + _stack.Add(_currentPosition); _currentPosition = new JsonPosition(value); @@ -366,7 +374,7 @@ namespace Newtonsoft.Json private JsonContainerType Pop() { JsonPosition oldPosition; - if (_stack.Count > 0) + if (_stack != null && _stack.Count > 0) { oldPosition = _currentPosition; _currentPosition = _stack[_stack.Count - 1]; @@ -379,7 +387,9 @@ namespace Newtonsoft.Json } if (_maxDepth != null && Depth <= _maxDepth) + { _hasExceededMaxDepth = false; + } return oldPosition.Type; } diff --git a/Src/Newtonsoft.Json/JsonWriter.cs b/Src/Newtonsoft.Json/JsonWriter.cs index dfc3e494..cc2ead1c 100644 --- a/Src/Newtonsoft.Json/JsonWriter.cs +++ b/Src/Newtonsoft.Json/JsonWriter.cs @@ -113,7 +113,7 @@ namespace Newtonsoft.Json StateArray = BuildStateArray(); } - private readonly List _stack; + private List _stack; private JsonPosition _currentPosition; private State _currentState; private Formatting _formatting; @@ -136,9 +136,11 @@ namespace Newtonsoft.Json { get { - int depth = _stack.Count; + int depth = (_stack != null) ? _stack.Count : 0; if (Peek() != JsonContainerType.None) + { depth++; + } return depth; } @@ -180,10 +182,12 @@ namespace Newtonsoft.Json { get { - if (_currentPosition.Type == JsonContainerType.None) + if (_currentPosition.Type == JsonContainerType.None || _stack == null) + { return string.Empty; + } - return JsonPosition.BuildPath(_stack); + return JsonPosition.BuildPath(_stack, null); } } @@ -195,17 +199,17 @@ namespace Newtonsoft.Json get { if (_currentPosition.Type == JsonContainerType.None) + { return string.Empty; + } bool insideContainer = (_currentState != State.ArrayStart && _currentState != State.ConstructorStart && _currentState != State.ObjectStart); - IEnumerable positions = (!insideContainer) - ? _stack - : _stack.Concat(new[] { _currentPosition }); + JsonPosition? current = insideContainer ? (JsonPosition?) _currentPosition : null; - return JsonPosition.BuildPath(positions); + return JsonPosition.BuildPath(_stack, current); } } @@ -332,7 +336,6 @@ namespace Newtonsoft.Json /// protected JsonWriter() { - _stack = new List(4); _currentState = State.Start; _formatting = Formatting.None; _dateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind; @@ -349,7 +352,14 @@ namespace Newtonsoft.Json private void Push(JsonContainerType value) { if (_currentPosition.Type != JsonContainerType.None) + { + if (_stack == null) + { + _stack = new List(); + } + _stack.Add(_currentPosition); + } _currentPosition = new JsonPosition(value); } @@ -358,7 +368,7 @@ namespace Newtonsoft.Json { JsonPosition oldPosition = _currentPosition; - if (_stack.Count > 0) + if (_stack != null && _stack.Count > 0) { _currentPosition = _stack[_stack.Count - 1]; _stack.RemoveAt(_stack.Count - 1); diff --git a/Src/Newtonsoft.Json/Linq/CommentHandling.cs b/Src/Newtonsoft.Json/Linq/CommentHandling.cs index 26baee20..5e91812c 100644 --- a/Src/Newtonsoft.Json/Linq/CommentHandling.cs +++ b/Src/Newtonsoft.Json/Linq/CommentHandling.cs @@ -14,4 +14,19 @@ /// Load = 1 } + + /// + /// Specifies how line information is handled when loading JSON. + /// + public enum LineInfoHandling + { + /// + /// Ignore line information. + /// + Ignore = 0, + /// + /// Load line information. + /// + Load = 1 + } } \ No newline at end of file diff --git a/Src/Newtonsoft.Json/Linq/JArray.cs b/Src/Newtonsoft.Json/Linq/JArray.cs index 07b364ba..ac4fdd30 100644 --- a/Src/Newtonsoft.Json/Linq/JArray.cs +++ b/Src/Newtonsoft.Json/Linq/JArray.cs @@ -139,7 +139,7 @@ namespace Newtonsoft.Json.Linq throw JsonReaderException.Create(reader, "Error reading JArray from JsonReader. Current JsonReader item is not an array: {0}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType)); JArray a = new JArray(); - a.SetLineInfo(reader as IJsonLineInfo); + a.SetLineInfo(reader as IJsonLineInfo, settings); a.ReadTokenFrom(reader, settings); diff --git a/Src/Newtonsoft.Json/Linq/JConstructor.cs b/Src/Newtonsoft.Json/Linq/JConstructor.cs index 112b14a0..8be66161 100644 --- a/Src/Newtonsoft.Json/Linq/JConstructor.cs +++ b/Src/Newtonsoft.Json/Linq/JConstructor.cs @@ -220,7 +220,7 @@ namespace Newtonsoft.Json.Linq throw JsonReaderException.Create(reader, "Error reading JConstructor from JsonReader. Current JsonReader item is not a constructor: {0}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType)); JConstructor c = new JConstructor((string)reader.Value); - c.SetLineInfo(reader as IJsonLineInfo); + c.SetLineInfo(reader as IJsonLineInfo, settings); c.ReadTokenFrom(reader, settings); diff --git a/Src/Newtonsoft.Json/Linq/JContainer.cs b/Src/Newtonsoft.Json/Linq/JContainer.cs index 9345c81d..8eb10515 100644 --- a/Src/Newtonsoft.Json/Linq/JContainer.cs +++ b/Src/Newtonsoft.Json/Linq/JContainer.cs @@ -693,7 +693,7 @@ namespace Newtonsoft.Json.Linq throw JsonReaderException.Create(reader, "Unexpected end of content while loading {0}.".FormatWith(CultureInfo.InvariantCulture, GetType().Name)); } - internal void ReadContentFrom(JsonReader r, JsonLoadSettings options) + internal void ReadContentFrom(JsonReader r, JsonLoadSettings settings) { ValidationUtils.ArgumentNotNull(r, "r"); IJsonLineInfo lineInfo = r as IJsonLineInfo; @@ -717,7 +717,7 @@ namespace Newtonsoft.Json.Linq break; case JsonToken.StartArray: JArray a = new JArray(); - a.SetLineInfo(lineInfo); + a.SetLineInfo(lineInfo, settings); parent.Add(a); parent = a; break; @@ -730,7 +730,7 @@ namespace Newtonsoft.Json.Linq break; case JsonToken.StartObject: JObject o = new JObject(); - o.SetLineInfo(lineInfo); + o.SetLineInfo(lineInfo, settings); parent.Add(o); parent = o; break; @@ -742,7 +742,7 @@ namespace Newtonsoft.Json.Linq break; case JsonToken.StartConstructor: JConstructor constructor = new JConstructor(r.Value.ToString()); - constructor.SetLineInfo(lineInfo); + constructor.SetLineInfo(lineInfo, settings); parent.Add(constructor); parent = constructor; break; @@ -759,31 +759,31 @@ namespace Newtonsoft.Json.Linq case JsonToken.Boolean: case JsonToken.Bytes: JValue v = new JValue(r.Value); - v.SetLineInfo(lineInfo); + v.SetLineInfo(lineInfo, settings); parent.Add(v); break; case JsonToken.Comment: - if (options != null && options.CommentHandling == CommentHandling.Load) + if (settings != null && settings.CommentHandling == CommentHandling.Load) { v = JValue.CreateComment(r.Value.ToString()); - v.SetLineInfo(lineInfo); + v.SetLineInfo(lineInfo, settings); parent.Add(v); } break; case JsonToken.Null: v = JValue.CreateNull(); - v.SetLineInfo(lineInfo); + v.SetLineInfo(lineInfo, settings); parent.Add(v); break; case JsonToken.Undefined: v = JValue.CreateUndefined(); - v.SetLineInfo(lineInfo); + v.SetLineInfo(lineInfo, settings); parent.Add(v); break; case JsonToken.PropertyName: string propertyName = r.Value.ToString(); JProperty property = new JProperty(propertyName); - property.SetLineInfo(lineInfo); + property.SetLineInfo(lineInfo, settings); JObject parentObject = (JObject)parent; // handle multiple properties with the same name in JSON JProperty existingPropertyWithName = parentObject.Property(propertyName); diff --git a/Src/Newtonsoft.Json/Linq/JObject.cs b/Src/Newtonsoft.Json/Linq/JObject.cs index 2d903ba2..b6ad9ada 100644 --- a/Src/Newtonsoft.Json/Linq/JObject.cs +++ b/Src/Newtonsoft.Json/Linq/JObject.cs @@ -354,7 +354,7 @@ namespace Newtonsoft.Json.Linq } JObject o = new JObject(); - o.SetLineInfo(reader as IJsonLineInfo); + o.SetLineInfo(reader as IJsonLineInfo, settings); o.ReadTokenFrom(reader, settings); diff --git a/Src/Newtonsoft.Json/Linq/JProperty.cs b/Src/Newtonsoft.Json/Linq/JProperty.cs index a6168b68..26c5bbec 100644 --- a/Src/Newtonsoft.Json/Linq/JProperty.cs +++ b/Src/Newtonsoft.Json/Linq/JProperty.cs @@ -357,7 +357,7 @@ namespace Newtonsoft.Json.Linq throw JsonReaderException.Create(reader, "Error reading JProperty from JsonReader. Current JsonReader item is not a property: {0}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType)); JProperty p = new JProperty((string)reader.Value); - p.SetLineInfo(reader as IJsonLineInfo); + p.SetLineInfo(reader as IJsonLineInfo, settings); p.ReadTokenFrom(reader, settings); diff --git a/Src/Newtonsoft.Json/Linq/JToken.cs b/Src/Newtonsoft.Json/Linq/JToken.cs index 2b5b4e15..4932eb87 100644 --- a/Src/Newtonsoft.Json/Linq/JToken.cs +++ b/Src/Newtonsoft.Json/Linq/JToken.cs @@ -186,15 +186,19 @@ namespace Newtonsoft.Json.Linq IList ancestors = AncestorsAndSelf().Reverse().ToList(); - IList positions = new List(); + List positions = new List(); for (int i = 0; i < ancestors.Count; i++) { JToken current = ancestors[i]; JToken next = null; if (i + 1 < ancestors.Count) + { next = ancestors[i + 1]; + } else if (ancestors[i].Type == JTokenType.Property) + { next = ancestors[i]; + } if (next != null) { @@ -214,7 +218,7 @@ namespace Newtonsoft.Json.Linq } } - return JsonPosition.BuildPath(positions); + return JsonPosition.BuildPath(positions, null); } } @@ -1894,7 +1898,7 @@ namespace Newtonsoft.Json.Linq case JsonToken.Boolean: case JsonToken.Bytes: JValue v = new JValue(reader.Value); - v.SetLineInfo(lineInfo); + v.SetLineInfo(lineInfo, settings); return v; case JsonToken.Comment: if (settings != null && settings.CommentHandling == CommentHandling.Ignore) @@ -1906,15 +1910,15 @@ namespace Newtonsoft.Json.Linq } v = JValue.CreateComment(reader.Value.ToString()); - v.SetLineInfo(lineInfo); + v.SetLineInfo(lineInfo, settings); return v; case JsonToken.Null: v = JValue.CreateNull(); - v.SetLineInfo(lineInfo); + v.SetLineInfo(lineInfo, settings); return v; case JsonToken.Undefined: v = JValue.CreateUndefined(); - v.SetLineInfo(lineInfo); + v.SetLineInfo(lineInfo, settings); return v; default: throw JsonReaderException.Create(reader, "Error reading JToken from JsonReader. Unexpected token: {0}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType)); @@ -1982,10 +1986,17 @@ namespace Newtonsoft.Json.Linq return Load(reader, null); } - internal void SetLineInfo(IJsonLineInfo lineInfo) + internal void SetLineInfo(IJsonLineInfo lineInfo, JsonLoadSettings settings) { - if (lineInfo == null || !lineInfo.HasLineInfo()) + if (settings != null && settings.LineInfoHandling == LineInfoHandling.Load) + { return; + } + + if (lineInfo == null || !lineInfo.HasLineInfo()) + { + return; + } SetLineInfo(lineInfo.LineNumber, lineInfo.LinePosition); } diff --git a/Src/Newtonsoft.Json/Linq/JsonLoadSettings.cs b/Src/Newtonsoft.Json/Linq/JsonLoadSettings.cs index b3170260..4b5dd370 100644 --- a/Src/Newtonsoft.Json/Linq/JsonLoadSettings.cs +++ b/Src/Newtonsoft.Json/Linq/JsonLoadSettings.cs @@ -8,6 +8,7 @@ namespace Newtonsoft.Json.Linq public class JsonLoadSettings { private CommentHandling _commentHandling; + private LineInfoHandling _lineInfoHandling; /// /// Gets or sets how JSON comments are handled when loading JSON. @@ -26,5 +27,23 @@ namespace Newtonsoft.Json.Linq _commentHandling = value; } } + + /// + /// Gets or sets how JSON line info is handled when loading JSON. + /// + /// The JSON line info handling. + public LineInfoHandling LineInfoHandling + { + get { return _lineInfoHandling; } + set + { + if (value < LineInfoHandling.Ignore || value > LineInfoHandling.Load) + { + throw new ArgumentOutOfRangeException("value"); + } + + _lineInfoHandling = value; + } + } } } \ No newline at end of file