PetaJson.cs 71 KB

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