PetaJson.cs 60 KB

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