RTF.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056
  1. // Permission is hereby granted, free of charge, to any person obtaining
  2. // a copy of this software and associated documentation files (the
  3. // "Software"), to deal in the Software without restriction, including
  4. // without limitation the rights to use, copy, modify, merge, publish,
  5. // distribute, sublicense, and/or sell copies of the Software, and to
  6. // permit persons to whom the Software is furnished to do so, subject to
  7. // the following conditions:
  8. //
  9. // The above copyright notice and this permission notice shall be
  10. // included in all copies or substantial portions of the Software.
  11. //
  12. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  13. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  14. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  15. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  16. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  17. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  18. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  19. //
  20. // Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
  21. //
  22. // Authors:
  23. // Peter Bartok ([email protected])
  24. //
  25. // COMPLETE
  26. #undef RTF_DEBUG
  27. using System;
  28. using System.Collections;
  29. using System.IO;
  30. using System.Text;
  31. namespace System.Windows.Forms.RTF {
  32. internal class RTF {
  33. #region Local Variables
  34. internal const char EOF = unchecked((char)-1);
  35. internal const int NoParam = -1000000;
  36. internal const int DefaultEncodingCodePage = 1252;
  37. private TokenClass rtf_class;
  38. private Major major;
  39. private Minor minor;
  40. private int param;
  41. private string encoded_text;
  42. private Encoding encoding;
  43. private int encoding_code_page = DefaultEncodingCodePage;
  44. private StringBuilder text_buffer;
  45. private Picture picture;
  46. private int line_num;
  47. private int line_pos;
  48. private char pushed_char;
  49. //private StringBuilder pushed_text_buffer;
  50. private TokenClass pushed_class;
  51. private Major pushed_major;
  52. private Minor pushed_minor;
  53. private int pushed_param;
  54. private char prev_char;
  55. private bool bump_line;
  56. private Font font_list;
  57. private Charset cur_charset;
  58. private Stack charset_stack;
  59. private Style styles;
  60. private Color colors;
  61. private Font fonts;
  62. private StreamReader source;
  63. private static Hashtable key_table;
  64. private static KeyStruct[] Keys = KeysInit.Init();
  65. private DestinationCallback destination_callbacks;
  66. private ClassCallback class_callbacks;
  67. #endregion // Local Variables
  68. #region Constructors
  69. static RTF() {
  70. key_table = new Hashtable(Keys.Length);
  71. for (int i = 0; i < Keys.Length; i++) {
  72. key_table[Keys[i].Symbol] = Keys[i];
  73. }
  74. }
  75. public RTF(Stream stream) {
  76. source = new StreamReader(stream);
  77. text_buffer = new StringBuilder(1024);
  78. //pushed_text_buffer = new StringBuilder(1024);
  79. rtf_class = TokenClass.None;
  80. pushed_class = TokenClass.None;
  81. pushed_char = unchecked((char)-1);
  82. line_num = 0;
  83. line_pos = 0;
  84. prev_char = unchecked((char)-1);
  85. bump_line = false;
  86. font_list = null;
  87. charset_stack = null;
  88. cur_charset = new Charset();
  89. destination_callbacks = new DestinationCallback();
  90. class_callbacks = new ClassCallback();
  91. destination_callbacks [Minor.OptDest] = new DestinationDelegate (HandleOptDest);
  92. destination_callbacks[Minor.FontTbl] = new DestinationDelegate(ReadFontTbl);
  93. destination_callbacks[Minor.ColorTbl] = new DestinationDelegate(ReadColorTbl);
  94. destination_callbacks[Minor.StyleSheet] = new DestinationDelegate(ReadStyleSheet);
  95. destination_callbacks[Minor.Info] = new DestinationDelegate(ReadInfoGroup);
  96. destination_callbacks[Minor.Pict] = new DestinationDelegate(ReadPictGroup);
  97. destination_callbacks[Minor.Object] = new DestinationDelegate(ReadObjGroup);
  98. }
  99. #endregion // Constructors
  100. #region Properties
  101. public TokenClass TokenClass {
  102. get {
  103. return this.rtf_class;
  104. }
  105. set {
  106. this.rtf_class = value;
  107. }
  108. }
  109. public Major Major {
  110. get {
  111. return this.major;
  112. }
  113. set {
  114. this.major = value;
  115. }
  116. }
  117. public Minor Minor {
  118. get {
  119. return this.minor;
  120. }
  121. set {
  122. this.minor = value;
  123. }
  124. }
  125. public int Param {
  126. get {
  127. return this.param;
  128. }
  129. set {
  130. this.param = value;
  131. }
  132. }
  133. public string Text {
  134. get {
  135. return this.text_buffer.ToString();
  136. }
  137. set {
  138. if (value == null) {
  139. this.text_buffer.Length = 0;
  140. } else {
  141. this.text_buffer = new StringBuilder(value);
  142. }
  143. }
  144. }
  145. public string EncodedText {
  146. get { return encoded_text; }
  147. }
  148. public Picture Picture {
  149. get { return picture; }
  150. set { picture = value; }
  151. }
  152. public Color Colors {
  153. get {
  154. return colors;
  155. }
  156. set {
  157. colors = value;
  158. }
  159. }
  160. public Style Styles {
  161. get {
  162. return styles;
  163. }
  164. set {
  165. styles = value;
  166. }
  167. }
  168. public Font Fonts {
  169. get {
  170. return fonts;
  171. }
  172. set {
  173. fonts = value;
  174. }
  175. }
  176. public ClassCallback ClassCallback {
  177. get {
  178. return class_callbacks;
  179. }
  180. set {
  181. class_callbacks = value;
  182. }
  183. }
  184. public DestinationCallback DestinationCallback {
  185. get {
  186. return destination_callbacks;
  187. }
  188. set {
  189. destination_callbacks = value;
  190. }
  191. }
  192. public int LineNumber {
  193. get {
  194. return line_num;
  195. }
  196. }
  197. public int LinePos {
  198. get {
  199. return line_pos;
  200. }
  201. }
  202. #endregion // Properties
  203. #region Methods
  204. /// <summary>Set the default font for documents without font table</summary>
  205. public void DefaultFont(string name) {
  206. Font font;
  207. font = new Font(this);
  208. font.Num = 0;
  209. font.Name = name;
  210. }
  211. /// <summary>Read the next character from the input - skip any crlf</summary>
  212. private char GetChar ()
  213. {
  214. return GetChar (true);
  215. }
  216. /// <summary>Read the next character from the input</summary>
  217. private char GetChar(bool skipCrLf)
  218. {
  219. int c;
  220. bool old_bump_line;
  221. SkipCRLF:
  222. if ((c = source.Read()) != -1) {
  223. this.text_buffer.Append((char) c);
  224. }
  225. if (this.prev_char == EOF) {
  226. this.bump_line = true;
  227. }
  228. old_bump_line = bump_line;
  229. bump_line = false;
  230. if (skipCrLf) {
  231. if (c == '\r') {
  232. bump_line = true;
  233. text_buffer.Length--;
  234. goto SkipCRLF;
  235. } else if (c == '\n') {
  236. bump_line = true;
  237. if (this.prev_char == '\r') {
  238. old_bump_line = false;
  239. }
  240. text_buffer.Length--;
  241. goto SkipCRLF;
  242. }
  243. }
  244. this.line_pos ++;
  245. if (old_bump_line) {
  246. this.line_num++;
  247. this.line_pos = 1;
  248. }
  249. this.prev_char = (char) c;
  250. return (char) c;
  251. }
  252. /// <summary>Parse the RTF stream</summary>
  253. public void Read() {
  254. while (GetToken() != TokenClass.EOF) {
  255. RouteToken();
  256. }
  257. }
  258. /// <summary>Route a token</summary>
  259. public void RouteToken() {
  260. if (CheckCM(TokenClass.Control, Major.Destination)) {
  261. DestinationDelegate d;
  262. d = destination_callbacks[minor];
  263. if (d != null) {
  264. d(this);
  265. }
  266. }
  267. // Invoke class callback if there is one
  268. ClassDelegate c;
  269. c = class_callbacks[rtf_class];
  270. if (c != null) {
  271. c(this);
  272. }
  273. }
  274. /// <summary>Skip to the end of the next group to start or current group we are in</summary>
  275. public void SkipGroup() {
  276. int level;
  277. level = 1;
  278. while (GetToken() != TokenClass.EOF) {
  279. if (rtf_class == TokenClass.Group) {
  280. if (this.major == Major.BeginGroup) {
  281. level++;
  282. } else if (this.major == Major.EndGroup) {
  283. level--;
  284. if (level < 1) {
  285. break;
  286. }
  287. }
  288. }
  289. }
  290. }
  291. /// <summary>Return the next token in the stream</summary>
  292. public TokenClass GetToken() {
  293. if (pushed_class != TokenClass.None) {
  294. this.rtf_class = this.pushed_class;
  295. this.major = this.pushed_major;
  296. this.minor = this.pushed_minor;
  297. this.param = this.pushed_param;
  298. this.pushed_class = TokenClass.None;
  299. return this.rtf_class;
  300. }
  301. GetToken2();
  302. if (this.rtf_class == TokenClass.Text) {
  303. this.minor = (Minor)this.cur_charset[(int)this.major];
  304. if (encoding == null) {
  305. encoding = Encoding.GetEncoding (encoding_code_page);
  306. }
  307. encoded_text = new String (encoding.GetChars (new byte [] { (byte) this.major }));
  308. }
  309. if (this.cur_charset.Flags == CharsetFlags.None) {
  310. return this.rtf_class;
  311. }
  312. if (CheckCMM (TokenClass.Control, Major.Unicode, Minor.UnicodeAnsiCodepage)) {
  313. encoding_code_page = param;
  314. // fallback to the default one in case we have an invalid value
  315. if (encoding_code_page < 0 || encoding_code_page > 65535)
  316. encoding_code_page = DefaultEncodingCodePage;
  317. }
  318. if (((this.cur_charset.Flags & CharsetFlags.Read) != 0) && CheckCM(TokenClass.Control, Major.CharSet)) {
  319. this.cur_charset.ReadMap();
  320. } else if (((this.cur_charset.Flags & CharsetFlags.Switch) != 0) && CheckCMM(TokenClass.Control, Major.CharAttr, Minor.FontNum)) {
  321. Font fp;
  322. fp = Font.GetFont(this.font_list, this.param);
  323. if (fp != null) {
  324. if (fp.Name.StartsWith("Symbol")) {
  325. this.cur_charset.ID = CharsetType.Symbol;
  326. } else {
  327. this.cur_charset.ID = CharsetType.General;
  328. }
  329. } else if (((this.cur_charset.Flags & CharsetFlags.Switch) != 0) && (this.rtf_class == TokenClass.Group)) {
  330. switch(this.major) {
  331. case Major.BeginGroup: {
  332. this.charset_stack.Push(this.cur_charset);
  333. break;
  334. }
  335. case Major.EndGroup: {
  336. this.cur_charset = (Charset)this.charset_stack.Pop();
  337. break;
  338. }
  339. }
  340. }
  341. }
  342. return this.rtf_class;
  343. }
  344. private void GetToken2() {
  345. char c;
  346. int sign;
  347. this.rtf_class = TokenClass.Unknown;
  348. this.param = NoParam;
  349. this.text_buffer.Length = 0;
  350. if (this.pushed_char != EOF) {
  351. c = this.pushed_char;
  352. this.text_buffer.Append(c);
  353. this.pushed_char = EOF;
  354. } else if ((c = GetChar()) == EOF) {
  355. this.rtf_class = TokenClass.EOF;
  356. return;
  357. }
  358. if (c == '{') {
  359. this.rtf_class = TokenClass.Group;
  360. this.major = Major.BeginGroup;
  361. return;
  362. }
  363. if (c == '}') {
  364. this.rtf_class = TokenClass.Group;
  365. this.major = Major.EndGroup;
  366. return;
  367. }
  368. if (c != '\\') {
  369. if (c != '\t') {
  370. this.rtf_class = TokenClass.Text;
  371. this.major = (Major)c; // FIXME - typing?
  372. return;
  373. } else {
  374. this.rtf_class = TokenClass.Control;
  375. this.major = Major.SpecialChar;
  376. this.minor = Minor.Tab;
  377. return;
  378. }
  379. }
  380. if ((c = GetChar()) == EOF) {
  381. // Not so good
  382. return;
  383. }
  384. if (!Char.IsLetter(c)) {
  385. if (c == '\'') {
  386. char c2;
  387. if ((c = GetChar()) == EOF) {
  388. return;
  389. }
  390. if ((c2 = GetChar()) == EOF) {
  391. return;
  392. }
  393. this.rtf_class = TokenClass.Text;
  394. this.major = (Major)((Char)((Convert.ToByte(c.ToString(), 16) * 16 + Convert.ToByte(c2.ToString(), 16))));
  395. return;
  396. }
  397. // Escaped char
  398. if (c == ':' || c == '{' || c == '}' || c == '\\') {
  399. this.rtf_class = TokenClass.Text;
  400. this.major = (Major)c;
  401. return;
  402. }
  403. Lookup(this.text_buffer.ToString());
  404. return;
  405. }
  406. while (Char.IsLetter(c)) {
  407. if ((c = GetChar(false)) == EOF) {
  408. break;
  409. }
  410. }
  411. if (c != EOF) {
  412. this.text_buffer.Length--;
  413. }
  414. Lookup(this.text_buffer.ToString());
  415. if (c != EOF) {
  416. this.text_buffer.Append(c);
  417. }
  418. sign = 1;
  419. if (c == '-') {
  420. sign = -1;
  421. c = GetChar();
  422. }
  423. if (c != EOF && Char.IsDigit(c) && minor != Minor.PngBlip) {
  424. this.param = 0;
  425. while (Char.IsDigit(c)) {
  426. this.param = this.param * 10 + Convert.ToByte(c) - 48;
  427. if ((c = GetChar()) == EOF) {
  428. break;
  429. }
  430. }
  431. this.param *= sign;
  432. }
  433. if (c != EOF) {
  434. if (c != ' ' && c != '\r' && c != '\n') {
  435. this.pushed_char = c;
  436. }
  437. this.text_buffer.Length--;
  438. }
  439. }
  440. public void SetToken(TokenClass cl, Major maj, Minor min, int par, string text) {
  441. this.rtf_class = cl;
  442. this.major = maj;
  443. this.minor = min;
  444. this.param = par;
  445. if (par == NoParam) {
  446. this.text_buffer = new StringBuilder(text);
  447. } else {
  448. this.text_buffer = new StringBuilder(text + par.ToString());
  449. }
  450. }
  451. public void UngetToken() {
  452. if (this.pushed_class != TokenClass.None) {
  453. throw new RTFException(this, "Cannot unget more than one token");
  454. }
  455. if (this.rtf_class == TokenClass.None) {
  456. throw new RTFException(this, "No token to unget");
  457. }
  458. this.pushed_class = this.rtf_class;
  459. this.pushed_major = this.major;
  460. this.pushed_minor = this.minor;
  461. this.pushed_param = this.param;
  462. //this.pushed_text_buffer = new StringBuilder(this.text_buffer.ToString());
  463. }
  464. public TokenClass PeekToken() {
  465. GetToken();
  466. UngetToken();
  467. return rtf_class;
  468. }
  469. public void Lookup(string token) {
  470. Object obj;
  471. KeyStruct key;
  472. obj = key_table[token.Substring(1)];
  473. if (obj == null) {
  474. rtf_class = TokenClass.Unknown;
  475. major = (Major) -1;
  476. minor = (Minor) -1;
  477. return;
  478. }
  479. key = (KeyStruct)obj;
  480. this.rtf_class = TokenClass.Control;
  481. this.major = key.Major;
  482. this.minor = key.Minor;
  483. }
  484. public bool CheckCM(TokenClass rtf_class, Major major) {
  485. if ((this.rtf_class == rtf_class) && (this.major == major)) {
  486. return true;
  487. }
  488. return false;
  489. }
  490. public bool CheckCMM(TokenClass rtf_class, Major major, Minor minor) {
  491. if ((this.rtf_class == rtf_class) && (this.major == major) && (this.minor == minor)) {
  492. return true;
  493. }
  494. return false;
  495. }
  496. public bool CheckMM(Major major, Minor minor) {
  497. if ((this.major == major) && (this.minor == minor)) {
  498. return true;
  499. }
  500. return false;
  501. }
  502. #endregion // Methods
  503. #region Default Delegates
  504. private void HandleOptDest (RTF rtf)
  505. {
  506. int group_levels = 1;
  507. while (true) {
  508. GetToken ();
  509. // Here is where we should handle recognised optional
  510. // destinations.
  511. //
  512. // Handle a picture group
  513. //
  514. if (rtf.CheckCMM (TokenClass.Control, Major.Destination, Minor.Pict)) {
  515. ReadPictGroup (rtf);
  516. return;
  517. }
  518. if (rtf.CheckCM (TokenClass.Group, Major.EndGroup)) {
  519. if ((--group_levels) == 0) {
  520. break;
  521. }
  522. }
  523. if (rtf.CheckCM (TokenClass.Group, Major.BeginGroup)) {
  524. group_levels++;
  525. }
  526. }
  527. }
  528. private void ReadFontTbl(RTF rtf) {
  529. int old;
  530. Font font;
  531. old = -1;
  532. font = null;
  533. while (true) {
  534. rtf.GetToken();
  535. if (rtf.CheckCM(TokenClass.Group, Major.EndGroup)) {
  536. break;
  537. }
  538. if (old < 0) {
  539. if (rtf.CheckCMM(TokenClass.Control, Major.CharAttr, Minor.FontNum)) {
  540. old = 1;
  541. } else if (rtf.CheckCM(TokenClass.Group, Major.BeginGroup)) {
  542. old = 0;
  543. } else {
  544. throw new RTFException(rtf, "Cannot determine format");
  545. }
  546. }
  547. if (old == 0) {
  548. if (!rtf.CheckCM(TokenClass.Group, Major.BeginGroup)) {
  549. throw new RTFException(rtf, "missing \"{\"");
  550. }
  551. rtf.GetToken();
  552. }
  553. font = new Font(rtf);
  554. while ((rtf.rtf_class != TokenClass.EOF) && (!rtf.CheckCM(TokenClass.Text, (Major)';')) && (!rtf.CheckCM(TokenClass.Group, Major.EndGroup))) {
  555. if (rtf.rtf_class == TokenClass.Control) {
  556. switch(rtf.major) {
  557. case Major.FontFamily: {
  558. font.Family = (int)rtf.minor;
  559. break;
  560. }
  561. case Major.CharAttr: {
  562. switch(rtf.minor) {
  563. case Minor.FontNum: {
  564. font.Num = rtf.param;
  565. break;
  566. }
  567. default: {
  568. #if RTF_DEBUG
  569. Console.WriteLine("Got unhandled Control.CharAttr.Minor: " + rtf.minor);
  570. #endif
  571. break;
  572. }
  573. }
  574. break;
  575. }
  576. case Major.FontAttr: {
  577. switch (rtf.minor) {
  578. case Minor.FontCharSet: {
  579. font.Charset = (CharsetType)rtf.param;
  580. break;
  581. }
  582. case Minor.FontPitch: {
  583. font.Pitch = rtf.param;
  584. break;
  585. }
  586. case Minor.FontCodePage: {
  587. font.Codepage = rtf.param;
  588. break;
  589. }
  590. case Minor.FTypeNil:
  591. case Minor.FTypeTrueType: {
  592. font.Type = rtf.param;
  593. break;
  594. }
  595. default: {
  596. #if RTF_DEBUG
  597. Console.WriteLine("Got unhandled Control.FontAttr.Minor: " + rtf.minor);
  598. #endif
  599. break;
  600. }
  601. }
  602. break;
  603. }
  604. default: {
  605. #if RTF_DEBUG
  606. Console.WriteLine("ReadFontTbl: Unknown Control token " + rtf.major);
  607. #endif
  608. break;
  609. }
  610. }
  611. } else if (rtf.CheckCM(TokenClass.Group, Major.BeginGroup)) {
  612. rtf.SkipGroup();
  613. } else if (rtf.rtf_class == TokenClass.Text) {
  614. StringBuilder sb;
  615. sb = new StringBuilder();
  616. while ((rtf.rtf_class != TokenClass.EOF) && (!rtf.CheckCM(TokenClass.Text, (Major)';')) && (!rtf.CheckCM(TokenClass.Group, Major.EndGroup)) && (!rtf.CheckCM(TokenClass.Group, Major.BeginGroup))) {
  617. sb.Append((char)rtf.major);
  618. rtf.GetToken();
  619. }
  620. if (rtf.CheckCM(TokenClass.Group, Major.EndGroup)) {
  621. rtf.UngetToken();
  622. }
  623. font.Name = sb.ToString();
  624. continue;
  625. #if RTF_DEBUG
  626. } else {
  627. Console.WriteLine("ReadFontTbl: Unknown token " + rtf.text_buffer);
  628. #endif
  629. }
  630. rtf.GetToken();
  631. }
  632. if (old == 0) {
  633. rtf.GetToken();
  634. if (!rtf.CheckCM(TokenClass.Group, Major.EndGroup)) {
  635. throw new RTFException(rtf, "Missing \"}\"");
  636. }
  637. }
  638. }
  639. if (font == null) {
  640. throw new RTFException(rtf, "No font created");
  641. }
  642. if (font.Num == -1) {
  643. throw new RTFException(rtf, "Missing font number");
  644. }
  645. rtf.RouteToken();
  646. }
  647. private void ReadColorTbl(RTF rtf) {
  648. Color color;
  649. int num;
  650. num = 0;
  651. while (true) {
  652. rtf.GetToken();
  653. if (rtf.CheckCM(TokenClass.Group, Major.EndGroup)) {
  654. break;
  655. }
  656. color = new Color(rtf);
  657. color.Num = num++;
  658. while (rtf.CheckCM(TokenClass.Control, Major.ColorName)) {
  659. switch (rtf.minor) {
  660. case Minor.Red: {
  661. color.Red = rtf.param;
  662. break;
  663. }
  664. case Minor.Green: {
  665. color.Green = rtf.param;
  666. break;
  667. }
  668. case Minor.Blue: {
  669. color.Blue = rtf.param;
  670. break;
  671. }
  672. }
  673. rtf.GetToken();
  674. }
  675. if (!rtf.CheckCM(TokenClass.Text, (Major)';')) {
  676. throw new RTFException(rtf, "Malformed color entry");
  677. }
  678. }
  679. rtf.RouteToken();
  680. }
  681. private void ReadStyleSheet(RTF rtf) {
  682. Style style;
  683. StringBuilder sb;
  684. sb = new StringBuilder();
  685. while (true) {
  686. rtf.GetToken();
  687. if (rtf.CheckCM(TokenClass.Group, Major.EndGroup)) {
  688. break;
  689. }
  690. style = new Style(rtf);
  691. if (!rtf.CheckCM(TokenClass.Group, Major.BeginGroup)) {
  692. throw new RTFException(rtf, "Missing \"{\"");
  693. }
  694. while (true) {
  695. rtf.GetToken();
  696. if ((rtf.rtf_class == TokenClass.EOF) || rtf.CheckCM(TokenClass.Text, (Major)';')) {
  697. break;
  698. }
  699. if (rtf.rtf_class == TokenClass.Control) {
  700. if (rtf.CheckMM(Major.ParAttr, Minor.StyleNum)) {
  701. style.Num = rtf.param;
  702. style.Type = StyleType.Paragraph;
  703. continue;
  704. }
  705. if (rtf.CheckMM(Major.CharAttr, Minor.CharStyleNum)) {
  706. style.Num = rtf.param;
  707. style.Type = StyleType.Character;
  708. continue;
  709. }
  710. if (rtf.CheckMM(Major.StyleAttr, Minor.SectStyleNum)) {
  711. style.Num = rtf.param;
  712. style.Type = StyleType.Section;
  713. continue;
  714. }
  715. if (rtf.CheckMM(Major.StyleAttr, Minor.BasedOn)) {
  716. style.BasedOn = rtf.param;
  717. continue;
  718. }
  719. if (rtf.CheckMM(Major.StyleAttr, Minor.Additive)) {
  720. style.Additive = true;
  721. continue;
  722. }
  723. if (rtf.CheckMM(Major.StyleAttr, Minor.Next)) {
  724. style.NextPar = rtf.param;
  725. continue;
  726. }
  727. new StyleElement(style, rtf.rtf_class, rtf.major, rtf.minor, rtf.param, rtf.text_buffer.ToString());
  728. } else if (rtf.CheckCM(TokenClass.Group, Major.BeginGroup)) {
  729. // This passes over "{\*\keycode ... }, among other things
  730. rtf.SkipGroup();
  731. } else if (rtf.rtf_class == TokenClass.Text) {
  732. while (rtf.rtf_class == TokenClass.Text) {
  733. if (rtf.major == (Major)';') {
  734. rtf.UngetToken();
  735. break;
  736. }
  737. sb.Append((char)rtf.major);
  738. rtf.GetToken();
  739. }
  740. style.Name = sb.ToString();
  741. #if RTF_DEBUG
  742. } else {
  743. Console.WriteLine("ReadStyleSheet: Ignored token " + rtf.text_buffer);
  744. #endif
  745. }
  746. }
  747. rtf.GetToken();
  748. if (!rtf.CheckCM(TokenClass.Group, Major.EndGroup)) {
  749. throw new RTFException(rtf, "Missing EndGroup (\"}\"");
  750. }
  751. // Sanity checks
  752. if (style.Name == null) {
  753. throw new RTFException(rtf, "Style must have name");
  754. }
  755. if (style.Num < 0) {
  756. if (!sb.ToString().StartsWith("Normal") && !sb.ToString().StartsWith("Standard")) {
  757. throw new RTFException(rtf, "Missing style number");
  758. }
  759. style.Num = Style.NormalStyleNum;
  760. }
  761. if (style.NextPar == -1) {
  762. style.NextPar = style.Num;
  763. }
  764. }
  765. rtf.RouteToken();
  766. }
  767. private void ReadInfoGroup(RTF rtf) {
  768. rtf.SkipGroup();
  769. rtf.RouteToken();
  770. }
  771. private void ReadPictGroup(RTF rtf)
  772. {
  773. bool read_image_data = false;
  774. Picture picture = new Picture ();
  775. while (true) {
  776. rtf.GetToken ();
  777. if (rtf.CheckCM (TokenClass.Group, Major.EndGroup))
  778. break;
  779. switch (minor) {
  780. case Minor.PngBlip:
  781. picture.ImageType = minor;
  782. read_image_data = true;
  783. break;
  784. case Minor.WinMetafile:
  785. picture.ImageType = minor;
  786. read_image_data = true;
  787. continue;
  788. case Minor.PicWid:
  789. continue;
  790. case Minor.PicHt:
  791. continue;
  792. case Minor.PicGoalWid:
  793. picture.SetWidthFromTwips (param);
  794. continue;
  795. case Minor.PicGoalHt:
  796. picture.SetHeightFromTwips (param);
  797. continue;
  798. }
  799. if (read_image_data && rtf.rtf_class == TokenClass.Text) {
  800. picture.Data.Seek (0, SeekOrigin.Begin);
  801. //char c = (char) rtf.major;
  802. uint digitValue1;
  803. uint digitValue2;
  804. char hexDigit1 = (char) rtf.major;
  805. char hexDigit2;
  806. while (true) {
  807. while (hexDigit1 == '\n' || hexDigit1 == '\r') {
  808. hexDigit1 = (char) source.Peek ();
  809. if (hexDigit1 == '}')
  810. break;
  811. hexDigit1 = (char) source.Read ();
  812. }
  813. hexDigit2 = (char) source.Peek ();
  814. if (hexDigit2 == '}')
  815. break;
  816. hexDigit2 = (char) source.Read ();
  817. while (hexDigit2 == '\n' || hexDigit2 == '\r') {
  818. hexDigit2 = (char) source.Peek ();
  819. if (hexDigit2 == '}')
  820. break;
  821. hexDigit2 = (char) source.Read ();
  822. }
  823. if (Char.IsDigit (hexDigit1))
  824. digitValue1 = (uint) (hexDigit1 - '0');
  825. else if (Char.IsLower (hexDigit1))
  826. digitValue1 = (uint) (hexDigit1 - 'a' + 10);
  827. else if (Char.IsUpper (hexDigit1))
  828. digitValue1 = (uint) (hexDigit1 - 'A' + 10);
  829. else if (hexDigit1 == '\n' || hexDigit1 == '\r')
  830. continue;
  831. else
  832. break;
  833. if (Char.IsDigit (hexDigit2))
  834. digitValue2 = (uint) (hexDigit2 - '0');
  835. else if (Char.IsLower (hexDigit2))
  836. digitValue2 = (uint) (hexDigit2 - 'a' + 10);
  837. else if (Char.IsUpper (hexDigit2))
  838. digitValue2 = (uint) (hexDigit2 - 'A' + 10);
  839. else if (hexDigit2 == '\n' || hexDigit2 == '\r')
  840. continue;
  841. else
  842. break;
  843. picture.Data.WriteByte ((byte) checked (digitValue1 * 16 + digitValue2));
  844. // We get the first hex digit at the end, since in the very first
  845. // iteration we use rtf.major as the first hex digit
  846. hexDigit1 = (char) source.Peek ();
  847. if (hexDigit1 == '}')
  848. break;
  849. hexDigit1 = (char) source.Read ();
  850. }
  851. read_image_data = false;
  852. break;
  853. }
  854. }
  855. if (picture.ImageType != Minor.Undefined && !read_image_data) {
  856. this.picture = picture;
  857. SetToken (TokenClass.Control, Major.PictAttr, picture.ImageType, 0, String.Empty);
  858. }
  859. }
  860. private void ReadObjGroup(RTF rtf) {
  861. rtf.SkipGroup();
  862. rtf.RouteToken();
  863. }
  864. #endregion // Default Delegates
  865. }
  866. }