You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by ay...@apache.org on 2008/07/19 12:53:51 UTC

svn commit: r678130 [1/2] - in /harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common: javax/swing/text/rtf/ org/apache/harmony/x/swing/text/rtf/

Author: ayza
Date: Sat Jul 19 03:53:50 2008
New Revision: 678130

URL: http://svn.apache.org/viewvc?rev=678130&view=rev
Log:
Applying patch for RTF parser from HARMONY-5911 ([classlib][rtf] RTF parser improvements and fixes)


Added:
    harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/org/apache/harmony/x/swing/text/rtf/DocumentRTFHandler.java   (with props)
    harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/org/apache/harmony/x/swing/text/rtf/RTFEncodings.java   (with props)
    harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/org/apache/harmony/x/swing/text/rtf/RTFHandler.java   (with props)
Removed:
    harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/org/apache/harmony/x/swing/text/rtf/RTFParserHandler.java
Modified:
    harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/rtf/RTFEditorKit.java
    harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/org/apache/harmony/x/swing/text/rtf/RTFParser.java
    harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/org/apache/harmony/x/swing/text/rtf/RTFParser.jj
    harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/org/apache/harmony/x/swing/text/rtf/RTFParserConstants.java
    harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/org/apache/harmony/x/swing/text/rtf/RTFParserTokenManager.java
    harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/org/apache/harmony/x/swing/text/rtf/SimpleCharStream.java

Modified: harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/rtf/RTFEditorKit.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/rtf/RTFEditorKit.java?rev=678130&r1=678129&r2=678130&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/rtf/RTFEditorKit.java (original)
+++ harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/javax/swing/text/rtf/RTFEditorKit.java Sat Jul 19 03:53:50 2008
@@ -14,10 +14,13 @@
  *  See the License for the specific language governing permissions and
  *  limitations under the License.
  */
+
 package javax.swing.text.rtf;
 
 import org.apache.harmony.x.swing.text.rtf.RTFParser;
 import org.apache.harmony.x.swing.text.rtf.ParseException;
+import org.apache.harmony.x.swing.text.rtf.RTFHandler;
+import org.apache.harmony.x.swing.text.rtf.DocumentRTFHandler;
 
 import javax.swing.text.StyledEditorKit;
 import javax.swing.text.Document;
@@ -25,7 +28,7 @@
 import java.io.*;
 
 /**
- * @author ayzen
+ * @author Aleksey Lagoshin
  */
 public class RTFEditorKit extends StyledEditorKit {
 
@@ -40,7 +43,8 @@
   public void read(InputStream in, Document doc, int pos) throws IOException, BadLocationException {
     RTFParser parser = new RTFParser(in);
     try {
-      parser.parse(doc, pos);
+      RTFHandler handler = new DocumentRTFHandler(doc, pos);
+      parser.parse(handler);
     }
     catch (ParseException e) {
       IOException ioex = new IOException(e.toString());
@@ -50,16 +54,26 @@
     }
   }
 
-  public void read(Reader in, Document doc, int pos) {
+  public void read(Reader in, Document doc, int pos) throws IOException, BadLocationException {
+    RTFParser parser = new RTFParser(in);
+    try {
+      RTFHandler handler = new DocumentRTFHandler(doc, pos);
+      parser.parse(handler);
+    }
+    catch (ParseException e) {
+      IOException ioex = new IOException(e.toString());
 
+      ioex.initCause(e);
+      throw ioex;
+    }
   }
 
   public void write(OutputStream out, Document doc, int pos, int len) {
-    
+
   }
 
   public void write(Writer out, Document doc, int pos, int len) {
 
   }
 
-}
+}
\ No newline at end of file

Added: harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/org/apache/harmony/x/swing/text/rtf/DocumentRTFHandler.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/org/apache/harmony/x/swing/text/rtf/DocumentRTFHandler.java?rev=678130&view=auto
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/org/apache/harmony/x/swing/text/rtf/DocumentRTFHandler.java (added)
+++ harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/org/apache/harmony/x/swing/text/rtf/DocumentRTFHandler.java Sat Jul 19 03:53:50 2008
@@ -0,0 +1,89 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.harmony.x.swing.text.rtf;
+
+import javax.swing.text.*;
+import java.util.Stack;
+
+/**
+ * @author Aleksey Lagoshin
+ */
+public class DocumentRTFHandler implements RTFHandler {
+
+  private StyledDocument sdoc;
+  private Document doc;
+
+  private int offset;
+
+  private Stack<MutableAttributeSet> stylesStack;
+  private MutableAttributeSet currentStyle;
+
+  public DocumentRTFHandler(Document doc, int position) {
+    stylesStack = new Stack<MutableAttributeSet>();
+    currentStyle = new SimpleAttributeSet();
+
+    if (doc instanceof StyledDocument)
+      sdoc = (StyledDocument) doc;
+    else
+      this.doc = doc;
+
+    offset = position;
+  }
+
+  public void startGroup() {
+    stylesStack.push(currentStyle);
+    currentStyle = new SimpleAttributeSet(currentStyle);
+  }
+
+  public void endGroup() {
+    currentStyle = stylesStack.pop();
+  }
+
+  public void addText(String text) {
+    try {
+      if (sdoc != null)
+        sdoc.insertString(offset, text, currentStyle);
+      else
+        doc.insertString(offset, text, null);
+
+      offset += text.length();
+    }
+    catch (BadLocationException e) {
+      //todo: throw it to RTFEditorKit?
+    }
+  }
+
+  public void newParagraph() {
+    addText("\n");
+  }
+
+  public void setBold(boolean enable) {
+    StyleConstants.setBold(currentStyle, enable);
+  }
+
+  public void setItalic(boolean enable) {
+    StyleConstants.setItalic(currentStyle, enable);
+  }
+
+  public void setUnderline(boolean enable) {
+    StyleConstants.setUnderline(currentStyle, enable);
+  }
+
+}
+
+

Propchange: harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/org/apache/harmony/x/swing/text/rtf/DocumentRTFHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/org/apache/harmony/x/swing/text/rtf/RTFEncodings.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/org/apache/harmony/x/swing/text/rtf/RTFEncodings.java?rev=678130&view=auto
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/org/apache/harmony/x/swing/text/rtf/RTFEncodings.java (added)
+++ harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/org/apache/harmony/x/swing/text/rtf/RTFEncodings.java Sat Jul 19 03:53:50 2008
@@ -0,0 +1,94 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.harmony.x.swing.text.rtf;
+
+/**
+ * This class contains methods for converting RTF code pages to Java encodings and vice versa.
+ *
+ * @author Aleksey Lagoshin
+ */
+public class RTFEncodings {
+
+  /**
+   * The default encoding for RTF files, it is also used for unsupported code pages.
+   */
+  public static final String DEFAULT_ENCODING = "Cp1252";
+
+  /**
+   * Returns an encoding name for Java corresponding to parsed code page.
+   * For all unsupported code pages this method returns the default encoding
+   * (see <a href="http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html">this</a> page)
+   *
+   * @param rtfCodePage code page parsed from RTF file
+   * @return an encoding name for Java
+   */
+  public static String getEncoding(int rtfCodePage) {
+    switch (rtfCodePage) {
+      case 437: return "Cp437";              // United States IBM
+      case 708: return "ISO8859_6";          // Arabic (ASMO 708)
+      case 709:                              // Arabic (ASMO 449+, BCON V4)
+      case 710:                              // Arabic (transparent Arabic)
+      case 711:                              // Arabic (Nafitha Enhanced)
+      case 720: return DEFAULT_ENCODING;     // Arabic (transparent ASMO)
+      case 819: return "ISO8859_1";          // Windows 3.1 (United States and Western Europe)
+      case 850: return "Cp850";              // IBM multilingual
+      case 852: return "Cp852";              // Eastern European
+      case 860: return "Cp860";              // Portuguese
+      case 862: return "Cp862";              // Hebrew
+      case 863: return "Cp863";              // French Canadian
+      case 864: return "Cp864";              // Arabic
+      case 865: return "Cp865";              // Norwegian
+      case 866: return "Cp866";              // Soviet Union
+      case 874: return "MS874";              // Thai
+      case 932: return "MS932";              // Japanese
+      case 936: return "MS936";              // Simplified Chinese
+      case 949: return "MS949";              // Korean
+      case 950: return "MS950";              // Traditional Chinese
+      case 1250: return "Cp1250";            // Eastern European
+      case 1251: return "Cp1251";            // Cyrillic
+      case 1252: return "Cp1252";            // Western European
+      case 1253: return "Cp1253";            // Greek
+      case 1254: return "Cp1255";            // Turkish
+      case 1255: return "Cp1255";            // Hebrew
+      case 1256: return "Cp1256";            // Arabic
+      case 1257: return "Cp1257";            // Baltic
+      case 1258: return "Cp1258";            // Vietnamese
+      case 1361: return "x-Johab";           // Johab
+      case 10000: return "MacRoman";         // MAC Roman
+      case 10001: return "SJIS";             // MAC Japan
+      case 10004: return "MacArabic";        // MAC Arabic
+      case 10005: return "MacHebrew";        // MAC Hebrew
+      case 10006: return "MacGreek";         // MAC Greek
+      case 10007: return "MacCyrillic";      // MAC Cyrillic
+      case 10029: return "MacCentralEurope"; // MAC Latin2
+      case 10081: return "MacTurkish";       // MAC Turkish
+      case 57002: return "ISCII91";          // Devanagari
+      case 57003:                            // Bengali
+      case 57004:                            // Tamil
+      case 57005:                            // Telugu
+      case 57006:                            // Assamese
+      case 57007:                            // Oriya
+      case 57008:                            // Kannada
+      case 57009:                            // Malayalam
+      case 57010:                            // Gujarati
+      case 57011:                            // Punjabi
+      default: return DEFAULT_ENCODING;
+    }
+  }
+
+}

