RTF_Container.cs 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Drawing;
  4. using System.IO;
  5. using System.Text;
  6. namespace FastReport.RichTextParser
  7. {
  8. internal static class ExportUtils
  9. {
  10. public static void Write(Stream stream, string value)
  11. {
  12. byte[] buf = Encoding.UTF8.GetBytes(value);
  13. stream.Write(buf, 0, buf.Length);
  14. }
  15. public static void WriteLn(Stream stream, string value)
  16. {
  17. Write(stream, value);
  18. stream.WriteByte(13);
  19. stream.WriteByte(10);
  20. }
  21. }
  22. /// <summary>
  23. /// This class represents a RTF run.
  24. /// </summary>
  25. internal class RTF_Run
  26. {
  27. private readonly Run run;
  28. internal RTF_Run(RunFormat f, string text)
  29. {
  30. run = new Run(text, f);
  31. }
  32. }
  33. internal abstract class RTF_CommonRichElement
  34. {
  35. static readonly int DpiX = 96;
  36. protected static int Twips2Pixels(int twips)
  37. {
  38. return (int)(((double)twips) * (1.0 / 1440.0) * DpiX);
  39. }
  40. protected static int Twips2Pixels(long twips)
  41. {
  42. return (int)(((double)twips) * (1.0 / 1440.0) * DpiX);
  43. }
  44. internal abstract RichObject RichObject { get; }
  45. internal abstract bool Parse(RTF_Parser parser, RTF_Header header);
  46. }
  47. internal class RTF_SequenceParser
  48. {
  49. private RichObjectSequence sequence;
  50. private RTF_Picture picture_parser = null;
  51. private RTF_Paragraph paragraph_parser = null;
  52. private RTF_Column curr_column = new RTF_Column();
  53. private RTF_Row current_row = null;
  54. private List<RichObjectSequence> cells_queue;
  55. RichObjectSequence cell_sequence;
  56. private Table table;
  57. private bool new_table = false;
  58. public RichObjectSequence Sequence { get { return sequence; } }
  59. public Table CurrentTable { get { return table; } }
  60. internal RTF_SequenceParser()
  61. {
  62. sequence.objects = new List<RichObject>();
  63. cells_queue = new List<RichObjectSequence>();
  64. cell_sequence.objects = new List<RichObject>();
  65. }
  66. /// <summary>
  67. /// Insert paragraph into list of paragraphs
  68. /// </summary>
  69. private void InsertParagraph(RTF_Parser parser)
  70. {
  71. paragraph_parser.Fix(parser);
  72. if (!parser.insideTable)
  73. {
  74. sequence.objects.Add(paragraph_parser.RichObject);
  75. sequence.size += paragraph_parser.RichObject.size;
  76. }
  77. else
  78. {
  79. cell_sequence.objects.Add(paragraph_parser.RichObject);
  80. }
  81. paragraph_parser = new RTF_Paragraph(parser);
  82. }
  83. private void InsertCell(RTF_Parser parser)
  84. {
  85. Fix(parser);
  86. cells_queue.Add(cell_sequence);
  87. cell_sequence = new RichObjectSequence();
  88. cell_sequence.objects = new List<RichObject>();
  89. paragraph_parser = new RTF_Paragraph(parser);
  90. }
  91. /// <summary>
  92. /// Insert row into list of paragraphs
  93. /// </summary>
  94. private void InsertRow()
  95. {
  96. // Move parsed cells to current row
  97. foreach (RichObjectSequence sequence in cells_queue)
  98. {
  99. current_row.AddCell(sequence);
  100. }
  101. cells_queue = new List<RichObjectSequence>();
  102. table.rows.Add(current_row.Row);
  103. current_row = new RTF_Row(this);
  104. if (new_table)
  105. {
  106. InsertTable();
  107. new_table = false;
  108. }
  109. }
  110. private void InsertTable()
  111. {
  112. RichObject rich = new RichObject();
  113. rich.type = RichObject.Type.Table;
  114. rich.table = table;
  115. sequence.objects.Add(rich);
  116. sequence.size += rich.size;
  117. }
  118. private void CreateTable()
  119. {
  120. new_table = true;
  121. table.columns = new List<Column>();
  122. table.rows = new List<TableRow>();
  123. current_row = new RTF_Row(this);
  124. }
  125. internal void Fix(RTF_Parser parser)
  126. {
  127. if (paragraph_parser != null)
  128. {
  129. paragraph_parser.Fix(parser);
  130. if (parser.insideTable)
  131. cell_sequence.objects.Add(paragraph_parser.RichObject);
  132. /* Following code adds empty paragraph at end of page, so disable it now */
  133. else if (paragraph_parser.RichObject.type == RichObject.Type.Paragraph)
  134. {
  135. if (paragraph_parser.RichObject.pargraph.runs.Count != 0)
  136. {
  137. sequence.objects.Add(paragraph_parser.RichObject);
  138. sequence.size += paragraph_parser.RichObject.size;
  139. }
  140. }
  141. }
  142. if (new_table)
  143. {
  144. InsertTable();
  145. new_table = false;
  146. }
  147. return;
  148. }
  149. internal bool Parse(RTF_Parser parser, RTF_Header header)
  150. {
  151. bool parsed = true;
  152. if (picture_parser != null)
  153. {
  154. parsed = picture_parser.Parse(parser, header);
  155. if (parsed)
  156. return true;
  157. // 20210211: check if picture within paragraph
  158. if(paragraph_parser.Runs.Count > 0)
  159. {
  160. sequence.objects.Add(paragraph_parser.RichObject);
  161. paragraph_parser = new RTF_Paragraph(parser);
  162. }
  163. if (parser.insideTable)
  164. cell_sequence.objects.Add(picture_parser.RichObject);
  165. else
  166. {
  167. sequence.objects.Add(picture_parser.RichObject);
  168. sequence.size += picture_parser.RichObject.size;
  169. }
  170. picture_parser = null;
  171. return true;
  172. }
  173. if (paragraph_parser == null)
  174. paragraph_parser = new RTF_Paragraph(parser);
  175. parsed = paragraph_parser.Parse(parser, header);
  176. if (parsed)
  177. return true;
  178. parsed = curr_column.Parse(parser, header);
  179. if (parsed)
  180. return true;
  181. if (current_row != null)
  182. {
  183. parsed = current_row.Parse(parser, header);
  184. if (parsed)
  185. return true;
  186. }
  187. parsed = true;
  188. switch (parser.Control)
  189. {
  190. case "par":
  191. InsertParagraph(parser);
  192. parser.ListItem = false; // Disable list
  193. break;
  194. case "cellx":
  195. uint w = (uint)parser.Number;
  196. curr_column.SetWidth(w);
  197. table.columns.Add(curr_column.Column);
  198. curr_column = new RTF_Column();
  199. break;
  200. case "cell":
  201. InsertCell(parser);
  202. break;
  203. case "row":
  204. InsertRow();
  205. break;
  206. case "trowd":
  207. CreateTable();
  208. break;
  209. case "pict":
  210. picture_parser = new RTF_Picture();
  211. break;
  212. default:
  213. ////if(parser.Status == ParserStatus.CloseBlock)
  214. ////{
  215. //// InsertParagraph(parser);
  216. //// break;
  217. ////}
  218. parsed = false;
  219. break;
  220. }
  221. return parsed;
  222. }
  223. }
  224. /// <summary>
  225. /// This class represents a RTF properies.
  226. /// </summary>
  227. class RTF_PageParser
  228. {
  229. private Page page;
  230. RichDocument document;
  231. RTF_SequenceParser sequence_parser = new RTF_SequenceParser();
  232. private RTF_SequenceParser page_header = null;
  233. private RTF_SequenceParser page_footer = null;
  234. public Page Page { get { return page; } }
  235. public RTF_PageParser(bool soft, RichDocument document)
  236. {
  237. page.soft_break = soft;
  238. page.margin_top = 0;
  239. page.margin_left = 0;
  240. page.margin_right = 0;
  241. page.margin_bottom = 0;
  242. page.sequence.objects = new List<RichObject>();
  243. this.document = document;
  244. }
  245. internal void Fix(RTF_Parser parser)
  246. {
  247. sequence_parser.Fix(parser);
  248. page.sequence = sequence_parser.Sequence;
  249. page.size = page.sequence.size;
  250. }
  251. static int indirection_count = 0;
  252. internal bool Parse(RTF_Parser parser, RTF_Header header)
  253. {
  254. bool parsed = false;
  255. if (page_header != null)
  256. {
  257. parsed = page_header.Parse(parser, header);
  258. if (!parsed)
  259. {
  260. //this.page_header.AddString(parser, "\\" + parser.Control);
  261. }
  262. if (parser.Status == ParserStatus.CloseBlock)
  263. {
  264. indirection_count--;
  265. if (indirection_count < 0)
  266. {
  267. indirection_count = 0;
  268. if (Page.header.objects == null)
  269. this.page.header.objects = new List<RichObject>();
  270. foreach (RichObject o in page_header.Sequence.objects)
  271. {
  272. this.Page.header.objects.Add(o);
  273. }
  274. page_header = null;
  275. return false;
  276. }
  277. }
  278. else if (parser.Status == ParserStatus.OpenBlock)
  279. {
  280. indirection_count++;
  281. }
  282. return true;
  283. }
  284. if (page_footer != null)
  285. {
  286. parsed = page_footer.Parse(parser, header);
  287. if (!parsed)
  288. {
  289. //this.page_footer.AddString(parser, "\\" + parser.Control);
  290. }
  291. if (parser.Status == ParserStatus.CloseBlock)
  292. {
  293. indirection_count--;
  294. if (indirection_count < 0)
  295. {
  296. indirection_count = 0;
  297. if (Page.footer.objects == null)
  298. this.page.footer.objects = new List<RichObject>();
  299. foreach (RichObject o in page_footer.Sequence.objects)
  300. {
  301. this.Page.footer.objects.Add(o);
  302. }
  303. page_footer = null;
  304. return false;
  305. }
  306. }
  307. else if (parser.Status == ParserStatus.OpenBlock)
  308. {
  309. indirection_count++;
  310. }
  311. return true;
  312. }
  313. parsed = sequence_parser.Parse(parser, header);
  314. if (!parsed)
  315. {
  316. parsed = true;
  317. switch (parser.Control)
  318. {
  319. case "pgwsxn":
  320. page.page_width = parser.Number;
  321. break;
  322. case "pghsxn":
  323. page.page_heigh = parser.Number;
  324. break;
  325. case "marglsxn":
  326. page.margin_left = parser.Number;
  327. break;
  328. case "margrsxn":
  329. page.margin_right = parser.Number;
  330. break;
  331. case "margtsxn":
  332. page.margin_top = parser.Number;
  333. break;
  334. case "margbsxn":
  335. page.margin_bottom = parser.Number;
  336. break;
  337. case "headerr":
  338. case "header":
  339. page_header = new RTF_SequenceParser();
  340. break;
  341. case "footer":
  342. case "footerr":
  343. page_footer = new RTF_SequenceParser();
  344. break;
  345. default:
  346. parsed = false;
  347. break;
  348. }
  349. }
  350. return parsed;
  351. }
  352. }
  353. class RTF_BorderLine_Parser
  354. {
  355. internal BorderLine line;
  356. internal void Clear()
  357. {
  358. line.style = BorderLine.Style.Thin;
  359. line.width = 0;
  360. line.color = System.Drawing.Color.Black;
  361. }
  362. internal bool Parse(RTF_Parser parser, RTF_Header header)
  363. {
  364. bool parsed = true;
  365. switch (parser.Control)
  366. {
  367. case "brdrs":
  368. line.style = BorderLine.Style.Thin;
  369. break;
  370. case "brdrth":
  371. line.style = BorderLine.Style.Thick;
  372. break;
  373. case "brdrdb":
  374. line.style = BorderLine.Style.Double;
  375. break;
  376. case "brdrdot":
  377. line.style = BorderLine.Style.Dotted;
  378. break;
  379. case "brdrw":
  380. line.width = (uint)parser.Number;
  381. break;
  382. case "brdrcf":
  383. {
  384. int cidx = (int)parser.Number;
  385. line.color = header.Document.color_list[cidx];
  386. break;
  387. }
  388. default:
  389. parsed = false;
  390. break;
  391. }
  392. return parsed;
  393. }
  394. }
  395. /// <summary>
  396. /// This class parses an entiry RTF document.
  397. /// </summary>
  398. public class RTF_DocumentParser : IDisposable
  399. {
  400. private RichDocument doc;
  401. int nested_block_count;
  402. bool skip_rtf_extension;
  403. enum GlobalMode { Header, Document }
  404. private RTF_PageParser curr_page;
  405. private RTF_Header header_parser;
  406. private Stack<RunFormat> run_formats_stack;
  407. private Stack<ParagraphFormat> parahraph_format_stack; // Do we need keep track of paragraphs format?
  408. public RichDocument Document { get { return doc; } }
  409. #if false
  410. Dictionary<RTF_RunFormat, RTF_RunFormat> format_hash;
  411. internal RTF_RunFormat FindFormat(RTF_RunFormat key)
  412. {
  413. if (!format_hash.ContainsKey(key))
  414. return null;
  415. return format_hash[key];
  416. }
  417. #endif
  418. internal static bool ParseParagraphFormat(RTF_Parser parser)
  419. {
  420. bool status = true;
  421. switch (parser.Control)
  422. {
  423. case "clvertalt":
  424. parser.current_paragraph_format.Valign = ParagraphFormat.VerticalAlign.Top;
  425. break;
  426. case "clvertalc":
  427. parser.current_paragraph_format.Valign = ParagraphFormat.VerticalAlign.Center;
  428. break;
  429. case "clvertalb":
  430. parser.current_paragraph_format.Valign = ParagraphFormat.VerticalAlign.Bottom;
  431. break;
  432. default:
  433. parser.current_paragraph_format.Valign = ParagraphFormat.VerticalAlign.Top; // 20210722
  434. break;
  435. }
  436. switch (parser.Control)
  437. {
  438. case "qc":
  439. parser.current_paragraph_format.align = ParagraphFormat.HorizontalAlign.Centered;
  440. break;
  441. case "ql":
  442. parser.current_paragraph_format.align = ParagraphFormat.HorizontalAlign.Left;
  443. break;
  444. case "qr":
  445. parser.current_paragraph_format.align = ParagraphFormat.HorizontalAlign.Right;
  446. break;
  447. case "qj":
  448. parser.current_paragraph_format.align = ParagraphFormat.HorizontalAlign.Justified;
  449. break;
  450. case "qd":
  451. parser.current_paragraph_format.align = ParagraphFormat.HorizontalAlign.Distributed;
  452. break;
  453. case "qk":
  454. parser.current_paragraph_format.align = ParagraphFormat.HorizontalAlign.Kashida;
  455. break;
  456. case "qt":
  457. parser.current_paragraph_format.align = ParagraphFormat.HorizontalAlign.Thai;
  458. break;
  459. case "sl":
  460. parser.current_paragraph_format.line_spacing = (int)parser.Number;
  461. break;
  462. case "sb":
  463. parser.current_paragraph_format.space_before = (int)parser.Number;
  464. break;
  465. case "sa":
  466. parser.current_paragraph_format.space_after = (int)parser.Number;
  467. break;
  468. case "li":
  469. parser.current_paragraph_format.left_indent = (int)parser.Number;
  470. break;
  471. case "ri":
  472. parser.current_paragraph_format.right_indent = (int)parser.Number;
  473. break;
  474. case "fi":
  475. parser.current_paragraph_format.first_line_indent = (int)parser.Number;
  476. break;
  477. case "slmult":
  478. parser.current_paragraph_format.lnspcmult = (ParagraphFormat.LnSpcMult)parser.Number;
  479. break;
  480. case "pntext":
  481. parser.ResetRunFormat();
  482. parser.current_paragraph_format.list_id = new List<Run>();
  483. parser.current_paragraph_format.pnstart = 1; // No support of nested numbering in this version
  484. parser.ListItem = true;
  485. break;
  486. case "ltrpar":
  487. parser.current_paragraph_format.text_direction = ParagraphFormat.Direction.LeftToRight;
  488. break;
  489. case "rtlpar":
  490. parser.current_paragraph_format.text_direction = ParagraphFormat.Direction.RighgToLeft;
  491. break;
  492. case "tx":
  493. if (parser.current_paragraph_format.tab_positions == null)
  494. parser.current_paragraph_format.tab_positions = new List<int>();
  495. parser.current_paragraph_format.tab_positions.Add((int)parser.Number);
  496. break;
  497. case "pntxta":
  498. parser.ClearParsedText();
  499. break;
  500. case "pntxtb":
  501. parser.ClearParsedText();
  502. break;
  503. default:
  504. status = false;
  505. break;
  506. }
  507. return status;
  508. }
  509. internal static bool ParseRunFormat(RTF_Parser parser, RTF_Header header)
  510. {
  511. bool accepted = true;
  512. int cidx;
  513. switch (parser.Control)
  514. {
  515. case "b":
  516. parser.current_run_format.bold = parser.HasValue ? (parser.Number == 0 ? false : true) : true;
  517. break;
  518. case "i":
  519. parser.current_run_format.italic = parser.HasValue ? (parser.Number == 0 ? false : true) : true;
  520. break;
  521. case "cf":
  522. cidx = (int) parser.Number;
  523. if(cidx > 0)
  524. {
  525. if (cidx > header.Document.color_list.Count - 1)
  526. cidx = header.Document.color_list.Count - 1;
  527. }
  528. parser.current_run_format.color = header.Document.color_list[cidx];
  529. break;
  530. case "highlight":
  531. cidx = (int)parser.Number;
  532. if (cidx != 0)
  533. parser.current_run_format.BColor = header.Document.color_list[cidx];
  534. else
  535. parser.current_run_format.BColor = Color.White;
  536. break;
  537. case "cbpat":
  538. cidx = (int)parser.Number;
  539. parser.current_run_format.FillColor = header.Document.color_list[cidx];
  540. break;
  541. case "ul":
  542. parser.current_run_format.underline = parser.HasValue ? (parser.Number == 0 ? false : true) : true;
  543. break;
  544. case "f":
  545. uint idx = header.GetFontID(parser.Number);
  546. parser.current_run_format.font_idx = idx;
  547. RFont rf = header.Document.font_list[(int)idx];
  548. parser.font_charset = rf.charset;
  549. if(rf.charset != 0)
  550. {
  551. parser.SelectCodepageByFontCharset(rf.charset);
  552. }
  553. break;
  554. case "fs":
  555. parser.current_run_format.font_size = (int)parser.Number;
  556. break;
  557. case "ulnone":
  558. parser.current_run_format.underline = false;
  559. break;
  560. case "plain":
  561. parser.ResetRunFormat();
  562. break;
  563. case "up":
  564. if (parser.Number == 0)
  565. parser.current_run_format.script_type = RunFormat.ScriptType.PlainText;
  566. else
  567. parser.current_run_format.script_type = RunFormat.ScriptType.Superscript;
  568. break;
  569. case "dn":
  570. if (parser.Number == 0)
  571. parser.current_run_format.script_type = RunFormat.ScriptType.PlainText;
  572. else
  573. parser.current_run_format.script_type = RunFormat.ScriptType.Subscript;
  574. break;
  575. case "super":
  576. parser.current_run_format.script_type = RunFormat.ScriptType.Superscript;
  577. break;
  578. case "sub":
  579. parser.current_run_format.script_type = RunFormat.ScriptType.Subscript;
  580. break;
  581. case "nosupersub":
  582. parser.current_run_format.script_type = RunFormat.ScriptType.PlainText;
  583. break;
  584. case "strike":
  585. parser.current_run_format.strike = parser.HasValue ? (parser.Number == 0 ? false : true) : true;
  586. break;
  587. default:
  588. accepted = false;
  589. break;
  590. }
  591. return accepted;
  592. }
  593. /// <inheritdoc/>
  594. public void Load(byte[] bytes)
  595. {
  596. using (MemoryStream stream = new MemoryStream(bytes))
  597. Load(stream);
  598. }
  599. /// <inheritdoc/>
  600. public Color GetFillColor()
  601. {
  602. Color color = Color.White;
  603. foreach(RichObject obj in curr_page.Page.sequence.objects)
  604. {
  605. if (obj.type == RichObject.Type.Paragraph )
  606. {
  607. if(obj.pargraph.runs.Count > 0)
  608. {
  609. color = obj.pargraph.runs[0].format.FillColor;
  610. break;
  611. }
  612. }
  613. }
  614. return color;
  615. }
  616. /// <inheritdoc/>
  617. public void Load(string rich_text)
  618. {
  619. // System.Diagnostics.Trace.WriteLine(rich_text);
  620. MemoryStream stream = new MemoryStream();
  621. StreamWriter writer = new StreamWriter(stream);
  622. writer.Write(rich_text);
  623. writer.Flush();
  624. stream.Position = 0;
  625. Load(stream);
  626. }
  627. /// <inheritdoc/>
  628. public void Load(Stream stream)
  629. {
  630. GlobalMode mode;
  631. ParserStatus status = ParserStatus.Collecting;
  632. int ch;
  633. RTF_Parser parser = new RTF_Parser();
  634. int block_sychro = 0;
  635. header_parser = new RTF_Header(doc);
  636. mode = GlobalMode.Header;
  637. while (true)
  638. {
  639. ch = stream.ReadByte();
  640. if (ch == -1)
  641. {
  642. if (status == ParserStatus.Collecting && parser.EndOfFile)
  643. {
  644. header_parser.Header = false;
  645. doc = header_parser.Document;
  646. mode = GlobalMode.Document;
  647. Parse(parser);
  648. }
  649. break;
  650. }
  651. status = parser.ParseByte((char)ch);
  652. if (status == ParserStatus.Collecting)
  653. continue;
  654. if (status == ParserStatus.OpenBlock)
  655. {
  656. run_formats_stack.Push(parser.current_run_format);
  657. ++block_sychro;
  658. }
  659. //if(parser.Control == "tx")
  660. //{
  661. // System.Diagnostics.Trace.Write("tx");
  662. //}
  663. switch (mode)
  664. {
  665. case GlobalMode.Header:
  666. if (header_parser.Parse(parser) == true)
  667. break;
  668. doc = header_parser.Document;
  669. mode = GlobalMode.Document;
  670. Parse(parser);
  671. break;
  672. case GlobalMode.Document:
  673. if(parser.Control == "rtf")
  674. {
  675. mode = GlobalMode.Header;
  676. header_parser.StartParseEmbeddedDocument();
  677. break;
  678. }
  679. Parse(parser);
  680. break;
  681. }
  682. if (status == ParserStatus.CloseBlock)
  683. {
  684. --block_sychro;
  685. parser.ListItem = false; // Disable list
  686. if (block_sychro < 0)
  687. throw new Exception("Document structure error");
  688. parser.current_run_format = run_formats_stack.Pop();
  689. if (block_sychro == 0)
  690. {
  691. if (mode == GlobalMode.Header)
  692. Parse(parser);
  693. break;
  694. }
  695. }
  696. }
  697. AddPage(parser);
  698. }
  699. internal void Parse(RTF_Parser parser)
  700. {
  701. bool parsed = false;
  702. #if false // debug
  703. if (parser.Status == ParserStatus.OpenBlock)
  704. {
  705. string dbg = String.Format("{{{0}", formats_stack.Count);
  706. System.Diagnostics.Trace.Write(dbg);
  707. }
  708. else if (parser.Status == ParserStatus.CloseBlock)
  709. {
  710. System.Diagnostics.Trace.Write(@"}");
  711. }
  712. //if (parser.Control == "cell")
  713. // System.Diagnostics.Trace.WriteLine(@"Cell is not parsed yet");
  714. #endif
  715. if (skip_rtf_extension)
  716. {
  717. switch (parser.Control)
  718. {
  719. case "fldinst":
  720. break;
  721. }
  722. if (parser.Status == ParserStatus.OpenBlock)
  723. ++nested_block_count;
  724. else if (parser.Status == ParserStatus.CloseBlock)
  725. {
  726. if (nested_block_count == 0)
  727. throw new Exception("Document structure error");
  728. --nested_block_count;
  729. if (nested_block_count == 0)
  730. skip_rtf_extension = false;
  731. }
  732. return;
  733. }
  734. parsed = curr_page.Parse(parser, this.header_parser);
  735. if (!parsed)
  736. switch (parser.Control)
  737. {
  738. case "page":
  739. AddPage(parser);
  740. curr_page = new RTF_PageParser(false, doc);
  741. break;
  742. case "softpage":
  743. doc.pages.Add(curr_page.Page);
  744. curr_page = new RTF_PageParser(true, doc);
  745. break;
  746. case "paperw":
  747. doc.paper_width = parser.Number;
  748. break;
  749. case "paperh":
  750. doc.paper_height = parser.Number;
  751. break;
  752. case "margl":
  753. doc.global_margin_left = parser.Number;
  754. break;
  755. case "margt":
  756. doc.global_margin_top = parser.Number;
  757. break;
  758. case "margr":
  759. doc.global_margin_right = parser.Number;
  760. break;
  761. case "margb":
  762. doc.global_margin_bottom = parser.Number;
  763. break;
  764. case "deftab":
  765. doc.default_tab_width = parser.Number;
  766. break;
  767. case "viewkind":
  768. doc.view_kind = parser.Number;
  769. break;
  770. case "shp":
  771. //// Shape must be parsed in another place
  772. //skip_rtf_extension = true;
  773. break;
  774. case "ftnsep":
  775. case "ftnsepc":
  776. case "aftnsep":
  777. case "aftnsepc":
  778. skip_rtf_extension = true;
  779. nested_block_count = 1; // Not sure
  780. break;
  781. case "":
  782. if (parser.Delimiter == '*')
  783. {
  784. // Preivous version which ignore pictures in \*\shppict tag (20210211)
  785. // Just ignore delimiter
  786. }
  787. break;
  788. default:
  789. ;
  790. break;
  791. }
  792. }
  793. void AddPage(RTF_Parser parser)
  794. {
  795. curr_page.Fix(parser);
  796. Page pg = curr_page.Page;
  797. doc.pages.Add(pg);
  798. long sz = pg.sequence.size;
  799. doc.size += sz;
  800. }
  801. public void Dispose()
  802. {
  803. header_parser = null;
  804. }
  805. /// <summary>
  806. /// Get RTF structure based on range of elements
  807. /// </summary>
  808. public RichDocument GetRange(int Start, int Length)
  809. {
  810. RichDocument ranged_doc = new RichDocument();
  811. long position = 0;
  812. long finish = Start + Length;
  813. ranged_doc.pages = new List<Page>();
  814. foreach (Page page in doc.pages)
  815. {
  816. if (Start > position)
  817. {
  818. position += page.size;
  819. if (Start > position)
  820. continue;
  821. position -= page.size;
  822. }
  823. Page ranged_page = new Page();
  824. ranged_page.sequence.objects = new List<RichObject>();
  825. foreach (RichObject sequence in page.sequence.objects)
  826. {
  827. position += sequence.size;
  828. if (Start > position)
  829. continue;
  830. position -= sequence.size;
  831. RichObject ranged_object = new RichObject();
  832. switch (sequence.type)
  833. {
  834. case RichObject.Type.Paragraph:
  835. {
  836. ranged_object.type = RichObject.Type.Paragraph;
  837. ranged_object.pargraph = new Paragraph();
  838. ranged_object.pargraph.runs = new List<Run>();
  839. Paragraph par = sequence.pargraph;
  840. ranged_object.pargraph.format = par.format;
  841. foreach (Run run in par.runs)
  842. {
  843. position += run.text.Length;
  844. if (Start > position)
  845. continue;
  846. position -= run.text.Length;
  847. // Here is it
  848. string run_text;
  849. if (Start == position)
  850. run_text = run.text;
  851. else
  852. {
  853. int diff = (int)(Start - position);
  854. run_text = run.text.Substring(diff);
  855. }
  856. if (Length < run_text.Length)
  857. run_text = run_text.Substring(0, Length);
  858. Run ranged_run = new Run(run_text, run.format);
  859. ranged_object.pargraph.runs.Add(ranged_run);
  860. Length -= run_text.Length;
  861. if (Length == 0)
  862. break;
  863. }
  864. }
  865. break;
  866. case RichObject.Type.Table:
  867. {
  868. position += sequence.size;
  869. if (Start > position)
  870. continue;
  871. position -= sequence.size;
  872. // TODO: split table
  873. if (Length < sequence.size)
  874. Length = 0; // and this too
  875. }
  876. break;
  877. case RichObject.Type.Picture:
  878. {
  879. position += sequence.size;
  880. if (Start > position)
  881. continue;
  882. position -= sequence.size;
  883. // TODO: split picture?
  884. if (Length < sequence.size)
  885. Length = 0; // and this too
  886. }
  887. break;
  888. }
  889. ranged_page.sequence.objects.Add(ranged_object);
  890. if (Length == 0)
  891. break;
  892. if (Length < 0)
  893. throw new Exception("Negative length in RTF_DocumentParser::GetRange()");
  894. }
  895. ranged_doc.pages.Add(ranged_page);
  896. if (Length == 0)
  897. break;
  898. if (Length < 0)
  899. throw new Exception("Negative length in RTF_DocumentParser::GetRange()");
  900. ranged_page = new Page();
  901. ranged_page.sequence.objects = new List<RichObject>();
  902. }
  903. ranged_doc.font_list = doc.font_list;
  904. ranged_doc.color_list = doc.color_list;
  905. ranged_doc.style_list = doc.style_list;
  906. ranged_doc.codepage = doc.codepage;
  907. ranged_doc.default_font = doc.default_font;
  908. ranged_doc.default_lang = doc.default_lang;
  909. ranged_doc.paper_width = doc.paper_width;
  910. ranged_doc.paper_height = doc.paper_height;
  911. ranged_doc.global_margin_left = doc.global_margin_left;
  912. ranged_doc.global_margin_top = doc.global_margin_top;
  913. ranged_doc.global_margin_right = doc.global_margin_right;
  914. ranged_doc.global_margin_bottom = doc.global_margin_bottom;
  915. ranged_doc.default_tab_width = doc.default_tab_width;
  916. ranged_doc.view_kind = doc.view_kind;
  917. return ranged_doc;
  918. }
  919. /// RichText document object
  920. /// </summary>
  921. public RTF_DocumentParser()
  922. {
  923. doc.paper_width = 12240;
  924. doc.paper_height = 15840;
  925. doc.global_margin_left = 1800;
  926. doc.global_margin_top = 1440;
  927. doc.global_margin_right = 1800;
  928. doc.global_margin_bottom = 1440;
  929. doc.default_tab_width = 720;
  930. doc.pages = new List<Page>();
  931. curr_page = new RTF_PageParser(false, doc);
  932. skip_rtf_extension = false;
  933. run_formats_stack = new Stack<RunFormat>();
  934. parahraph_format_stack = new Stack<ParagraphFormat>(); // Do we need keep track of paragraphs format?
  935. }
  936. }
  937. }