FRReader.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669
  1. using System;
  2. using System.IO;
  3. using System.Reflection;
  4. using System.Collections.Generic;
  5. using System.Windows.Forms;
  6. namespace FastReport.Utils
  7. {
  8. /// <summary>
  9. /// The reader used to deserialize object's properties from a report file.
  10. /// </summary>
  11. public class FRReader : IDisposable
  12. {
  13. #region Fields
  14. private XmlDocument doc;
  15. private XmlItem root;
  16. private XmlItem curItem;
  17. private XmlItem curRoot;
  18. private XmlProperty[] props;
  19. private string errors;
  20. private List<FixupInfo> fixups;
  21. private Report report;
  22. private BlobStore blobStore;
  23. private bool readChildren;
  24. private SerializeTo deserializeFrom;
  25. #endregion
  26. #region Properties
  27. /// <summary>
  28. /// Gets a string that contains errors occured during the load.
  29. /// </summary>
  30. public string Errors
  31. {
  32. get { return errors; }
  33. }
  34. internal BlobStore BlobStore
  35. {
  36. get { return blobStore; }
  37. set { blobStore = value; }
  38. }
  39. /// <summary>
  40. /// Gets the current item name.
  41. /// </summary>
  42. public string ItemName
  43. {
  44. get { return curItem.Name; }
  45. }
  46. /// <summary>
  47. /// Gets or sets a value indicating whther is necessary to read the object's children.
  48. /// </summary>
  49. public bool ReadChildren
  50. {
  51. get { return readChildren; }
  52. set { readChildren = value; }
  53. }
  54. /// <summary>
  55. /// Returns Root element for this reader
  56. /// </summary>
  57. public XmlItem Root
  58. {
  59. get
  60. {
  61. if (curItem != null)
  62. return GetRoot(curItem, 11);
  63. return null;
  64. }
  65. }
  66. /// <summary>
  67. /// Gets or sets target of serialization.
  68. /// </summary>
  69. public SerializeTo DeserializeFrom
  70. {
  71. get { return deserializeFrom; }
  72. set { deserializeFrom = value; }
  73. }
  74. public Report Report
  75. {
  76. get { return report; }
  77. }
  78. private XmlItem GetRoot(XmlItem item, int count)
  79. {
  80. if (count < 0 || item.Parent==null)
  81. return item;
  82. return GetRoot(item.Parent, count - 1);
  83. }
  84. #endregion
  85. #region Private Methods
  86. private void GetProps()
  87. {
  88. if (curRoot != null)
  89. {
  90. props = curRoot.Properties;
  91. }
  92. }
  93. private string PropName(string name)
  94. {
  95. return ShortProperties.GetFullName(name);
  96. }
  97. private string PropValue(string name)
  98. {
  99. int i = IndexOf(name);
  100. if (i != -1)
  101. return props[i].Value;
  102. return "";
  103. }
  104. private int IndexOf(string name)
  105. {
  106. if (props == null)
  107. return -1;
  108. // property key should be trimmed
  109. name = name.Trim();
  110. int result = -1;
  111. for (int i = 0; i < props.Length; i++)
  112. {
  113. if (String.Compare(props[i].Key, name, true) == 0)
  114. {
  115. result = i;
  116. break;
  117. }
  118. }
  119. return result;
  120. }
  121. private void FixupReferences()
  122. {
  123. if (report == null)
  124. return;
  125. foreach (FixupInfo fixup in fixups)
  126. {
  127. PropertyInfo pi = fixup.obj.GetType().GetProperty(fixup.name);
  128. if (pi != null)
  129. pi.SetValue(fixup.obj, report.FindObject(fixup.value), null);
  130. }
  131. fixups.Clear();
  132. }
  133. #endregion
  134. #region Public Methods
  135. /// <summary>
  136. /// Reads the specified object.
  137. /// </summary>
  138. /// <param name="obj">The object to read.</param>
  139. /// <remarks>
  140. /// The object must implement the <see cref="IFRSerializable"/> interface. This method
  141. /// invokes the <b>Deserialize</b> method of the object.
  142. /// </remarks>
  143. /// <example>This example demonstrates the use of <b>ReadProperties</b>, <b>ReadChildren</b>,
  144. /// <b>NextItem</b>, <b>Read</b> methods.
  145. /// <code>
  146. /// public void Deserialize(FRReader reader)
  147. /// {
  148. /// // read simple properties like "Text", complex properties like "Border.Lines"
  149. /// reader.ReadProperties(this);
  150. ///
  151. /// // moves the current reader item
  152. /// while (reader.NextItem())
  153. /// {
  154. /// // read the "Styles" collection
  155. /// if (String.Compare(reader.ItemName, "Styles", true) == 0)
  156. /// reader.Read(Styles);
  157. /// else if (reader.ReadChildren)
  158. /// {
  159. /// // if read of children is enabled, read them
  160. /// Base obj = reader.Read();
  161. /// if (obj != null)
  162. /// obj.Parent = this;
  163. /// }
  164. /// }
  165. /// }
  166. /// </code>
  167. /// </example>
  168. public void Read(IFRSerializable obj)
  169. {
  170. XmlItem saveCurItem = curItem;
  171. XmlItem saveCurRoot = curRoot;
  172. XmlProperty[] saveProps = props;
  173. try
  174. {
  175. if (curItem == null)
  176. curItem = root;
  177. curRoot = curItem;
  178. GetProps();
  179. obj.Deserialize(this);
  180. }
  181. finally
  182. {
  183. curItem = saveCurItem;
  184. curRoot = saveCurRoot;
  185. props = saveProps;
  186. }
  187. }
  188. internal void Read(IFRSerializable obj, XmlItem Root)
  189. {
  190. curItem = Root;
  191. Read(obj);
  192. }
  193. /// <summary>
  194. /// Reads an object from current xml node.
  195. /// </summary>
  196. /// <returns>The object.</returns>
  197. /// <remarks>
  198. /// This method creates an instance of object described by the current xml node, then invokes
  199. /// its <b>Deserialize</b> method.
  200. /// </remarks>
  201. /// <example>This example demonstrates the use of <b>ReadProperties</b>, <b>ReadChildren</b>,
  202. /// <b>NextItem</b>, <b>Read</b> methods.
  203. /// <code>
  204. /// public void Deserialize(FRReader reader)
  205. /// {
  206. /// // read simple properties like "Text", complex properties like "Border.Lines"
  207. /// reader.ReadProperties(this);
  208. ///
  209. /// // moves the current reader item
  210. /// while (reader.NextItem())
  211. /// {
  212. /// // read the "Styles" collection
  213. /// if (String.Compare(reader.ItemName, "Styles", true) == 0)
  214. /// reader.Read(Styles);
  215. /// else if (reader.ReadChildren)
  216. /// {
  217. /// // if read of children is enabled, read them
  218. /// Base obj = reader.Read();
  219. /// if (obj != null)
  220. /// obj.Parent = this;
  221. /// }
  222. /// }
  223. /// }
  224. /// </code>
  225. /// </example>
  226. public IFRSerializable Read()
  227. {
  228. XmlItem saveCurItem = curItem;
  229. XmlItem saveCurRoot = curRoot;
  230. XmlProperty[] saveProps = props;
  231. IFRSerializable result = null;
  232. try
  233. {
  234. if (curItem == null)
  235. curItem = root;
  236. curRoot = curItem;
  237. GetProps();
  238. if (report != null && report.IsAncestor)
  239. result = report.FindObject(ReadStr("Name"));
  240. if (result == null && curItem.Name != "inherited")
  241. {
  242. Type type = RegisteredObjects.FindType(curItem.Name);
  243. if (type != null)
  244. {
  245. result = Activator.CreateInstance(type) as IFRSerializable;
  246. if (result is Report)
  247. report = result as Report;
  248. }
  249. else
  250. {
  251. if (!Config.WebMode)
  252. MessageBox.Show(Res.Get("Messages,CantFindObject") + " " + curItem.Name);
  253. else
  254. throw new ClassException(curItem.Name);
  255. }
  256. }
  257. if (result != null)
  258. result.Deserialize(this);
  259. }
  260. finally
  261. {
  262. curItem = saveCurItem;
  263. curRoot = saveCurRoot;
  264. props = saveProps;
  265. }
  266. return result;
  267. }
  268. private int getDotCount(string s)
  269. {
  270. if (String.IsNullOrEmpty(s))
  271. return 0;
  272. int i = 0;
  273. int count = 0;
  274. while ((i = s.IndexOf('.', i)) != -1)
  275. {
  276. ++i;
  277. ++count;
  278. }
  279. return count;
  280. }
  281. private void DoReadProperties(object obj, XmlProperty[] properties)
  282. {
  283. for (int i = 0; i < properties.Length; i++)
  284. {
  285. string name = properties[i].Key;
  286. string value = properties[i].Value;
  287. // check multiple properties like Frame.LeftLine.Typ
  288. object obj1 = obj;
  289. int len = name.Length;
  290. int start = 0;
  291. int j = 0;
  292. // find '.'
  293. while (j < len && name[j] != '.')
  294. j++;
  295. if (j < len)
  296. {
  297. while (j < len)
  298. {
  299. // get subproperty
  300. PropertyInfo pi = obj1.GetType().GetProperty(name.Substring(start, j - start));
  301. if (pi == null) break;
  302. obj1 = pi.GetValue(obj1, null);
  303. // find next '.'
  304. start = j + 1;
  305. j++;
  306. while (j < len && name[j] != '.')
  307. j++;
  308. }
  309. name = name.Substring(start);
  310. }
  311. try
  312. {
  313. name = PropName(name);
  314. PropertyInfo pi = obj1.GetType().GetProperty(name);
  315. if (pi == null)
  316. continue;
  317. if (value == "null")
  318. {
  319. if (pi.PropertyType == typeof(string))
  320. pi.SetValue(obj1, "null", null);
  321. else
  322. pi.SetValue(obj1, null, null);
  323. }
  324. else
  325. {
  326. if (pi.PropertyType == typeof(string))
  327. {
  328. pi.SetValue(obj1, value, null);
  329. }
  330. else if (pi.PropertyType.IsClass && pi.PropertyType.IsSubclassOf(typeof(Base)))
  331. {
  332. // it's a reference
  333. fixups.Add(new FixupInfo(obj1, name, value));
  334. }
  335. else
  336. {
  337. pi.SetValue(obj1, Converter.FromString(pi.PropertyType, value), null);
  338. }
  339. }
  340. }
  341. catch (Exception e)
  342. {
  343. errors += e.Message + "\r\n";
  344. }
  345. }
  346. }
  347. /// <summary>
  348. /// Reads properties of specified object.
  349. /// </summary>
  350. /// <param name="obj">The object to read.</param>
  351. /// <remarks>
  352. /// This method reads simple properties like "Text", "Border.Lines" etc. for specified object.
  353. /// To read nested properties like collections, you should override the <see cref="Base.DeserializeSubItems"/>
  354. /// method of an object.
  355. /// </remarks>
  356. /// <example>This example demonstrates the use of <b>ReadProperties</b>, <b>ReadChildren</b>,
  357. /// <b>NextItem</b>, <b>Read</b> methods.
  358. /// <code>
  359. /// public void Deserialize(FRReader reader)
  360. /// {
  361. /// // read simple properties like "Text", complex properties like "Border.Lines"
  362. /// reader.ReadProperties(this);
  363. ///
  364. /// // moves the current reader item
  365. /// while (reader.NextItem())
  366. /// {
  367. /// // read the "Styles" collection
  368. /// if (String.Compare(reader.ItemName, "Styles", true) == 0)
  369. /// reader.Read(Styles);
  370. /// else if (reader.ReadChildren)
  371. /// {
  372. /// // if read of children is enabled, read them
  373. /// Base obj = reader.Read();
  374. /// if (obj != null)
  375. /// obj.Parent = this;
  376. /// }
  377. /// }
  378. /// }
  379. /// </code>
  380. /// </example>
  381. public void ReadProperties(object obj)
  382. {
  383. if (props == null)
  384. return;
  385. // speed optimization, for use in the preview mode
  386. if (obj is TextObject && props.Length == 1 && props[0].Key == "x")
  387. {
  388. (obj as TextObject).Text = props[0].Value;
  389. return;
  390. }
  391. // Fix for multilevel properties with dots such Barcode.CalcCheckSum
  392. // Reported wrong working with saving from On-line Designer
  393. XmlProperty[] FProps0 = new XmlProperty[0];
  394. XmlProperty[] FProps1 = new XmlProperty[0];
  395. XmlProperty[] FProps2 = new XmlProperty[0];
  396. for (int i = 0; i < props.Length; i++)
  397. {
  398. int dotCount = getDotCount(props[i].Key);
  399. switch (dotCount)
  400. {
  401. case 0:
  402. AppendProperty(ref FProps0, props[i]);
  403. break;
  404. case 1:
  405. AppendProperty(ref FProps1, props[i]);
  406. break;
  407. default:
  408. AppendProperty(ref FProps2, props[i]);
  409. break;
  410. }
  411. }
  412. // without dots
  413. if (FProps0.Length > 0)
  414. DoReadProperties(obj, FProps0);
  415. // with one dot
  416. if (FProps1.Length > 0)
  417. DoReadProperties(obj, FProps1);
  418. // with two dots
  419. if (FProps2.Length > 0)
  420. DoReadProperties(obj, FProps2);
  421. }
  422. private void AppendProperty(ref XmlProperty[] fProps, XmlProperty xmlProperty)
  423. {
  424. Array.Resize<XmlProperty>(ref fProps, fProps.Length + 1);
  425. fProps[fProps.Length - 1] = xmlProperty;
  426. }
  427. /// <summary>
  428. /// Moves the current xml item.
  429. /// </summary>
  430. /// <returns><b>false</b> if there is no more items to move on; <b>true</b> otherwise.</returns>
  431. /// <remarks>
  432. /// This method is used to read child objects.
  433. /// </remarks>
  434. /// <example>This example demonstrates the use of <b>ReadProperties</b>, <b>ReadChildren</b>,
  435. /// <b>NextItem</b>, <b>Read</b> methods.
  436. /// <code>
  437. /// public void Deserialize(FRReader reader)
  438. /// {
  439. /// // read simple properties like "Text", complex properties like "Border.Lines"
  440. /// reader.ReadProperties(this);
  441. ///
  442. /// // moves the current reader item
  443. /// while (reader.NextItem())
  444. /// {
  445. /// // read the "Styles" collection
  446. /// if (String.Compare(reader.ItemName, "Styles", true) == 0)
  447. /// reader.Read(Styles);
  448. /// else if (reader.ReadChildren)
  449. /// {
  450. /// // if read of children is enabled, read them
  451. /// Base obj = reader.Read();
  452. /// if (obj != null)
  453. /// obj.Parent = this;
  454. /// }
  455. /// }
  456. /// }
  457. /// </code>
  458. /// </example>
  459. public bool NextItem()
  460. {
  461. if (curItem == curRoot)
  462. {
  463. if (curRoot.Count > 0)
  464. {
  465. curItem = curRoot[0];
  466. return true;
  467. }
  468. else
  469. return false;
  470. }
  471. else
  472. {
  473. int i = curRoot.IndexOf(curItem);
  474. if (i < curRoot.Count - 1)
  475. {
  476. curItem = curRoot[i + 1];
  477. return true;
  478. }
  479. else
  480. return false;
  481. }
  482. }
  483. /// <summary>
  484. /// Checks if current item has specified property.
  485. /// </summary>
  486. /// <param name="name">The property name to check.</param>
  487. /// <returns><b>true</b> if current item has specified property.</returns>
  488. public bool HasProperty(string name)
  489. {
  490. return IndexOf(name) != -1;
  491. }
  492. /// <summary>
  493. /// Reads the string property.
  494. /// </summary>
  495. /// <param name="name">Name of property.</param>
  496. /// <returns>Property value.</returns>
  497. public string ReadStr(string name)
  498. {
  499. return PropValue(name);
  500. }
  501. /// <summary>
  502. /// Reads the boolean property.
  503. /// </summary>
  504. /// <param name="name">Name of property.</param>
  505. /// <returns>Property value.</returns>
  506. public bool ReadBool(string name)
  507. {
  508. string prop = PropValue(name);
  509. return (prop == "1" || prop.ToLower() == "true") ? true : false;
  510. }
  511. /// <summary>
  512. /// Reads the integer property.
  513. /// </summary>
  514. /// <param name="name">Name of property.</param>
  515. /// <returns>Property value.</returns>
  516. public int ReadInt(string name)
  517. {
  518. return int.Parse(PropValue(name));
  519. }
  520. /// <summary>
  521. /// Reads the float property.
  522. /// </summary>
  523. /// <param name="name">Name of property.</param>
  524. /// <returns>Property value.</returns>
  525. public float ReadFloat(string name)
  526. {
  527. return (float)Converter.FromString(typeof(float), PropValue(name));
  528. }
  529. /// <summary>
  530. /// Reads the double property.
  531. /// </summary>
  532. /// <param name="name">Name of property.</param>
  533. /// <returns>Property value.</returns>
  534. public double ReadDouble(string name)
  535. {
  536. return (double)Converter.FromString(typeof(double), PropValue(name));
  537. }
  538. /// <summary>
  539. /// Reads the enum property.
  540. /// </summary>
  541. /// <param name="name">Name of property.</param>
  542. /// <param name="typ">Type of property.</param>
  543. /// <returns>Property value.</returns>
  544. public object ReadValue(string name, Type typ)
  545. {
  546. string propValue = PropValue(name);
  547. if (propValue == "null")
  548. {
  549. if (typ == typeof(string))
  550. return "null";
  551. return null;
  552. }
  553. return Converter.FromString(typ, propValue);
  554. }
  555. /// <summary>
  556. /// Reads the standalone property value.
  557. /// </summary>
  558. /// <returns>Property value.</returns>
  559. public string ReadPropertyValue()
  560. {
  561. return curItem.Value;
  562. }
  563. /// <summary>
  564. /// Disposes the reader, fixups the property references.
  565. /// </summary>
  566. public void Dispose()
  567. {
  568. FixupReferences();
  569. doc.Dispose();
  570. }
  571. /// <summary>
  572. /// Loads the xml items from a stream.
  573. /// </summary>
  574. /// <param name="stream">The stream to load from.</param>
  575. public void Load(Stream stream)
  576. {
  577. doc.Load(stream);
  578. }
  579. #endregion
  580. /// <summary>
  581. /// Initializes a new instance of the <b>FRReader</b> class with specified report.
  582. /// </summary>
  583. /// <param name="report">Reference to a report.</param>
  584. public FRReader(Report report)
  585. {
  586. doc = new XmlDocument();
  587. root = doc.Root;
  588. fixups = new List<FixupInfo>();
  589. errors = "";
  590. this.report = report;
  591. readChildren = true;
  592. }
  593. /// <summary>
  594. /// Initializes a new instance of the <b>FRReader</b> class with specified report and xml item with
  595. /// contents to read.
  596. /// </summary>
  597. /// <param name="report">Reference to a report.</param>
  598. /// <param name="root">Xml item with contents to read.</param>
  599. public FRReader(Report report, XmlItem root) : this(report)
  600. {
  601. this.root = root;
  602. }
  603. private class FixupInfo
  604. {
  605. public object obj;
  606. public string name;
  607. public string value;
  608. public FixupInfo(object obj, string name, string value)
  609. {
  610. this.obj = obj;
  611. this.name = name;
  612. this.value = value;
  613. }
  614. }
  615. }
  616. }