Propchange: harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/org/apache/harmony/x/swing/text/rtf/RTFEncodings.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/org/apache/harmony/x/swing/text/rtf/RTFHandler.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/org/apache/harmony/x/swing/text/rtf/RTFHandler.java?rev=678130&view=auto
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/org/apache/harmony/x/swing/text/rtf/RTFHandler.java (added)
+++ harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/org/apache/harmony/x/swing/text/rtf/RTFHandler.java Sat Jul 19 03:53:50 2008
@@ -0,0 +1,39 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.harmony.x.swing.text.rtf;
+
+/**
+ * @author Aleksey Lagoshin
+ */
+public interface RTFHandler {
+
+  public void startGroup();
+
+  public void endGroup();
+
+  public void addText(String text);
+
+  public void newParagraph();
+
+  public void setBold(boolean enable);
+
+  public void setItalic(boolean enable);
+
+  public void setUnderline(boolean enable);
+
+}

Propchange: harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/org/apache/harmony/x/swing/text/rtf/RTFHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/org/apache/harmony/x/swing/text/rtf/RTFParser.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/org/apache/harmony/x/swing/text/rtf/RTFParser.java?rev=678130&r1=678129&r2=678130&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/org/apache/harmony/x/swing/text/rtf/RTFParser.java (original)
+++ harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/org/apache/harmony/x/swing/text/rtf/RTFParser.java Sat Jul 19 03:53:50 2008
@@ -2,12 +2,21 @@
 package org.apache.harmony.x.swing.text.rtf;
 
 import java.io.*;
