/Newtonsoft.Json/Linq/JTokenReader.cs

https://github.com/ayoung/Newtonsoft.Json · C# · 303 lines · 241 code · 33 blank · 29 comment · 53 complexity · 1c055cd295f01604f771c4b587b8f719 MD5 · raw file

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using Newtonsoft.Json.Utilities;
  6. using System.Globalization;
  7. namespace Newtonsoft.Json.Linq
  8. {
  9. /// <summary>
  10. /// Represents a reader that provides fast, non-cached, forward-only access to serialized Json data.
  11. /// </summary>
  12. public class JTokenReader : JsonReader, IJsonLineInfo
  13. {
  14. private readonly JToken _root;
  15. private JToken _parent;
  16. private JToken _current;
  17. /// <summary>
  18. /// Initializes a new instance of the <see cref="JTokenReader"/> class.
  19. /// </summary>
  20. /// <param name="token">The token to read from.</param>
  21. public JTokenReader(JToken token)
  22. {
  23. ValidationUtils.ArgumentNotNull(token, "token");
  24. _root = token;
  25. _current = token;
  26. }
  27. /// <summary>
  28. /// Reads the next JSON token from the stream as a <see cref="T:Byte[]"/>.
  29. /// </summary>
  30. /// <returns>
  31. /// A <see cref="T:Byte[]"/> or a null reference if the next JSON token is null.
  32. /// </returns>
  33. public override byte[] ReadAsBytes()
  34. {
  35. Read();
  36. // attempt to convert possible base 64 string to bytes
  37. if (TokenType == JsonToken.String)
  38. {
  39. string s = (string) Value;
  40. byte[] data = (s.Length == 0) ? new byte[0] : Convert.FromBase64String(s);
  41. SetToken(JsonToken.Bytes, data);
  42. }
  43. if (TokenType == JsonToken.Null)
  44. return null;
  45. if (TokenType == JsonToken.Bytes)
  46. return (byte[])Value;
  47. throw new JsonReaderException("Error reading bytes. Expected bytes but got {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
  48. }
  49. /// <summary>
  50. /// Reads the next JSON token from the stream as a <see cref="Nullable{Decimal}"/>.
  51. /// </summary>
  52. /// <returns>A <see cref="Nullable{Decimal}"/>.</returns>
  53. public override decimal? ReadAsDecimal()
  54. {
  55. Read();
  56. if (TokenType == JsonToken.Null)
  57. return null;
  58. if (TokenType == JsonToken.Integer || TokenType == JsonToken.Float)
  59. {
  60. SetToken(JsonToken.Float, Convert.ToDecimal(Value, CultureInfo.InvariantCulture));
  61. return (decimal) Value;
  62. }
  63. throw new JsonReaderException("Error reading decimal. Expected a number but got {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
  64. }
  65. #if !NET20
  66. /// <summary>
  67. /// Reads the next JSON token from the stream as a <see cref="Nullable{DateTimeOffset}"/>.
  68. /// </summary>
  69. /// <returns>A <see cref="Nullable{DateTimeOffset}"/>.</returns>
  70. public override DateTimeOffset? ReadAsDateTimeOffset()
  71. {
  72. Read();
  73. if (TokenType == JsonToken.Null)
  74. return null;
  75. if (TokenType == JsonToken.Date)
  76. {
  77. SetToken(JsonToken.Date, new DateTimeOffset((DateTime)Value));
  78. return (DateTimeOffset)Value;
  79. }
  80. throw new JsonReaderException("Error reading date. Expected bytes but got {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
  81. }
  82. #endif
  83. /// <summary>
  84. /// Reads the next JSON token from the stream.
  85. /// </summary>
  86. /// <returns>
  87. /// true if the next token was read successfully; false if there are no more tokens to read.
  88. /// </returns>
  89. public override bool Read()
  90. {
  91. if (CurrentState != State.Start)
  92. {
  93. JContainer container = _current as JContainer;
  94. if (container != null && _parent != container)
  95. return ReadInto(container);
  96. else
  97. return ReadOver(_current);
  98. }
  99. SetToken(_current);
  100. return true;
  101. }
  102. private bool ReadOver(JToken t)
  103. {
  104. if (t == _root)
  105. return ReadToEnd();
  106. JToken next = t.Next;
  107. if ((next == null || next == t) || t == t.Parent.Last)
  108. {
  109. if (t.Parent == null)
  110. return ReadToEnd();
  111. return SetEnd(t.Parent);
  112. }
  113. else
  114. {
  115. _current = next;
  116. SetToken(_current);
  117. return true;
  118. }
  119. }
  120. private bool ReadToEnd()
  121. {
  122. //CurrentState = State.Finished;
  123. return false;
  124. }
  125. private bool IsEndElement
  126. {
  127. get { return (_current == _parent); }
  128. }
  129. private JsonToken? GetEndToken(JContainer c)
  130. {
  131. switch (c.Type)
  132. {
  133. case JTokenType.Object:
  134. return JsonToken.EndObject;
  135. case JTokenType.Array:
  136. return JsonToken.EndArray;
  137. case JTokenType.Constructor:
  138. return JsonToken.EndConstructor;
  139. case JTokenType.Property:
  140. return null;
  141. default:
  142. throw MiscellaneousUtils.CreateArgumentOutOfRangeException("Type", c.Type, "Unexpected JContainer type.");
  143. }
  144. }
  145. private bool ReadInto(JContainer c)
  146. {
  147. JToken firstChild = c.First;
  148. if (firstChild == null)
  149. {
  150. return SetEnd(c);
  151. }
  152. else
  153. {
  154. SetToken(firstChild);
  155. _current = firstChild;
  156. _parent = c;
  157. return true;
  158. }
  159. }
  160. private bool SetEnd(JContainer c)
  161. {
  162. JsonToken? endToken = GetEndToken(c);
  163. if (endToken != null)
  164. {
  165. SetToken(endToken.Value);
  166. _current = c;
  167. _parent = c;
  168. return true;
  169. }
  170. else
  171. {
  172. return ReadOver(c);
  173. }
  174. }
  175. private void SetToken(JToken token)
  176. {
  177. switch (token.Type)
  178. {
  179. case JTokenType.Object:
  180. SetToken(JsonToken.StartObject);
  181. break;
  182. case JTokenType.Array:
  183. SetToken(JsonToken.StartArray);
  184. break;
  185. case JTokenType.Constructor:
  186. SetToken(JsonToken.StartConstructor);
  187. break;
  188. case JTokenType.Property:
  189. SetToken(JsonToken.PropertyName, ((JProperty)token).Name);
  190. break;
  191. case JTokenType.Comment:
  192. SetToken(JsonToken.Comment, ((JValue)token).Value);
  193. break;
  194. case JTokenType.Integer:
  195. SetToken(JsonToken.Integer, ((JValue)token).Value);
  196. break;
  197. case JTokenType.Float:
  198. SetToken(JsonToken.Float, ((JValue)token).Value);
  199. break;
  200. case JTokenType.String:
  201. SetToken(JsonToken.String, ((JValue)token).Value);
  202. break;
  203. case JTokenType.Boolean:
  204. SetToken(JsonToken.Boolean, ((JValue)token).Value);
  205. break;
  206. case JTokenType.Null:
  207. SetToken(JsonToken.Null, ((JValue)token).Value);
  208. break;
  209. case JTokenType.Undefined:
  210. SetToken(JsonToken.Undefined, ((JValue)token).Value);
  211. break;
  212. case JTokenType.Date:
  213. SetToken(JsonToken.Date, ((JValue)token).Value);
  214. break;
  215. case JTokenType.Raw:
  216. SetToken(JsonToken.Raw, ((JValue)token).Value);
  217. break;
  218. case JTokenType.Bytes:
  219. SetToken(JsonToken.Bytes, ((JValue)token).Value);
  220. break;
  221. case JTokenType.Guid:
  222. SetToken(JsonToken.String, SafeToString(((JValue)token).Value));
  223. break;
  224. case JTokenType.Uri:
  225. SetToken(JsonToken.String, SafeToString(((JValue)token).Value));
  226. break;
  227. case JTokenType.TimeSpan:
  228. SetToken(JsonToken.String, SafeToString(((JValue)token).Value));
  229. break;
  230. default:
  231. throw MiscellaneousUtils.CreateArgumentOutOfRangeException("Type", token.Type, "Unexpected JTokenType.");
  232. }
  233. }
  234. private string SafeToString(object value)
  235. {
  236. return (value != null) ? value.ToString() : null;
  237. }
  238. bool IJsonLineInfo.HasLineInfo()
  239. {
  240. if (CurrentState == State.Start)
  241. return false;
  242. IJsonLineInfo info = IsEndElement ? null : _current;
  243. return (info != null && info.HasLineInfo());
  244. }
  245. int IJsonLineInfo.LineNumber
  246. {
  247. get
  248. {
  249. if (CurrentState == State.Start)
  250. return 0;
  251. IJsonLineInfo info = IsEndElement ? null : _current;
  252. if (info != null)
  253. return info.LineNumber;
  254. return 0;
  255. }
  256. }
  257. int IJsonLineInfo.LinePosition
  258. {
  259. get
  260. {
  261. if (CurrentState == State.Start)
  262. return 0;
  263. IJsonLineInfo info = IsEndElement ? null : _current;
  264. if (info != null)
  265. return info.LinePosition;
  266. return 0;
  267. }
  268. }
  269. }
  270. }