RTF_Container.cs 37 KB

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