PetaJson.cs 61 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.IO;
  6. using System.Reflection;
  7. using System.Globalization;
  8. using System.Collections;
  9. #if SIMPLEJSON_DYNAMIC
  10. using System.Dynamic;
  11. #endif
  12. namespace PetaJson
  13. {
  14. public static class Json
  15. {
  16. // Write an object to a text writer
  17. public static void Write(TextWriter w, object o)
  18. {
  19. var writer = new Internal.Writer(w);
  20. writer.WriteValue(o);
  21. }
  22. // Write an object to a file
  23. public static void WriteFile(string filename, object o)
  24. {
  25. using (var w = new StreamWriter(filename))
  26. {
  27. Write(w, o);
  28. }
  29. }
  30. // Format an object as a json string
  31. public static string Format(object o)
  32. {
  33. var sw = new StringWriter();
  34. var writer = new Internal.Writer(sw);
  35. writer.WriteValue(o);
  36. return sw.ToString();
  37. }
  38. // Parse an object of specified type from a text reader
  39. public static object Parse(TextReader r, Type type)
  40. {
  41. Internal.Reader reader = null;
  42. try
  43. {
  44. reader = new Internal.Reader(r);
  45. var retv = reader.Parse(type);
  46. reader.CheckEOF();
  47. return retv;
  48. }
  49. catch (Exception x)
  50. {
  51. throw new JsonParseException(x, reader==null ? new JsonLineOffset() : reader.CurrentTokenPosition);
  52. }
  53. }
  54. // Parse an object of specified type from a text reader
  55. public static T Parse<T>(TextReader r)
  56. {
  57. return (T)Parse(r, typeof(T));
  58. }
  59. // Parse from text reader into an already instantied object
  60. public static void ParseInto(TextReader r, Object into)
  61. {
  62. Internal.Reader reader = null;
  63. try
  64. {
  65. reader = new Internal.Reader(r);
  66. reader.ParseInto(into);
  67. reader.CheckEOF();
  68. }
  69. catch (Exception x)
  70. {
  71. throw new JsonParseException(x, reader==null ? new JsonLineOffset() : reader.CurrentTokenPosition);
  72. }
  73. }
  74. // Parse an object of specified type from a text reader
  75. public static object ParseFile(string filename, Type type)
  76. {
  77. using (var r = new StreamReader(filename))
  78. {
  79. return Parse(r, type);
  80. }
  81. }
  82. // Parse an object of specified type from a text reader
  83. public static T ParseFile<T>(string filename)
  84. {
  85. using (var r = new StreamReader(filename))
  86. {
  87. return Parse<T>(r);
  88. }
  89. }
  90. // Parse from text reader into an already instantied object
  91. public static void ParseFileInto(string filename, Object into)
  92. {
  93. using (var r = new StreamReader(filename))
  94. {
  95. ParseInto(r, into);
  96. }
  97. }
  98. // Parse an object from a string
  99. public static object Parse(string data, Type type)
  100. {
  101. return Parse(new StringReader(data), type);
  102. }
  103. // Parse an object from a string
  104. public static T Parse<T>(string data)
  105. {
  106. return (T)Parse<T>(new StringReader(data));
  107. }
  108. // Parse from string into an already instantiated object
  109. public static void ParseInto(string data, Object into)
  110. {
  111. ParseInto(new StringReader(data), into);
  112. }
  113. public static T Clone<T>(T source)
  114. {
  115. return (T)Clone((object)source);
  116. }
  117. public static object Clone(object source)
  118. {
  119. if (source == null)
  120. return null;
  121. return Parse(Format(source), source.GetType());
  122. }
  123. public static void CloneInto<T>(T dest, T source)
  124. {
  125. ParseInto(Format(source), dest);
  126. }
  127. // Register a callback that can format a value of a particular type into json
  128. public static void RegisterFormatter(Type type, Action<IJsonWriter, object> formatter)
  129. {
  130. Internal.Writer._typeWriters[type] = formatter;
  131. }
  132. // Typed version of above
  133. public static void RegisterFormatter<T>(Action<IJsonWriter, T> formatter)
  134. {
  135. RegisterFormatter(typeof(T), (w, o) => formatter(w, (T)o));
  136. }
  137. // Register a parser for a specified type
  138. public static void RegisterParser(Type type, Func<IJsonReader, Type, object> parser)
  139. {
  140. Internal.Reader._typeReaders[type] = parser;
  141. }
  142. // Register a typed parser
  143. public static void RegisterParser<T>(Func<IJsonReader, Type, T> parser)
  144. {
  145. RegisterParser(typeof(T), (r, t) => parser(r, t));
  146. }
  147. // Simpler version for simple types
  148. public static void RegisterParser(Type type, Func<object, object> parser)
  149. {
  150. RegisterParser(type, (r, t) => r.ReadLiteral(parser));
  151. }
  152. // Simpler and typesafe parser for simple types
  153. public static void RegisterParser<T>(Func<object, T> parser)
  154. {
  155. RegisterParser(typeof(T), literal => parser(literal));
  156. }
  157. // Register a factory for instantiating objects (typically abstract classes)
  158. // Callback will be invoked for each key in the dictionary until it returns an object
  159. // instance and which point it will switch to serialization using reflection
  160. public static void RegisterTypeFactory(Type type, Func<IJsonReader, string, object> factory)
  161. {
  162. Internal.Reader._typeFactories[type] = factory;
  163. }
  164. }
  165. // Called before loading via reflection
  166. public interface IJsonLoading
  167. {
  168. void OnJsonLoading(IJsonReader r);
  169. }
  170. // Called after loading via reflection
  171. public interface IJsonLoaded
  172. {
  173. void OnJsonLoaded(IJsonReader r);
  174. }
  175. // Called for each field while loading from reflection
  176. // Return true if handled
  177. public interface IJsonLoadField
  178. {
  179. bool OnJsonField(IJsonReader r, string key);
  180. }
  181. // Called when about to write using reflection
  182. public interface IJsonWriting
  183. {
  184. void OnJsonWriting(IJsonWriter w);
  185. }
  186. // Called after written using reflection
  187. public interface IJsonWritten
  188. {
  189. void OnJsonWritten(IJsonWriter w);
  190. }
  191. // Passed to registered parsers
  192. public interface IJsonReader
  193. {
  194. object ReadLiteral(Func<object, object> converter);
  195. object Parse(Type type);
  196. T Parse<T>();
  197. void ReadDictionary(Action<string> callback);
  198. void ReadArray(Action callback);
  199. }
  200. // Passed to registered formatters
  201. public interface IJsonWriter
  202. {
  203. void WriteStringLiteral(string str);
  204. void WriteRaw(string str);
  205. void WriteArray(Action callback);
  206. void WriteDictionary(Action callback);
  207. void WriteValue(object value);
  208. void WriteElement();
  209. void WriteKey(string key);
  210. }
  211. public class JsonParseException : Exception
  212. {
  213. public JsonParseException(Exception inner, JsonLineOffset position) :
  214. base(string.Format("Json parse error at {0} - {1}", position, inner.Message), inner)
  215. {
  216. }
  217. }
  218. public struct JsonLineOffset
  219. {
  220. public int Line;
  221. public int Offset;
  222. public override string ToString()
  223. {
  224. return string.Format("line {0}, position {1}", Line + 1, Offset + 1);
  225. }
  226. }
  227. // Used to decorate fields and properties that should be serialized
  228. //
  229. // - [Json] on class or struct causes all public fields and properties to be serialized
  230. // - [Json] on a public or non-public field or property causes that member to be serialized
  231. // - [JsonExclude] on a field or property causes that field to be not serialized
  232. // - A class or struct with no [Json] attribute has all public fields/properties serialized
  233. // - A class or struct with no [Json] attribute but a [Json] attribute on one or more members only serializes those members
  234. //
  235. // Use [Json("keyname")] to explicitly specify the key to be used
  236. // [Json] without the keyname will be serialized using the name of the member with the first letter lowercased.
  237. //
  238. // [Json(KeepInstance=true)] causes container/subobject types to be serialized into the existing member instance (if not null)
  239. //
  240. [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Property | AttributeTargets.Field)]
  241. public class JsonAttribute : Attribute
  242. {
  243. public JsonAttribute()
  244. {
  245. _key = null;
  246. }
  247. public JsonAttribute(string key)
  248. {
  249. _key = key;
  250. }
  251. string _key;
  252. public string Key
  253. {
  254. get { return _key; }
  255. }
  256. public bool KeepInstance
  257. {
  258. get;
  259. set;
  260. }
  261. }
  262. // See comments above
  263. [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
  264. public class JsonExcludeAttribute : Attribute
  265. {
  266. public JsonExcludeAttribute()
  267. {
  268. }
  269. }
  270. namespace Internal
  271. {
  272. public enum Token
  273. {
  274. EOF,
  275. Identifier,
  276. Literal,
  277. OpenBrace,
  278. CloseBrace,
  279. OpenSquare,
  280. CloseSquare,
  281. Equal,
  282. Colon,
  283. SemiColon,
  284. Comma,
  285. }
  286. public class Reader : IJsonReader
  287. {
  288. static Reader()
  289. {
  290. Func<IJsonReader, Type, object> simpleConverter = (reader, type) =>
  291. {
  292. return reader.ReadLiteral(literal => Convert.ChangeType(literal, type, CultureInfo.InvariantCulture));
  293. };
  294. _typeReaders.Add(typeof(string), simpleConverter);
  295. _typeReaders.Add(typeof(char), simpleConverter);
  296. _typeReaders.Add(typeof(bool), simpleConverter);
  297. _typeReaders.Add(typeof(byte), simpleConverter);
  298. _typeReaders.Add(typeof(sbyte), simpleConverter);
  299. _typeReaders.Add(typeof(short), simpleConverter);
  300. _typeReaders.Add(typeof(ushort), simpleConverter);
  301. _typeReaders.Add(typeof(int), simpleConverter);
  302. _typeReaders.Add(typeof(uint), simpleConverter);
  303. _typeReaders.Add(typeof(long), simpleConverter);
  304. _typeReaders.Add(typeof(ulong), simpleConverter);
  305. _typeReaders.Add(typeof(decimal), simpleConverter);
  306. _typeReaders.Add(typeof(float), simpleConverter);
  307. _typeReaders.Add(typeof(double), simpleConverter);
  308. _typeReaders.Add(typeof(DateTime), (reader, type) =>
  309. {
  310. return reader.ReadLiteral(literal => Utils.FromUnixMilliseconds((long)Convert.ChangeType(literal, typeof(long), CultureInfo.InvariantCulture)));
  311. });
  312. _typeReaders.Add(typeof(byte[]), (reader, type) =>
  313. {
  314. return reader.ReadLiteral(literal => Convert.FromBase64String((string)Convert.ChangeType(literal, typeof(string), CultureInfo.InvariantCulture)));
  315. });
  316. }
  317. public Reader(TextReader r)
  318. {
  319. _tokenizer = new Tokenizer(r);
  320. }
  321. Tokenizer _tokenizer;
  322. public JsonLineOffset CurrentTokenPosition
  323. {
  324. get { return _tokenizer.CurrentTokenPosition; }
  325. }
  326. // ReadLiteral is implemented with a converter callback so that any
  327. // errors on converting to the target type are thrown before the tokenizer
  328. // is advanced to the next token. This ensures error location is reported
  329. // at the start of the literal, not the following token.
  330. public object ReadLiteral(Func<object, object> converter)
  331. {
  332. _tokenizer.Check(Token.Literal);
  333. var retv = converter(_tokenizer.Literal);
  334. _tokenizer.NextToken();
  335. return retv;
  336. }
  337. public void CheckEOF()
  338. {
  339. _tokenizer.Check(Token.EOF);
  340. }
  341. public object Parse(Type type)
  342. {
  343. // Null?
  344. if (_tokenizer.CurrentToken == Token.Literal && _tokenizer.Literal == null)
  345. {
  346. _tokenizer.NextToken();
  347. return null;
  348. }
  349. // Handle nullable types
  350. var typeUnderlying = Nullable.GetUnderlyingType(type);
  351. if (typeUnderlying != null)
  352. type = typeUnderlying;
  353. // See if we have a reader
  354. Func<IJsonReader, Type, object> typeReader;
  355. if (Reader._typeReaders.TryGetValue(type, out typeReader))
  356. {
  357. return typeReader(this, type);
  358. }
  359. // Enumerated type?
  360. if (type.IsEnum)
  361. {
  362. return ReadLiteral(literal => Enum.Parse(type, (string)literal));
  363. }
  364. // See if we have factory
  365. Func<IJsonReader, string, object> typeFactory;
  366. if (Reader._typeFactories.TryGetValue(type, out typeFactory))
  367. {
  368. // Try first without passing dictionary keys
  369. object into = typeFactory(this, null);
  370. if (into == null)
  371. {
  372. // This is a awkward situation. The factory requires a value from the dictionary
  373. // in order to create the target object (typically an abstract class with the class
  374. // kind recorded in the Json). Since there's no guarantee of order in a json dictionary
  375. // we can't assume the required key is first.
  376. // So, create a bookmark on the tokenizer, read keys until the factory returns an
  377. // object instance and then rewind the tokenizer and continue
  378. // Create a bookmark so we can rewind
  379. _tokenizer.CreateBookmark();
  380. // Skip the opening brace
  381. _tokenizer.Skip(Token.OpenBrace);
  382. // First pass to work out type
  383. ReadDictionaryKeys(key =>
  384. {
  385. // Try to instantiate the object
  386. into = typeFactory(this, key);
  387. return into == null;
  388. });
  389. // Move back to start of the dictionary
  390. _tokenizer.RewindToBookmark();
  391. // Quit if still didn't get an object from the factory
  392. if (into == null)
  393. throw new InvalidOperationException("Factory didn't create object instance (probably due to a missing key in the Json)");
  394. }
  395. // Second pass
  396. ParseInto(into);
  397. // Done
  398. return into;
  399. }
  400. // Is it a type we can parse into?
  401. if (CanParseInto(type))
  402. {
  403. var into = Activator.CreateInstance(type);
  404. ParseInto(into);
  405. return into;
  406. }
  407. // Array?
  408. if (type.IsArray && type.GetArrayRank() == 1)
  409. {
  410. // First parse as a List<>
  411. var listType = typeof(List<>).MakeGenericType(type.GetElementType());
  412. var list = Activator.CreateInstance(listType);
  413. ParseInto(list);
  414. return listType.GetMethod("ToArray").Invoke(list, null);
  415. }
  416. // Untyped dictionary?
  417. if (_tokenizer.CurrentToken == Token.OpenBrace && (type.IsAssignableFrom(typeof(Dictionary<string, object>))))
  418. {
  419. #if SIMPLEJSON_DYNAMIC
  420. var container = (new ExpandoObject()) as IDictionary<string, object>;
  421. #else
  422. var container = new Dictionary<string, object>();
  423. #endif
  424. ReadDictionary(key =>
  425. {
  426. container[key] = Parse(typeof(Object));
  427. });
  428. return container;
  429. }
  430. // Untyped list?
  431. if (_tokenizer.CurrentToken == Token.OpenSquare && (type.IsAssignableFrom(typeof(List<object>))))
  432. {
  433. var container = new List<object>();
  434. ReadArray(() =>
  435. {
  436. container.Add(Parse(typeof(Object)));
  437. });
  438. return container;
  439. }
  440. // Untyped literal?
  441. if (_tokenizer.CurrentToken == Token.Literal && type.IsAssignableFrom(_tokenizer.Literal.GetType()))
  442. {
  443. var lit = _tokenizer.Literal;
  444. _tokenizer.NextToken();
  445. return lit;
  446. }
  447. throw new InvalidDataException(string.Format("syntax error - unexpected token {0}", _tokenizer.CurrentToken));
  448. }
  449. public static bool CanParseInto(Type type)
  450. {
  451. /* These two checks are redundant as they're covered by IDictionary/IList below
  452. if (typeof(IDictionary<,>).IsAssignableFrom(type))
  453. return true;
  454. if (typeof(IList<>).IsAssignableFrom(type))
  455. return true;
  456. */
  457. if (type.IsArray)
  458. return false;
  459. if (typeof(IDictionary).IsAssignableFrom(type))
  460. return true;
  461. if (typeof(IList).IsAssignableFrom(type))
  462. return true;
  463. if (ReflectionInfo.GetReflectionInfo(type) != null)
  464. return true;
  465. return false;
  466. }
  467. public void ParseInto(object into)
  468. {
  469. if (TryParseInto(into))
  470. return;
  471. throw new InvalidOperationException(string.Format("Don't know how to load into '{0}'", into.GetType().FullName));
  472. }
  473. public Type FindGenericInterface(Type type, Type tItf)
  474. {
  475. foreach (var t in type.GetInterfaces())
  476. {
  477. // Is this a generic list?
  478. if (t.IsGenericType && t.GetGenericTypeDefinition() == tItf)
  479. return type;
  480. }
  481. return null;
  482. }
  483. public bool TryParseInto(object into)
  484. {
  485. if (into == null)
  486. return false;
  487. var type = into.GetType();
  488. // Generic dictionary?
  489. var dictType = FindGenericInterface(type, typeof(IDictionary<,>));
  490. if (dictType!=null)
  491. {
  492. // Get the key and value types
  493. var typeKey = dictType.GetGenericArguments()[0];
  494. var typeValue = dictType.GetGenericArguments()[1];
  495. // Parse it
  496. IDictionary dict = (IDictionary)into;
  497. dict.Clear();
  498. ReadDictionary(key =>
  499. {
  500. dict.Add(Convert.ChangeType(key, typeKey), Parse(typeValue));
  501. });
  502. return true;
  503. }
  504. // Generic list
  505. var listType = FindGenericInterface(type, typeof(IList<>));
  506. if (listType!=null)
  507. {
  508. // Get element type
  509. var typeElement = listType.GetGenericArguments()[0];
  510. // Parse it
  511. IList list = (IList)into;
  512. list.Clear();
  513. ReadArray(() =>
  514. {
  515. list.Add(Parse(typeElement));
  516. });
  517. return true;
  518. }
  519. // Untyped dictionary
  520. var objDict = into as IDictionary;
  521. if (objDict != null)
  522. {
  523. objDict.Clear();
  524. ReadDictionary(key =>
  525. {
  526. objDict[key] = Parse(typeof(Object));
  527. });
  528. return true;
  529. }
  530. // Untyped list
  531. var objList = into as IList;
  532. if (objList!=null)
  533. {
  534. objList.Clear();
  535. ReadArray(() =>
  536. {
  537. objList.Add(Parse(typeof(Object)));
  538. });
  539. return true;
  540. }
  541. // Use reflection?
  542. var ri = ReflectionInfo.GetReflectionInfo(type);
  543. if (ri != null)
  544. {
  545. ri.ParseInto(this, into);
  546. return true;
  547. }
  548. return false;
  549. }
  550. public T Parse<T>()
  551. {
  552. return (T)Parse(typeof(T));
  553. }
  554. public void ReadDictionary(Action<string> callback)
  555. {
  556. _tokenizer.Skip(Token.OpenBrace);
  557. ReadDictionaryKeys(key => { callback(key); return true; });
  558. _tokenizer.Skip(Token.CloseBrace);
  559. }
  560. private void ReadDictionaryKeys(Func<string, bool> callback)
  561. {
  562. while (_tokenizer.CurrentToken != Token.CloseBrace)
  563. {
  564. // Parse the key
  565. string key = null;
  566. if (_tokenizer.CurrentToken == Token.Identifier)
  567. {
  568. key = _tokenizer.String;
  569. }
  570. else if (_tokenizer.CurrentToken == Token.Literal && _tokenizer.Literal is String)
  571. {
  572. key = (string)_tokenizer.Literal;
  573. }
  574. else
  575. {
  576. throw new InvalidDataException("syntax error, expected string literal or identifier");
  577. }
  578. _tokenizer.NextToken();
  579. _tokenizer.Skip(Token.Colon);
  580. _tokenizer.DidMove = false;
  581. if (!callback(key))
  582. return;
  583. if (!_tokenizer.DidMove)
  584. {
  585. // The callback didn't handle the key, so skip the value
  586. Parse(typeof(object));
  587. }
  588. if (_tokenizer.SkipIf(Token.Comma))
  589. continue;
  590. break;
  591. }
  592. }
  593. public void ReadArray(Action callback)
  594. {
  595. _tokenizer.Skip(Token.OpenSquare);
  596. while (_tokenizer.CurrentToken != Token.CloseSquare)
  597. {
  598. callback();
  599. if (_tokenizer.SkipIf(Token.Comma))
  600. continue;
  601. break;
  602. }
  603. _tokenizer.Skip(Token.CloseSquare);
  604. }
  605. public static Dictionary<Type, Func<IJsonReader, Type, object>> _typeReaders = new Dictionary<Type, Func<IJsonReader, Type, object>>();
  606. public static Dictionary<Type, Func<IJsonReader, string, object>> _typeFactories = new Dictionary<Type, Func<IJsonReader, string, object>>();
  607. }
  608. public class Writer : IJsonWriter
  609. {
  610. static Writer()
  611. {
  612. // Strings
  613. _typeWriters.Add(typeof(string), (w, o) => w.WriteStringLiteral((string)o));
  614. _typeWriters.Add(typeof(char), (w, o) => w.WriteStringLiteral(((char)o).ToString()));
  615. // Boolean
  616. _typeWriters.Add(typeof(bool), (w, o) => w.WriteRaw(((bool)o) ? "true" : "false"));
  617. // Integer
  618. Action<IJsonWriter, object> convertWriter = (w, o) => w.WriteRaw((string)Convert.ChangeType(o, typeof(string), System.Globalization.CultureInfo.InvariantCulture));
  619. _typeWriters.Add(typeof(int), convertWriter);
  620. _typeWriters.Add(typeof(uint), convertWriter);
  621. _typeWriters.Add(typeof(long), convertWriter);
  622. _typeWriters.Add(typeof(ulong), convertWriter);
  623. _typeWriters.Add(typeof(short), convertWriter);
  624. _typeWriters.Add(typeof(ushort), convertWriter);
  625. _typeWriters.Add(typeof(decimal), convertWriter);
  626. _typeWriters.Add(typeof(byte), convertWriter);
  627. _typeWriters.Add(typeof(sbyte), convertWriter);
  628. // Date
  629. _typeWriters.Add(typeof(DateTime), (w, o) => convertWriter(w, Utils.ToUnixMilliseconds((DateTime)o)));
  630. // Floating point
  631. _typeWriters.Add(typeof(float), (w, o) => w.WriteRaw(((float)o).ToString("R", System.Globalization.CultureInfo.InvariantCulture)));
  632. _typeWriters.Add(typeof(double), (w, o) => w.WriteRaw(((double)o).ToString("R", System.Globalization.CultureInfo.InvariantCulture)));
  633. // Byte array
  634. _typeWriters.Add(typeof(byte[]), (w, o) =>
  635. {
  636. w.WriteRaw("\"");
  637. w.WriteRaw(Convert.ToBase64String((byte[])o));
  638. w.WriteRaw("\"");
  639. });
  640. }
  641. public static Dictionary<Type, Action<IJsonWriter, object>> _typeWriters = new Dictionary<Type, Action<IJsonWriter, object>>();
  642. public Writer(TextWriter w)
  643. {
  644. _writer = w;
  645. _atStartOfLine = true;
  646. _needElementSeparator = false;
  647. }
  648. TextWriter _writer;
  649. public int IndentLevel;
  650. bool _atStartOfLine;
  651. bool _needElementSeparator = false;
  652. char _currentBlockKind = '\0';
  653. public void NextLine()
  654. {
  655. if (_atStartOfLine)
  656. return;
  657. WriteRaw("\n");
  658. WriteRaw(new string('\t', IndentLevel));
  659. _atStartOfLine = true;
  660. }
  661. void NextElement()
  662. {
  663. if (_needElementSeparator)
  664. {
  665. WriteRaw(",");
  666. NextLine();
  667. }
  668. else
  669. {
  670. NextLine();
  671. IndentLevel++;
  672. WriteRaw(_currentBlockKind.ToString());
  673. NextLine();
  674. }
  675. _needElementSeparator = true;
  676. }
  677. public void WriteElement()
  678. {
  679. if (_currentBlockKind != '[')
  680. throw new InvalidOperationException("Attempt to write array element when not in array block");
  681. NextElement();
  682. }
  683. public void WriteKey(string key)
  684. {
  685. if (_currentBlockKind != '{')
  686. throw new InvalidOperationException("Attempt to write dictionary element when not in dictionary block");
  687. NextElement();
  688. WriteStringLiteral(key);
  689. WriteRaw(": ");
  690. }
  691. public void WriteRaw(string str)
  692. {
  693. _atStartOfLine = false;
  694. _writer.Write(str);
  695. }
  696. public void WriteStringLiteral(string str)
  697. {
  698. _writer.Write("\"");
  699. foreach (var ch in str)
  700. {
  701. switch (ch)
  702. {
  703. case '\"': _writer.Write("\\\""); break;
  704. case '\r': _writer.Write("\\r"); break;
  705. case '\n': _writer.Write("\\n"); break;
  706. case '\t': _writer.Write("\\t"); break;
  707. case '\0': _writer.Write("\\0"); break;
  708. case '\\': _writer.Write("\\\\"); break;
  709. case '\'': _writer.Write("\\'"); break;
  710. default: _writer.Write(ch); break;
  711. }
  712. }
  713. _writer.Write("\"");
  714. }
  715. void WriteBlock(string open, string close, Action callback)
  716. {
  717. var prevBlockKind = _currentBlockKind;
  718. _currentBlockKind = open[0];
  719. var didNeedElementSeparator = _needElementSeparator;
  720. _needElementSeparator = false;
  721. callback();
  722. if (_needElementSeparator)
  723. {
  724. IndentLevel--;
  725. NextLine();
  726. }
  727. else
  728. {
  729. WriteRaw(open);
  730. }
  731. WriteRaw(close);
  732. _needElementSeparator = didNeedElementSeparator;
  733. _currentBlockKind = prevBlockKind;
  734. }
  735. public void WriteArray(Action callback)
  736. {
  737. WriteBlock("[", "]", callback);
  738. }
  739. public void WriteDictionary(Action callback)
  740. {
  741. WriteBlock("{", "}", callback);
  742. }
  743. public void WriteValue(object value)
  744. {
  745. // Special handling for null
  746. if (value == null)
  747. {
  748. _writer.Write("null");
  749. return;
  750. }
  751. var type = value.GetType();
  752. // Handle nullable types
  753. var typeUnderlying = Nullable.GetUnderlyingType(type);
  754. if (typeUnderlying != null)
  755. type = typeUnderlying;
  756. // Look up type writer
  757. Action<IJsonWriter, object> typeWriter;
  758. if (_typeWriters.TryGetValue(type, out typeWriter))
  759. {
  760. // Write it
  761. typeWriter(this, value);
  762. return;
  763. }
  764. // Enumerated type?
  765. if (type.IsEnum)
  766. {
  767. WriteStringLiteral(value.ToString());
  768. return;
  769. }
  770. // Dictionary?
  771. var d = value as System.Collections.IDictionary;
  772. if (d != null)
  773. {
  774. WriteDictionary(() =>
  775. {
  776. foreach (var key in d.Keys)
  777. {
  778. WriteKey(key.ToString());
  779. WriteValue(d[key]);
  780. }
  781. });
  782. return;
  783. }
  784. // Array?
  785. var e = value as System.Collections.IEnumerable;
  786. if (e != null)
  787. {
  788. WriteArray(() =>
  789. {
  790. foreach (var i in e)
  791. {
  792. WriteElement();
  793. WriteValue(i);
  794. }
  795. });
  796. return;
  797. }
  798. // Try using reflection
  799. var ri = ReflectionInfo.GetReflectionInfo(type);
  800. if (ri != null)
  801. {
  802. ri.Write(this, value);
  803. return;
  804. }
  805. // What the?
  806. throw new InvalidDataException(string.Format("Don't know how to write '{0}' to json", value.GetType()));
  807. }
  808. }
  809. class JsonMemberInfo
  810. {
  811. public MemberInfo Member;
  812. public string JsonKey;
  813. public bool KeepInstance;
  814. public Type MemberType
  815. {
  816. get
  817. {
  818. if (Member is PropertyInfo)
  819. {
  820. return ((PropertyInfo)Member).PropertyType;
  821. }
  822. else
  823. {
  824. return ((FieldInfo)Member).FieldType;
  825. }
  826. }
  827. }
  828. public void SetValue(object target, object value)
  829. {
  830. if (Member is PropertyInfo)
  831. {
  832. ((PropertyInfo)Member).SetValue(target, value, null);
  833. }
  834. else
  835. {
  836. ((FieldInfo)Member).SetValue(target, value);
  837. }
  838. }
  839. public object GetValue(object target)
  840. {
  841. if (Member is PropertyInfo)
  842. {
  843. return ((PropertyInfo)Member).GetValue(target, null);
  844. }
  845. else
  846. {
  847. return ((FieldInfo)Member).GetValue(target);
  848. }
  849. }
  850. }
  851. class ReflectionInfo
  852. {
  853. List<JsonMemberInfo> _members;
  854. static Dictionary<Type, ReflectionInfo> _cache = new Dictionary<Type, ReflectionInfo>();
  855. public void Write(Writer w, object val)
  856. {
  857. w.WriteDictionary(() =>
  858. {
  859. var writing = val as IJsonWriting;
  860. if (writing != null)
  861. writing.OnJsonWriting(w);
  862. foreach (var jmi in _members)
  863. {
  864. w.WriteKey(jmi.JsonKey);
  865. w.WriteValue(jmi.GetValue(val));
  866. }
  867. var written = val as IJsonWritten;
  868. if (written != null)
  869. written.OnJsonWritten(w);
  870. });
  871. }
  872. // The member info is stored in a list (as opposed to a dictionary) so that
  873. // the json is written in the same order as the fields/properties are defined
  874. // On loading, we assume the fields will be in the same order, but need to
  875. // handle if they're not. This function performs a linear search, but
  876. // starts after the last found item as an optimization that should work
  877. // most of the time.
  878. int _lastFoundIndex = 0;
  879. bool FindMemberInfo(string name, out JsonMemberInfo found)
  880. {
  881. for (int i = 0; i < _members.Count; i++)
  882. {
  883. int index = (i + _lastFoundIndex) % _members.Count;
  884. var jmi = _members[index];
  885. if (jmi.JsonKey == name)
  886. {
  887. _lastFoundIndex = index;
  888. found = jmi;
  889. return true;
  890. }
  891. }
  892. found = null;
  893. return false;
  894. }
  895. public void ParseFieldOrProperty(Reader r, object into, string key)
  896. {
  897. var lf = into as IJsonLoadField;
  898. if (lf != null)
  899. {
  900. if (lf.OnJsonField(r, key))
  901. return;
  902. }
  903. JsonMemberInfo jmi;
  904. if (FindMemberInfo(key, out jmi))
  905. {
  906. if (jmi.KeepInstance && Reader.CanParseInto(jmi.MemberType))
  907. {
  908. var subInto = jmi.GetValue(into);
  909. if (subInto != null)
  910. {
  911. r.ParseInto(subInto);
  912. return;
  913. }
  914. }
  915. var val = r.Parse(jmi.MemberType);
  916. jmi.SetValue(into, val);
  917. return;
  918. }
  919. }
  920. public void ParseInto(Reader r, object into)
  921. {
  922. var loading = into as IJsonLoading;
  923. r.ReadDictionary(key => {
  924. if (loading != null)
  925. {
  926. loading.OnJsonLoading(r);
  927. loading = null;
  928. }
  929. ParseFieldOrProperty(r, into, key);
  930. });
  931. var loaded = into as IJsonLoaded;
  932. if (loaded != null)
  933. loaded.OnJsonLoaded(r);
  934. }
  935. public static ReflectionInfo GetReflectionInfo(Type type)
  936. {
  937. // Already created?
  938. ReflectionInfo existing;
  939. if (_cache.TryGetValue(type, out existing))
  940. return existing;
  941. // Does type have a [Json] attribute
  942. bool typeMarked = type.GetCustomAttributes(typeof(JsonAttribute), true).OfType<JsonAttribute>().Any();
  943. // Do any members have a [Json] attribute
  944. bool anyFieldsMarked = GetAllFieldsAndProperties(type).Any(x => x.GetCustomAttributes(typeof(JsonAttribute), false).OfType<JsonAttribute>().Any());
  945. // Should we serialize all public methods?
  946. bool serializeAllPublics = typeMarked || !anyFieldsMarked;
  947. // Build
  948. var ri = CreateReflectionInfo(type, mi =>
  949. {
  950. // Explicitly excluded?
  951. if (mi.GetCustomAttributes(typeof(JsonExcludeAttribute), false).OfType<JsonExcludeAttribute>().Any())
  952. return null;
  953. // Get attributes
  954. var attr = mi.GetCustomAttributes(typeof(JsonAttribute), false).OfType<JsonAttribute>().FirstOrDefault();
  955. if (attr != null)
  956. {
  957. return new JsonMemberInfo()
  958. {
  959. Member = mi,
  960. JsonKey = attr.Key ?? mi.Name.Substring(0, 1).ToLower() + mi.Name.Substring(1),
  961. KeepInstance = attr.KeepInstance,
  962. };
  963. }
  964. // Serialize all publics?
  965. if (serializeAllPublics && IsPublic(mi))
  966. {
  967. return new JsonMemberInfo()
  968. {
  969. Member = mi,
  970. JsonKey = mi.Name.Substring(0, 1).ToLower() + mi.Name.Substring(1),
  971. };
  972. }
  973. return null;
  974. });
  975. // Cache it
  976. _cache[type] = ri;
  977. return ri;
  978. }
  979. static bool IsPublic(MemberInfo mi)
  980. {
  981. // Public field
  982. var fi = mi as FieldInfo;
  983. if (fi!=null)
  984. return fi.IsPublic;
  985. // Public property
  986. // (We only check the get method so we can work with anonymous types)
  987. var pi = mi as PropertyInfo;
  988. if (pi != null)
  989. {
  990. var gm = pi.GetGetMethod();
  991. return (gm != null && gm.IsPublic);
  992. }
  993. return false;
  994. }
  995. public static ReflectionInfo CreateReflectionInfo(Type type, Func<MemberInfo, JsonMemberInfo> callback)
  996. {
  997. // Already created?
  998. ReflectionInfo existing;
  999. if (_cache.TryGetValue(type, out existing))
  1000. return existing;
  1001. // Work out properties and fields
  1002. var members = GetAllFieldsAndProperties(type).Select(x => callback(x)).Where(x => x != null).ToList();
  1003. // Must have some members
  1004. if (!members.Any())
  1005. return null;
  1006. // Create reflection info
  1007. var ri = new ReflectionInfo()
  1008. {
  1009. _members = members,
  1010. };
  1011. return ri;
  1012. }
  1013. static IEnumerable<MemberInfo> GetAllFieldsAndProperties(Type t)
  1014. {
  1015. if (t == null)
  1016. return Enumerable.Empty<FieldInfo>();
  1017. BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly;
  1018. return t.GetMembers(flags).Where(x => x is FieldInfo || x is PropertyInfo).Concat(GetAllFieldsAndProperties(t.BaseType));
  1019. }
  1020. }
  1021. internal static class Utils
  1022. {
  1023. public static long ToUnixMilliseconds(DateTime This)
  1024. {
  1025. return (long)This.Subtract(new DateTime(1970, 1, 1)).TotalMilliseconds;
  1026. }
  1027. public static DateTime FromUnixMilliseconds(long timeStamp)
  1028. {
  1029. return new DateTime(1970, 1, 1).AddMilliseconds(timeStamp);
  1030. }
  1031. }
  1032. public class RewindableTextReader
  1033. {
  1034. public RewindableTextReader(TextReader underlying)
  1035. {
  1036. _underlying = underlying;
  1037. ReadUnderlying();
  1038. }
  1039. TextReader _underlying;
  1040. char[] _buf = new char[1024];
  1041. int _pos;
  1042. int _bufUsed;
  1043. StringBuilder _rewindBuffer;
  1044. int _rewindBufferPos;
  1045. void ReadUnderlying()
  1046. {
  1047. _bufUsed = _underlying.Read(_buf, 0, _buf.Length);
  1048. _pos = 0;
  1049. }
  1050. char ReadUnderlyingChar()
  1051. {
  1052. if (_pos >= _bufUsed)
  1053. {
  1054. if (_bufUsed > 0)
  1055. {
  1056. ReadUnderlying();
  1057. }
  1058. if (_bufUsed == 0)
  1059. {
  1060. return '\0';
  1061. }
  1062. }
  1063. // Next
  1064. return _buf[_pos++];
  1065. }
  1066. public char ReadChar()
  1067. {
  1068. if (_rewindBuffer == null)
  1069. return ReadUnderlyingChar();
  1070. if (_rewindBufferPos < _rewindBuffer.Length)
  1071. {
  1072. return _rewindBuffer[_rewindBufferPos++];
  1073. }
  1074. else
  1075. {
  1076. char ch = ReadUnderlyingChar();
  1077. _rewindBuffer.Append(ch);
  1078. _rewindBufferPos++;
  1079. return ch;
  1080. }
  1081. }
  1082. Stack<int> _bookmarks = new Stack<int>();
  1083. public void CreateBookmark()
  1084. {
  1085. if (_rewindBuffer == null)
  1086. {
  1087. _rewindBuffer = new StringBuilder();
  1088. _rewindBufferPos = 0;
  1089. }
  1090. _bookmarks.Push(_rewindBufferPos);
  1091. }
  1092. public void RewindToBookmark()
  1093. {
  1094. _rewindBufferPos = _bookmarks.Pop();
  1095. }
  1096. public void DiscardBookmark()
  1097. {
  1098. _bookmarks.Pop();
  1099. if (_bookmarks.Count == 0)
  1100. {
  1101. _rewindBuffer = null;
  1102. _rewindBufferPos = 0;
  1103. }
  1104. }
  1105. }
  1106. public class Tokenizer
  1107. {
  1108. public Tokenizer(TextReader r)
  1109. {
  1110. _reader = new RewindableTextReader(r);
  1111. _state._nextCharPos.Line = 0;
  1112. _state._nextCharPos.Offset = 0;
  1113. _state._currentCharPos = _state._nextCharPos;
  1114. // Load up
  1115. NextChar();
  1116. NextToken();
  1117. }
  1118. RewindableTextReader _reader;
  1119. StringBuilder _sb = new StringBuilder();
  1120. ReaderState _state;
  1121. // this object represents the entire state of the reader
  1122. // which when combined with the RewindableTextReader allows
  1123. // use to rewind to an arbitrary point in the token stream
  1124. struct ReaderState
  1125. {
  1126. public JsonLineOffset _nextCharPos;
  1127. public JsonLineOffset _currentCharPos;
  1128. public JsonLineOffset _currentTokenPos;
  1129. public char _currentChar;
  1130. public char _pendingChar;
  1131. public Token _currentToken;
  1132. public string _string;
  1133. public object _literal;
  1134. }
  1135. Stack<ReaderState> _bookmarks = new Stack<ReaderState>();
  1136. public void CreateBookmark()
  1137. {
  1138. _bookmarks.Push(_state);
  1139. _reader.CreateBookmark();
  1140. }
  1141. public void DiscardBookmark()
  1142. {
  1143. _bookmarks.Pop();
  1144. _reader.DiscardBookmark();
  1145. }
  1146. public void RewindToBookmark()
  1147. {
  1148. _state = _bookmarks.Pop();
  1149. _reader.RewindToBookmark();
  1150. }
  1151. char NextChar()
  1152. {
  1153. // Normalize line endings to '\n'
  1154. char ch;
  1155. if (_state._pendingChar != '\0')
  1156. {
  1157. ch = _state._pendingChar;
  1158. }
  1159. else
  1160. {
  1161. ch = _reader.ReadChar();
  1162. if (ch == '\r')
  1163. {
  1164. ch = _reader.ReadChar();
  1165. if (ch != '\n')
  1166. {
  1167. _state._pendingChar = ch;
  1168. ch = '\n';
  1169. }
  1170. }
  1171. }
  1172. _state._currentCharPos = _state._nextCharPos;
  1173. // Update line position counter
  1174. if (ch == '\n')
  1175. {
  1176. _state._nextCharPos.Line++;
  1177. _state._nextCharPos.Offset = 0;
  1178. }
  1179. else
  1180. {
  1181. _state._nextCharPos.Offset++;
  1182. }
  1183. return _state._currentChar = ch;
  1184. }
  1185. public bool DidMove
  1186. {
  1187. get;
  1188. set;
  1189. }
  1190. public void NextToken()
  1191. {
  1192. DidMove = true;
  1193. _sb.Length = 0;
  1194. State state = State.Initial;
  1195. _state._currentTokenPos = _state._currentCharPos;
  1196. while (true)
  1197. {
  1198. switch (state)
  1199. {
  1200. case State.Initial:
  1201. if (IsIdentifierLeadChar(_state._currentChar))
  1202. {
  1203. state = State.Identifier;
  1204. break;
  1205. }
  1206. else if (char.IsDigit(_state._currentChar) || _state._currentChar == '-')
  1207. {
  1208. TokenizeNumber();
  1209. _state._currentToken = Token.Literal;
  1210. return;
  1211. }
  1212. else if (char.IsWhiteSpace(_state._currentChar))
  1213. {
  1214. NextChar();
  1215. _state._currentTokenPos = _state._currentCharPos;
  1216. break;
  1217. }
  1218. switch (_state._currentChar)
  1219. {
  1220. case '/':
  1221. NextChar();
  1222. state = State.Slash;
  1223. break;
  1224. case '\"':
  1225. NextChar();
  1226. _sb.Length = 0;
  1227. state = State.QuotedString;
  1228. break;
  1229. case '\'':
  1230. NextChar();
  1231. _sb.Length = 0;
  1232. state = State.QuotedChar;
  1233. break;
  1234. case '\0':
  1235. _state._currentToken = Token.EOF;
  1236. return;
  1237. case '{': _state._currentToken = Token.OpenBrace; NextChar(); return;
  1238. case '}': _state._currentToken = Token.CloseBrace; NextChar(); return;
  1239. case '[': _state._currentToken = Token.OpenSquare; NextChar(); return;
  1240. case ']': _state._currentToken = Token.CloseSquare; NextChar(); return;
  1241. case '=': _state._currentToken = Token.Equal; NextChar(); return;
  1242. case ':': _state._currentToken = Token.Colon; NextChar(); return;
  1243. case ';': _state._currentToken = Token.SemiColon; NextChar(); return;
  1244. case ',': _state._currentToken = Token.Comma; NextChar(); return;
  1245. default:
  1246. throw new InvalidDataException(string.Format("syntax error - unexpected character '{0}'", _state._currentChar));
  1247. }
  1248. break;
  1249. case State.Slash:
  1250. switch (_state._currentChar)
  1251. {
  1252. case '/':
  1253. NextChar();
  1254. state = State.SingleLineComment;
  1255. break;
  1256. case '*':
  1257. NextChar();
  1258. state = State.BlockComment;
  1259. break;
  1260. }
  1261. throw new InvalidDataException("syntax error - unexpected character after slash");
  1262. case State.SingleLineComment:
  1263. if (_state._currentChar == '\r' || _state._currentChar == '\n')
  1264. {
  1265. state = State.Initial;
  1266. }
  1267. NextChar();
  1268. break;
  1269. case State.BlockComment:
  1270. if (_state._currentChar == '*')
  1271. {
  1272. NextChar();
  1273. if (_state._currentChar == '/')
  1274. {
  1275. state = State.Initial;
  1276. }
  1277. }
  1278. NextChar();
  1279. break;
  1280. case State.Identifier:
  1281. if (IsIdentifierChar(_state._currentChar))
  1282. {
  1283. _sb.Append(_state._currentChar);
  1284. NextChar();
  1285. }
  1286. else
  1287. {
  1288. _state._string = _sb.ToString();
  1289. switch (this.String)
  1290. {
  1291. case "true":
  1292. _state._literal = true;
  1293. _state._currentToken = Token.Literal;
  1294. break;
  1295. case "false":
  1296. _state._literal = false;
  1297. _state._currentToken = Token.Literal;
  1298. break;
  1299. case "null":
  1300. _state._literal = null;
  1301. _state._currentToken = Token.Literal;
  1302. break;
  1303. default:
  1304. _state._currentToken = Token.Identifier;
  1305. break;
  1306. }
  1307. return;
  1308. }
  1309. break;
  1310. case State.QuotedString:
  1311. if (_state._currentChar == '\\')
  1312. {
  1313. AppendSpecialChar();
  1314. }
  1315. else if (_state._currentChar == '\"')
  1316. {
  1317. _state._literal = _sb.ToString();
  1318. _state._currentToken = Token.Literal;
  1319. NextChar();
  1320. return;
  1321. }
  1322. else
  1323. {
  1324. _sb.Append(_state._currentChar);
  1325. NextChar();
  1326. continue;
  1327. }
  1328. break;
  1329. case State.QuotedChar:
  1330. if (_state._currentChar == '\\')
  1331. {
  1332. AppendSpecialChar();
  1333. }
  1334. else if (_state._currentChar == '\'')
  1335. {
  1336. _state._literal = _sb.ToString();
  1337. _state._currentToken = Token.Literal;
  1338. NextChar();
  1339. return;
  1340. }
  1341. else
  1342. {
  1343. _sb.Append(_state._currentChar);
  1344. NextChar();
  1345. continue;
  1346. }
  1347. break;
  1348. }
  1349. }
  1350. }
  1351. void TokenizeNumber()
  1352. {
  1353. _sb.Length = 0;
  1354. // Leading -
  1355. bool signed = false;
  1356. if (_state._currentChar == '-')
  1357. {
  1358. signed = true;
  1359. _sb.Append(_state._currentChar);
  1360. NextChar();
  1361. if (!Char.IsDigit(_state._currentChar))
  1362. {
  1363. throw new InvalidDataException("syntax error - expected digit to follow negative sign");
  1364. }
  1365. }
  1366. // Parse all digits
  1367. bool fp = false;
  1368. while (char.IsDigit(_state._currentChar) || _state._currentChar == '.' || _state._currentChar == 'e' || _state._currentChar == 'E' || _state._currentChar == 'x' || _state._currentChar == 'X')
  1369. {
  1370. if (_state._currentChar == 'e' || _state._currentChar == 'E')
  1371. {
  1372. fp = true;
  1373. _sb.Append(_state._currentChar);
  1374. NextChar();
  1375. if (_state._currentChar == '-' || _state._currentChar == '+')
  1376. {
  1377. _sb.Append(_state._currentChar);
  1378. NextChar();
  1379. }
  1380. }
  1381. else
  1382. {
  1383. if (_state._currentChar == '.')
  1384. fp = true;
  1385. _sb.Append(_state._currentChar);
  1386. NextChar();
  1387. }
  1388. }
  1389. Type type = fp ? typeof(double) : (signed ? typeof(long) : typeof(ulong));
  1390. if (char.IsLetterOrDigit(_state._currentChar))
  1391. throw new InvalidDataException(string.Format("syntax error - invalid character following number '{0}'", _state._currentChar));
  1392. // Convert type
  1393. try
  1394. {
  1395. _state._literal = Convert.ChangeType(_sb.ToString(), type, System.Globalization.CultureInfo.InvariantCulture);
  1396. }
  1397. catch
  1398. {
  1399. throw new InvalidDataException(string.Format("syntax error - incorrectly formatted number '{0}'", _sb.ToString()));
  1400. }
  1401. }
  1402. public void Check(Token tokenRequired)
  1403. {
  1404. if (tokenRequired != CurrentToken)
  1405. {
  1406. throw new InvalidDataException(string.Format("syntax error - expected {0} found {1}", tokenRequired, CurrentToken));
  1407. }
  1408. }
  1409. public void Skip(Token tokenRequired)
  1410. {
  1411. Check(tokenRequired);
  1412. NextToken();
  1413. }
  1414. public bool SkipIf(Token tokenRequired)
  1415. {
  1416. if (tokenRequired == CurrentToken)
  1417. {
  1418. NextToken();
  1419. return true;
  1420. }
  1421. return false;
  1422. }
  1423. void AppendSpecialChar()
  1424. {
  1425. NextChar();
  1426. var escape = _state._currentChar;
  1427. NextChar();
  1428. switch (escape)
  1429. {
  1430. case '\'': _sb.Append('\''); break;
  1431. case '\"': _sb.Append('\"'); break;
  1432. case '\\': _sb.Append('\\'); break;
  1433. case 'r': _sb.Append('\r'); break;
  1434. case 'n': _sb.Append('\n'); break;
  1435. case 't': _sb.Append('\t'); break;
  1436. case '0': _sb.Append('\0'); break;
  1437. case 'u':
  1438. var sbHex = new StringBuilder();
  1439. for (int i = 0; i < 4; i++)
  1440. {
  1441. sbHex.Append(_state._currentChar);
  1442. NextChar();
  1443. }
  1444. _sb.Append((char)Convert.ToUInt16(sbHex.ToString(), 16));
  1445. break;
  1446. default:
  1447. throw new InvalidDataException(string.Format("Invalid escape sequence in string literal: '\\{0}'", _state._currentChar));
  1448. }
  1449. }
  1450. public Token CurrentToken
  1451. {
  1452. get { return _state._currentToken; }
  1453. }
  1454. public JsonLineOffset CurrentTokenPosition
  1455. {
  1456. get { return _state._currentTokenPos; }
  1457. }
  1458. public string String
  1459. {
  1460. get { return _state._string; }
  1461. }
  1462. public object Literal
  1463. {
  1464. get { return _state._literal; }
  1465. }
  1466. private enum State
  1467. {
  1468. Initial,
  1469. Slash,
  1470. SingleLineComment,
  1471. BlockComment,
  1472. Identifier,
  1473. QuotedString,
  1474. QuotedChar,
  1475. }
  1476. public static bool IsIdentifierChar(char ch)
  1477. {
  1478. return Char.IsLetterOrDigit(ch) || ch == '_' || ch == '$';
  1479. }
  1480. public static bool IsIdentifierLeadChar(char ch)
  1481. {
  1482. return Char.IsLetter(ch) || ch == '_' || ch == '$';
  1483. }
  1484. public static bool IsIdentifier(string str)
  1485. {
  1486. return IsIdentifierLeadChar(str[0]) && str.All(x => IsIdentifierChar(x));
  1487. }
  1488. }
  1489. }
  1490. }