You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

176 lines
5.8 KiB

  1. #region License
  2. // Copyright (c) 2007 James Newton-King
  3. //
  4. // Permission is hereby granted, free of charge, to any person
  5. // obtaining a copy of this software and associated documentation
  6. // files (the "Software"), to deal in the Software without
  7. // restriction, including without limitation the rights to use,
  8. // copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the
  10. // Software is furnished to do so, subject to the following
  11. // conditions:
  12. //
  13. // The above copyright notice and this permission notice shall be
  14. // included in all copies or substantial portions of the Software.
  15. //
  16. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  17. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  18. // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  19. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  20. // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  21. // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  22. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  23. // OTHER DEALINGS IN THE SOFTWARE.
  24. #endregion
  25. using System;
  26. using System.Collections.Generic;
  27. using System.Globalization;
  28. using System.IO;
  29. using System.Text;
  30. using Newtonsoft.Json.Utilities;
  31. namespace Newtonsoft.Json
  32. {
  33. internal enum JsonContainerType
  34. {
  35. None = 0,
  36. Object = 1,
  37. Array = 2,
  38. Constructor = 3
  39. }
  40. internal struct JsonPosition
  41. {
  42. private static readonly char[] SpecialCharacters = { '.', ' ', '\'', '/', '"', '[', ']', '(', ')', '\t', '\n', '\r', '\f', '\b', '\\', '\u0085', '\u2028', '\u2029' };
  43. internal JsonContainerType Type;
  44. internal int Position;
  45. internal string PropertyName;
  46. internal bool HasIndex;
  47. public JsonPosition(JsonContainerType type)
  48. {
  49. Type = type;
  50. HasIndex = TypeHasIndex(type);
  51. Position = -1;
  52. PropertyName = null;
  53. }
  54. internal int CalculateLength()
  55. {
  56. switch (Type)
  57. {
  58. case JsonContainerType.Object:
  59. return PropertyName.Length + 5;
  60. case JsonContainerType.Array:
  61. case JsonContainerType.Constructor:
  62. return MathUtils.IntLength((ulong)Position) + 2;
  63. default:
  64. throw new ArgumentOutOfRangeException(nameof(Type));
  65. }
  66. }
  67. internal void WriteTo(StringBuilder sb, ref StringWriter writer, ref char[] buffer)
  68. {
  69. switch (Type)
  70. {
  71. case JsonContainerType.Object:
  72. string propertyName = PropertyName;
  73. if (propertyName.IndexOfAny(SpecialCharacters) != -1)
  74. {
  75. sb.Append(@"['");
  76. if (writer == null)
  77. {
  78. writer = new StringWriter(sb);
  79. }
  80. JavaScriptUtils.WriteEscapedJavaScriptString(writer, propertyName, '\'', false, JavaScriptUtils.SingleQuoteCharEscapeFlags, StringEscapeHandling.Default, null, ref buffer);
  81. sb.Append(@"']");
  82. }
  83. else
  84. {
  85. if (sb.Length > 0)
  86. {
  87. sb.Append('.');
  88. }
  89. sb.Append(propertyName);
  90. }
  91. break;
  92. case JsonContainerType.Array:
  93. case JsonContainerType.Constructor:
  94. sb.Append('[');
  95. sb.Append(Position);
  96. sb.Append(']');
  97. break;
  98. }
  99. }
  100. internal static bool TypeHasIndex(JsonContainerType type)
  101. {
  102. return (type == JsonContainerType.Array || type == JsonContainerType.Constructor);
  103. }
  104. internal static string BuildPath(List<JsonPosition> positions, JsonPosition? currentPosition)
  105. {
  106. int capacity = 0;
  107. if (positions != null)
  108. {
  109. for (int i = 0; i < positions.Count; i++)
  110. {
  111. capacity += positions[i].CalculateLength();
  112. }
  113. }
  114. if (currentPosition != null)
  115. {
  116. capacity += currentPosition.GetValueOrDefault().CalculateLength();
  117. }
  118. StringBuilder sb = new StringBuilder(capacity);
  119. StringWriter writer = null;
  120. char[] buffer = null;
  121. if (positions != null)
  122. {
  123. foreach (JsonPosition state in positions)
  124. {
  125. state.WriteTo(sb, ref writer, ref buffer);
  126. }
  127. }
  128. if (currentPosition != null)
  129. {
  130. currentPosition.GetValueOrDefault().WriteTo(sb, ref writer, ref buffer);
  131. }
  132. return sb.ToString();
  133. }
  134. internal static string FormatMessage(IJsonLineInfo lineInfo, string path, string message)
  135. {
  136. // don't add a fullstop and space when message ends with a new line
  137. if (!message.EndsWith(Environment.NewLine, StringComparison.Ordinal))
  138. {
  139. message = message.Trim();
  140. if (!message.EndsWith('.'))
  141. {
  142. message += ".";
  143. }
  144. message += " ";
  145. }
  146. message += "Path '{0}'".FormatWith(CultureInfo.InvariantCulture, path);
  147. if (lineInfo != null && lineInfo.HasLineInfo())
  148. {
  149. message += ", line {0}, position {1}".FormatWith(CultureInfo.InvariantCulture, lineInfo.LineNumber, lineInfo.LinePosition);
  150. }
  151. message += ".";
  152. return message;
  153. }
  154. }
  155. }