Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'mcs/class/Managed.Windows.Forms/System.Windows.Forms.RTF/RTF.cs')
-rw-r--r--mcs/class/Managed.Windows.Forms/System.Windows.Forms.RTF/RTF.cs883
1 files changed, 883 insertions, 0 deletions
diff --git a/mcs/class/Managed.Windows.Forms/System.Windows.Forms.RTF/RTF.cs b/mcs/class/Managed.Windows.Forms/System.Windows.Forms.RTF/RTF.cs
new file mode 100644
index 00000000000..689deafa8a4
--- /dev/null
+++ b/mcs/class/Managed.Windows.Forms/System.Windows.Forms.RTF/RTF.cs
@@ -0,0 +1,883 @@
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Authors:
+// Peter Bartok (pbartok@novell.com)
+//
+
+// COMPLETE
+
+#undef RTF_DEBUG
+
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+namespace System.Windows.Forms.RTF {
+ internal class RTF {
+ #region Local Variables
+ internal const char EOF = unchecked((char)-1);
+ internal const int NoParam = -1000000;
+
+ private TokenClass rtf_class;
+ private Major major;
+ private Minor minor;
+ private int param;
+ private int format;
+ private StringBuilder text_buffer;
+ private int line_num;
+ private int line_pos;
+
+ private char pushed_char;
+ private StringBuilder pushed_text_buffer;
+ private TokenClass pushed_class;
+ private Major pushed_major;
+ private Minor pushed_minor;
+ private int pushed_param;
+
+ private char prev_char;
+ private bool bump_line;
+
+ private Font font_list;
+ private Color color_list;
+ private Style style_list;
+
+ private Charset cur_charset;
+ private Stack charset_stack;
+
+ private Style styles;
+ private Color colors;
+ private Font fonts;
+
+ private StreamReader source;
+
+ private static Hashtable key_table;
+ private static KeyStruct[] Keys = KeysInit.Init();
+
+ private DestinationCallback destination_callbacks;
+ private ClassCallback class_callbacks;
+ #endregion // Local Variables
+
+ #region Constructors
+ static RTF() {
+ key_table = new Hashtable(Keys.Length);
+ for (int i = 0; i < Keys.Length; i++) {
+ key_table[Keys[i].Symbol] = Keys[i];
+ }
+ }
+
+ public RTF(Stream stream) {
+ source = new StreamReader(stream);
+
+ text_buffer = new StringBuilder(1024);
+ pushed_text_buffer = new StringBuilder(1024);
+
+ rtf_class = TokenClass.None;
+ pushed_class = TokenClass.None;
+ pushed_char = unchecked((char)-1);
+
+ line_num = 0;
+ line_pos = 0;
+ prev_char = unchecked((char)-1);
+ bump_line = false;
+
+ cur_charset = new Charset();
+
+ destination_callbacks = new DestinationCallback();
+ class_callbacks = new ClassCallback();
+
+ destination_callbacks[Minor.FontTbl] = new DestinationDelegate(ReadFontTbl);
+ destination_callbacks[Minor.ColorTbl] = new DestinationDelegate(ReadColorTbl);
+ destination_callbacks[Minor.StyleSheet] = new DestinationDelegate(ReadStyleSheet);
+ destination_callbacks[Minor.Info] = new DestinationDelegate(ReadInfoGroup);
+ destination_callbacks[Minor.Pict] = new DestinationDelegate(ReadPictGroup);
+ destination_callbacks[Minor.Object] = new DestinationDelegate(ReadObjGroup);
+ }
+ #endregion // Constructors
+
+ #region Properties
+ public TokenClass TokenClass {
+ get {
+ return this.rtf_class;
+ }
+
+ set {
+ this.rtf_class = value;
+ }
+ }
+
+ public Major Major {
+ get {
+ return this.major;
+ }
+
+ set {
+ this.major = value;
+ }
+ }
+
+ public Minor Minor {
+ get {
+ return this.minor;
+ }
+
+ set {
+ this.minor = value;
+ }
+ }
+
+ public int Param {
+ get {
+ return this.param;
+ }
+
+ set {
+ this.param = value;
+ }
+ }
+
+ public string Text {
+ get {
+ return this.text_buffer.ToString();
+ }
+
+ set {
+ if (value == null) {
+ this.text_buffer.Length = 0;
+ } else {
+ this.text_buffer = new StringBuilder(value);
+ }
+ }
+ }
+
+ public Color Colors {
+ get {
+ return colors;
+ }
+
+ set {
+ colors = value;
+ }
+ }
+
+ public Style Styles {
+ get {
+ return styles;
+ }
+
+ set {
+ styles = value;
+ }
+ }
+
+ public Font Fonts {
+ get {
+ return fonts;
+ }
+
+ set {
+ fonts = value;
+ }
+ }
+
+ public ClassCallback ClassCallback {
+ get {
+ return class_callbacks;
+ }
+
+ set {
+ class_callbacks = value;
+ }
+ }
+
+ public DestinationCallback DestinationCallback {
+ get {
+ return destination_callbacks;
+ }
+
+ set {
+ destination_callbacks = value;
+ }
+ }
+
+ public int LineNumber {
+ get {
+ return line_num;
+ }
+ }
+
+ public int LinePos {
+ get {
+ return line_pos;
+ }
+ }
+ #endregion // Properties
+
+ #region Methods
+ /// <summary>Set the default font for documents without font table</summary>
+ public void DefaultFont(string name) {
+ Font font;
+
+ font = new Font(this);
+ font.Num = 0;
+ font.Name = name;
+ }
+
+ /// <summary>Read the next character from the input</summary>
+ private char GetChar() {
+ char c;
+ bool old_bump_line;
+
+ if ((c = (char)source.Read()) != EOF) {
+ this.text_buffer.Append(c);
+ }
+
+ if (this.prev_char == EOF) {
+ this.bump_line = true;
+ }
+
+ old_bump_line = bump_line;
+ bump_line = false;
+
+ if (c == '\r') {
+ bump_line = true;
+ } else if (c == '\n') {
+ bump_line = true;
+ if (this.prev_char == '\r') {
+ old_bump_line = false;
+ }
+ }
+
+ this.line_pos ++;
+ if (old_bump_line) {
+ this.line_num++;
+ this.line_pos = 1;
+ }
+
+ this.prev_char = c;
+ return c;
+ }
+
+ /// <summary>Parse the RTF stream</summary>
+ public void Read() {
+ while (GetToken() != TokenClass.EOF) {
+ RouteToken();
+ }
+ }
+
+ /// <summary>Route a token</summary>
+ public void RouteToken() {
+ if (CheckCM(TokenClass.Control, Major.Destination)) {
+ DestinationDelegate d;
+
+ d = destination_callbacks[minor];
+ if (d != null) {
+ d(this);
+ }
+ }
+
+ // Invoke class callback if there is one
+ ClassDelegate c;
+
+ c = class_callbacks[rtf_class];
+ if (c != null) {
+ c(this);
+ }
+
+ }
+
+ /// <summary>Skip to the end of the current group</summary>
+ public void SkipGroup() {
+ int level;
+
+ level = 1;
+
+ while (GetToken() != TokenClass.EOF) {
+ if (rtf_class == TokenClass.Group) {
+ if (this.major == Major.BeginGroup) {
+ level++;
+ } else if (this.major == Major.EndGroup) {
+ level--;
+ if (level < 1) {
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /// <summary>Return the next token in the stream</summary>
+ public TokenClass GetToken() {
+ if (pushed_class != TokenClass.None) {
+ this.rtf_class = this.pushed_class;
+ this.major = this.pushed_major;
+ this.minor = this.pushed_minor;
+ this.param = this.pushed_param;
+ this.pushed_class = TokenClass.None;
+ return this.rtf_class;
+ }
+
+ GetToken2();
+
+ if (this.rtf_class == TokenClass.Text) {
+ this.minor = (Minor)this.cur_charset[(int)this.major];
+ }
+
+ if (this.cur_charset.Flags == CharsetFlags.None) {
+ return this.rtf_class;
+ }
+
+ if (((this.cur_charset.Flags & CharsetFlags.Read) != 0) && CheckCM(TokenClass.Control, Major.CharSet)) {
+ this.cur_charset.ReadMap();
+ } else if (((this.cur_charset.Flags & CharsetFlags.Switch) != 0) && CheckCMM(TokenClass.Control, Major.CharAttr, Minor.FontNum)) {
+ Font fp;
+
+ fp = Font.GetFont(this.font_list, this.param);
+
+ if (fp != null) {
+ if (fp.Name.StartsWith("Symbol")) {
+ this.cur_charset.ID = CharsetType.Symbol;
+ } else {
+ this.cur_charset.ID = CharsetType.General;
+ }
+ } else if (((this.cur_charset.Flags & CharsetFlags.Switch) != 0) && (this.rtf_class == TokenClass.Group)) {
+ switch(this.major) {
+ case Major.BeginGroup: {
+ this.charset_stack.Push(this.cur_charset);
+ break;
+ }
+
+ case Major.EndGroup: {
+ this.cur_charset = (Charset)this.charset_stack.Pop();
+ break;
+ }
+ }
+ }
+ }
+
+ return this.rtf_class;
+ }
+
+ private void GetToken2() {
+ char c;
+ int sign;
+
+ this.rtf_class = TokenClass.Unknown;
+ this.param = NoParam;
+
+ this.text_buffer.Length = 0;
+
+ if (this.pushed_char != EOF) {
+ c = this.pushed_char;
+ this.text_buffer.Append(c);
+ this.pushed_char = EOF;
+ } else if ((c = GetChar()) == EOF) {
+ this.rtf_class = TokenClass.EOF;
+ return;
+ }
+
+ if (c == '{') {
+ this.rtf_class = TokenClass.Group;
+ this.major = Major.BeginGroup;
+ return;
+ }
+
+ if (c == '}') {
+ this.rtf_class = TokenClass.Group;
+ this.major = Major.EndGroup;
+ return;
+ }
+
+ if (c != '\\') {
+ if (c != '\t') {
+ this.rtf_class = TokenClass.Text;
+ this.major = (Major)c; // FIXME - typing?
+ return;
+ } else {
+ this.rtf_class = TokenClass.Control;
+ this.major = Major.SpecialChar;
+ this.minor = Minor.Tab;
+ return;
+ }
+ }
+
+ if ((c = GetChar()) == EOF) {
+ // Not so good
+ return;
+ }
+
+ if (!Char.IsLetter(c)) {
+ if (c == '\'') {
+ char c2;
+
+ if ((c = GetChar()) == EOF) {
+ return;
+ }
+
+ if ((c2 = GetChar()) == EOF) {
+ return;
+ }
+
+ this.rtf_class = TokenClass.Text;
+ this.major = (Major)((Char)((Convert.ToByte(c.ToString(), 16) * 16 + Convert.ToByte(c2.ToString(), 16))));
+ return;
+ }
+
+ // Escaped char
+ if (c == ':' || c == '{' || c == '}' || c == '\\') {
+ this.rtf_class = TokenClass.Text;
+ this.major = (Major)c;
+ return;
+ }
+
+ Lookup(this.text_buffer.ToString());
+ return;
+ }
+
+ while (Char.IsLetter(c)) {
+ if ((c = GetChar()) == EOF) {
+ break;
+ }
+ }
+
+ if (c != EOF) {
+ this.text_buffer.Length--;
+ }
+
+ Lookup(this.text_buffer.ToString());
+
+ if (c != EOF) {
+ this.text_buffer.Append(c);
+ }
+
+ sign = 1;
+ if (c == '-') {
+ sign = -1;
+ c = GetChar();
+ }
+
+ if (c != EOF && Char.IsDigit(c)) {
+ this.param = 0;
+ while (Char.IsDigit(c)) {
+ this.param = this.param * 10 + Convert.ToByte(c) - 48;
+ if ((c = GetChar()) == EOF) {
+ break;
+ }
+ }
+ this.param *= sign;
+ }
+
+ if (c != EOF) {
+ if (c != ' ') {
+ this.pushed_char = c;
+ }
+ this.text_buffer.Length--;
+ }
+ }
+
+ public void SetToken(TokenClass cl, Major maj, Minor min, int par, string text) {
+ this.rtf_class = cl;
+ this.major = maj;
+ this.minor = min;
+ this.param = par;
+ if (par == NoParam) {
+ this.text_buffer = new StringBuilder(text);
+ } else {
+ this.text_buffer = new StringBuilder(text + par.ToString());
+ }
+ }
+
+ public void UngetToken() {
+ if (this.pushed_class != TokenClass.None) {
+ throw new RTFException(this, "Cannot unget more than one token");
+ }
+
+ if (this.rtf_class == TokenClass.None) {
+ throw new RTFException(this, "No token to unget");
+ }
+
+ this.pushed_class = this.rtf_class;
+ this.pushed_major = this.major;
+ this.pushed_minor = this.minor;
+ this.pushed_param = this.param;
+ this.pushed_text_buffer = new StringBuilder(this.text_buffer.ToString());
+ }
+
+ public TokenClass PeekToken() {
+ GetToken();
+ UngetToken();
+ return rtf_class;
+ }
+
+ public void Lookup(string token) {
+ Object obj;
+ KeyStruct key;
+
+ obj = key_table[token.Substring(1)];
+ if (obj == null) {
+ rtf_class = TokenClass.Unknown;
+ return;
+ }
+
+ key = (KeyStruct)obj;
+ this.rtf_class = TokenClass.Control;
+ this.major = key.Major;
+ this.minor = key.Minor;
+ }
+
+ public bool CheckCM(TokenClass rtf_class, Major major) {
+ if ((this.rtf_class == rtf_class) && (this.major == major)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ public bool CheckCMM(TokenClass rtf_class, Major major, Minor minor) {
+ if ((this.rtf_class == rtf_class) && (this.major == major) && (this.minor == minor)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ public bool CheckMM(Major major, Minor minor) {
+ if ((this.major == major) && (this.minor == minor)) {
+ return true;
+ }
+
+ return false;
+ }
+ #endregion // Methods
+
+ #region Default Delegates
+ private void ReadFontTbl(RTF rtf) {
+ int old;
+ Font font;
+
+ old = -1;
+ font = null;
+
+ while (true) {
+ rtf.GetToken();
+
+ if (rtf.CheckCM(TokenClass.Group, Major.EndGroup)) {
+ break;
+ }
+
+ if (old < 0) {
+ if (rtf.CheckCMM(TokenClass.Control, Major.CharAttr, Minor.FontNum)) {
+ old = 1;
+ } else if (rtf.CheckCM(TokenClass.Group, Major.BeginGroup)) {
+ old = 0;
+ } else {
+ throw new RTFException(rtf, "Cannot determine format");
+ }
+ }
+
+ if (old == 0) {
+ if (!rtf.CheckCM(TokenClass.Group, Major.BeginGroup)) {
+ throw new RTFException(rtf, "missing \"{\"");
+ }
+ rtf.GetToken();
+ }
+
+ font = new Font(rtf);
+
+ while ((rtf.rtf_class != TokenClass.EOF) && (!rtf.CheckCM(TokenClass.Text, (Major)';')) && (!rtf.CheckCM(TokenClass.Group, Major.EndGroup))) {
+ if (rtf.rtf_class == TokenClass.Control) {
+ switch(rtf.major) {
+ case Major.FontFamily: {
+ font.Family = (int)rtf.minor;
+ break;
+ }
+
+ case Major.CharAttr: {
+ switch(rtf.minor) {
+ case Minor.FontNum: {
+ font.Num = rtf.param;
+ break;
+ }
+
+ default: {
+ #if RTF_DEBUG
+ Console.WriteLine("Got unhandled Control.CharAttr.Minor: " + rtf.minor);
+ #endif
+ break;
+ }
+ }
+ break;
+ }
+
+ case Major.FontAttr: {
+ switch (rtf.minor) {
+ case Minor.FontCharSet: {
+ font.Charset = (CharsetType)rtf.param;
+ break;
+ }
+
+ case Minor.FontPitch: {
+ font.Pitch = rtf.param;
+ break;
+ }
+
+ case Minor.FontCodePage: {
+ font.Codepage = rtf.param;
+ break;
+ }
+
+ case Minor.FTypeNil:
+ case Minor.FTypeTrueType: {
+ font.Type = rtf.param;
+ break;
+ }
+ default: {
+ #if RTF_DEBUG
+ Console.WriteLine("Got unhandled Control.FontAttr.Minor: " + rtf.minor);
+ #endif
+ break;
+ }
+ }
+ break;
+ }
+
+ default: {
+ #if RTF_DEBUG
+ Console.WriteLine("ReadFontTbl: Unknown Control token " + rtf.major);
+ #endif
+ break;
+ }
+ }
+ } else if (rtf.CheckCM(TokenClass.Group, Major.BeginGroup)) {
+ rtf.SkipGroup();
+ } else if (rtf.rtf_class == TokenClass.Text) {
+ StringBuilder sb;
+
+ sb = new StringBuilder();
+
+ while ((rtf.rtf_class != TokenClass.EOF) && (!rtf.CheckCM(TokenClass.Text, (Major)';')) && (!rtf.CheckCM(TokenClass.Group, Major.EndGroup))) {
+ sb.Append((char)rtf.major);
+ rtf.GetToken();
+ }
+
+ if (rtf.CheckCM(TokenClass.Group, Major.EndGroup)) {
+ rtf.UngetToken();
+ }
+
+ font.Name = sb.ToString();
+ continue;
+#if RTF_DEBUG
+ } else {
+ Console.WriteLine("ReadFontTbl: Unknown token " + rtf.text_buffer);
+#endif
+ }
+
+ rtf.GetToken();
+ }
+
+ if (old == 0) {
+ rtf.GetToken();
+
+ if (!rtf.CheckCM(TokenClass.Group, Major.EndGroup)) {
+ throw new RTFException(rtf, "Missing \"}\"");
+ }
+ }
+ }
+
+ if (font == null) {
+ throw new RTFException(rtf, "No font created");
+ }
+
+ if (font.Num == -1) {
+ throw new RTFException(rtf, "Missing font number");
+ }
+
+ rtf.RouteToken();
+ }
+
+ private void ReadColorTbl(RTF rtf) {
+ Color color;
+ int num;
+
+ num = 0;
+
+ while (true) {
+ rtf.GetToken();
+
+ if (rtf.CheckCM(TokenClass.Group, Major.EndGroup)) {
+ break;
+ }
+
+ color = new Color(rtf);
+ color.Num = num++;
+
+ while (rtf.CheckCM(TokenClass.Control, Major.ColorName)) {
+ switch (rtf.minor) {
+ case Minor.Red: {
+ color.Red = rtf.param;
+ break;
+ }
+
+ case Minor.Green: {
+ color.Green = rtf.param;
+ break;
+ }
+
+ case Minor.Blue: {
+ color.Blue = rtf.param;
+ break;
+ }
+ }
+
+ rtf.GetToken();
+ }
+ if (!rtf.CheckCM(TokenClass.Text, (Major)';')) {
+ throw new RTFException(rtf, "Malformed color entry");
+ }
+ }
+ rtf.RouteToken();
+ }
+
+ private void ReadStyleSheet(RTF rtf) {
+ Style style;
+ StringBuilder sb;
+
+ sb = new StringBuilder();
+
+ while (true) {
+ rtf.GetToken();
+
+ if (rtf.CheckCM(TokenClass.Group, Major.EndGroup)) {
+ break;
+ }
+
+ style = new Style(rtf);
+
+ if (!rtf.CheckCM(TokenClass.Group, Major.BeginGroup)) {
+ throw new RTFException(rtf, "Missing \"{\"");
+ }
+
+ while (true) {
+ rtf.GetToken();
+
+ if ((rtf.rtf_class == TokenClass.EOF) || rtf.CheckCM(TokenClass.Text, (Major)';')) {
+ break;
+ }
+
+ if (rtf.rtf_class == TokenClass.Control) {
+ if (rtf.CheckMM(Major.SpecialChar, Minor.OptDest)) {
+ continue;
+ }
+ if (rtf.CheckMM(Major.ParAttr, Minor.StyleNum)) {
+ style.Num = rtf.param;
+ style.Type = StyleType.Paragraph;
+ continue;
+ }
+ if (rtf.CheckMM(Major.CharAttr, Minor.CharStyleNum)) {
+ style.Num = rtf.param;
+ style.Type = StyleType.Character;
+ continue;
+ }
+ if (rtf.CheckMM(Major.StyleAttr, Minor.SectStyleNum)) {
+ style.Num = rtf.param;
+ style.Type = StyleType.Section;
+ continue;
+ }
+ if (rtf.CheckMM(Major.StyleAttr, Minor.BasedOn)) {
+ style.BasedOn = rtf.param;
+ continue;
+ }
+ if (rtf.CheckMM(Major.StyleAttr, Minor.Additive)) {
+ style.Additive = true;
+ continue;
+ }
+ if (rtf.CheckMM(Major.StyleAttr, Minor.Next)) {
+ style.NextPar = rtf.param;
+ continue;
+ }
+
+ new StyleElement(style, rtf.rtf_class, rtf.major, rtf.minor, rtf.param, rtf.text_buffer.ToString());
+ } else if (rtf.CheckCM(TokenClass.Group, Major.BeginGroup)) {
+ // This passes over "{\*\keycode ... }, among other things
+ rtf.SkipGroup();
+ } else if (rtf.rtf_class == TokenClass.Text) {
+ while (rtf.rtf_class == TokenClass.Text) {
+ if (rtf.major == (Major)';') {
+ rtf.UngetToken();
+ break;
+ }
+
+ sb.Append((char)rtf.major);
+ rtf.GetToken();
+ }
+
+ style.Name = sb.ToString();
+#if RTF_DEBUG
+ } else {
+ Console.WriteLine("ReadStyleSheet: Ignored token " + rtf.text_buffer);
+#endif
+ }
+ }
+ rtf.GetToken();
+
+ if (!rtf.CheckCM(TokenClass.Group, Major.EndGroup)) {
+ throw new RTFException(rtf, "Missing EndGroup (\"}\"");
+ }
+
+ // Sanity checks
+ if (style.Name == null) {
+ throw new RTFException(rtf, "Style must have name");
+ }
+
+ if (style.Num < 0) {
+ if (!sb.ToString().StartsWith("Normal") && !sb.ToString().StartsWith("Standard")) {
+ throw new RTFException(rtf, "Missing style number");
+ }
+
+ style.Num = Style.NormalStyleNum;
+ }
+
+ if (style.NextPar == -1) {
+ style.NextPar = style.Num;
+ }
+ }
+
+ rtf.RouteToken();
+ }
+
+ private void ReadInfoGroup(RTF rtf) {
+ rtf.SkipGroup();
+ rtf.RouteToken();
+ }
+
+ private void ReadPictGroup(RTF rtf) {
+ rtf.SkipGroup();
+ rtf.RouteToken();
+ }
+
+ private void ReadObjGroup(RTF rtf) {
+ rtf.SkipGroup();
+ rtf.RouteToken();
+ }
+ #endregion // Default Delegates
+ }
+}