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 26 using System; 27 using Newtonsoft.Json.Utilities; 28 29 namespace Newtonsoft.Json.Linq 30 { 31 /// <summary> 32 /// Represents a reader that provides fast, non-cached, forward-only access to serialized Json data. 33 /// </summary> 34 public class JTokenReader : JsonReader, IJsonLineInfo 35 { 36 private readonly JToken _root; 37 private JToken _parent; 38 private JToken _current; 39 40 /// <summary> 41 /// Initializes a new instance of the <see cref="JTokenReader"/> class. 42 /// </summary> 43 /// <param name="token">The token to read from.</param> JTokenReader(JToken token)44 public JTokenReader(JToken token) 45 { 46 ValidationUtils.ArgumentNotNull(token, "token"); 47 48 _root = token; 49 _current = token; 50 } 51 52 /// <summary> 53 /// Reads the next JSON token from the stream as a <see cref="T:Byte[]"/>. 54 /// </summary> 55 /// <returns> 56 /// A <see cref="T:Byte[]"/> or a null reference if the next JSON token is null. This method will return <c>null</c> at the end of an array. 57 /// </returns> ReadAsBytes()58 public override byte[] ReadAsBytes() 59 { 60 return ReadAsBytesInternal(); 61 } 62 63 /// <summary> 64 /// Reads the next JSON token from the stream as a <see cref="Nullable{Decimal}"/>. 65 /// </summary> 66 /// <returns>A <see cref="Nullable{Decimal}"/>. This method will return <c>null</c> at the end of an array.</returns> ReadAsDecimal()67 public override decimal? ReadAsDecimal() 68 { 69 return ReadAsDecimalInternal(); 70 } 71 72 /// <summary> 73 /// Reads the next JSON token from the stream as a <see cref="Nullable{Int32}"/>. 74 /// </summary> 75 /// <returns>A <see cref="Nullable{Int32}"/>. This method will return <c>null</c> at the end of an array.</returns> ReadAsInt32()76 public override int? ReadAsInt32() 77 { 78 return ReadAsInt32Internal(); 79 } 80 81 /// <summary> 82 /// Reads the next JSON token from the stream as a <see cref="String"/>. 83 /// </summary> 84 /// <returns>A <see cref="String"/>. This method will return <c>null</c> at the end of an array.</returns> ReadAsString()85 public override string ReadAsString() 86 { 87 return ReadAsStringInternal(); 88 } 89 90 /// <summary> 91 /// Reads the next JSON token from the stream as a <see cref="Nullable{DateTime}"/>. 92 /// </summary> 93 /// <returns>A <see cref="String"/>. This method will return <c>null</c> at the end of an array.</returns> ReadAsDateTime()94 public override DateTime? ReadAsDateTime() 95 { 96 return ReadAsDateTimeInternal(); 97 } 98 99 #if !NET20 100 /// <summary> 101 /// Reads the next JSON token from the stream as a <see cref="Nullable{DateTimeOffset}"/>. 102 /// </summary> 103 /// <returns>A <see cref="Nullable{DateTimeOffset}"/>. This method will return <c>null</c> at the end of an array.</returns> ReadAsDateTimeOffset()104 public override DateTimeOffset? ReadAsDateTimeOffset() 105 { 106 return ReadAsDateTimeOffsetInternal(); 107 } 108 #endif 109 ReadInternal()110 internal override bool ReadInternal() 111 { 112 if (CurrentState != State.Start) 113 { 114 JContainer container = _current as JContainer; 115 if (container != null && _parent != container) 116 return ReadInto(container); 117 else 118 return ReadOver(_current); 119 } 120 121 SetToken(_current); 122 return true; 123 } 124 125 /// <summary> 126 /// Reads the next JSON token from the stream. 127 /// </summary> 128 /// <returns> 129 /// true if the next token was read successfully; false if there are no more tokens to read. 130 /// </returns> Read()131 public override bool Read() 132 { 133 _readType = ReadType.Read; 134 135 return ReadInternal(); 136 } 137 ReadOver(JToken t)138 private bool ReadOver(JToken t) 139 { 140 if (t == _root) 141 return ReadToEnd(); 142 143 JToken next = t.Next; 144 if ((next == null || next == t) || t == t.Parent.Last) 145 { 146 if (t.Parent == null) 147 return ReadToEnd(); 148 149 return SetEnd(t.Parent); 150 } 151 else 152 { 153 _current = next; 154 SetToken(_current); 155 return true; 156 } 157 } 158 ReadToEnd()159 private bool ReadToEnd() 160 { 161 SetToken(JsonToken.None); 162 return false; 163 } 164 165 private bool IsEndElement 166 { 167 get { return (_current == _parent); } 168 } 169 GetEndToken(JContainer c)170 private JsonToken? GetEndToken(JContainer c) 171 { 172 switch (c.Type) 173 { 174 case JTokenType.Object: 175 return JsonToken.EndObject; 176 case JTokenType.Array: 177 return JsonToken.EndArray; 178 case JTokenType.Constructor: 179 return JsonToken.EndConstructor; 180 case JTokenType.Property: 181 return null; 182 default: 183 throw MiscellaneousUtils.CreateArgumentOutOfRangeException("Type", c.Type, "Unexpected JContainer type."); 184 } 185 } 186 ReadInto(JContainer c)187 private bool ReadInto(JContainer c) 188 { 189 JToken firstChild = c.First; 190 if (firstChild == null) 191 { 192 return SetEnd(c); 193 } 194 else 195 { 196 SetToken(firstChild); 197 _current = firstChild; 198 _parent = c; 199 return true; 200 } 201 } 202 SetEnd(JContainer c)203 private bool SetEnd(JContainer c) 204 { 205 JsonToken? endToken = GetEndToken(c); 206 if (endToken != null) 207 { 208 SetToken(endToken.Value); 209 _current = c; 210 _parent = c; 211 return true; 212 } 213 else 214 { 215 return ReadOver(c); 216 } 217 } 218 SetToken(JToken token)219 private void SetToken(JToken token) 220 { 221 switch (token.Type) 222 { 223 case JTokenType.Object: 224 SetToken(JsonToken.StartObject); 225 break; 226 case JTokenType.Array: 227 SetToken(JsonToken.StartArray); 228 break; 229 case JTokenType.Constructor: 230 SetToken(JsonToken.StartConstructor); 231 break; 232 case JTokenType.Property: 233 SetToken(JsonToken.PropertyName, ((JProperty)token).Name); 234 break; 235 case JTokenType.Comment: 236 SetToken(JsonToken.Comment, ((JValue)token).Value); 237 break; 238 case JTokenType.Integer: 239 SetToken(JsonToken.Integer, ((JValue)token).Value); 240 break; 241 case JTokenType.Float: 242 SetToken(JsonToken.Float, ((JValue)token).Value); 243 break; 244 case JTokenType.String: 245 SetToken(JsonToken.String, ((JValue)token).Value); 246 break; 247 case JTokenType.Boolean: 248 SetToken(JsonToken.Boolean, ((JValue)token).Value); 249 break; 250 case JTokenType.Null: 251 SetToken(JsonToken.Null, ((JValue)token).Value); 252 break; 253 case JTokenType.Undefined: 254 SetToken(JsonToken.Undefined, ((JValue)token).Value); 255 break; 256 case JTokenType.Date: 257 SetToken(JsonToken.Date, ((JValue)token).Value); 258 break; 259 case JTokenType.Raw: 260 SetToken(JsonToken.Raw, ((JValue)token).Value); 261 break; 262 case JTokenType.Bytes: 263 SetToken(JsonToken.Bytes, ((JValue)token).Value); 264 break; 265 case JTokenType.Guid: 266 SetToken(JsonToken.String, SafeToString(((JValue)token).Value)); 267 break; 268 case JTokenType.Uri: 269 SetToken(JsonToken.String, SafeToString(((JValue)token).Value)); 270 break; 271 case JTokenType.TimeSpan: 272 SetToken(JsonToken.String, SafeToString(((JValue)token).Value)); 273 break; 274 default: 275 throw MiscellaneousUtils.CreateArgumentOutOfRangeException("Type", token.Type, "Unexpected JTokenType."); 276 } 277 } 278 SafeToString(object value)279 private string SafeToString(object value) 280 { 281 return (value != null) ? value.ToString() : null; 282 } 283 IJsonLineInfo.HasLineInfo()284 bool IJsonLineInfo.HasLineInfo() 285 { 286 if (CurrentState == State.Start) 287 return false; 288 289 IJsonLineInfo info = IsEndElement ? null : _current; 290 return (info != null && info.HasLineInfo()); 291 } 292 293 int IJsonLineInfo.LineNumber 294 { 295 get 296 { 297 if (CurrentState == State.Start) 298 return 0; 299 300 IJsonLineInfo info = IsEndElement ? null : _current; 301 if (info != null) 302 return info.LineNumber; 303 304 return 0; 305 } 306 } 307 308 int IJsonLineInfo.LinePosition 309 { 310 get 311 { 312 if (CurrentState == State.Start) 313 return 0; 314 315 IJsonLineInfo info = IsEndElement ? null : _current; 316 if (info != null) 317 return info.LinePosition; 318 319 return 0; 320 } 321 } 322 } 323 }