MetsysBson.cs 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632
  1. /*
  2. Copyright (c) 2010, Karl Seguin - http://www.openmymind.net/
  3. All rights reserved.
  4. Redistribution and use in source and binary forms, with or without
  5. modification, are permitted provided that the following conditions are met:
  6. * Redistributions of source code must retain the above copyright
  7. notice, this list of conditions and the following disclaimer.
  8. * Redistributions in binary form must reproduce the above copyright
  9. notice, this list of conditions and the following disclaimer in the
  10. documentation and/or other materials provided with the distribution.
  11. * Neither the name of the <organization> nor the
  12. names of its contributors may be used to endorse or promote products
  13. derived from this software without specific prior written permission.
  14. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  15. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  16. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  17. DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
  18. DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  19. (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  20. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  21. ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  23. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. Code imported from https://github.com/elaberge/Metsys.Bson without any changes
  25. */
  26. using System.Text;
  27. using System.Text.RegularExpressions;
  28. using System.IO;
  29. using System.Collections;
  30. using System.Collections.Generic;
  31. using System.Diagnostics;
  32. using System.Net;
  33. using System.Security.Cryptography;
  34. using System.Linq;
  35. using System.Linq.Expressions;
  36. using System.Reflection;
  37. using System;
  38. using System.Runtime.Serialization;
  39. using Metsys.Bson.Configuration;
  40. // ReSharper disable All
  41. namespace Metsys.Bson
  42. {
  43. internal enum Types
  44. {
  45. Double = 1,
  46. String = 2,
  47. Object = 3,
  48. Array = 4,
  49. Binary = 5,
  50. Undefined = 6,
  51. ObjectId = 7,
  52. Boolean = 8,
  53. DateTime = 9,
  54. Null = 10,
  55. Regex = 11,
  56. Reference = 12,
  57. Code = 13,
  58. Symbol = 14,
  59. ScopedCode = 15,
  60. Int32 = 16,
  61. Timestamp = 17,
  62. Int64 = 18,
  63. }
  64. }
  65. namespace Metsys.Bson
  66. {
  67. internal class Serializer
  68. {
  69. private static readonly IDictionary<Type, Types> _typeMap = new Dictionary<Type, Types>
  70. {
  71. {typeof (int), Types.Int32},
  72. {typeof (long), Types.Int64},
  73. {typeof (bool), Types.Boolean},
  74. {typeof (string), Types.String},
  75. {typeof (double), Types.Double},
  76. {typeof (Guid), Types.Binary},
  77. {typeof (Regex), Types.Regex},
  78. {typeof (DateTime), Types.DateTime},
  79. {typeof (float), Types.Double},
  80. {typeof (byte[]), Types.Binary},
  81. {typeof (ObjectId), Types.ObjectId},
  82. {typeof (ScopedCode), Types.ScopedCode}
  83. };
  84. private readonly BinaryWriter _writer;
  85. private Document _current;
  86. public static byte[] Serialize<T>(T document)
  87. {
  88. var type = document.GetType();
  89. if (type.IsValueType ||
  90. (typeof(IEnumerable).IsAssignableFrom(type) && typeof(IDictionary).IsAssignableFrom(type) == false)
  91. )
  92. {
  93. throw new BsonException("Root type must be an object");
  94. }
  95. using (var ms = new MemoryStream(250))
  96. using (var writer = new BinaryWriter(ms))
  97. {
  98. new Serializer(writer).WriteDocument(document);
  99. return ms.ToArray();
  100. }
  101. }
  102. public static byte[] Serialize(object document)
  103. {
  104. var type = document.GetType();
  105. if (type.IsValueType ||
  106. (typeof(IEnumerable).IsAssignableFrom(type) && typeof(IDictionary).IsAssignableFrom(type) == false)
  107. )
  108. {
  109. throw new BsonException("Root type must be an object");
  110. }
  111. using (var ms = new MemoryStream(250))
  112. using (var writer = new BinaryWriter(ms))
  113. {
  114. new Serializer(writer).WriteDocument(document);
  115. return ms.ToArray();
  116. }
  117. }
  118. private Serializer(BinaryWriter writer)
  119. {
  120. _writer = writer;
  121. }
  122. private void NewDocument()
  123. {
  124. var old = _current;
  125. _current = new Document { Parent = old, Length = (int)_writer.BaseStream.Position, Digested = 4 };
  126. _writer.Write(0); // length placeholder
  127. }
  128. private void EndDocument(bool includeEeo)
  129. {
  130. var old = _current;
  131. if (includeEeo)
  132. {
  133. Written(1);
  134. _writer.Write((byte)0);
  135. }
  136. _writer.Seek(_current.Length, SeekOrigin.Begin);
  137. _writer.Write(_current.Digested); // override the document length placeholder
  138. _writer.Seek(0, SeekOrigin.End); // back to the end
  139. _current = _current.Parent;
  140. if (_current != null)
  141. {
  142. Written(old.Digested);
  143. }
  144. }
  145. private void Written(int length)
  146. {
  147. _current.Digested += length;
  148. }
  149. private void WriteDocument(object document)
  150. {
  151. NewDocument();
  152. WriteObject(document);
  153. EndDocument(true);
  154. }
  155. private void WriteObject(object document)
  156. {
  157. var asDictionary = document as IDictionary;
  158. if (asDictionary != null)
  159. {
  160. Write(asDictionary);
  161. return;
  162. }
  163. var typeHelper = TypeHelper.GetHelperForType(document.GetType());
  164. foreach (var property in typeHelper.GetProperties())
  165. {
  166. if (property.Ignored) { continue; }
  167. var name = property.Name;
  168. var value = property.Getter(document);
  169. if (value == null && property.IgnoredIfNull)
  170. {
  171. continue;
  172. }
  173. SerializeMember(name, value);
  174. }
  175. }
  176. private void SerializeMember(string name, object value)
  177. {
  178. if (value == null)
  179. {
  180. Write(Types.Null);
  181. WriteName(name);
  182. return;
  183. }
  184. var type = value.GetType();
  185. if (type.IsEnum)
  186. {
  187. type = Enum.GetUnderlyingType(type);
  188. }
  189. Types storageType;
  190. if (!_typeMap.TryGetValue(type, out storageType))
  191. {
  192. // this isn't a simple type;
  193. Write(name, value);
  194. return;
  195. }
  196. Write(storageType);
  197. WriteName(name);
  198. switch (storageType)
  199. {
  200. case Types.Int32:
  201. Written(4);
  202. _writer.Write((int)value);
  203. return;
  204. case Types.Int64:
  205. Written(8);
  206. _writer.Write((long)value);
  207. return;
  208. case Types.String:
  209. Write((string)value);
  210. return;
  211. case Types.Double:
  212. Written(8);
  213. if (value is float)
  214. {
  215. _writer.Write(Convert.ToDouble((float)value));
  216. }
  217. else
  218. {
  219. _writer.Write((double)value);
  220. }
  221. return;
  222. case Types.Boolean:
  223. Written(1);
  224. _writer.Write((bool)value ? (byte)1 : (byte)0);
  225. return;
  226. case Types.DateTime:
  227. Written(8);
  228. _writer.Write((long)((DateTime)value).ToUniversalTime().Subtract(Helper.Epoch).TotalMilliseconds);
  229. return;
  230. case Types.Binary:
  231. WriteBinnary(value);
  232. return;
  233. case Types.ScopedCode:
  234. Write((ScopedCode)value);
  235. return;
  236. case Types.ObjectId:
  237. Written(((ObjectId)value).Value.Length);
  238. _writer.Write(((ObjectId)value).Value);
  239. return;
  240. case Types.Regex:
  241. Write((Regex)value);
  242. break;
  243. }
  244. }
  245. private void Write(string name, object value)
  246. {
  247. if (value is IDictionary)
  248. {
  249. Write(Types.Object);
  250. WriteName(name);
  251. NewDocument();
  252. Write((IDictionary)value);
  253. EndDocument(true);
  254. }
  255. else if (value is IEnumerable)
  256. {
  257. Write(Types.Array);
  258. WriteName(name);
  259. NewDocument();
  260. Write((IEnumerable)value);
  261. EndDocument(true);
  262. }
  263. else
  264. {
  265. Write(Types.Object);
  266. WriteName(name);
  267. WriteDocument(value); // Write manages new/end document
  268. }
  269. }
  270. private void Write(IEnumerable enumerable)
  271. {
  272. var index = 0;
  273. foreach (var value in enumerable)
  274. {
  275. SerializeMember((index++).ToString(), value);
  276. }
  277. }
  278. private void Write(IDictionary dictionary)
  279. {
  280. foreach (var key in dictionary.Keys)
  281. {
  282. SerializeMember((string)key, dictionary[key]);
  283. }
  284. }
  285. private void WriteBinnary(object value)
  286. {
  287. if (value is byte[])
  288. {
  289. var bytes = (byte[])value;
  290. var length = bytes.Length;
  291. _writer.Write(length + 4);
  292. _writer.Write((byte)2);
  293. _writer.Write(length);
  294. _writer.Write(bytes);
  295. Written(9 + length);
  296. }
  297. else if (value is Guid)
  298. {
  299. var guid = (Guid)value;
  300. var bytes = guid.ToByteArray();
  301. _writer.Write(bytes.Length);
  302. _writer.Write((byte)3);
  303. _writer.Write(bytes);
  304. Written(5 + bytes.Length);
  305. }
  306. }
  307. private void Write(Types type)
  308. {
  309. _writer.Write((byte)type);
  310. Written(1);
  311. }
  312. private void WriteName(string name)
  313. {
  314. var bytes = Encoding.UTF8.GetBytes(name);
  315. _writer.Write(bytes);
  316. _writer.Write((byte)0);
  317. Written(bytes.Length + 1);
  318. }
  319. private void Write(string name)
  320. {
  321. var bytes = Encoding.UTF8.GetBytes(name);
  322. _writer.Write(bytes.Length + 1);
  323. _writer.Write(bytes);
  324. _writer.Write((byte)0);
  325. Written(bytes.Length + 5); // stringLength + length + null byte
  326. }
  327. private void Write(Regex regex)
  328. {
  329. WriteName(regex.ToString());
  330. var options = string.Empty;
  331. if ((regex.Options & RegexOptions.ECMAScript) == RegexOptions.ECMAScript)
  332. {
  333. options = string.Concat(options, 'e');
  334. }
  335. if ((regex.Options & RegexOptions.IgnoreCase) == RegexOptions.IgnoreCase)
  336. {
  337. options = string.Concat(options, 'i');
  338. }
  339. if ((regex.Options & RegexOptions.CultureInvariant) == RegexOptions.CultureInvariant)
  340. {
  341. options = string.Concat(options, 'l');
  342. }
  343. if ((regex.Options & RegexOptions.Multiline) == RegexOptions.Multiline)
  344. {
  345. options = string.Concat(options, 'm');
  346. }
  347. if ((regex.Options & RegexOptions.Singleline) == RegexOptions.Singleline)
  348. {
  349. options = string.Concat(options, 's');
  350. }
  351. options = string.Concat(options, 'u'); // all .net regex are unicode regex, therefore:
  352. if ((regex.Options & RegexOptions.IgnorePatternWhitespace) == RegexOptions.IgnorePatternWhitespace)
  353. {
  354. options = string.Concat(options, 'w');
  355. }
  356. if ((regex.Options & RegexOptions.ExplicitCapture) == RegexOptions.ExplicitCapture)
  357. {
  358. options = string.Concat(options, 'x');
  359. }
  360. WriteName(options);
  361. }
  362. private void Write(ScopedCode value)
  363. {
  364. NewDocument();
  365. Write(value.CodeString);
  366. WriteDocument(value.Scope);
  367. EndDocument(false);
  368. }
  369. }
  370. }
  371. namespace Metsys.Bson
  372. {
  373. internal class ScopedCode
  374. {
  375. public string CodeString { get; set; }
  376. public object Scope { get; set; }
  377. }
  378. internal class ScopedCode<T> : ScopedCode
  379. {
  380. public new T Scope { get; set; }
  381. }
  382. }
  383. namespace Metsys.Bson
  384. {
  385. internal static class ObjectIdGenerator
  386. {
  387. private static readonly object _inclock = new object();
  388. private static int _counter;
  389. private static readonly byte[] _machineHash = GenerateHostHash();
  390. private static readonly byte[] _processId = BitConverter.GetBytes(GenerateProcId());
  391. public static byte[] Generate()
  392. {
  393. var oid = new byte[12];
  394. var copyidx = 0;
  395. Array.Copy(BitConverter.GetBytes(GenerateTime()), 0, oid, copyidx, 4);
  396. copyidx += 4;
  397. Array.Copy(_machineHash, 0, oid, copyidx, 3);
  398. copyidx += 3;
  399. Array.Copy(_processId, 0, oid, copyidx, 2);
  400. copyidx += 2;
  401. Array.Copy(BitConverter.GetBytes(GenerateInc()), 0, oid, copyidx, 3);
  402. return oid;
  403. }
  404. private static int GenerateTime()
  405. {
  406. var now = DateTime.Now.ToUniversalTime();
  407. var nowtime = new DateTime(Helper.Epoch.Year, Helper.Epoch.Month, Helper.Epoch.Day, now.Hour, now.Minute, now.Second, now.Millisecond);
  408. var diff = nowtime - Helper.Epoch;
  409. return Convert.ToInt32(Math.Floor(diff.TotalMilliseconds));
  410. }
  411. private static int GenerateInc()
  412. {
  413. lock (_inclock)
  414. {
  415. return _counter++;
  416. }
  417. }
  418. private static byte[] GenerateHostHash()
  419. {
  420. using (var md5 = MD5.Create())
  421. {
  422. var host = Dns.GetHostName();
  423. return md5.ComputeHash(Encoding.Default.GetBytes(host));
  424. }
  425. }
  426. private static int GenerateProcId()
  427. {
  428. var proc = Process.GetCurrentProcess();
  429. return proc.Id;
  430. }
  431. }
  432. }
  433. namespace Metsys.Bson
  434. {
  435. internal class ObjectId
  436. {
  437. private string _string;
  438. public ObjectId()
  439. {
  440. }
  441. public ObjectId(string value) : this(DecodeHex(value))
  442. {
  443. }
  444. internal ObjectId(byte[] value)
  445. {
  446. Value = value;
  447. }
  448. public static ObjectId Empty
  449. {
  450. get { return new ObjectId("000000000000000000000000"); }
  451. }
  452. public byte[] Value { get; private set; }
  453. public static ObjectId NewObjectId()
  454. {
  455. // TODO: generate random-ish bits.
  456. return new ObjectId { Value = ObjectIdGenerator.Generate() };
  457. }
  458. public static bool TryParse(string value, out ObjectId id)
  459. {
  460. id = Empty;
  461. if (value == null || value.Length != 24)
  462. {
  463. return false;
  464. }
  465. try
  466. {
  467. id = new ObjectId(value);
  468. return true;
  469. }
  470. catch (FormatException)
  471. {
  472. return false;
  473. }
  474. }
  475. public static bool operator ==(ObjectId a, ObjectId b)
  476. {
  477. if (ReferenceEquals(a, b))
  478. {
  479. return true;
  480. }
  481. if (((object)a == null) || ((object)b == null))
  482. {
  483. return false;
  484. }
  485. return a.Equals(b);
  486. }
  487. public static bool operator !=(ObjectId a, ObjectId b)
  488. {
  489. return !(a == b);
  490. }
  491. public override int GetHashCode()
  492. {
  493. return Value != null ? ToString().GetHashCode() : 0;
  494. }
  495. public override string ToString()
  496. {
  497. if (_string == null && Value != null)
  498. {
  499. _string = BitConverter.ToString(Value).Replace("-", string.Empty).ToLower();
  500. }
  501. return _string;
  502. }
  503. public override bool Equals(object o)
  504. {
  505. var other = o as ObjectId;
  506. return Equals(other);
  507. }
  508. public bool Equals(ObjectId other)
  509. {
  510. return other != null && ToString() == other.ToString();
  511. }
  512. protected static byte[] DecodeHex(string val)
  513. {
  514. var chars = val.ToCharArray();
  515. var numberChars = chars.Length;
  516. var bytes = new byte[numberChars / 2];
  517. for (var i = 0; i < numberChars; i += 2)
  518. {
  519. bytes[i / 2] = Convert.ToByte(new string(chars, i, 2), 16);
  520. }
  521. return bytes;
  522. }
  523. public static implicit operator string(ObjectId oid)
  524. {
  525. return oid == null ? null : oid.ToString();
  526. }
  527. public static implicit operator ObjectId(string oidString)
  528. {
  529. return new ObjectId(oidString);
  530. }
  531. }
  532. }
  533. namespace Metsys.Bson
  534. {
  535. public interface IExpando
  536. {
  537. IDictionary<string, object> Expando { get; }
  538. }
  539. }
  540. namespace Metsys.Bson
  541. {
  542. internal class MagicProperty
  543. {
  544. private readonly PropertyInfo _property;
  545. private readonly string _name;
  546. private readonly bool _ignored;
  547. public readonly bool _ignoredIfNull;
  548. public Type Type
  549. {
  550. get { return _property.PropertyType; }
  551. }
  552. public string Name
  553. {
  554. get { return _name; }
  555. }
  556. public bool Ignored
  557. {
  558. get { return _ignored; }
  559. }
  560. public bool IgnoredIfNull
  561. {
  562. get { return _ignoredIfNull; }
  563. }
  564. public Action<object, object> Setter { get; private set; }
  565. public Func<object, object> Getter { get; private set; }
  566. public MagicProperty(PropertyInfo property, string name, bool ignored, bool ignoredIfNull)
  567. {
  568. _property = property;
  569. _name = name;
  570. _ignored = ignored;
  571. _ignoredIfNull = ignoredIfNull;
  572. Getter = CreateGetterMethod(property);
  573. Setter = CreateSetterMethod(property);
  574. }
  575. private static Action<object, object> CreateSetterMethod(PropertyInfo property)
  576. {
  577. var genericHelper = typeof(MagicProperty).GetMethod("SetterMethod", BindingFlags.Static | BindingFlags.NonPublic);
  578. var constructedHelper = genericHelper.MakeGenericMethod(property.DeclaringType, property.PropertyType);
  579. return (Action<object, object>)constructedHelper.Invoke(null, new object[] { property });
  580. }
  581. private static Func<object, object> CreateGetterMethod(PropertyInfo property)
  582. {
  583. var genericHelper = typeof(MagicProperty).GetMethod("GetterMethod", BindingFlags.Static | BindingFlags.NonPublic);
  584. var constructedHelper = genericHelper.MakeGenericMethod(property.DeclaringType, property.PropertyType);
  585. return (Func<object, object>)constructedHelper.Invoke(null, new object[] { property });
  586. }
  587. //called via reflection
  588. private static Action<object, object> SetterMethod<TTarget, TParam>(PropertyInfo method) where TTarget : class
  589. {
  590. var m = method.GetSetMethod(true);
  591. if (m == null) { return null; } //no setter
  592. var func = (Action<TTarget, TParam>)Delegate.CreateDelegate(typeof(Action<TTarget, TParam>), m);
  593. return (target, param) => func((TTarget)target, (TParam)param);
  594. }
  595. //called via reflection
  596. private static Func<object, object> GetterMethod<TTarget, TParam>(PropertyInfo method) where TTarget : class
  597. {
  598. var m = method.GetGetMethod(true);
  599. var func = (Func<TTarget, TParam>)Delegate.CreateDelegate(typeof(Func<TTarget, TParam>), m);
  600. return target => func((TTarget)target);
  601. }
  602. }
  603. }
  604. namespace Metsys.Bson
  605. {
  606. internal class TypeHelper
  607. {
  608. private static readonly IDictionary<Type, TypeHelper> _cachedTypeLookup = new Dictionary<Type, TypeHelper>();
  609. private static readonly BsonConfiguration _configuration = BsonConfiguration.Instance;
  610. private readonly IDictionary<string, MagicProperty> _properties;
  611. private TypeHelper(Type type)
  612. {
  613. var properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
  614. _properties = LoadMagicProperties(type, properties);
  615. if (typeof(IExpando).IsAssignableFrom(type))
  616. {
  617. Expando = _properties["Expando"];
  618. }
  619. }
  620. public MagicProperty Expando { get; private set; }
  621. public ICollection<MagicProperty> GetProperties()
  622. {
  623. return _properties.Values;
  624. }
  625. public MagicProperty FindProperty(string name)
  626. {
  627. return _properties.ContainsKey(name) ? _properties[name] : null;
  628. }
  629. public static TypeHelper GetHelperForType(Type type)
  630. {
  631. TypeHelper helper;
  632. if (!_cachedTypeLookup.TryGetValue(type, out helper))
  633. {
  634. helper = new TypeHelper(type);
  635. _cachedTypeLookup[type] = helper;
  636. }
  637. return helper;
  638. }
  639. public static string FindProperty(LambdaExpression lambdaExpression)
  640. {
  641. Expression expressionToCheck = lambdaExpression;
  642. var done = false;
  643. while (!done)
  644. {
  645. switch (expressionToCheck.NodeType)
  646. {
  647. case ExpressionType.Convert:
  648. expressionToCheck = ((UnaryExpression)expressionToCheck).Operand;
  649. break;
  650. case ExpressionType.Lambda:
  651. expressionToCheck = ((LambdaExpression)expressionToCheck).Body;
  652. break;
  653. case ExpressionType.MemberAccess:
  654. var memberExpression = (MemberExpression)expressionToCheck;
  655. if (memberExpression.Expression.NodeType != ExpressionType.Parameter && memberExpression.Expression.NodeType != ExpressionType.Convert)
  656. {
  657. throw new ArgumentException(string.Format("Expression '{0}' must resolve to top-level member.", lambdaExpression), "lambdaExpression");
  658. }
  659. return memberExpression.Member.Name;
  660. default:
  661. done = true;
  662. break;
  663. }
  664. }
  665. return null;
  666. }
  667. public static PropertyInfo FindProperty(Type type, string name)
  668. {
  669. return type.GetProperties().Where(p => p.Name == name).First();
  670. }
  671. private static IDictionary<string, MagicProperty> LoadMagicProperties(Type type, IEnumerable<PropertyInfo> properties)
  672. {
  673. var magic = new Dictionary<string, MagicProperty>(StringComparer.CurrentCultureIgnoreCase);
  674. foreach (var property in properties)
  675. {
  676. if (property.GetIndexParameters().Length > 0)
  677. {
  678. continue;
  679. }
  680. var name = _configuration.AliasFor(type, property.Name);
  681. var ignored = _configuration.IsIgnored(type, property.Name);
  682. var ignoredIfNull = _configuration.IsIgnoredIfNull(type, property.Name);
  683. magic.Add(name, new MagicProperty(property, name, ignored, ignoredIfNull));
  684. }
  685. return magic;
  686. }
  687. }
  688. }
  689. namespace Metsys.Bson
  690. {
  691. internal class ListWrapper : BaseWrapper
  692. {
  693. private IList _list;
  694. public override object Collection
  695. {
  696. get { return _list; }
  697. }
  698. public override void Add(object value)
  699. {
  700. _list.Add(value);
  701. }
  702. protected override object CreateContainer(Type type, Type itemType)
  703. {
  704. if (type.IsInterface)
  705. {
  706. return Activator.CreateInstance(typeof(List<>).MakeGenericType(itemType));
  707. }
  708. if (type.GetConstructor(BindingFlags.Instance | BindingFlags.Public, null, new Type[0], null) != null)
  709. {
  710. return Activator.CreateInstance(type);
  711. }
  712. return null;
  713. }
  714. protected override void SetContainer(object container)
  715. {
  716. _list = container == null ? new ArrayList() : (IList)container;
  717. }
  718. }
  719. }
  720. namespace Metsys.Bson
  721. {
  722. internal static class ListHelper
  723. {
  724. public static Type GetListItemType(Type enumerableType)
  725. {
  726. if (enumerableType.IsArray)
  727. {
  728. return enumerableType.GetElementType();
  729. }
  730. return enumerableType.IsGenericType ? enumerableType.GetGenericArguments()[0] : typeof(object);
  731. }
  732. public static Type GetDictionarKeyType(Type enumerableType)
  733. {
  734. return enumerableType.IsGenericType
  735. ? enumerableType.GetGenericArguments()[0]
  736. : typeof(object);
  737. }
  738. public static Type GetDictionarValueType(Type enumerableType)
  739. {
  740. return enumerableType.IsGenericType
  741. ? enumerableType.GetGenericArguments()[1]
  742. : typeof(object);
  743. }
  744. public static IDictionary CreateDictionary(Type dictionaryType, Type keyType, Type valueType)
  745. {
  746. if (dictionaryType.IsInterface)
  747. {
  748. return (IDictionary)Activator.CreateInstance(typeof(Dictionary<,>).MakeGenericType(keyType, valueType));
  749. }
  750. if (dictionaryType.GetConstructor(BindingFlags.Instance | BindingFlags.Public, null, new Type[0], null) != null)
  751. {
  752. return (IDictionary)Activator.CreateInstance(dictionaryType);
  753. }
  754. return new Dictionary<object, object>();
  755. }
  756. }
  757. }
  758. namespace Metsys.Bson
  759. {
  760. internal class CollectionWrapper<T> : BaseWrapper
  761. {
  762. private ICollection<T> _list;
  763. public override object Collection
  764. {
  765. get { return _list; }
  766. }
  767. public override void Add(object value)
  768. {
  769. _list.Add((T)value);
  770. }
  771. protected override object CreateContainer(Type type, Type itemType)
  772. {
  773. return Activator.CreateInstance(type);
  774. }
  775. protected override void SetContainer(object container)
  776. {
  777. _list = (ICollection<T>)container;
  778. }
  779. }
  780. }
  781. namespace Metsys.Bson
  782. {
  783. internal abstract class BaseWrapper
  784. {
  785. public static BaseWrapper Create(Type type, Type itemType, object existingContainer)
  786. {
  787. var instance = CreateWrapperFromType(existingContainer == null ? type : existingContainer.GetType(), itemType);
  788. instance.SetContainer(existingContainer ?? instance.CreateContainer(type, itemType));
  789. return instance;
  790. }
  791. private static BaseWrapper CreateWrapperFromType(Type type, Type itemType)
  792. {
  793. if (type.IsArray)
  794. {
  795. return (BaseWrapper)Activator.CreateInstance(typeof(ArrayWrapper<>).MakeGenericType(itemType));
  796. }
  797. var isCollection = false;
  798. var types = new List<Type>(type.GetInterfaces().Select(h => h.IsGenericType ? h.GetGenericTypeDefinition() : h));
  799. types.Insert(0, type.IsGenericType ? type.GetGenericTypeDefinition() : type);
  800. foreach (var @interface in types)
  801. {
  802. if (typeof(IList<>).IsAssignableFrom(@interface) || typeof(IList).IsAssignableFrom(@interface))
  803. {
  804. return new ListWrapper();
  805. }
  806. if (typeof(ICollection<>).IsAssignableFrom(@interface))
  807. {
  808. isCollection = true;
  809. }
  810. }
  811. if (isCollection)
  812. {
  813. return (BaseWrapper)Activator.CreateInstance(typeof(CollectionWrapper<>).MakeGenericType(itemType));
  814. }
  815. //a last-ditch pass
  816. foreach (var @interface in types)
  817. {
  818. if (typeof(IEnumerable<>).IsAssignableFrom(@interface) || typeof(IEnumerable).IsAssignableFrom(@interface))
  819. {
  820. return new ListWrapper();
  821. }
  822. }
  823. throw new BsonException(string.Format("Collection of type {0} cannot be deserialized", type.FullName));
  824. }
  825. public abstract void Add(object value);
  826. public abstract object Collection { get; }
  827. protected abstract object CreateContainer(Type type, Type itemType);
  828. protected abstract void SetContainer(object container);
  829. }
  830. }
  831. namespace Metsys.Bson
  832. {
  833. internal class ArrayWrapper<T> : BaseWrapper
  834. {
  835. private readonly List<T> _list = new List<T>();
  836. public override void Add(object value)
  837. {
  838. _list.Add((T)value);
  839. }
  840. protected override object CreateContainer(Type type, Type itemType)
  841. {
  842. return null;
  843. }
  844. protected override void SetContainer(object container)
  845. {
  846. if (container != null)
  847. {
  848. throw new BsonException("An container cannot exist when trying to deserialize an array");
  849. }
  850. }
  851. public override object Collection
  852. {
  853. get
  854. {
  855. return _list.ToArray();
  856. }
  857. }
  858. }
  859. }
  860. namespace Metsys.Bson
  861. {
  862. public static class Helper
  863. {
  864. public static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
  865. }
  866. }
  867. namespace Metsys.Bson
  868. {
  869. internal class Document
  870. {
  871. public int Length;
  872. public Document Parent;
  873. public int Digested;
  874. }
  875. }
  876. namespace Metsys.Bson
  877. {
  878. internal class Deserializer
  879. {
  880. internal class Options
  881. {
  882. public bool LongIntegers { get; set; }
  883. public bool StringDates { get; set; }
  884. }
  885. private readonly static IDictionary<Types, Type> _typeMap = new Dictionary<Types, Type>
  886. {
  887. {Types.Int32, typeof(int)},
  888. {Types.Int64, typeof (long)},
  889. {Types.Boolean, typeof (bool)},
  890. {Types.String, typeof (string)},
  891. {Types.Double, typeof(double)},
  892. {Types.Binary, typeof (byte[])},
  893. {Types.Regex, typeof (Regex)},
  894. {Types.DateTime, typeof (DateTime)},
  895. {Types.ObjectId, typeof(ObjectId)},
  896. {Types.Array, typeof(List<object>)},
  897. {Types.Object, typeof(Dictionary<string, object>)},
  898. {Types.Null, null},
  899. };
  900. private readonly BinaryReader _reader;
  901. private Document _current;
  902. private Deserializer(BinaryReader reader)
  903. {
  904. _reader = reader;
  905. }
  906. public static T Deserialize<T>(byte[] objectData, Options options = null) where T : class
  907. {
  908. using (var ms = new MemoryStream())
  909. {
  910. ms.Write(objectData, 0, objectData.Length);
  911. ms.Position = 0;
  912. return Deserialize<T>(new BinaryReader(ms), options ?? new Options());
  913. }
  914. }
  915. private static T Deserialize<T>(BinaryReader stream, Options options)
  916. {
  917. return new Deserializer(stream).Read<T>(options);
  918. }
  919. private T Read<T>(Options options)
  920. {
  921. NewDocument(_reader.ReadInt32());
  922. var @object = (T)DeserializeValue(typeof(T), Types.Object, options);
  923. return @object;
  924. }
  925. public static object Deserialize(BinaryReader stream, Type t, Options options = null)
  926. {
  927. return new Deserializer(stream).Read(t, options ?? new Options());
  928. }
  929. object Read(Type t, Options options)
  930. {
  931. NewDocument(_reader.ReadInt32());
  932. return DeserializeValue(t, Types.Object, options);
  933. }
  934. private void Read(int read)
  935. {
  936. _current.Digested += read;
  937. }
  938. private bool IsDone()
  939. {
  940. var isDone = _current.Digested + 1 == _current.Length;
  941. if (isDone)
  942. {
  943. _reader.ReadByte(); // EOO
  944. var old = _current;
  945. _current = old.Parent;
  946. if (_current != null) { Read(old.Length); }
  947. }
  948. return isDone;
  949. }
  950. private void NewDocument(int length)
  951. {
  952. var old = _current;
  953. _current = new Document { Length = length, Parent = old, Digested = 4 };
  954. }
  955. private object DeserializeValue(Type type, Types storedType, Options options)
  956. {
  957. return DeserializeValue(type, storedType, null, options);
  958. }
  959. private object DeserializeValue(Type type, Types storedType, object container, Options options)
  960. {
  961. if (storedType == Types.Null)
  962. {
  963. return null;
  964. }
  965. if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
  966. {
  967. type = Nullable.GetUnderlyingType(type);
  968. }
  969. if (type == typeof(string))
  970. {
  971. return ReadString();
  972. }
  973. if (type == typeof(int))
  974. {
  975. var val = ReadInt(storedType);
  976. return options.LongIntegers ? (object)(long)val : (object)val;
  977. }
  978. if (type.IsEnum)
  979. {
  980. return ReadEnum(type, storedType);
  981. }
  982. if (type == typeof(float))
  983. {
  984. Read(8);
  985. return (float)_reader.ReadDouble();
  986. }
  987. if (storedType == Types.Binary)
  988. {
  989. return ReadBinary();
  990. }
  991. if (typeof(IEnumerable).IsAssignableFrom(type))
  992. {
  993. return ReadList(type, container, options);
  994. }
  995. if (type == typeof(bool))
  996. {
  997. Read(1);
  998. return _reader.ReadBoolean();
  999. }
  1000. if (type == typeof(DateTime))
  1001. {
  1002. var value = Helper.Epoch.AddMilliseconds(ReadLong(Types.Int64));
  1003. return options.StringDates ? value.ToString("s", System.Globalization.CultureInfo.InvariantCulture) : (object)value;
  1004. }
  1005. if (type == typeof(ObjectId))
  1006. {
  1007. Read(12);
  1008. return new ObjectId(_reader.ReadBytes(12));
  1009. }
  1010. if (type == typeof(long))
  1011. {
  1012. return ReadLong(storedType);
  1013. }
  1014. if (type == typeof(double))
  1015. {
  1016. Read(8);
  1017. return _reader.ReadDouble();
  1018. }
  1019. if (type == typeof(Regex))
  1020. {
  1021. return ReadRegularExpression();
  1022. }
  1023. if (type == typeof(ScopedCode))
  1024. {
  1025. return ReadScopedCode(options);
  1026. }
  1027. return ReadObject(type, options);
  1028. }
  1029. private object ReadObject(Type type, Options options)
  1030. {
  1031. var instance = Activator.CreateInstance(type, true);
  1032. var typeHelper = TypeHelper.GetHelperForType(type);
  1033. while (true)
  1034. {
  1035. var storageType = ReadType();
  1036. var name = ReadName();
  1037. var isNull = false;
  1038. if (storageType == Types.Object)
  1039. {
  1040. var length = _reader.ReadInt32();
  1041. if (length == 5)
  1042. {
  1043. _reader.ReadByte(); //eoo
  1044. Read(5);
  1045. isNull = true;
  1046. }
  1047. else
  1048. {
  1049. NewDocument(length);
  1050. }
  1051. }
  1052. object container = null;
  1053. var property = typeHelper.FindProperty(name);
  1054. var propertyType = property != null ? property.Type : _typeMap.ContainsKey(storageType) ? _typeMap[storageType] : typeof(object);
  1055. if (property == null && typeHelper.Expando == null)
  1056. {
  1057. throw new BsonException(string.Format("Deserialization failed: type {0} does not have a property named {1}", type.FullName, name));
  1058. }
  1059. if (property != null && property.Setter == null)
  1060. {
  1061. container = property.Getter(instance);
  1062. }
  1063. var value = isNull ? null : DeserializeValue(propertyType, storageType, container, options);
  1064. if (property == null)
  1065. {
  1066. ((IDictionary<string, object>)typeHelper.Expando.Getter(instance))[name] = value;
  1067. }
  1068. else if (container == null && value != null && !property.Ignored)
  1069. {
  1070. property.Setter(instance, value);
  1071. }
  1072. if (IsDone())
  1073. {
  1074. break;
  1075. }
  1076. }
  1077. return instance;
  1078. }
  1079. private object ReadList(Type listType, object existingContainer, Options options)
  1080. {
  1081. if (IsDictionary(listType))
  1082. {
  1083. return ReadDictionary(listType, existingContainer, options);
  1084. }
  1085. NewDocument(_reader.ReadInt32());
  1086. var itemType = ListHelper.GetListItemType(listType);
  1087. var isObject = typeof(object) == itemType;
  1088. var wrapper = BaseWrapper.Create(listType, itemType, existingContainer);
  1089. while (!IsDone())
  1090. {
  1091. var storageType = ReadType();
  1092. ReadName();
  1093. if (storageType == Types.Object)
  1094. {
  1095. NewDocument(_reader.ReadInt32());
  1096. }
  1097. var specificItemType = isObject ? _typeMap[storageType] : itemType;
  1098. var value = DeserializeValue(specificItemType, storageType, options);
  1099. wrapper.Add(value);
  1100. }
  1101. return wrapper.Collection;
  1102. }
  1103. private static bool IsDictionary(Type type)
  1104. {
  1105. var types = new List<Type>(type.GetInterfaces());
  1106. types.Insert(0, type);
  1107. foreach (var interfaceType in types)
  1108. {
  1109. if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof(IDictionary<,>))
  1110. {
  1111. return true;
  1112. }
  1113. }
  1114. return false;
  1115. }
  1116. private object ReadDictionary(Type listType, object existingContainer, Options options)
  1117. {
  1118. var valueType = ListHelper.GetDictionarValueType(listType);
  1119. var isObject = typeof(object) == valueType;
  1120. var container = existingContainer == null ? ListHelper.CreateDictionary(listType, ListHelper.GetDictionarKeyType(listType), valueType) : (IDictionary)existingContainer;
  1121. while (!IsDone())
  1122. {
  1123. var storageType = ReadType();
  1124. var key = ReadName();
  1125. if (storageType == Types.Object)
  1126. {
  1127. NewDocument(_reader.ReadInt32());
  1128. }
  1129. var specificItemType = isObject ? _typeMap[storageType] : valueType;
  1130. var value = DeserializeValue(specificItemType, storageType, options);
  1131. container.Add(key, value);
  1132. }
  1133. return container;
  1134. }
  1135. private object ReadBinary()
  1136. {
  1137. var length = _reader.ReadInt32();
  1138. var subType = _reader.ReadByte();
  1139. Read(5 + length);
  1140. if (subType == 2)
  1141. {
  1142. return _reader.ReadBytes(_reader.ReadInt32());
  1143. }
  1144. if (subType == 3)
  1145. {
  1146. return new Guid(_reader.ReadBytes(length));
  1147. }
  1148. throw new BsonException("No support for binary type: " + subType);
  1149. }
  1150. private string ReadName()
  1151. {
  1152. var buffer = new List<byte>(128); //todo: use a pool to prevent fragmentation
  1153. byte b;
  1154. while ((b = _reader.ReadByte()) > 0)
  1155. {
  1156. buffer.Add(b);
  1157. }
  1158. Read(buffer.Count + 1);
  1159. return Encoding.UTF8.GetString(buffer.ToArray());
  1160. }
  1161. private string ReadString()
  1162. {
  1163. var length = _reader.ReadInt32();
  1164. var buffer = _reader.ReadBytes(length - 1); //todo: again, look at fragementation prevention
  1165. _reader.ReadByte(); //null;
  1166. Read(4 + length);
  1167. return Encoding.UTF8.GetString(buffer);
  1168. }
  1169. private int ReadInt(Types storedType)
  1170. {
  1171. switch (storedType)
  1172. {
  1173. case Types.Int32:
  1174. Read(4);
  1175. return _reader.ReadInt32();
  1176. case Types.Int64:
  1177. Read(8);
  1178. return (int)_reader.ReadInt64();
  1179. case Types.Double:
  1180. Read(8);
  1181. return (int)_reader.ReadDouble();
  1182. default:
  1183. throw new BsonException("Could not create an int from " + storedType);
  1184. }
  1185. }
  1186. private long ReadLong(Types storedType)
  1187. {
  1188. switch (storedType)
  1189. {
  1190. case Types.Int32:
  1191. Read(4);
  1192. return _reader.ReadInt32();
  1193. case Types.Int64:
  1194. Read(8);
  1195. return _reader.ReadInt64();
  1196. case Types.Double:
  1197. Read(8);
  1198. return (long)_reader.ReadDouble();
  1199. default:
  1200. throw new BsonException("Could not create an int64 from " + storedType);
  1201. }
  1202. }
  1203. private object ReadEnum(Type type, Types storedType)
  1204. {
  1205. if (storedType == Types.Int64)
  1206. {
  1207. return Enum.Parse(type, ReadLong(storedType).ToString(), false);
  1208. }
  1209. return Enum.Parse(type, ReadInt(storedType).ToString(), false);
  1210. }
  1211. private object ReadRegularExpression()
  1212. {
  1213. var pattern = ReadName();
  1214. var optionsString = ReadName();
  1215. var options = RegexOptions.None;
  1216. if (optionsString.Contains("e")) options = options | RegexOptions.ECMAScript;
  1217. if (optionsString.Contains("i")) options = options | RegexOptions.IgnoreCase;
  1218. if (optionsString.Contains("l")) options = options | RegexOptions.CultureInvariant;
  1219. if (optionsString.Contains("m")) options = options | RegexOptions.Multiline;
  1220. if (optionsString.Contains("s")) options = options | RegexOptions.Singleline;
  1221. if (optionsString.Contains("w")) options = options | RegexOptions.IgnorePatternWhitespace;
  1222. if (optionsString.Contains("x")) options = options | RegexOptions.ExplicitCapture;
  1223. return new Regex(pattern, options);
  1224. }
  1225. private Types ReadType()
  1226. {
  1227. Read(1);
  1228. return (Types)_reader.ReadByte();
  1229. }
  1230. private ScopedCode ReadScopedCode(Options options)
  1231. {
  1232. _reader.ReadInt32(); //length
  1233. Read(4);
  1234. var name = ReadString();
  1235. NewDocument(_reader.ReadInt32());
  1236. return new ScopedCode { CodeString = name, Scope = DeserializeValue(typeof(object), Types.Object, options) };
  1237. }
  1238. }
  1239. }
  1240. namespace Metsys.Bson.Configuration
  1241. {
  1242. public interface ITypeConfiguration<T>
  1243. {
  1244. ITypeConfiguration<T> UseAlias(Expression<Func<T, object>> expression, string alias);
  1245. ITypeConfiguration<T> Ignore(Expression<Func<T, object>> expression);
  1246. ITypeConfiguration<T> Ignore(string name);
  1247. ITypeConfiguration<T> IgnoreIfNull(Expression<Func<T, object>> expression);
  1248. }
  1249. internal class TypeConfiguration<T> : ITypeConfiguration<T>
  1250. {
  1251. private readonly BsonConfiguration _configuration;
  1252. internal TypeConfiguration(BsonConfiguration configuration)
  1253. {
  1254. _configuration = configuration;
  1255. }
  1256. public ITypeConfiguration<T> UseAlias(Expression<Func<T, object>> expression, string alias)
  1257. {
  1258. var member = expression.GetMemberExpression();
  1259. _configuration.AddMap<T>(member.GetName(), alias);
  1260. return this;
  1261. }
  1262. public ITypeConfiguration<T> Ignore(Expression<Func<T, object>> expression)
  1263. {
  1264. var member = expression.GetMemberExpression();
  1265. return Ignore(member.GetName());
  1266. }
  1267. public ITypeConfiguration<T> Ignore(string name)
  1268. {
  1269. _configuration.AddIgnore<T>(name);
  1270. return this;
  1271. }
  1272. public ITypeConfiguration<T> IgnoreIfNull(Expression<Func<T, object>> expression)
  1273. {
  1274. var member = expression.GetMemberExpression();
  1275. _configuration.AddIgnoreIfNull<T>(member.GetName());
  1276. return this;
  1277. }
  1278. }
  1279. }
  1280. namespace Metsys.Bson.Configuration
  1281. {
  1282. public static class ExpressionHelper
  1283. {
  1284. public static string GetName(this MemberExpression expression)
  1285. {
  1286. return new ExpressionNameVisitor().Visit(expression);
  1287. }
  1288. public static MemberExpression GetMemberExpression<T, TValue>(this Expression<Func<T, TValue>> expression)
  1289. {
  1290. if (expression == null)
  1291. {
  1292. return null;
  1293. }
  1294. if (expression.Body is MemberExpression)
  1295. {
  1296. return (MemberExpression)expression.Body;
  1297. }
  1298. if (expression.Body is UnaryExpression)
  1299. {
  1300. var operand = ((UnaryExpression)expression.Body).Operand;
  1301. if (operand is MemberExpression)
  1302. {
  1303. return (MemberExpression)operand;
  1304. }
  1305. if (operand is MethodCallExpression)
  1306. {
  1307. return ((MethodCallExpression)operand).Object as MemberExpression;
  1308. }
  1309. }
  1310. return null;
  1311. }
  1312. private class ExpressionNameVisitor
  1313. {
  1314. public string Visit(Expression expression)
  1315. {
  1316. if (expression is UnaryExpression)
  1317. {
  1318. expression = ((UnaryExpression)expression).Operand;
  1319. }
  1320. if (expression is MethodCallExpression)
  1321. {
  1322. return Visit((MethodCallExpression)expression);
  1323. }
  1324. if (expression is MemberExpression)
  1325. {
  1326. return Visit((MemberExpression)expression);
  1327. }
  1328. if (expression is BinaryExpression && expression.NodeType == ExpressionType.ArrayIndex)
  1329. {
  1330. return Visit((BinaryExpression)expression);
  1331. }
  1332. return null;
  1333. }
  1334. private string Visit(BinaryExpression expression)
  1335. {
  1336. string result = null;
  1337. if (expression.Left is MemberExpression)
  1338. {
  1339. result = Visit((MemberExpression)expression.Left);
  1340. }
  1341. var index = Expression.Lambda(expression.Right).Compile().DynamicInvoke();
  1342. return result + string.Format("[{0}]", index);
  1343. }
  1344. private string Visit(MemberExpression expression)
  1345. {
  1346. var name = expression.Member.Name;
  1347. var ancestorName = Visit(expression.Expression);
  1348. if (ancestorName != null)
  1349. {
  1350. name = ancestorName + "." + name;
  1351. }
  1352. return name;
  1353. }
  1354. private string Visit(MethodCallExpression expression)
  1355. {
  1356. string name = null;
  1357. if (expression.Object is MemberExpression)
  1358. {
  1359. name = Visit((MemberExpression)expression.Object);
  1360. }
  1361. //TODO: Is there a more certain way to determine if this is an indexed property?
  1362. if (expression.Method.Name == "get_Item" && expression.Arguments.Count == 1)
  1363. {
  1364. var index = Expression.Lambda(expression.Arguments[0]).Compile().DynamicInvoke();
  1365. name += string.Format("[{0}]", index);
  1366. }
  1367. return name;
  1368. }
  1369. }
  1370. }
  1371. }
  1372. namespace Metsys.Bson.Configuration
  1373. {
  1374. internal class BsonConfiguration
  1375. {
  1376. private readonly IDictionary<Type, IDictionary<string, string>> _aliasMap = new Dictionary<Type, IDictionary<string, string>>();
  1377. private readonly IDictionary<Type, HashSet<string>> _ignored = new Dictionary<Type, HashSet<string>>();
  1378. private readonly IDictionary<Type, HashSet<string>> _ignoredIfNull = new Dictionary<Type, HashSet<string>>();
  1379. //not thread safe
  1380. private static BsonConfiguration _instance;
  1381. internal static BsonConfiguration Instance
  1382. {
  1383. get
  1384. {
  1385. if (_instance == null) { _instance = new BsonConfiguration(); }
  1386. return _instance;
  1387. }
  1388. }
  1389. private BsonConfiguration() { }
  1390. public static void ForType<T>(Action<ITypeConfiguration<T>> action)
  1391. {
  1392. action(new TypeConfiguration<T>(Instance));
  1393. }
  1394. internal void AddMap<T>(string property, string alias)
  1395. {
  1396. var type = typeof(T);
  1397. if (!_aliasMap.ContainsKey(type))
  1398. {
  1399. _aliasMap[type] = new Dictionary<string, string>();
  1400. }
  1401. _aliasMap[type][property] = alias;
  1402. }
  1403. internal string AliasFor(Type type, string property)
  1404. {
  1405. IDictionary<string, string> map;
  1406. if (!_aliasMap.TryGetValue(type, out map))
  1407. {
  1408. return property;
  1409. }
  1410. return map.ContainsKey(property) ? map[property] : property;
  1411. }
  1412. public void AddIgnore<T>(string name)
  1413. {
  1414. var type = typeof(T);
  1415. if (!_ignored.ContainsKey(type))
  1416. {
  1417. _ignored[type] = new HashSet<string>();
  1418. }
  1419. _ignored[type].Add(name);
  1420. }
  1421. public bool IsIgnored(Type type, string name)
  1422. {
  1423. HashSet<string> list;
  1424. return _ignored.TryGetValue(type, out list) && list.Contains(name);
  1425. }
  1426. public void AddIgnoreIfNull<T>(string name)
  1427. {
  1428. var type = typeof(T);
  1429. if (!_ignoredIfNull.ContainsKey(type))
  1430. {
  1431. _ignoredIfNull[type] = new HashSet<string>();
  1432. }
  1433. _ignoredIfNull[type].Add(name);
  1434. }
  1435. public bool IsIgnoredIfNull(Type type, string name)
  1436. {
  1437. HashSet<string> list;
  1438. return _ignoredIfNull.TryGetValue(type, out list) && list.Contains(name);
  1439. }
  1440. }
  1441. }
  1442. namespace Metsys.Bson
  1443. {
  1444. internal class BsonException : Exception
  1445. {
  1446. public BsonException() { }
  1447. public BsonException(string message) : base(message) { }
  1448. public BsonException(string message, Exception innerException) : base(message, innerException) { }
  1449. protected BsonException(SerializationInfo info, StreamingContext context) : base(info, context) { }
  1450. }
  1451. }