-import javax.swing.text.Document;
+import java.util.Stack;
 import javax.swing.text.DefaultStyledDocument;
 
 public class RTFParser implements RTFParserConstants {
 
-  private static RTFParserHandler handler;
+  private RTFHandler handler;
+
+  private String encoding = RTFEncodings.DEFAULT_ENCODING;
+
+  private int ucValue = 1;
+  /**
+   * This stack contains only UC values as a scope parameter.
+   * It could be modified to contain additional parameters.
+   */
+  private Stack scopeStack = new Stack();
 
   public static void main(String args[]) throws Exception {
     InputStream in;
@@ -18,16 +27,27 @@
       in = System.in;
 
     RTFParser parser = new RTFParser(in);
-    parser.parse(new DefaultStyledDocument(), 0);
+    RTFHandler handler = new DocumentRTFHandler(new DefaultStyledDocument(), 0);
+    parser.parse(handler);
   }
 
-  static final public void parse(Document doc, int position) throws ParseException {
-    handler = new RTFParserHandler(doc, position);
+  private byte[] getBytes(String str) {
+    char[] chars = str.toCharArray();
+    byte[] bytes = new byte[chars.length];
+    for (int i = 0; i < chars.length; i++)
+      bytes[i] = (byte) chars[i];
+    return bytes;
+  }
+
+  final public void parse(RTFHandler handler) throws ParseException {
+    if (handler == null)
+      {if (true) throw new NullPointerException("Parameter handler cannot be null");}
+    this.handler = handler;
     file();
     jj_consume_token(0);
   }
 
-  static final private int parameter() throws ParseException {
+  final private int parameter() throws ParseException {
   Token param = null;
     switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
     case PARAM:
@@ -37,11 +57,11 @@
       jj_la1[0] = jj_gen;
       ;
     }
-    {if (true) return param == null ? -1 : Integer.parseInt(param.image);}
+    {if (true) return param == null ? -1 : Integer.parseInt(param.image.trim());}
     throw new Error("Missing return statement in function");
   }
 
-  static final private void unknownControlWord() throws ParseException {
+  final private void unknownControlWord() throws ParseException {
     jj_consume_token(CONTROL_WORD);
     switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
     case PARAM:
@@ -54,173 +74,323 @@
   }
 
 /**
- *  Catches all unhandled control symbols.
+ * Catches all unhandled control symbols.
  */
-  static final public void unknownControlSymbol() throws ParseException {
+  final public void unknownControlSymbol() throws ParseException {
     jj_consume_token(CONTROL_SYMBOL);
   }
 
-  static final public void text() throws ParseException {
-  Token text;
-    text = jj_consume_token(TEXT);
-    handler.addText(text.image);
-  }
-
-  static final public void file() throws ParseException {
+/**
+ * Group which starts with "{\*" and describes destination, currently this part
+ * is ignored.
+ */
+  final public void ignoredDestination() throws ParseException {
     jj_consume_token(OPEN_BRACE);
-    header();
-    document();
+    jj_consume_token(IGNORED_DESTINATION);
+    ignoredBlock();
     jj_consume_token(CLOSE_BRACE);
   }
 
-  static final public void header() throws ParseException {
-    jj_consume_token(RTF);
-    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
-    case PARAM:
-      jj_consume_token(PARAM);
-      break;
-    default:
-      jj_la1[2] = jj_gen;
-      ;
-    }
-  }
-
-  static final public void document() throws ParseException {
+  final public String parseText() throws ParseException {
+  byte[] bytes;
+  String text;
+  ByteArrayOutputStream textBytes = new ByteArrayOutputStream();
+  StringBuffer parsedText = new StringBuffer();
     label_1:
     while (true) {
       switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
-      case B:
-      case I:
-      case UL:
-        paragraph();
-        break;
-      default:
-        jj_la1[3] = jj_gen;
-        if (jj_2_1(2147483647)) {
-          fonttbl();
-        } else if (jj_2_2(2147483647)) {
-          stylesheet();
-        } else if (jj_2_3(2147483647)) {
-          info();
-        } else if (jj_2_4(2147483647)) {
-          ignoredDestination();
-        } else {
+      case HEX_CHAR:
+      case TEXT:
+        label_2:
+        while (true) {
           switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
-          case OPEN_BRACE:
-            documentBlock();
-            break;
-          case CONTROL_WORD:
-            unknownControlWord();
-            break;
-          case CONTROL_SYMBOL:
-            unknownControlSymbol();
+          case HEX_CHAR:
+            bytes = parseHexBytes();
             break;
           case TEXT:
-            text();
+            bytes = parseTextBytes();
             break;
           default:
-            jj_la1[4] = jj_gen;
+            jj_la1[2] = jj_gen;
             jj_consume_token(-1);
             throw new ParseException();
           }
+          try {
+            textBytes.write(bytes);
+          } catch (IOException e) {}
+          switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+          case HEX_CHAR:
+          case TEXT:
+            ;
+            break;
+          default:
+            jj_la1[3] = jj_gen;
+            break label_2;
+          }
         }
+      // Decoding collected characters using specified encoding
+      try {
+        parsedText.append(textBytes.toString(encoding));
+        textBytes.reset();
+      }
+      catch (UnsupportedEncodingException e) {
+        {if (true) throw new ParseException("Unsupported encoding");}
+      }
+        break;
+      case ESCAPED_OPEN_BRACE:
+      case ESCAPED_CLOSE_BRACE:
+      case ESCAPED_BACKSLASH:
+      case U:
+        switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+        case ESCAPED_OPEN_BRACE:
+        case ESCAPED_CLOSE_BRACE:
+        case ESCAPED_BACKSLASH:
+          text = parseSpecialCharacter();
+          break;
+        case U:
+          text = parseUnicodeText();
+          break;
+        default:
+          jj_la1[4] = jj_gen;
+          jj_consume_token(-1);
+          throw new ParseException();
+        }
+        parsedText.append(text);
+        break;
+      default:
+        jj_la1[5] = jj_gen;
+        jj_consume_token(-1);
+        throw new ParseException();
       }
       switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
-      case OPEN_BRACE:
+      case ESCAPED_OPEN_BRACE:
+      case ESCAPED_CLOSE_BRACE:
+      case ESCAPED_BACKSLASH:
+      case HEX_CHAR:
       case TEXT:
-      case B:
-      case I:
-      case UL:
-      case CONTROL_WORD:
-      case CONTROL_SYMBOL:
+      case U:
         ;
         break;
       default:
-        jj_la1[5] = jj_gen;
+        jj_la1[6] = jj_gen;
         break label_1;
       }
     }
+    {if (true) return parsedText.toString();}
+    throw new Error("Missing return statement in function");
   }
 
-/**
- *  A group.
- */
-  static final public void documentBlock() throws ParseException {
+  final public byte[] parseHexBytes() throws ParseException {
+  Token token;
+  byte[] result = new byte[1];
+    token = jj_consume_token(HEX_CHAR);
+    result[0] = (byte) Integer.parseInt(token.image.substring(2), 16);
+    {if (true) return result;}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public byte[] parseTextBytes() throws ParseException {
+  Token token;
+    token = jj_consume_token(TEXT);
+    {if (true) return getBytes(token.image);}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public String parseSpecialCharacter() throws ParseException {
+    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+    case ESCAPED_OPEN_BRACE:
+      jj_consume_token(ESCAPED_OPEN_BRACE);
+                          {if (true) return "{";}
+      break;
+    case ESCAPED_CLOSE_BRACE:
+      jj_consume_token(ESCAPED_CLOSE_BRACE);
+                          {if (true) return "}";}
+      break;
+    case ESCAPED_BACKSLASH:
+      jj_consume_token(ESCAPED_BACKSLASH);
+                          {if (true) return "\\";}
+      break;
+    default:
+      jj_la1[7] = jj_gen;
+      jj_consume_token(-1);
+      throw new ParseException();
+    }
+    throw new Error("Missing return statement in function");
+  }
+
+  final public String parseUnicodeText() throws ParseException {
+  int param;
+  StringBuffer unicodeBuffer = new StringBuffer();
+    label_3:
+    while (true) {
+      jj_consume_token(U);
+      param = parameter();
+      if (param < 0)
+        param += 65536;
+
+      unicodeBuffer.append((char) param);
+      skipAfterUnicode(ucValue);
+      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+      case U:
+        ;
+        break;
+      default:
+        jj_la1[8] = jj_gen;
+        break label_3;
+      }
+    }
+    {if (true) return unicodeBuffer.toString();}
+    throw new Error("Missing return statement in function");
+  }
+
+  final public void file() throws ParseException {
     jj_consume_token(OPEN_BRACE);
-                 handler.startGroup();
+    jj_consume_token(RTF);
+    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+    case PARAM:
+      jj_consume_token(PARAM);
+      break;
+    default:
+      jj_la1[9] = jj_gen;
+      ;
+    }
     document();
     jj_consume_token(CLOSE_BRACE);
-                  handler.endGroup();
   }
 
-/**
- *  Ignored block of RTF file, currently is using to ignore unknown parts
- *  of file.
- */
-  static final public void ignoredBlock() throws ParseException {
-    label_2:
+  final public void document() throws ParseException {
+  boolean skipped;
+  String text;
+    label_4:
     while (true) {
-      if (jj_2_5(2147483647)) {
-        ignoredDestination();
+      if (jj_2_1(2)) {
+        header();
       } else {
         switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
         case B:
         case I:
         case UL:
-          characterFormat();
-          break;
-        case CONTROL_WORD:
-          unknownControlWord();
-          break;
-        case CONTROL_SYMBOL:
-          unknownControlSymbol();
-          break;
-        case TEXT:
-          jj_consume_token(TEXT);
-          break;
-        case OPEN_BRACE:
-          jj_consume_token(OPEN_BRACE);
-          ignoredBlock();
-          jj_consume_token(CLOSE_BRACE);
+        case PAR:
+          paragraph();
           break;
         default:
-          jj_la1[6] = jj_gen;
-          jj_consume_token(-1);
-          throw new ParseException();
+          jj_la1[10] = jj_gen;
+          if (jj_2_2(2147483647)) {
+            info();
+          } else if (jj_2_3(2147483647)) {
+            ignoredDestination();
+          } else {
+            switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+            case OPEN_BRACE:
+              documentGroup();
+              break;
+            case CONTROL_WORD:
+              unknownControlWord();
+              break;
+            case CONTROL_SYMBOL:
+              unknownControlSymbol();
+              break;
+            case ESCAPED_OPEN_BRACE:
+            case ESCAPED_CLOSE_BRACE:
+            case ESCAPED_BACKSLASH:
+            case HEX_CHAR:
+            case TEXT:
+            case U:
+              text = parseText();
+                         handler.addText(text);
+              break;
+            default:
+              jj_la1[11] = jj_gen;
+              skipped = handleUnexpectedControlWord();
+                                              if (!skipped) {if (true) return;}
+            }
+          }
         }
       }
-      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
-      case OPEN_BRACE:
-      case TEXT:
-      case B:
-      case I:
-      case UL:
-      case CONTROL_WORD:
-      case CONTROL_SYMBOL:
-        ;
-        break;
-      default:
-        jj_la1[7] = jj_gen;
-        break label_2;
-      }
+      ;
     }
   }
 
 /**
- *  Group which starts with "{\*" and describes destination, currently this part
- *  is ignored.
+ * A group.
  */
-  static final public void ignoredDestination() throws ParseException {
+  final public void documentGroup() throws ParseException {
+    startGroup();
+    document();
+    endGroup();
+  }
+
+  final public void startGroup() throws ParseException {
     jj_consume_token(OPEN_BRACE);
-    jj_consume_token(IGNORED_DESTINATION);
-    ignoredBlock();
+    scopeStack.push(ucValue);
+    handler.startGroup();
+  }
+
+  final public void endGroup() throws ParseException {
     jj_consume_token(CLOSE_BRACE);
+    ucValue = (Integer) scopeStack.pop();
+    handler.endGroup();
+  }
+
+  final public void header() throws ParseException {
+    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+    case ANSI:
+    case MAC:
+    case PC:
+    case PCA:
+    case ANSICPG:
+      characterSet();
+      break;
+    default:
+      jj_la1[12] = jj_gen;
+      if (jj_2_4(2147483647)) {
+        fonttbl();
+      } else if (jj_2_5(2147483647)) {
+        colortbl();
+      } else if (jj_2_6(2147483647)) {
+        stylesheet();
+      } else {
+        jj_consume_token(-1);
+        throw new ParseException();
+      }
+    }
+  }
+
+  final public void characterSet() throws ParseException {
+  int param;
+    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+    case ANSI:
+      jj_consume_token(ANSI);
+              encoding = "Cp1252";
+      break;
+    case MAC:
+      jj_consume_token(MAC);
+              encoding = "MacRoman";
+      break;
+    case PC:
+      jj_consume_token(PC);
+              encoding = "Cp437";
+      break;
+    case PCA:
+      jj_consume_token(PCA);
+              encoding = "Cp850";
+      break;
+    case ANSICPG:
+      jj_consume_token(ANSICPG);
+      param = parameter();
+    encoding = RTFEncodings.getEncoding(param);
+      break;
+    default:
+      jj_la1[13] = jj_gen;
+      jj_consume_token(-1);
+      throw new ParseException();
+    }
   }
 
 /**
  * Part which describes font table group.
  */
