PetaJson.cs 72 KB

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