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 (pbartok@novell.com) 24 // 25 26 // COMPLETE 27 28 #undef RTF_DEBUG 29 30 using System; 31 using System.Collections; 32 using System.IO; 33 using System.Text; 34 35 namespace System.Windows.Forms.RTF { 36 internal class RTF { 37 #region Local Variables 38 internal const char EOF = unchecked((char)-1); 39 internal const int NoParam = -1000000; 40 internal const int DefaultEncodingCodePage = 1252; 41 42 private TokenClass rtf_class; 43 private Major major; 44 private Minor minor; 45 private int param; 46 private string encoded_text; 47 private Encoding encoding; 48 private int encoding_code_page = DefaultEncodingCodePage; 49 private StringBuilder text_buffer; 50 private Picture picture; 51 private int line_num; 52 private int line_pos; 53 54 private char pushed_char; 55 //private StringBuilder pushed_text_buffer; 56 private TokenClass pushed_class; 57 private Major pushed_major; 58 private Minor pushed_minor; 59 private int pushed_param; 60 61 private char prev_char; 62 private bool bump_line; 63 64 private Font font_list; 65 66 private Charset cur_charset; 67 private Stack charset_stack; 68 69 private Style styles; 70 private Color colors; 71 private Font fonts; 72 73 private StreamReader source; 74 75 private static Hashtable key_table; 76 private static KeyStruct[] Keys = KeysInit.Init(); 77 78 private DestinationCallback destination_callbacks; 79 private ClassCallback class_callbacks; 80 #endregion // Local Variables 81 82 #region Constructors RTF()83 static RTF() { 84 key_table = new Hashtable(Keys.Length); 85 for (int i = 0; i < Keys.Length; i++) { 86 key_table[Keys[i].Symbol] = Keys[i]; 87 } 88 } 89 RTF(Stream stream)90 public RTF(Stream stream) { 91 source = new StreamReader(stream); 92 93 text_buffer = new StringBuilder(1024); 94 //pushed_text_buffer = new StringBuilder(1024); 95 96 rtf_class = TokenClass.None; 97 pushed_class = TokenClass.None; 98 pushed_char = unchecked((char)-1); 99 100 line_num = 0; 101 line_pos = 0; 102 prev_char = unchecked((char)-1); 103 bump_line = false; 104 font_list = null; 105 charset_stack = null; 106 107 cur_charset = new Charset(); 108 109 destination_callbacks = new DestinationCallback(); 110 class_callbacks = new ClassCallback(); 111 112 destination_callbacks [Minor.OptDest] = new DestinationDelegate (HandleOptDest); 113 destination_callbacks[Minor.FontTbl] = new DestinationDelegate(ReadFontTbl); 114 destination_callbacks[Minor.ColorTbl] = new DestinationDelegate(ReadColorTbl); 115 destination_callbacks[Minor.StyleSheet] = new DestinationDelegate(ReadStyleSheet); 116 destination_callbacks[Minor.Info] = new DestinationDelegate(ReadInfoGroup); 117 destination_callbacks[Minor.Pict] = new DestinationDelegate(ReadPictGroup); 118 destination_callbacks[Minor.Object] = new DestinationDelegate(ReadObjGroup); 119 } 120 #endregion // Constructors 121 122 #region Properties 123 public TokenClass TokenClass { 124 get { 125 return this.rtf_class; 126 } 127 128 set { 129 this.rtf_class = value; 130 } 131 } 132 133 public Major Major { 134 get { 135 return this.major; 136 } 137 138 set { 139 this.major = value; 140 } 141 } 142 143 public Minor Minor { 144 get { 145 return this.minor; 146 } 147 148 set { 149 this.minor = value; 150 } 151 } 152 153 public int Param { 154 get { 155 return this.param; 156 } 157 158 set { 159 this.param = value; 160 } 161 } 162 163 public string Text { 164 get { 165 return this.text_buffer.ToString(); 166 } 167 168 set { 169 if (value == null) { 170 this.text_buffer.Length = 0; 171 } else { 172 this.text_buffer = new StringBuilder(value); 173 } 174 } 175 } 176 177 public string EncodedText { 178 get { return encoded_text; } 179 } 180 181 public Picture Picture { 182 get { return picture; } 183 set { picture = value; } 184 } 185 186 public Color Colors { 187 get { 188 return colors; 189 } 190 191 set { 192 colors = value; 193 } 194 } 195 196 public Style Styles { 197 get { 198 return styles; 199 } 200 201 set { 202 styles = value; 203 } 204 } 205 206 public Font Fonts { 207 get { 208 return fonts; 209 } 210 211 set { 212 fonts = value; 213 } 214 } 215 216 public ClassCallback ClassCallback { 217 get { 218 return class_callbacks; 219 } 220 221 set { 222 class_callbacks = value; 223 } 224 } 225 226 public DestinationCallback DestinationCallback { 227 get { 228 return destination_callbacks; 229 } 230 231 set { 232 destination_callbacks = value; 233 } 234 } 235 236 public int LineNumber { 237 get { 238 return line_num; 239 } 240 } 241 242 public int LinePos { 243 get { 244 return line_pos; 245 } 246 } 247 #endregion // Properties 248 249 #region Methods 250 /// <summary>Set the default font for documents without font table</summary> DefaultFont(string name)251 public void DefaultFont(string name) { 252 Font font; 253 254 font = new Font(this); 255 font.Num = 0; 256 font.Name = name; 257 } 258 259 /// <summary>Read the next character from the input - skip any crlf</summary> GetChar()260 private char GetChar () 261 { 262 return GetChar (true); 263 } 264 265 /// <summary>Read the next character from the input</summary> GetChar(bool skipCrLf)266 private char GetChar(bool skipCrLf) 267 { 268 int c; 269 bool old_bump_line; 270 271 SkipCRLF: 272 if ((c = source.Read()) != -1) { 273 this.text_buffer.Append((char) c); 274 } 275 276 if (this.prev_char == EOF) { 277 this.bump_line = true; 278 } 279 280 old_bump_line = bump_line; 281 bump_line = false; 282 283 if (skipCrLf) { 284 if (c == '\r') { 285 bump_line = true; 286 text_buffer.Length--; 287 goto SkipCRLF; 288 } else if (c == '\n') { 289 bump_line = true; 290 if (this.prev_char == '\r') { 291 old_bump_line = false; 292 } 293 294 text_buffer.Length--; 295 goto SkipCRLF; 296 } 297 } 298 299 this.line_pos ++; 300 if (old_bump_line) { 301 this.line_num++; 302 this.line_pos = 1; 303 } 304 305 this.prev_char = (char) c; 306 return (char) c; 307 } 308 309 /// <summary>Parse the RTF stream</summary> Read()310 public void Read() { 311 while (GetToken() != TokenClass.EOF) { 312 RouteToken(); 313 } 314 } 315 316 /// <summary>Route a token</summary> RouteToken()317 public void RouteToken() { 318 319 if (CheckCM(TokenClass.Control, Major.Destination)) { 320 DestinationDelegate d; 321 322 d = destination_callbacks[minor]; 323 if (d != null) { 324 d(this); 325 } 326 } 327 328 // Invoke class callback if there is one 329 ClassDelegate c; 330 331 c = class_callbacks[rtf_class]; 332 if (c != null) { 333 c(this); 334 } 335 336 } 337 338 /// <summary>Skip to the end of the next group to start or current group we are in</summary> SkipGroup()339 public void SkipGroup() { 340 int level; 341 342 level = 1; 343 344 while (GetToken() != TokenClass.EOF) { 345 if (rtf_class == TokenClass.Group) { 346 if (this.major == Major.BeginGroup) { 347 level++; 348 } else if (this.major == Major.EndGroup) { 349 level--; 350 if (level < 1) { 351 break; 352 } 353 } 354 } 355 } 356 } 357 358 /// <summary>Return the next token in the stream</summary> GetToken()359 public TokenClass GetToken() { 360 if (pushed_class != TokenClass.None) { 361 this.rtf_class = this.pushed_class; 362 this.major = this.pushed_major; 363 this.minor = this.pushed_minor; 364 this.param = this.pushed_param; 365 this.pushed_class = TokenClass.None; 366 return this.rtf_class; 367 } 368 369 GetToken2(); 370 371 if (this.rtf_class == TokenClass.Text) { 372 this.minor = (Minor)this.cur_charset[(int)this.major]; 373 if (encoding == null) { 374 encoding = Encoding.GetEncoding (encoding_code_page); 375 } 376 encoded_text = new String (encoding.GetChars (new byte [] { (byte) this.major })); 377 } 378 379 if (this.cur_charset.Flags == CharsetFlags.None) { 380 return this.rtf_class; 381 } 382 383 if (CheckCMM (TokenClass.Control, Major.Unicode, Minor.UnicodeAnsiCodepage)) { 384 encoding_code_page = param; 385 386 // fallback to the default one in case we have an invalid value 387 if (encoding_code_page < 0 || encoding_code_page > 65535) 388 encoding_code_page = DefaultEncodingCodePage; 389 } 390 391 if (((this.cur_charset.Flags & CharsetFlags.Read) != 0) && CheckCM(TokenClass.Control, Major.CharSet)) { 392 this.cur_charset.ReadMap(); 393 } else if (((this.cur_charset.Flags & CharsetFlags.Switch) != 0) && CheckCMM(TokenClass.Control, Major.CharAttr, Minor.FontNum)) { 394 Font fp; 395 396 fp = Font.GetFont(this.font_list, this.param); 397 398 if (fp != null) { 399 if (fp.Name.StartsWith("Symbol")) { 400 this.cur_charset.ID = CharsetType.Symbol; 401 } else { 402 this.cur_charset.ID = CharsetType.General; 403 } 404 } else if (((this.cur_charset.Flags & CharsetFlags.Switch) != 0) && (this.rtf_class == TokenClass.Group)) { 405 switch(this.major) { 406 case Major.BeginGroup: { 407 this.charset_stack.Push(this.cur_charset); 408 break; 409 } 410 411 case Major.EndGroup: { 412 this.cur_charset = (Charset)this.charset_stack.Pop(); 413 break; 414 } 415 } 416 } 417 } 418 419 return this.rtf_class; 420 } 421 GetToken2()422 private void GetToken2() { 423 char c; 424 int sign; 425 426 this.rtf_class = TokenClass.Unknown; 427 this.param = NoParam; 428 429 this.text_buffer.Length = 0; 430 431 if (this.pushed_char != EOF) { 432 c = this.pushed_char; 433 this.text_buffer.Append(c); 434 this.pushed_char = EOF; 435 } else if ((c = GetChar()) == EOF) { 436 this.rtf_class = TokenClass.EOF; 437 return; 438 } 439 440 if (c == '{') { 441 this.rtf_class = TokenClass.Group; 442 this.major = Major.BeginGroup; 443 return; 444 } 445 446 if (c == '}') { 447 this.rtf_class = TokenClass.Group; 448 this.major = Major.EndGroup; 449 return; 450 } 451 452 if (c != '\\') { 453 if (c != '\t') { 454 this.rtf_class = TokenClass.Text; 455 this.major = (Major)c; // FIXME - typing? 456 return; 457 } else { 458 this.rtf_class = TokenClass.Control; 459 this.major = Major.SpecialChar; 460 this.minor = Minor.Tab; 461 return; 462 } 463 } 464 465 if ((c = GetChar()) == EOF) { 466 // Not so good 467 return; 468 } 469 470 if (!Char.IsLetter(c)) { 471 if (c == '\'') { 472 char c2; 473 474 if ((c = GetChar()) == EOF) { 475 return; 476 } 477 478 if ((c2 = GetChar()) == EOF) { 479 return; 480 } 481 482 this.rtf_class = TokenClass.Text; 483 this.major = (Major)((Char)((Convert.ToByte(c.ToString(), 16) * 16 + Convert.ToByte(c2.ToString(), 16)))); 484 return; 485 } 486 487 // Escaped char 488 if (c == ':' || c == '{' || c == '}' || c == '\\') { 489 this.rtf_class = TokenClass.Text; 490 this.major = (Major)c; 491 return; 492 } 493 494 Lookup(this.text_buffer.ToString()); 495 return; 496 } 497 498 while (Char.IsLetter(c)) { 499 if ((c = GetChar(false)) == EOF) { 500 break; 501 } 502 } 503 504 if (c != EOF) { 505 this.text_buffer.Length--; 506 } 507 508 Lookup(this.text_buffer.ToString()); 509 510 if (c != EOF) { 511 this.text_buffer.Append(c); 512 } 513 514 sign = 1; 515 if (c == '-') { 516 sign = -1; 517 c = GetChar(); 518 } 519 520 if (c != EOF && Char.IsDigit(c) && minor != Minor.PngBlip) { 521 this.param = 0; 522 while (Char.IsDigit(c)) { 523 this.param = this.param * 10 + Convert.ToByte(c) - 48; 524 if ((c = GetChar()) == EOF) { 525 break; 526 } 527 } 528 this.param *= sign; 529 } 530 531 if (c != EOF) { 532 if (c != ' ' && c != '\r' && c != '\n') { 533 this.pushed_char = c; 534 } 535 this.text_buffer.Length--; 536 } 537 } 538 SetToken(TokenClass cl, Major maj, Minor min, int par, string text)539 public void SetToken(TokenClass cl, Major maj, Minor min, int par, string text) { 540 this.rtf_class = cl; 541 this.major = maj; 542 this.minor = min; 543 this.param = par; 544 if (par == NoParam) { 545 this.text_buffer = new StringBuilder(text); 546 } else { 547 this.text_buffer = new StringBuilder(text + par.ToString()); 548 } 549 } 550 UngetToken()551 public void UngetToken() { 552 if (this.pushed_class != TokenClass.None) { 553 throw new RTFException(this, "Cannot unget more than one token"); 554 } 555 556 if (this.rtf_class == TokenClass.None) { 557 throw new RTFException(this, "No token to unget"); 558 } 559 560 this.pushed_class = this.rtf_class; 561 this.pushed_major = this.major; 562 this.pushed_minor = this.minor; 563 this.pushed_param = this.param; 564 //this.pushed_text_buffer = new StringBuilder(this.text_buffer.ToString()); 565 } 566 PeekToken()567 public TokenClass PeekToken() { 568 GetToken(); 569 UngetToken(); 570 return rtf_class; 571 } 572 Lookup(string token)573 public void Lookup(string token) { 574 Object obj; 575 KeyStruct key; 576 577 obj = key_table[token.Substring(1)]; 578 if (obj == null) { 579 rtf_class = TokenClass.Unknown; 580 major = (Major) -1; 581 minor = (Minor) -1; 582 return; 583 } 584 585 key = (KeyStruct)obj; 586 this.rtf_class = TokenClass.Control; 587 this.major = key.Major; 588 this.minor = key.Minor; 589 } 590 CheckCM(TokenClass rtf_class, Major major)591 public bool CheckCM(TokenClass rtf_class, Major major) { 592 if ((this.rtf_class == rtf_class) && (this.major == major)) { 593 return true; 594 } 595 596 return false; 597 } 598 CheckCMM(TokenClass rtf_class, Major major, Minor minor)599 public bool CheckCMM(TokenClass rtf_class, Major major, Minor minor) { 600 if ((this.rtf_class == rtf_class) && (this.major == major) && (this.minor == minor)) { 601 return true; 602 } 603 604 return false; 605 } 606 CheckMM(Major major, Minor minor)607 public bool CheckMM(Major major, Minor minor) { 608 if ((this.major == major) && (this.minor == minor)) { 609 return true; 610 } 611 612 return false; 613 } 614 #endregion // Methods 615 616 #region Default Delegates 617 HandleOptDest(RTF rtf)618 private void HandleOptDest (RTF rtf) 619 { 620 int group_levels = 1; 621 622 while (true) { 623 GetToken (); 624 625 // Here is where we should handle recognised optional 626 // destinations. 627 // 628 // Handle a picture group 629 // 630 if (rtf.CheckCMM (TokenClass.Control, Major.Destination, Minor.Pict)) { 631 ReadPictGroup (rtf); 632 return; 633 } 634 635 if (rtf.CheckCM (TokenClass.Group, Major.EndGroup)) { 636 if ((--group_levels) == 0) { 637 break; 638 } 639 } 640 641 if (rtf.CheckCM (TokenClass.Group, Major.BeginGroup)) { 642 group_levels++; 643 } 644 } 645 } 646 ReadFontTbl(RTF rtf)647 private void ReadFontTbl(RTF rtf) { 648 int old; 649 Font font; 650 651 old = -1; 652 font = null; 653 654 while (true) { 655 rtf.GetToken(); 656 657 if (rtf.CheckCM(TokenClass.Group, Major.EndGroup)) { 658 break; 659 } 660 661 if (old < 0) { 662 if (rtf.CheckCMM(TokenClass.Control, Major.CharAttr, Minor.FontNum)) { 663 old = 1; 664 } else if (rtf.CheckCM(TokenClass.Group, Major.BeginGroup)) { 665 old = 0; 666 } else { 667 throw new RTFException(rtf, "Cannot determine format"); 668 } 669 } 670 671 if (old == 0) { 672 if (!rtf.CheckCM(TokenClass.Group, Major.BeginGroup)) { 673 throw new RTFException(rtf, "missing \"{\""); 674 } 675 rtf.GetToken(); 676 } 677 678 font = new Font(rtf); 679 680 while ((rtf.rtf_class != TokenClass.EOF) && (!rtf.CheckCM(TokenClass.Text, (Major)';')) && (!rtf.CheckCM(TokenClass.Group, Major.EndGroup))) { 681 if (rtf.rtf_class == TokenClass.Control) { 682 switch(rtf.major) { 683 case Major.FontFamily: { 684 font.Family = (int)rtf.minor; 685 break; 686 } 687 688 case Major.CharAttr: { 689 switch(rtf.minor) { 690 case Minor.FontNum: { 691 font.Num = rtf.param; 692 break; 693 } 694 695 default: { 696 #if RTF_DEBUG 697 Console.WriteLine("Got unhandled Control.CharAttr.Minor: " + rtf.minor); 698 #endif 699 break; 700 } 701 } 702 break; 703 } 704 705 case Major.FontAttr: { 706 switch (rtf.minor) { 707 case Minor.FontCharSet: { 708 font.Charset = (CharsetType)rtf.param; 709 break; 710 } 711 712 case Minor.FontPitch: { 713 font.Pitch = rtf.param; 714 break; 715 } 716 717 case Minor.FontCodePage: { 718 font.Codepage = rtf.param; 719 break; 720 } 721 722 case Minor.FTypeNil: 723 case Minor.FTypeTrueType: { 724 font.Type = rtf.param; 725 break; 726 } 727 default: { 728 #if RTF_DEBUG 729 Console.WriteLine("Got unhandled Control.FontAttr.Minor: " + rtf.minor); 730 #endif 731 break; 732 } 733 } 734 break; 735 } 736 737 default: { 738 #if RTF_DEBUG 739 Console.WriteLine("ReadFontTbl: Unknown Control token " + rtf.major); 740 #endif 741 break; 742 } 743 } 744 } else if (rtf.CheckCM(TokenClass.Group, Major.BeginGroup)) { 745 rtf.SkipGroup(); 746 } else if (rtf.rtf_class == TokenClass.Text) { 747 StringBuilder sb; 748 749 sb = new StringBuilder(); 750 751 while ((rtf.rtf_class != TokenClass.EOF) && (!rtf.CheckCM(TokenClass.Text, (Major)';')) && (!rtf.CheckCM(TokenClass.Group, Major.EndGroup)) && (!rtf.CheckCM(TokenClass.Group, Major.BeginGroup))) { 752 sb.Append((char)rtf.major); 753 rtf.GetToken(); 754 } 755 756 if (rtf.CheckCM(TokenClass.Group, Major.EndGroup)) { 757 rtf.UngetToken(); 758 } 759 760 font.Name = sb.ToString(); 761 continue; 762 #if RTF_DEBUG 763 } else { 764 Console.WriteLine("ReadFontTbl: Unknown token " + rtf.text_buffer); 765 #endif 766 } 767 768 rtf.GetToken(); 769 } 770 771 if (old == 0) { 772 rtf.GetToken(); 773 774 if (!rtf.CheckCM(TokenClass.Group, Major.EndGroup)) { 775 throw new RTFException(rtf, "Missing \"}\""); 776 } 777 } 778 } 779 780 if (font == null) { 781 throw new RTFException(rtf, "No font created"); 782 } 783 784 if (font.Num == -1) { 785 throw new RTFException(rtf, "Missing font number"); 786 } 787 788 rtf.RouteToken(); 789 } 790 ReadColorTbl(RTF rtf)791 private void ReadColorTbl(RTF rtf) { 792 Color color; 793 int num; 794 795 num = 0; 796 797 while (true) { 798 rtf.GetToken(); 799 800 if (rtf.CheckCM(TokenClass.Group, Major.EndGroup)) { 801 break; 802 } 803 804 color = new Color(rtf); 805 color.Num = num++; 806 807 while (rtf.CheckCM(TokenClass.Control, Major.ColorName)) { 808 switch (rtf.minor) { 809 case Minor.Red: { 810 color.Red = rtf.param; 811 break; 812 } 813 814 case Minor.Green: { 815 color.Green = rtf.param; 816 break; 817 } 818 819 case Minor.Blue: { 820 color.Blue = rtf.param; 821 break; 822 } 823 } 824 825 rtf.GetToken(); 826 } 827 if (!rtf.CheckCM(TokenClass.Text, (Major)';')) { 828 throw new RTFException(rtf, "Malformed color entry"); 829 } 830 } 831 rtf.RouteToken(); 832 } 833 ReadStyleSheet(RTF rtf)834 private void ReadStyleSheet(RTF rtf) { 835 Style style; 836 StringBuilder sb; 837 838 sb = new StringBuilder(); 839 840 while (true) { 841 rtf.GetToken(); 842 843 if (rtf.CheckCM(TokenClass.Group, Major.EndGroup)) { 844 break; 845 } 846 847 style = new Style(rtf); 848 849 if (!rtf.CheckCM(TokenClass.Group, Major.BeginGroup)) { 850 throw new RTFException(rtf, "Missing \"{\""); 851 } 852 853 while (true) { 854 rtf.GetToken(); 855 856 if ((rtf.rtf_class == TokenClass.EOF) || rtf.CheckCM(TokenClass.Text, (Major)';')) { 857 break; 858 } 859 860 if (rtf.rtf_class == TokenClass.Control) { 861 if (rtf.CheckMM(Major.ParAttr, Minor.StyleNum)) { 862 style.Num = rtf.param; 863 style.Type = StyleType.Paragraph; 864 continue; 865 } 866 if (rtf.CheckMM(Major.CharAttr, Minor.CharStyleNum)) { 867 style.Num = rtf.param; 868 style.Type = StyleType.Character; 869 continue; 870 } 871 if (rtf.CheckMM(Major.StyleAttr, Minor.SectStyleNum)) { 872 style.Num = rtf.param; 873 style.Type = StyleType.Section; 874 continue; 875 } 876 if (rtf.CheckMM(Major.StyleAttr, Minor.BasedOn)) { 877 style.BasedOn = rtf.param; 878 continue; 879 } 880 if (rtf.CheckMM(Major.StyleAttr, Minor.Additive)) { 881 style.Additive = true; 882 continue; 883 } 884 if (rtf.CheckMM(Major.StyleAttr, Minor.Next)) { 885 style.NextPar = rtf.param; 886 continue; 887 } 888 889 new StyleElement(style, rtf.rtf_class, rtf.major, rtf.minor, rtf.param, rtf.text_buffer.ToString()); 890 } else if (rtf.CheckCM(TokenClass.Group, Major.BeginGroup)) { 891 // This passes over "{\*\keycode ... }, among other things 892 rtf.SkipGroup(); 893 } else if (rtf.rtf_class == TokenClass.Text) { 894 while (rtf.rtf_class == TokenClass.Text) { 895 if (rtf.major == (Major)';') { 896 rtf.UngetToken(); 897 break; 898 } 899 900 sb.Append((char)rtf.major); 901 rtf.GetToken(); 902 } 903 904 style.Name = sb.ToString(); 905 #if RTF_DEBUG 906 } else { 907 Console.WriteLine("ReadStyleSheet: Ignored token " + rtf.text_buffer); 908 #endif 909 } 910 } 911 rtf.GetToken(); 912 913 if (!rtf.CheckCM(TokenClass.Group, Major.EndGroup)) { 914 throw new RTFException(rtf, "Missing EndGroup (\"}\""); 915 } 916 917 // Sanity checks 918 if (style.Name == null) { 919 throw new RTFException(rtf, "Style must have name"); 920 } 921 922 if (style.Num < 0) { 923 if (!sb.ToString().StartsWith("Normal") && !sb.ToString().StartsWith("Standard")) { 924 throw new RTFException(rtf, "Missing style number"); 925 } 926 927 style.Num = Style.NormalStyleNum; 928 } 929 930 if (style.NextPar == -1) { 931 style.NextPar = style.Num; 932 } 933 } 934 935 rtf.RouteToken(); 936 } 937 ReadInfoGroup(RTF rtf)938 private void ReadInfoGroup(RTF rtf) { 939 rtf.SkipGroup(); 940 rtf.RouteToken(); 941 } 942 ReadPictGroup(RTF rtf)943 private void ReadPictGroup(RTF rtf) 944 { 945 bool read_image_data = false; 946 947 Picture picture = new Picture (); 948 while (true) { 949 rtf.GetToken (); 950 951 if (rtf.CheckCM (TokenClass.Group, Major.EndGroup)) 952 break; 953 954 switch (minor) { 955 case Minor.PngBlip: 956 picture.ImageType = minor; 957 read_image_data = true; 958 break; 959 case Minor.WinMetafile: 960 picture.ImageType = minor; 961 read_image_data = true; 962 continue; 963 case Minor.PicWid: 964 continue; 965 case Minor.PicHt: 966 continue; 967 case Minor.PicGoalWid: 968 picture.SetWidthFromTwips (param); 969 continue; 970 case Minor.PicGoalHt: 971 picture.SetHeightFromTwips (param); 972 continue; 973 } 974 975 if (read_image_data && rtf.rtf_class == TokenClass.Text) { 976 977 picture.Data.Seek (0, SeekOrigin.Begin); 978 979 //char c = (char) rtf.major; 980 981 uint digitValue1; 982 uint digitValue2; 983 char hexDigit1 = (char) rtf.major; 984 char hexDigit2; 985 986 while (true) { 987 988 while (hexDigit1 == '\n' || hexDigit1 == '\r') { 989 hexDigit1 = (char) source.Peek (); 990 if (hexDigit1 == '}') 991 break; 992 hexDigit1 = (char) source.Read (); 993 } 994 995 hexDigit2 = (char) source.Peek (); 996 if (hexDigit2 == '}') 997 break; 998 hexDigit2 = (char) source.Read (); 999 while (hexDigit2 == '\n' || hexDigit2 == '\r') { 1000 hexDigit2 = (char) source.Peek (); 1001 if (hexDigit2 == '}') 1002 break; 1003 hexDigit2 = (char) source.Read (); 1004 } 1005 1006 if (Char.IsDigit (hexDigit1)) 1007 digitValue1 = (uint) (hexDigit1 - '0'); 1008 else if (Char.IsLower (hexDigit1)) 1009 digitValue1 = (uint) (hexDigit1 - 'a' + 10); 1010 else if (Char.IsUpper (hexDigit1)) 1011 digitValue1 = (uint) (hexDigit1 - 'A' + 10); 1012 else if (hexDigit1 == '\n' || hexDigit1 == '\r') 1013 continue; 1014 else 1015 break; 1016 1017 if (Char.IsDigit (hexDigit2)) 1018 digitValue2 = (uint) (hexDigit2 - '0'); 1019 else if (Char.IsLower (hexDigit2)) 1020 digitValue2 = (uint) (hexDigit2 - 'a' + 10); 1021 else if (Char.IsUpper (hexDigit2)) 1022 digitValue2 = (uint) (hexDigit2 - 'A' + 10); 1023 else if (hexDigit2 == '\n' || hexDigit2 == '\r') 1024 continue; 1025 else 1026 break; 1027 1028 picture.Data.WriteByte ((byte) checked (digitValue1 * 16 + digitValue2)); 1029 1030 // We get the first hex digit at the end, since in the very first 1031 // iteration we use rtf.major as the first hex digit 1032 hexDigit1 = (char) source.Peek (); 1033 if (hexDigit1 == '}') 1034 break; 1035 hexDigit1 = (char) source.Read (); 1036 } 1037 1038 1039 read_image_data = false; 1040 break; 1041 } 1042 } 1043 1044 if (picture.ImageType != Minor.Undefined && !read_image_data) { 1045 this.picture = picture; 1046 SetToken (TokenClass.Control, Major.PictAttr, picture.ImageType, 0, String.Empty); 1047 } 1048 } 1049 ReadObjGroup(RTF rtf)1050 private void ReadObjGroup(RTF rtf) { 1051 rtf.SkipGroup(); 1052 rtf.RouteToken(); 1053 } 1054 #endregion // Default Delegates 1055 } 1056 } 1057