-  static final public void fonttbl() throws ParseException {
+  final public void fonttbl() throws ParseException {
     jj_consume_token(OPEN_BRACE);
     jj_consume_token(FONTTBL);
     ignoredBlock();
@@ -228,9 +398,19 @@
   }
 
 /**
+ * Part which describes color table group.
+ */
+  final public void colortbl() throws ParseException {
+    jj_consume_token(OPEN_BRACE);
+    jj_consume_token(COLORTBL);
+    ignoredBlock();
+    jj_consume_token(CLOSE_BRACE);
+  }
+
+/**
  * Part which describes the style sheet group.
  */
-  static final public void stylesheet() throws ParseException {
+  final public void stylesheet() throws ParseException {
     jj_consume_token(OPEN_BRACE);
     jj_consume_token(STYLESHEET);
     ignoredBlock();
@@ -240,18 +420,32 @@
 /**
  * Part which describes the information group inside document area.
  */
-  static final public void info() throws ParseException {
+  final public void info() throws ParseException {
     jj_consume_token(OPEN_BRACE);
     jj_consume_token(INFO);
     ignoredBlock();
     jj_consume_token(CLOSE_BRACE);
   }
 
-  static final public void paragraph() throws ParseException {
-    characterFormat();
+  final public void paragraph() throws ParseException {
+    switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+    case B:
+    case I:
+    case UL:
+      characterFormat();
+      break;
+    case PAR:
+      jj_consume_token(PAR);
+          handler.newParagraph();
+      break;
+    default:
+      jj_la1[14] = jj_gen;
+      jj_consume_token(-1);
+      throw new ParseException();
+    }
   }
 
-  static final public void characterFormat() throws ParseException {
+  final public void characterFormat() throws ParseException {
   int param;
     switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
     case B:
@@ -270,172 +464,343 @@
                              handler.setUnderline(param != 0);
       break;
     default:
-      jj_la1[8] = jj_gen;
+      jj_la1[15] = jj_gen;
       jj_consume_token(-1);
       throw new ParseException();
     }
   }
 
-  static final private boolean jj_2_1(int xla) {
+  private void ignoredBlock() throws ParseException {
+  Token token;
+  int nesting = 1;
+  while (true) {
+    token = getToken(1);
+    if (token.kind == OPEN_BRACE)
+      nesting++;
+    else if (token.kind == CLOSE_BRACE) {
+      nesting--;
+      if (nesting == 0)
+        return;
+    }
+    getNextToken();
+  }
+  }
+
+  private boolean handleUnexpectedControlWord() throws ParseException {
+  Token token = getToken(1);
+
+  if (token.kind == UC) {
+    getNextToken();
+    token = getToken(1);
+    if (token.kind == PARAM) {
+      ucValue = Integer.parseInt(token.image);
+      getNextToken();
+    }
+    return true;
+  }
+
+  String text = token.image;
+  if (text.matches("\\\\[a-zA-Z]+")) {
+    getNextToken();
+    token = getToken(1);
+    if (token.kind == PARAM)
+      getNextToken();
+    return true;
+  }
+
+  return false;
+  }
+
+  private void skipAfterUnicode(int n) throws ParseException {
+  while (n-- > 0) {
+    Token token = getToken(1);
+    // If token is a control word or a control symbol
+    if (token.image.startsWith("\\")) {
+      getNextToken();
+      token = getToken(1);
+      // If control word has parameter
+      if (token.kind == PARAM)
+        getNextToken();
+      //TODO: Need to skip \bin data
+    }
+    else if (token.kind == HEX_CHAR)
+      getNextToken();
+    else if (token.kind == TEXT) {
+      String text = token.image;
+      if (text.length() <= n + 1) {
+        n -= text.length() - 1;
+        getNextToken();
+      }
+      else {
+        token.image = text.substring(n + 1);
+        return;
+      }
+    }
+    else throw new ParseException("Wrong token " + token + " while skipping data after Unicode character");
+  }
+  }
+
+  final private boolean jj_2_1(int xla) {
     jj_la = xla; jj_lastpos = jj_scanpos = token;
     try { return !jj_3_1(); }
     catch(LookaheadSuccess ls) { return true; }
     finally { jj_save(0, xla); }
   }
 
-  static final private boolean jj_2_2(int xla) {
+  final private boolean jj_2_2(int xla) {
     jj_la = xla; jj_lastpos = jj_scanpos = token;
     try { return !jj_3_2(); }
     catch(LookaheadSuccess ls) { return true; }
     finally { jj_save(1, xla); }
   }
 
-  static final private boolean jj_2_3(int xla) {
+  final private boolean jj_2_3(int xla) {
     jj_la = xla; jj_lastpos = jj_scanpos = token;
     try { return !jj_3_3(); }
     catch(LookaheadSuccess ls) { return true; }
     finally { jj_save(2, xla); }
   }
 
-  static final private boolean jj_2_4(int xla) {
+  final private boolean jj_2_4(int xla) {
     jj_la = xla; jj_lastpos = jj_scanpos = token;
     try { return !jj_3_4(); }
     catch(LookaheadSuccess ls) { return true; }
     finally { jj_save(3, xla); }
   }
 
-  static final private boolean jj_2_5(int xla) {
+  final private boolean jj_2_5(int xla) {
     jj_la = xla; jj_lastpos = jj_scanpos = token;
     try { return !jj_3_5(); }
     catch(LookaheadSuccess ls) { return true; }
     finally { jj_save(4, xla); }
   }
 
-  static final private boolean jj_3_3() {
+  final private boolean jj_2_6(int xla) {
+    jj_la = xla; jj_lastpos = jj_scanpos = token;
+    try { return !jj_3_6(); }
+    catch(LookaheadSuccess ls) { return true; }
+    finally { jj_save(5, xla); }
+  }
+
+  final private boolean jj_3R_18() {
+    if (jj_scan_token(ANSICPG)) return true;
+    if (jj_3R_19()) return true;
+    return false;
+  }
+
+  final private boolean jj_3R_17() {
+    if (jj_scan_token(PCA)) return true;
+    return false;
+  }
+
+  final private boolean jj_3_3() {
+    if (jj_scan_token(OPEN_BRACE)) return true;
+    if (jj_scan_token(IGNORED_DESTINATION)) return true;
+    return false;
+  }
+
+  final private boolean jj_3R_16() {
+    if (jj_scan_token(PC)) return true;
+    return false;
+  }
+
+  final private boolean jj_3_2() {
     if (jj_scan_token(OPEN_BRACE)) return true;
     if (jj_scan_token(INFO)) return true;
     return false;
   }
 
-  static final private boolean jj_3_2() {
+  final private boolean jj_3_6() {
     if (jj_scan_token(OPEN_BRACE)) return true;
     if (jj_scan_token(STYLESHEET)) return true;
     return false;
   }
 
-  static final private boolean jj_3_5() {
+  final private boolean jj_3R_15() {
+    if (jj_scan_token(MAC)) return true;
+    return false;
+  }
+
+  final private boolean jj_3R_10() {
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_3R_14()) {
+    jj_scanpos = xsp;
+    if (jj_3R_15()) {
+    jj_scanpos = xsp;
+    if (jj_3R_16()) {
+    jj_scanpos = xsp;
+    if (jj_3R_17()) {
+    jj_scanpos = xsp;
+    if (jj_3R_18()) return true;
+    }
+    }
+    }
+    }
+    return false;
+  }
+
+  final private boolean jj_3R_14() {
+    if (jj_scan_token(ANSI)) return true;
+    return false;
+  }
+
+  final private boolean jj_3_5() {
     if (jj_scan_token(OPEN_BRACE)) return true;
-    if (jj_scan_token(IGNORED_DESTINATION)) return true;
+    if (jj_scan_token(COLORTBL)) return true;
     return false;
   }
 
-  static final private boolean jj_3_1() {
+  final private boolean jj_3_4() {
     if (jj_scan_token(OPEN_BRACE)) return true;
     if (jj_scan_token(FONTTBL)) return true;
     return false;
   }
 
-  static final private boolean jj_3_4() {
+  final private boolean jj_3R_9() {
+    if (jj_3R_13()) return true;
+    return false;
+  }
+
+  final private boolean jj_3R_19() {
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_scan_token(38)) jj_scanpos = xsp;
+    return false;
+  }
+
+  final private boolean jj_3R_8() {
+    if (jj_3R_12()) return true;
+    return false;
+  }
+
+  final private boolean jj_3_1() {
+    if (jj_3R_5()) return true;
+    return false;
+  }
+
+  final private boolean jj_3R_7() {
+    if (jj_3R_11()) return true;
+    return false;
+  }
+
+  final private boolean jj_3R_13() {
     if (jj_scan_token(OPEN_BRACE)) return true;
-    if (jj_scan_token(IGNORED_DESTINATION)) return true;
+    if (jj_scan_token(STYLESHEET)) return true;
+    return false;
+  }
+
+  final private boolean jj_3R_6() {
+    if (jj_3R_10()) return true;
+    return false;
+  }
+
+  final private boolean jj_3R_5() {
+    Token xsp;
+    xsp = jj_scanpos;
+    if (jj_3R_6()) {
+    jj_scanpos = xsp;
+    if (jj_3R_7()) {
+    jj_scanpos = xsp;
+    if (jj_3R_8()) {
+    jj_scanpos = xsp;
+    if (jj_3R_9()) return true;
+    }
+    }
+    }
     return false;
   }
 
-  static private boolean jj_initialized_once = false;
-  static public RTFParserTokenManager token_source;
-  static SimpleCharStream jj_input_stream;
-  static public Token token, jj_nt;
-  static private int jj_ntk;
-  static private Token jj_scanpos, jj_lastpos;
-  static private int jj_la;
-  static public boolean lookingAhead = false;
-  static private boolean jj_semLA;
-  static private int jj_gen;
-  static final private int[] jj_la1 = new int[9];
+  final private boolean jj_3R_12() {
+    if (jj_scan_token(OPEN_BRACE)) return true;
+    if (jj_scan_token(COLORTBL)) return true;
+    return false;
+  }
+
+  final private boolean jj_3R_11() {
+    if (jj_scan_token(OPEN_BRACE)) return true;
+    if (jj_scan_token(FONTTBL)) return true;
+    return false;
+  }
+
+  public RTFParserTokenManager token_source;
+  SimpleCharStream jj_input_stream;
+  public Token token, jj_nt;
+  private int jj_ntk;
+  private Token jj_scanpos, jj_lastpos;
+  private int jj_la;
+  public boolean lookingAhead = false;
+  private boolean jj_semLA;
+  private int jj_gen;
+  final private int[] jj_la1 = new int[16];
   static private int[] jj_la1_0;
+  static private int[] jj_la1_1;
   static {
       jj_la1_0();
+      jj_la1_1();
    }
    private static void jj_la1_0() {
-      jj_la1_0 = new int[] {0x400000,0x400000,0x400000,0x70000,0x3000a0,0x3700a0,0x3700a0,0x3700a0,0x70000,};
+      jj_la1_0 = new int[] {0x0,0x0,0x4400,0x4400,0x40000e0,0x40044e0,0x40044e0,0xe0,0x4000000,0x0,0x0,0x40055e0,0x1f00000,0x1f00000,0x0,0x0,};
    }
-  static final private JJCalls[] jj_2_rtns = new JJCalls[5];
-  static private boolean jj_rescan = false;
-  static private int jj_gc = 0;
+   private static void jj_la1_1() {
+      jj_la1_1 = new int[] {0x40,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40,0x1e,0x20,0x0,0x0,0x1e,0xe,};
+   }
+  final private JJCalls[] jj_2_rtns = new JJCalls[6];
+  private boolean jj_rescan = false;
+  private int jj_gc = 0;
 
   public RTFParser(java.io.InputStream stream) {
      this(stream, null);
   }
   public RTFParser(java.io.InputStream stream, String encoding) {
-    if (jj_initialized_once) {
-      System.out.println("ERROR: Second call to constructor of static parser.  You must");
-      System.out.println("       either use ReInit() or set the JavaCC option STATIC to false");
-      System.out.println("       during parser generation.");
-      throw new Error();
-    }
-    jj_initialized_once = true;
     try { jj_input_stream = new SimpleCharStream(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
     token_source = new RTFParserTokenManager(jj_input_stream);
     token = new Token();
     jj_ntk = -1;
     jj_gen = 0;
-    for (int i = 0; i < 9; i++) jj_la1[i] = -1;
+    for (int i = 0; i < 16; i++) jj_la1[i] = -1;
     for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
   }
 
-  static public void ReInit(java.io.InputStream stream) {
+  public void ReInit(java.io.InputStream stream) {
      ReInit(stream, null);
   }
-  static public void ReInit(java.io.InputStream stream, String encoding) {
+  public void ReInit(java.io.InputStream stream, String encoding) {
     try { jj_input_stream.ReInit(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
     token_source.ReInit(jj_input_stream);
     token = new Token();
     jj_ntk = -1;
     jj_gen = 0;
-    for (int i = 0; i < 9; i++) jj_la1[i] = -1;
+    for (int i = 0; i < 16; i++) jj_la1[i] = -1;
     for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
   }
 
   public RTFParser(java.io.Reader stream) {
-    if (jj_initialized_once) {
-      System.out.println("ERROR: Second call to constructor of static parser.  You must");
-      System.out.println("       either use ReInit() or set the JavaCC option STATIC to false");
-      System.out.println("       during parser generation.");
-      throw new Error();
-    }
-    jj_initialized_once = true;
     jj_input_stream = new SimpleCharStream(stream, 1, 1);
     token_source = new RTFParserTokenManager(jj_input_stream);
     token = new Token();
     jj_ntk = -1;
     jj_gen = 0;
-    for (int i = 0; i < 9; i++) jj_la1[i] = -1;
+    for (int i = 0; i < 16; i++) jj_la1[i] = -1;
     for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
   }
 
-  static public void ReInit(java.io.Reader stream) {
+  public void ReInit(java.io.Reader stream) {
     jj_input_stream.ReInit(stream, 1, 1);
     token_source.ReInit(jj_input_stream);
     token = new Token();
     jj_ntk = -1;
     jj_gen = 0;
-    for (int i = 0; i < 9; i++) jj_la1[i] = -1;
+    for (int i = 0; i < 16; i++) jj_la1[i] = -1;
     for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
   }
 
   public RTFParser(RTFParserTokenManager tm) {
-    if (jj_initialized_once) {
-      System.out.println("ERROR: Second call to constructor of static parser.  You must");
-      System.out.println("       either use ReInit() or set the JavaCC option STATIC to false");
-      System.out.println("       during parser generation.");
-      throw new Error();
-    }
-    jj_initialized_once = true;
     token_source = tm;
     token = new Token();
     jj_ntk = -1;
     jj_gen = 0;
-    for (int i = 0; i < 9; i++) jj_la1[i] = -1;
+    for (int i = 0; i < 16; i++) jj_la1[i] = -1;
     for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
   }
 
@@ -444,11 +809,11 @@
     token = new Token();
     jj_ntk = -1;
     jj_gen = 0;
-    for (int i = 0; i < 9; i++) jj_la1[i] = -1;
+    for (int i = 0; i < 16; i++) jj_la1[i] = -1;
     for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
   }
 
-  static final private Token jj_consume_token(int kind) throws ParseException {
+  final private Token jj_consume_token(int kind) throws ParseException {
     Token oldToken;
     if ((oldToken = token).next != null) token = token.next;
     else token = token.next = token_source.getNextToken();
@@ -473,8 +838,8 @@
   }
 
   static private final class LookaheadSuccess extends java.lang.Error { }
-  static final private LookaheadSuccess jj_ls = new LookaheadSuccess();
-  static final private boolean jj_scan_token(int kind) {
+  final private LookaheadSuccess jj_ls = new LookaheadSuccess();
+  final private boolean jj_scan_token(int kind) {
     if (jj_scanpos == jj_lastpos) {
       jj_la--;
       if (jj_scanpos.next == null) {
@@ -495,7 +860,7 @@
     return false;
   }
 
-  static final public Token getNextToken() {
+  final public Token getNextToken() {
     if (token.next != null) token = token.next;
     else token = token.next = token_source.getNextToken();
     jj_ntk = -1;
@@ -503,7 +868,7 @@
     return token;
   }
 
-  static final public Token getToken(int index) {
+  final public Token getToken(int index) {
     Token t = lookingAhead ? jj_scanpos : token;
     for (int i = 0; i < index; i++) {
       if (t.next != null) t = t.next;
@@ -512,20 +877,20 @@
     return t;
   }
 
-  static final private int jj_ntk() {
+  final private int jj_ntk() {
     if ((jj_nt=token.next) == null)
       return (jj_ntk = (token.next=token_source.getNextToken()).kind);
     else
       return (jj_ntk = jj_nt.kind);
   }
 
-  static private java.util.Vector jj_expentries = new java.util.Vector();
-  static private int[] jj_expentry;
-  static private int jj_kind = -1;
-  static private int[] jj_lasttokens = new int[100];
-  static private int jj_endpos;
+  private java.util.Vector jj_expentries = new java.util.Vector();
+  private int[] jj_expentry;
+  private int jj_kind = -1;
+  private int[] jj_lasttokens = new int[100];
+  private int jj_endpos;
 
-  static private void jj_add_error_token(int kind, int pos) {
+  private void jj_add_error_token(int kind, int pos) {
     if (pos >= 100) return;
     if (pos == jj_endpos + 1) {
       jj_lasttokens[jj_endpos++] = kind;
@@ -553,26 +918,29 @@
     }
   }
 
-  static public ParseException generateParseException() {
+  public ParseException generateParseException() {
     jj_expentries.removeAllElements();
-    boolean[] la1tokens = new boolean[24];
-    for (int i = 0; i < 24; i++) {
+    boolean[] la1tokens = new boolean[40];
+    for (int i = 0; i < 40; i++) {
       la1tokens[i] = false;
     }
     if (jj_kind >= 0) {
       la1tokens[jj_kind] = true;
       jj_kind = -1;
     }
-    for (int i = 0; i < 9; i++) {
+    for (int i = 0; i < 16; i++) {
       if (jj_la1[i] == jj_gen) {
         for (int j = 0; j < 32; j++) {
           if ((jj_la1_0[i] & (1<<j)) != 0) {
             la1tokens[j] = true;
           }
+          if ((jj_la1_1[i] & (1<<j)) != 0) {
+            la1tokens[32+j] = true;
+          }
         }
       }
     }
-    for (int i = 0; i < 24; i++) {
+    for (int i = 0; i < 40; i++) {
       if (la1tokens[i]) {
         jj_expentry = new int[1];
         jj_expentry[0] = i;
@@ -589,15 +957,15 @@
     return new ParseException(token, exptokseq, tokenImage);
   }
 
-  static final public void enable_tracing() {
+  final public void enable_tracing() {
   }
 
-  static final public void disable_tracing() {
+  final public void disable_tracing() {
   }
 
-  static final private void jj_rescan_token() {
+  final private void jj_rescan_token() {
     jj_rescan = true;
-    for (int i = 0; i < 5; i++) {
+    for (int i = 0; i < 6; i++) {
     try {
       JJCalls p = jj_2_rtns[i];
       do {
@@ -609,6 +977,7 @@
             case 2: jj_3_3(); break;
             case 3: jj_3_4(); break;
             case 4: jj_3_5(); break;
+            case 5: jj_3_6(); break;
           }
         }
         p = p.next;
@@ -618,7 +987,7 @@
     jj_rescan = false;
   }
 
-  static final private void jj_save(int index, int xla) {
+  final private void jj_save(int index, int xla) {
     JJCalls p = jj_2_rtns[index];
     while (p.gen > jj_gen) {
       if (p.next == null) { p = p.next = new JJCalls(); break; }

Modified: harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/org/apache/harmony/x/swing/text/rtf/RTFParser.jj
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/org/apache/harmony/x/swing/text/rtf/RTFParser.jj?rev=678130&r1=678129&r2=678130&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/org/apache/harmony/x/swing/text/rtf/RTFParser.jj (original)
+++ harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/org/apache/harmony/x/swing/text/rtf/RTFParser.jj Sat Jul 19 03:53:50 2008
@@ -1,35 +1,45 @@
 /*
-  Licensed to the Apache Software Foundation (ASF) under one or more
-  contributor license agreements.  See the NOTICE file distributed with
-  this work for additional information regarding copyright ownership.
-  The ASF licenses this file to You under the Apache License, Version 2.0
-  (the "License"); you may not use this file except in compliance with
-  the License.  You may obtain a copy of the License at
-
-     http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-*/
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
 
-//options {
+options {
 //  DEBUG_PARSER = true;
-//  DEBUG_TOKEN_MANAGER=true;
-//}
+//  DEBUG_TOKEN_MANAGER = true;
+  STATIC = false;
+}
 
 PARSER_BEGIN(RTFParser)
 package org.apache.harmony.x.swing.text.rtf;
 
 import java.io.*;
-import javax.swing.text.Document;
+import java.util.Stack;
 import javax.swing.text.DefaultStyledDocument;
 
 public class RTFParser {
 
-  private static RTFParserHandler handler; 
+  private RTFHandler handler;
+
+  private String encoding = RTFEncodings.DEFAULT_ENCODING;
+
+  private int ucValue = 1;
+  /**
+   * This stack contains only UC values as a scope parameter.
+   * It could be modified to contain additional parameters.
+   */
+  private Stack scopeStack = new Stack();
 
   public static void main(String args[]) throws Exception {
     InputStream in;
@@ -38,48 +48,49 @@
       in = new FileInputStream(args[0]);
     else
       in = System.in;
-      
+
     RTFParser parser = new RTFParser(in);
-    parser.parse(new DefaultStyledDocument(), 0);
+    RTFHandler handler = new DocumentRTFHandler(new DefaultStyledDocument(), 0);
+    parser.parse(handler);
   }
-  
+
+  private byte[] getBytes(String str) {
+    char[] chars = str.toCharArray();
+    byte[] bytes = new byte[chars.length];
+    for (int i = 0; i < chars.length; i++)
+      bytes[i] = (byte) chars[i];
+    return bytes;
+  }
+
 }
 
 PARSER_END(RTFParser)
 
-/*<*> MORE :
+<DEFAULT>
+SKIP :
 {
-  "\\" : InControlWord
+  "\n"
+| "\r"
+| "\t"
 }
 
-<InControlWord> TOKEN :
-{
-  <RTF: "rtf"<PARAM>> {System.out.println("rtf");} : DEFAULT
-}
-  (
-    documentBlock()
-<InControlWord> TOKEN :
+<*>
+TOKEN:
 {
-  {System.out.println("param");} <PARAM: "123"> 
+  <IGNORED_DESTINATION: "\\*"> : DEFAULT
+| <ESCAPED_OPEN_BRACE: "\\{"> : DEFAULT
+| <ESCAPED_CLOSE_BRACE: "\\}"> : DEFAULT
+| <ESCAPED_BACKSLASH: "\\\\"> : DEFAULT
+| <CONTROL_SYMBOL: "\\" ~["a"-"z", "A"-"Z", "0"-"9", " ", "\t",
+                          "{", "}", "\n", "\r"]> : DEFAULT
+|  <#HEX_DIGIT: ["0"-"9","a"-"f","A"-"F"]>
+| <HEX_CHAR: "\\'" <HEX_DIGIT> <HEX_DIGIT>> : DEFAULT
 }
 
-<InControlWord> MORE:
-{
- <~[]> : DEFAULT
-}*/
-
 <*>
 MORE:
 {
-  <BACKSLASH: "\\"> : IN_CONTROL
-}
-
-<DEFAULT>
-SKIP :
-{
-  "\n"
-| "\r"
-| "\t"
+  <BACKSLASH: "\\"> : IN_CONTROL_WORD
 }
 
 <*>
@@ -92,10 +103,10 @@
 <DEFAULT>
 TOKEN:
 {
- <TEXT: (~["\\","{","}","\n","\r", "\t"])+>
+  <TEXT: (~["\\", "{", "}", "\n", "\r", "\t"])+>
 }
 
-<IN_CONTROL>
+<IN_CONTROL_WORD>
 SKIP:
 {
   " " : DEFAULT
@@ -104,54 +115,47 @@
 | "\t" : DEFAULT
 }
 
-<IN_CONTROL>
+<IN_CONTROL_WORD>
 TOKEN:
 {
   <RTF: "rtf">
+| <ANSI: "ansi">
+| <MAC: "mac">
+| <PC: "pc">
+| <PCA: "pca">
+| <ANSICPG: "ansicpg">
+| <UC: "uc">
+| <U: "u">
+| <UPR: "upr">
+| <UD: "ud">
 | <FONTTBL: "fonttbl">
+| <COLORTBL: "colortbl">
 | <STYLESHEET: "stylesheet">
-| <INFO: "info"> 
+| <INFO: "info">
 | <B: "b">
 | <I: "i">
 | <UL: "ul">
 //|  <SECT: "sect">
 //|  <SUBDOCUMENT: "subdocument">
-//|  <PAR: "par">
-}
+| <PAR: "par">
 
-<IN_CONTROL>
-TOKEN:
-{
-  <IGNORED_DESTINATION: "*">
+| <CONTROL_WORD: (["a"-"z", "A"-"Z"])+>
+| <PARAM: (["-"])? (["0"-"9"])+ (" ")?> : DEFAULT
 }
 
-<IN_CONTROL>
-TOKEN:
-{
-  <CONTROL_WORD: (["a"-"z", "A"-"Z"])+>
-| <CONTROL_SYMBOL: ~["a"-"z", "A"-"Z", "0"-"9", " ", "\t",
-                   "{", "}", "\n", "\r", "\\"]>
-}
-
-<IN_CONTROL>
-TOKEN:
-{
-  <PARAM: (["-"])? (["0"-"9"])+>
-}
-
-<IN_CONTROL>
+<IN_CONTROL_WORD>
 SKIP:
 {
  <~[]> : DEFAULT
 }
 
-
-
-public void parse(Document doc, int position) :
+public void parse(RTFHandler handler) :
 {}
 {
   {
-    handler = new RTFParserHandler(doc, position);
+    if (handler == null)
+      throw new NullPointerException("Parameter handler cannot be null");
+    this.handler = handler;
   }
   file() <EOF>
 }
@@ -161,14 +165,14 @@
   Token param = null;
 }
 {
-  [param=<PARAM>] 
+  [param=<PARAM>]
   {
-    return param == null ? -1 : Integer.parseInt(param.image);
+    return param == null ? -1 : Integer.parseInt(param.image.trim());
   }
 }
 
 /**
- *  Catches all unhandled control words.
+ * Catches all unhandled control words.
  */
 private void unknownControlWord() :
 {}
@@ -177,94 +181,197 @@
 }
 
 /**
- *  Catches all unhandled control symbols.
+ * Catches all unhandled control symbols.
  */
-void unknownControlSymbol() : 
+void unknownControlSymbol() :
 {}
 {
   <CONTROL_SYMBOL>
 }
 
-void text() :
+/**
+ * Group which starts with "{\*" and describes destination, currently this part
+ * is ignored.
+ */
+void ignoredDestination() :
+{}
+{
+  <OPEN_BRACE> <IGNORED_DESTINATION> ignoredBlock() <CLOSE_BRACE>
+}
+
+String parseText() :
 {
-  Token text;
+  byte[] bytes;
+  String text;
+  ByteArrayOutputStream textBytes = new ByteArrayOutputStream();
+  StringBuffer parsedText = new StringBuffer();
 }
 {
-  text=<TEXT> 
-  { 
-    handler.addText(text.image); 
+  (
+    (
+      // Here we collecting all the characters which should be decoded
+      // using specified encoding
+      (
+        bytes = parseHexBytes()
+      | bytes = parseTextBytes()
+      ) {
+          try {
+            textBytes.write(bytes);
+          } catch (IOException e) {}
+        }
+    )+
+    {
+      // Decoding collected characters using specified encoding
+      try {
+        parsedText.append(textBytes.toString(encoding));
+        textBytes.reset();
+      }
+      catch (UnsupportedEncodingException e) {
+        throw new ParseException("Unsupported encoding");
+      }
+    }
+  // Appending characters which don't require decoding to parsed text
+  | (
+      text = parseSpecialCharacter()
+    | text = parseUnicodeText()
+    ) { parsedText.append(text); }
+  )+
+  { return parsedText.toString(); }
+}
+
+byte[] parseHexBytes() :
+{
+  Token token;
+  byte[] result = new byte[1];
+}
+{
+  token = <HEX_CHAR>
+  {
+    result[0] = (byte) Integer.parseInt(token.image.substring(2), 16);
+    return result;
   }
 }
 
-void file() :
+byte[] parseTextBytes() :
+{
+  Token token;
+}
+{
+  token = <TEXT>
+  {
+    return getBytes(token.image);
+  }
+}
+
+String parseSpecialCharacter() :
 {}
 {
-  <OPEN_BRACE> header() document() <CLOSE_BRACE>
+  <ESCAPED_OPEN_BRACE>  { return "{"; }
+| <ESCAPED_CLOSE_BRACE> { return "}"; }
+| <ESCAPED_BACKSLASH>   { return "\\"; }
 }
 
-void header() :
+String parseUnicodeText() :
+{
+  int param;
+  StringBuffer unicodeBuffer = new StringBuffer();
+}
+{
+  (
+    <U> param = parameter()
+    {
+      if (param < 0)
+        param += 65536;
+
+      unicodeBuffer.append((char) param);
+    }
+    skipAfterUnicode(ucValue)
+  )+
+  { return unicodeBuffer.toString(); }
+}
+
+void file() :
 {}
 {
-  <RTF>[<PARAM>]
+  <OPEN_BRACE> <RTF>[<PARAM>] document() <CLOSE_BRACE>
 }
 
 void document() :
-{}
+{
+  boolean skipped;
+  String text;
+}
 {
   (
-    paragraph()
-  | LOOKAHEAD(<OPEN_BRACE> <FONTTBL>)
-    fonttbl()
-  | LOOKAHEAD(<OPEN_BRACE> <STYLESHEET>)
-    stylesheet()
+    LOOKAHEAD(2)
+    header()
+  | paragraph()
   | LOOKAHEAD(<OPEN_BRACE> <INFO>)
     info()
   | LOOKAHEAD(<OPEN_BRACE> <IGNORED_DESTINATION>)
-    ignoredDestination()   
-  | documentBlock() 
-  | unknownControlWord() 
-  | unknownControlSymbol() 
-  | text() 
+    ignoredDestination()
+  | documentGroup()
+  | unknownControlWord()
+  | unknownControlSymbol()
+  | text = parseText() { handler.addText(text); }
+  | skipped = handleUnexpectedControlWord() { if (!skipped) return; }
   )+
 }
 
 /**
- *  A group.
+ * A group.
  */
-void documentBlock() :
+void documentGroup() :
 {}
 {
-  <OPEN_BRACE> { handler.startGroup(); }
-  document() 
-  <CLOSE_BRACE> { handler.endGroup(); }
+  startGroup() document() endGroup()
 }
 
-/**
- *  Ignored block of RTF file, currently is using to ignore unknown parts
- *  of file.
- */
-void ignoredBlock() :
+void startGroup() :
 {}
 {
-  (
-    LOOKAHEAD(<OPEN_BRACE> <IGNORED_DESTINATION>)
-    ignoredDestination()
-  | characterFormat() //TODO: Need to find a way to ignore control words declared as TOKENS  
-  | unknownControlWord() 
-  | unknownControlSymbol()
-  | <TEXT>
-  | <OPEN_BRACE> ignoredBlock() <CLOSE_BRACE>
-  )+
+  <OPEN_BRACE>
+  {
+    scopeStack.push(ucValue);
+    handler.startGroup();
+  }
 }
 
-/**
- *  Group which starts with "{\*" and describes destination, currently this part
- *  is ignored.
- */
-void ignoredDestination() :
+void endGroup() :
 {}
 {
-  <OPEN_BRACE> <IGNORED_DESTINATION> ignoredBlock() <CLOSE_BRACE>
+  <CLOSE_BRACE>
+  {
+    ucValue = (Integer) scopeStack.pop();
+    handler.endGroup();
+  }
+}
+
+void header() :
+{}
+{
+  characterSet()
+| LOOKAHEAD(<OPEN_BRACE> <FONTTBL>)
+  fonttbl()
+| LOOKAHEAD(<OPEN_BRACE> <COLORTBL>)
+  colortbl()
+| LOOKAHEAD(<OPEN_BRACE> <STYLESHEET>)
+  stylesheet()
+}
+
+void characterSet() :
+{
+  int param;
+}
+{
+  <ANSI>    { encoding = "Cp1252"; }
+| <MAC>     { encoding = "MacRoman"; }
+| <PC>      { encoding = "Cp437"; }
+| <PCA>     { encoding = "Cp850"; }
+| <ANSICPG> param = parameter()
+  {
+    encoding = RTFEncodings.getEncoding(param);
+  }
 }
 
 /**
@@ -277,6 +384,15 @@
 }
 
 /**
+ * Part which describes color table group.
+ */
+void colortbl() :
+{}
+{
+  <OPEN_BRACE> <COLORTBL> ignoredBlock() <CLOSE_BRACE>
+}
+
+/**
  * Part which describes the style sheet group.
  */
 void stylesheet() :
@@ -298,10 +414,11 @@
 {}
 {
   characterFormat()
+| <PAR> { handler.newParagraph(); }
 }
 
 void characterFormat() :
-{ 
+{
   int param;
 }
 {
@@ -309,3 +426,90 @@
 | <I> param = parameter() { handler.setItalic(param != 0); }
 | <UL> param = parameter() { handler.setUnderline(param != 0); }
 }
+
+JAVACODE
+/**
+ * Ignoring a block of RTF file enclosed in braces, it is using
+ * to ignore unknown or unnecessary parts of file.
+ */
+private void ignoredBlock() {
+  Token token;
+  int nesting = 1;
+  while (true) {
+    token = getToken(1);
+    if (token.kind == OPEN_BRACE)
+      nesting++;
+    else if (token.kind == CLOSE_BRACE) {
+      nesting--;
+      if (nesting == 0)
+        return;
+    }
+    getNextToken();
+  }
+}
+
+JAVACODE
+/**
+ * This function skips an unexpected control word defined as token
+ * and handle control words which could appear anywhere in a file.
+ *
+ * @return true if control was skipped or handled
+ */
+private boolean handleUnexpectedControlWord() {
+  Token token = getToken(1);
+
+  if (token.kind == UC) {
+    getNextToken();
+    token = getToken(1);
+    if (token.kind == PARAM) {
+      ucValue = Integer.parseInt(token.image);
+      getNextToken();
+    }
+    return true;
+  }
+
+  String text = token.image;
+  if (text.matches("\\\\[a-zA-Z]+")) {
+    getNextToken();
+    token = getToken(1);
+    if (token.kind == PARAM)
+      getNextToken();
+    return true;
+  }
+
+  return false;
+}
+
+JAVACODE
+/**
+ * This function skips n characters and/or control words and/or
+ * control symbols after Unicode character.
+ */
+private void skipAfterUnicode(int n) {
+  while (n-- > 0) {
+    Token token = getToken(1);
+    // If token is a control word or a control symbol
+    if (token.image.startsWith("\\")) {
+      getNextToken();
+      token = getToken(1);
+      // If control word has parameter
+      if (token.kind == PARAM)
+        getNextToken();
+      //TODO: Need to skip \bin data
+    }
+    else if (token.kind == HEX_CHAR)
+      getNextToken();
+    else if (token.kind == TEXT) {
+      String text = token.image;
+      if (text.length() <= n + 1) {
+        n -= text.length() - 1;
+        getNextToken();
+      }
+      else {
+        token.image = text.substring(n + 1);
+        return;
+      }
+    }
+    else throw new ParseException("Wrong token " + token + " while skipping data after Unicode character");
+  }
+}
\ No newline at end of file

Modified: harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/org/apache/harmony/x/swing/text/rtf/RTFParserConstants.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/org/apache/harmony/x/swing/text/rtf/RTFParserConstants.java?rev=678130&r1=678129&r2=678130&view=diff
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/org/apache/harmony/x/swing/text/rtf/RTFParserConstants.java (original)
+++ harmony/enhanced/classlib/trunk/modules/swing/src/main/java/common/org/apache/harmony/x/swing/text/rtf/RTFParserConstants.java Sat Jul 19 03:53:50 2008
@@ -4,31 +4,54 @@
 public interface RTFParserConstants {
 
   int EOF = 0;
-  int BACKSLASH = 1;
-  int OPEN_BRACE = 5;
-  int CLOSE_BRACE = 6;
-  int TEXT = 7;
-  int RTF = 12;
-  int FONTTBL = 13;
-  int STYLESHEET = 14;
-  int INFO = 15;
-  int B = 16;
-  int I = 17;
-  int UL = 18;
-  int IGNORED_DESTINATION = 19;
-  int CONTROL_WORD = 20;
-  int CONTROL_SYMBOL = 21;
-  int PARAM = 22;
+  int IGNORED_DESTINATION = 4;
+  int ESCAPED_OPEN_BRACE = 5;
+  int ESCAPED_CLOSE_BRACE = 6;
+  int ESCAPED_BACKSLASH = 7;
+  int CONTROL_SYMBOL = 8;
+  int HEX_DIGIT = 9;
+  int HEX_CHAR = 10;
+  int BACKSLASH = 11;
+  int OPEN_BRACE = 12;
+  int CLOSE_BRACE = 13;
+  int TEXT = 14;
+  int RTF = 19;
+  int ANSI = 20;
+  int MAC = 21;
+  int PC = 22;
+  int PCA = 23;
+  int ANSICPG = 24;
+  int UC = 25;
+  int U = 26;
+  int UPR = 27;
+  int UD = 28;
+  int FONTTBL = 29;
+  int COLORTBL = 30;
+  int STYLESHEET = 31;
+  int INFO = 32;
+  int B = 33;
+  int I = 34;
+  int UL = 35;
+  int PAR = 36;
+  int CONTROL_WORD = 37;
+  int PARAM = 38;
 
-  int IN_CONTROL = 0;
-  int DEFAULT = 1;
+  int DEFAULT = 0;
+  int IN_CONTROL_WORD = 1;
 
   String[] tokenImage = {
     "<EOF>",
-    "\"\\\\\"",
     "\"\\n\"",
     "\"\\r\"",
     "\"\\t\"",
+    "\"\\\\*\"",
+    "\"\\\\{\"",
+    "\"\\\\}\"",
+    "\"\\\\\\\\\"",
+    "<CONTROL_SYMBOL>",
+    "<HEX_DIGIT>",
+    "<HEX_CHAR>",
+    "\"\\\\\"",
     "\"{\"",
     "\"}\"",
     "<TEXT>",
@@ -37,17 +60,26 @@
     "\"\\r\"",
     "\"\\t\"",
     "\"rtf\"",
+    "\"ansi\"",
+    "\"mac\"",
+    "\"pc\"",
+    "\"pca\"",
+    "\"ansicpg\"",
+    "\"uc\"",
+    "\"u\"",
+    "\"upr\"",
+    "\"ud\"",
     "\"fonttbl\"",
+    "\"colortbl\"",
     "\"stylesheet\"",
     "\"info\"",
     "\"b\"",
     "\"i\"",
     "\"ul\"",
-    "\"*\"",
+    "\"par\"",
     "<CONTROL_WORD>",
-    "<CONTROL_SYMBOL>",
     "<PARAM>",
-    "<token of kind 23>",
+    "<token of kind 39>",
   };
 
 }