PetaJson.cs 74 KB

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