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