gt:     jj_ntk = -1;
context: /* RTFParser.java */
  /* Generated By:JavaCC: Do not edit this line. RTFParser.java */
  package com.etranslate.tm.processing.rtf;
  
  import java.io.*;
  import java.util.*;
  
  public class RTFParser implements RTFParserDelegate, RTFParserConstants {
  
    /**
     * This value will be passed to Delegate if there was no value specified with the CONTROL_WORD.
     * This is to allow Delegate to be able to differentiate between commands like \b and \b0.
     */
    public static final int VALUE_NOT_SPECIFIED = Integer.MIN_VALUE + 12;
  
    /* maps windows character sets to java encoding names */
    /* note: sparse array */
    private static final String[] CHARSET_ENCODING_TABLE = new String[257];
    static {
          CHARSET_ENCODING_TABLE[0] = "Cp1252";     // ANSI
          CHARSET_ENCODING_TABLE[1] = "Cp1252";     // Default
          CHARSET_ENCODING_TABLE[2] = "Cp1252";     // Symbol
          CHARSET_ENCODING_TABLE[3] = null;         // Invalid
          CHARSET_ENCODING_TABLE[77] = "MacRoman";  // Mac
          CHARSET_ENCODING_TABLE[128] = "MS932";    // Shift JIS
          CHARSET_ENCODING_TABLE[129] = "MS949";    // Hangul
          CHARSET_ENCODING_TABLE[130] = "Johab";    // Johab
          CHARSET_ENCODING_TABLE[134] = "MS936";    // GB2312
          CHARSET_ENCODING_TABLE[136] = "MS950";    // Big5
          CHARSET_ENCODING_TABLE[161] = "Cp1253";   // Greek
          CHARSET_ENCODING_TABLE[162] = "Cp1254";   // Turkish
          CHARSET_ENCODING_TABLE[163] = "Cp1258";   // Vietnamese
          CHARSET_ENCODING_TABLE[177] = "Cp1255";   // Hebrew
          CHARSET_ENCODING_TABLE[178] = "Cp1256";   // Arabic
          CHARSET_ENCODING_TABLE[179] = "Cp1256";   // Arabic Traditional
          CHARSET_ENCODING_TABLE[180] = "Cp1256";   // Arabic User
          CHARSET_ENCODING_TABLE[181] = "Cp1255";   // Hebrew User
          CHARSET_ENCODING_TABLE[186] = "Cp1257";   // Baltic
          CHARSET_ENCODING_TABLE[204] = "Cp1251";   // Russian
          CHARSET_ENCODING_TABLE[222] = "MS874";    // Thai
          CHARSET_ENCODING_TABLE[238] = "Cp1250";   // East European
          CHARSET_ENCODING_TABLE[254] = "Cp437";    // PC 437
          CHARSET_ENCODING_TABLE[255] = "Cp437";    // OEM, still 437
          CHARSET_ENCODING_TABLE[256] = "Cp1252";    // Custom charset?? Default to the ANSI value
    }
  
    /*
     * These next two tables map windows codepages to java encoding names.
     * The codepage ints are too large to do a sparse array, so we have
     * two parallel arrays and do a binary search to find the common offset.
     */
  
    private static final int[] RTF_CODEPAGE = {
          0,   // The default code page
  
          437, // United States IBM
  
          /*  Not supported by JDK 1.3.1
          708, // Arabic (ASMO 708) 
          709, // Arabic (ASMO 449+, BCON V4) 
          710, // Arabic (transparent Arabic) 
          711, // Arabic (Nafitha Enhanced) 
          720, // Arabic (transparent ASMO) 
          */
  
          819, // Windows 3.1 (United States and Western Europe) 
          850, // IBM multilingual 
          852, // Eastern European 
          860, // Portuguese 
          862, // Hebrew 
          863, // French Canadian 
          864, // Arabic 
          865, // Norwegian 
          866, // Soviet Union 
          874, // Thai 
          932, // Japanese 
          936, // Simplified Chinese 
          949, // Korean 
          950, // Traditional Chinese 
          1250, // Windows 3.1 (Eastern European) 
          1251, // Windows 3.1 (Cyrillic) 
          1252, // Western European 
          1253, // Greek 
          1254, // Turkish 
          1255, // Hebrew 
          1256, // Arabic 
          1257, // Baltic 
          1258, // Vietnamese 
          1361, // Johab
  
          10000, // Mac Roman
          10001, // Mac Japanese
          //10002, // Mac Traditional Chinese (x-mac-chinesetrad)
          //10003, // Mac Korean (x-mac-korean)
          10004, // Mac Arabic
          10005, // Mac Hebrew
          10006, // Mac Greek
          10007, // Mac Russian
          10021, // Mac Thai
          10081, // Mac Turkish
  
          20127, // US-ASCII (7-bit only, i.e. no values above 127)
  
          28591, // ISO 8859-1
  
          65001 // UTF-8
    };
  
    private static final String[] JAVA_ENCODINGS = {
          "Cp1252",// Default
          "Cp437", // United States IBM 
          /*  Not supported by JDK 1.3.1
          "Cp708", // Arabic (ASMO 708) 
          "Cp709", // Arabic (ASMO 449+, BCON V4) 
          "Cp710", // Arabic (transparent Arabic) 
          "Cp711", // Arabic (Nafitha Enhanced) 
          "Cp720", // Arabic (transparent ASMO) 
          */
          "Cp819", // Windows 3.1 (United States and Western Europe) 
          "Cp850", // IBM multilingual 
          "Cp852", // Eastern European 
          "Cp860", // Portuguese 
          "Cp862", // Hebrew 
          "Cp863", // French Canadian 
          "Cp864", // Arabic 
          "Cp865", // Norwegian 
          "Cp866", // Soviet Union 
          "MS874", // Thai 
          "MS932", // Japanese 
          "MS936", // Simplified Chinese 
          "MS949", // Korean 
          "MS950", // Traditional Chinese 
          "Cp1250", // Windows 3.1 (Eastern European) 
          "Cp1251", // Windows 3.1 (Cyrillic) 
          "Cp1252", // Western European 
          "Cp1253", // Greek 
          "Cp1254", // Turkish 
          "Cp1255", // Hebrew 
          "Cp1256", // Arabic 
          "Cp1257", // Baltic 
          "Cp1258", // Vietnamese 
          "Johab",  // Johab
  
          "MacRoman", // Mac Roman
          "Shift_JIS", // Best attempt for Mac Japanese (x-mac-japanese)
          "MacArabic", // Mac Arabic
          "MacHebrew", // Mac Hebrew
          "MacGreek", // Mac Greek
          "MacCyrillic", // Mac Russian??
          "MacThai", // Mac Thai
          "MacTurkish", // Mac Turkish
  
          "US-ASCII", // US-ASCII (7-bit only, i.e. no values above 127)
  
          "ISO-8859-1",
  
          "UTF-8"
    };
  
    /**
     * Searches RTF_CODEPAGE table for the offset of rtfCodepage and returns
     * the corresponding encoding name from the JAVA_ENCODINGS table, or
     * null if none is present.
     */
    private static final String getJavaEncoding(int rtfCodepage) {
      int offset = Arrays.binarySearch(RTF_CODEPAGE, rtfCodepage);
      return offset < 0 ? null : JAVA_ENCODINGS[offset];
    }
  
    /* support for skipping bytes after a unicode character.
     * TODO: handle \bin
     */
    // the default number of bytes to skip after a unicode character
    private static final Integer DEFAULT_SKIP_STATE = new Integer(1);
    // the current number of bytes to skip after a unicode character
    private Integer _currentSkipState = DEFAULT_SKIP_STATE;
    // a stack of skip states for bytes following a unicode character
    private final Stack<Integer> _ucSkipStates = new Stack<Integer>();
  
    // the default encoding for all RTF documents
    private static final String DEFAULT_ENCODING = "Cp1252";
    // the document encoding for this RTF document
    private String _documentEncoding = DEFAULT_ENCODING;
  
    /* support for parsing the \fonttbl to discover font codes and
     * their assigned encodings
     */
    // this holds the (\deffN) default font number
    private int _defaultFont = 0;
    // this holds the font table key (\fN) while we're waiting for the
    // font name (text) declaration in the font table.
    private int _currentFontValue = 0;
    // this holds the font table charset (\fcharsetN) while we're waiting for the
    // font name (text) declaration in the font table.
    private int _currentCharsetValue = 0;
    // this maps font codes (\fN) to the encodings assigned (\fcharsetN)
    // in the fonttbl
    private final Map<Integer, String> _fontEncodingMap = new HashMap<Integer, String>();
  
    /** support for encoding changes via references to the font table */
    // the current text encoding
    private String _currentEncoding = DEFAULT_ENCODING;
    // a stack of text encodings across groups
    private final Stack<String> _fontEncodingStack = new Stack<String>();
  
    private int _currentStyleValue = 0;
    private final Map<Integer, String> _styleMap = new HashMap<Integer, String>();
    private final Stack<String> _styleStack = new Stack<String>();
    private String _currentStyle = NO_STYLE;
  
    private int _where = IN_DOCUMENT;
    private int _rtfDepth = 1;
  
    private int _braceDepth = 0;
    private String _newline = "\u005cn";
  
    // The delegate to which the parser forwards productions.
    // Unless setDelegate is called, this will be the parser
    // itself, which supplies a no-op implementation (see below).
    // this enables us to avoid doing null checks in the delegate
    // calls.
  
    private RTFParserDelegate _delegate = this;
  
    public static void main(String args[]) throws ParseException {
      RTFParser parser = RTFParser.createParser(new InputStreamReader(System.in));
      parser.parse();
    }
  
    public void reinitialize(Reader reader) {
      ReInit(reader);
    }
  
    public static RTFParser createParser(Reader reader) {
      return new RTFParser(reader);
    }
  
    public void parse() throws ParseException {
      try {
        document();
      } catch (UnsupportedEncodingException uee) {
        throw new ParseException("Could not decode bytes in encoding: " +
                                 uee.getMessage(), uee);
      }
    }
  
    public void setDelegate(RTFParserDelegate delegate) {
      _delegate = delegate;
    }
  
    public String getNewLine() {
      return _newline;
    }
  
    public void setNewLine(String newline) {
      _newline = newline;
    }
  
    /**
     * Returns a numbered font which supports the encoding.
     * This data is gleaned from the RTF fonttbl, and so
     * is not available until after the fonttbl has been
     * parsed.  No guarantees are made about which font
     * will be returned if multiple fonts support the
     * encoding.
     *
     * @return a font control word value.
     */
    public int getFontForEncoding(String encoding) {
      for (Iterator i = _fontEncodingMap.entrySet().iterator(); i.hasNext();) {
          Map.Entry entry = (Map.Entry)i.next();
          if (entry.getValue().equals(encoding)) {
             return ((Integer)entry.getKey()).intValue();
          }
      }
      return -1;
    }
  
    // no-op implementation of RTFParserDelegate interface, for cases
    // when delegate is not set.
    public void text(String text, String style, int context) {}
  
    public OutputStream getNextOutputStream(int context) {return null;}
  
    public void controlSymbol(String controlSymbol, int context) {}
  
    public void controlWord(String controlWord, long value, int context) {}
  
    public void openGroup(int depth) {}
  
    public void closeGroup(int depth) {}
  
    public void styleList(List styles) {}
  
    public void startDocument() {}
  
    public void endDocument() {}
  
  
    protected String getEncodingForCharsetAndFontName(int charset, String fontName) {
      if (charset < 0) {
          // Bogus encoding passed in - default to windows-1252.
          return "Cp1252";
      }
      else if (charset >= CHARSET_ENCODING_TABLE.length) {
          String encoding = getJavaEncoding(charset);
          if (encoding == null) {
              return "Cp" + charset;
          }
          else {
              return encoding;
          }
      }
      else {
              return CHARSET_ENCODING_TABLE[charset];
          }
    }
  
    public void setCurrentEncoding(String encoding) {
      if (null == encoding) {
         throw new IllegalArgumentException("current encoding cannot be null");
      }
      _currentEncoding = encoding;
    }
  
    public String getCurrentEncoding() {
      if (_where == IN_DOCUMENT) {
        return _currentEncoding;
      } else {
        return _documentEncoding;
      }
    }
  
    private String getCurrentStyle() {
      return _currentStyle;
    }
  
    private void setCurrentStyle(String style) {
      _currentStyle = style;
    }
  
    private Integer getCurrentSkipState() {
      return _currentSkipState;
    }
  
    private void setCurrentSkipState(Integer skipState) {
      _currentSkipState = skipState;
    }
  
    private void setDocumentEncoding(String encoding) {
      if (null == encoding) {
         throw new IllegalArgumentException("document encoding cannot be null");
      }
      _documentEncoding = encoding;
    }
  
    public String getDocumentEncoding() {
      return _documentEncoding;
    }
  
    /**
     * convenience method which downcasts the chars in str to a byte
     * array without attempting to decode them.
     */
    private byte[] stringToBytes(String str) {
      char[] cbuf = str.toCharArray();
      byte[] buf = new byte[cbuf.length];
      for (int i = 0; i < cbuf.length; i++) {
        buf[i] = (byte)cbuf[i];
      }
      return buf;
    }
  
  // end of CONTROL lexical specification
  
  /**************************************/
  /* grammatical productions begin here */
  /**************************************/
  
  /**
   *  Sends the parser delegate a block of unicode text along with
   *  the name of the style in which it was found and the location
   *  in the document where it occurred.
   *  All text encoding is resolved here so the delegate doesn't need
   *  to concern itself with the various ways in which RTF encodes
   *  non-ASCII strings.
   */
    final public void text() throws ParseException, UnsupportedEncodingException {StringBuilder buf = new StringBuilder();
    StringBuilder cbuf = new StringBuilder();
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    byte b;
    byte[] raw;
      label_1:
      while (true) {
        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
        case NON_BREAKING_SPACE:
        case OPTIONAL_HYPHEN:
        case NON_BREAKING_HYPHEN:
        case ESCAPED_LBRACE:
        case ESCAPED_RBRACE:
        case ESCAPED_BACKSLASH:
        case U:
        case TAB:
        case ZWJ:
        case ZWNJ:
        case EMDASH:
        case ENDASH:
        case EMSPACE:
        case ENSPACE:
        case QMSPACE:
        case BULLET:
        case LQUOTE:
        case RQUOTE:
        case LTRMARK:
        case RTLMARK:
        case LDBLQUOTE:
        case RDBLQUOTE:{
          switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
          case U:{
            u(cbuf);
            raw = skip_after_unicode();
  if (raw != null) {
            cbuf.append(new String(raw, getCurrentEncoding()));
          }
            break;
            }
          case ESCAPED_LBRACE:
          case ESCAPED_RBRACE:
          case ESCAPED_BACKSLASH:{
            escaped(cbuf);
            break;
            }
          case TAB:
          case ZWJ:
          case ZWNJ:
          case EMDASH:
          case ENDASH:
          case EMSPACE:
          case ENSPACE:
          case QMSPACE:
          case BULLET:
          case LQUOTE:
          case RQUOTE:
          case LTRMARK:
          case RTLMARK:
          case LDBLQUOTE:
          case RDBLQUOTE:{
            special_character(cbuf);
            break;
            }
          case NON_BREAKING_SPACE:
          case OPTIONAL_HYPHEN:
          case NON_BREAKING_HYPHEN:{
            textual_control_symbol(cbuf);
            break;
            }
          default:
            jj_la1[0] = jj_gen;
            jj_consume_token(-1);
            throw new ParseException();
          }
  if (baos.size() > 0) {
          buf.append(baos.toString(getCurrentEncoding()));
          baos.reset();
        }
        buf.append(cbuf.toString());
        cbuf.setLength(0);
          break;
          }
        case HEX_CHAR:{
          b = hex();
  baos.write(b);
          break;
          }
        case TEXT:
        case TEXT_CONTROL_DELIMITER:{
          raw = raw_text();
  baos.write(raw,0,raw.length);
          break;
          }
        default:
          jj_la1[1] = jj_gen;
          jj_consume_token(-1);
          throw new ParseException();
        }
        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
        case NON_BREAKING_SPACE:
        case OPTIONAL_HYPHEN:
        case NON_BREAKING_HYPHEN:
        case ESCAPED_LBRACE:
        case ESCAPED_RBRACE:
        case ESCAPED_BACKSLASH:
        case TEXT:
        case HEX_CHAR:
        case U:
        case TAB:
        case ZWJ:
        case ZWNJ:
        case EMDASH:
        case ENDASH:
        case EMSPACE:
        case ENSPACE:
        case QMSPACE:
        case BULLET:
        case LQUOTE:
        case RQUOTE:
        case LTRMARK:
        case RTLMARK:
        case LDBLQUOTE:
        case RDBLQUOTE:
        case TEXT_CONTROL_DELIMITER:{
          ;
          break;
          }
        default:
          jj_la1[2] = jj_gen;
          break label_1;
        }
      }
  if (baos.size() > 0) {
        buf.append(baos.toString(getCurrentEncoding()));
        baos.reset();
      }
      if (_where == IN_STYLESHEET) {
        _styleMap.put(new Integer(_currentStyleValue), buf.toString());
      } else if (_where == IN_FONTTBL) {
        String encoding = getEncodingForCharsetAndFontName(_currentCharsetValue, buf.toString());
        _fontEncodingMap.put(new Integer(_currentFontValue), encoding);
      }
      _delegate.text(buf.toString(), getCurrentStyle(), _where);
    }
  
    final public byte[] raw_text() throws ParseException, UnsupportedEncodingException {Token tok;
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case TEXT:{
        tok = jj_consume_token(TEXT);
        break;
        }
      case TEXT_CONTROL_DELIMITER:{
        tok = jj_consume_token(TEXT_CONTROL_DELIMITER);
        break;
        }
      default:
        jj_la1[3] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
  {if ("" != null) return stringToBytes(tok.image);}
      throw new Error("Missing return statement in function");
    }
  
    final public void escaped(StringBuilder buf) throws ParseException {Token tok;
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case ESCAPED_BACKSLASH:{
        tok = jj_consume_token(ESCAPED_BACKSLASH);
        break;
        }
      case ESCAPED_LBRACE:{
        tok = jj_consume_token(ESCAPED_LBRACE);
        break;
        }
      case ESCAPED_RBRACE:{
        tok = jj_consume_token(ESCAPED_RBRACE);
        break;
        }
      default:
        jj_la1[4] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
  buf.append(tok.image.charAt(0));
    }
  
    final public void textual_control_symbol(StringBuilder buf) throws ParseException {Token tok;
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case NON_BREAKING_SPACE:{
        tok = jj_consume_token(NON_BREAKING_SPACE);
        break;
        }
      case OPTIONAL_HYPHEN:{
        tok = jj_consume_token(OPTIONAL_HYPHEN);
        break;
        }
      case NON_BREAKING_HYPHEN:{
        tok = jj_consume_token(NON_BREAKING_HYPHEN);
        break;
        }
      default:
        jj_la1[5] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
  buf.append(tok.image);
    }
  
    final public byte hex() throws ParseException {Token hex;
      hex = jj_consume_token(HEX_CHAR);
  byte b = (byte)Integer.parseInt(hex.image.substring(2), 16);
      {if ("" != null) return b;}
      throw new Error("Missing return statement in function");
    }
  
    final public void special_character(StringBuilder buf) throws ParseException {
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case TAB:{
        jj_consume_token(TAB);
  buf.append('\u0009');
        break;
        }
      case EMDASH:{
        jj_consume_token(EMDASH);
  buf.append('\u2014');
        break;
        }
      case ENDASH:{
        jj_consume_token(ENDASH);
  buf.append('\u2013');
        break;
        }
      case EMSPACE:{
        jj_consume_token(EMSPACE);
  buf.append('\u2003');
        break;
        }
      case ENSPACE:{
        jj_consume_token(ENSPACE);
  buf.append('\u2002');
        break;
        }
      case QMSPACE:{
        jj_consume_token(QMSPACE);
  buf.append('\u2005');
        break;
        }
      case BULLET:{
        jj_consume_token(BULLET);
  buf.append('\u2022');
        break;
        }
      case LQUOTE:{
        jj_consume_token(LQUOTE);
  buf.append('\u2018');
        break;
        }
      case RQUOTE:{
        jj_consume_token(RQUOTE);
  buf.append('\u2019');
        break;
        }
      case LDBLQUOTE:{
        jj_consume_token(LDBLQUOTE);
  buf.append('\u201c');
        break;
        }
      case RDBLQUOTE:{
        jj_consume_token(RDBLQUOTE);
  buf.append('\u201d');
        break;
        }
      case LTRMARK:{
        jj_consume_token(LTRMARK);
  buf.append('\u200e');
        break;
        }
      case RTLMARK:{
        jj_consume_token(RTLMARK);
  buf.append('\u200f');
        break;
        }
      case ZWJ:{
        jj_consume_token(ZWJ);
  buf.append('\u200d');
        break;
        }
      case ZWNJ:{
        jj_consume_token(ZWNJ);
  buf.append('\u200c');
        break;
        }
      default:
        jj_la1[6] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
    }
  
    final public void line_breaks() throws ParseException {Token word = null;
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case PAR:{
        word = jj_consume_token(PAR);
        break;
        }
      case LINE:{
        word = jj_consume_token(LINE);
        break;
        }
      case ESCAPED_NEWLINE:{
        word = jj_consume_token(ESCAPED_NEWLINE);
        break;
        }
      case ESCAPED_CARRIAGE_RETURN:{
        word = jj_consume_token(ESCAPED_CARRIAGE_RETURN);
        break;
        }
      default:
        jj_la1[7] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
  _delegate.text(getNewLine(), getCurrentStyle(), _where);
      _delegate.controlWord(word.image, VALUE_NOT_SPECIFIED, _where);
    }
  
    final public void lbrace() throws ParseException {
      jj_consume_token(LBRACE);
  _fontEncodingStack.push(getCurrentEncoding());
      _ucSkipStates.push(getCurrentSkipState());
      _styleStack.push(getCurrentStyle());
      _delegate.openGroup(++_braceDepth);
    }
  
    final public void rbrace() throws ParseException {
      jj_consume_token(RBRACE);
  setCurrentSkipState((Integer)_ucSkipStates.pop());
      setCurrentEncoding((String)_fontEncodingStack.pop());
      setCurrentStyle((String)_styleStack.pop());
      _delegate.closeGroup(_braceDepth);
  
      if (_rtfDepth == --_braceDepth) { // leaving a table
        if (_where == IN_STYLESHEET) {
          _delegate.styleList(new ArrayList<String>(_styleMap.values()));
        }
        _where = IN_DOCUMENT;
      } else if (_where == IN_PNTEXT) {
        _where = IN_DOCUMENT;
      }
    }
  
    final public void table_declaration() throws ParseException {Token word = null, val = null;
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case INFO:{
        word = jj_consume_token(INFO);
  _where = IN_INFO;
        break;
        }
      case FONTTBL:{
        word = jj_consume_token(FONTTBL);
  _where = IN_FONTTBL;
        break;
        }
      case COLORTBL:{
        word = jj_consume_token(COLORTBL);
  _where = IN_COLORTBL;
        break;
        }
      case STYLESHEET:{
        word = jj_consume_token(STYLESHEET);
  _where = IN_STYLESHEET;
        break;
        }
      case LISTTABLE:{
        word = jj_consume_token(LISTTABLE);
  _where = IN_LISTTABLE;
        break;
        }
      case REVTBL:{
        word = jj_consume_token(REVTBL);
  _where = IN_REVTBL;
        break;
        }
      case PNTEXT:{
        word = jj_consume_token(PNTEXT);
        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
        case CW_VAL:{
          val = jj_consume_token(CW_VAL);
          break;
          }
        default:
          jj_la1[8] = jj_gen;
          ;
        }
  _where = IN_PNTEXT;
        break;
        }
      case PNSECLVL:{
        word = jj_consume_token(PNSECLVL);
        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
        case CW_VAL:{
          val = jj_consume_token(CW_VAL);
          break;
          }
        default:
          jj_la1[9] = jj_gen;
          ;
        }
  _where = IN_PNTEXT;
        break;
        }
      default:
        jj_la1[10] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
  int v = null == val ? VALUE_NOT_SPECIFIED : Integer.parseInt(val.image);
      _delegate.controlWord(word.image, v, _where);
    }
  
    final public void control_symbol() throws ParseException {Token sym = null;
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case CONTROL_SYM:{
        sym = jj_consume_token(CONTROL_SYM);
        break;
        }
      case FORMULA_CHARACTER:{
        sym = jj_consume_token(FORMULA_CHARACTER);
        break;
        }
      case INDEX_SUBENTRY:{
        sym = jj_consume_token(INDEX_SUBENTRY);
        break;
        }
      default:
        jj_la1[11] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
  _delegate.controlSymbol(sym.image, _where);
    }
  
    final public void control_word() throws ParseException {Token word = null, val = null;
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case IGNORABLE_DESTINATION:{
        word = jj_consume_token(IGNORABLE_DESTINATION);
        break;
        }
      case CONTROL_WORD:{
        word = jj_consume_token(CONTROL_WORD);
        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
        case CW_VAL:{
          val = jj_consume_token(CW_VAL);
          break;
          }
        default:
          jj_la1[12] = jj_gen;
          ;
        }
        break;
        }
      default:
        jj_la1[13] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
  long v = null == val ? VALUE_NOT_SPECIFIED : Long.parseLong(val.image);
      _delegate.controlWord(word.image, v, _where);
    }
  
    final public void u(StringBuilder buf) throws ParseException {Token val;
      jj_consume_token(U);
      val = jj_consume_token(CW_VAL);
  int ucValue = Integer.parseInt(val.image);
      // correct RTF negative unicode char value
      if (ucValue < 0) {
        ucValue += 65536;
      }
      buf.append((char)ucValue);
    }
  
    byte[] skip_after_unicode() throws ParseException, UnsupportedEncodingException {Token tok;
    byte[] raw = null;
  
    for (int skip = getCurrentSkipState().intValue(); skip != 0; skip--) {
      tok = getNextToken();
      switch (tok.kind) {
      case HEX_CHAR:
        break; // buh bye!
      case TEXT:
      case TEXT_CONTROL_DELIMITER:
        if (tok.image.length() > skip) {
           byte[] tmp = stringToBytes(tok.image);
           raw = new byte[ tmp.length - skip ];
           System.arraycopy(tmp,skip,raw,0,raw.length);
           return raw;
        }
        break; // the text was exactly what we needed: buh bye!
      default:
        throw new IllegalStateException("unexpected token while skipping");
      }
    }
    return raw;
    }
  
    final public void uc() throws ParseException {Token word = null, val = null;
      word = jj_consume_token(UC);
      val = jj_consume_token(CW_VAL);
  int bytesToSkip = null == val ? 0 : Integer.parseInt(val.image);
      setCurrentSkipState(new Integer(bytesToSkip));
    }
  
    final public void fcharset() throws ParseException {Token word = null, val = null;
      word = jj_consume_token(FCHARSET);
      val = jj_consume_token(CW_VAL);
  _currentCharsetValue = null == val ? 0 : Integer.parseInt(val.image);
      _delegate.controlWord(word.image, _currentCharsetValue, _where);
    }
  
    final public void deff() throws ParseException {Token val = null;
      jj_consume_token(DEFF);
      val = jj_consume_token(CW_VAL);
  // need to figure out if this really has to be handled.
      _defaultFont = null == val ? 0 : Integer.parseInt(val.image);
      _delegate.controlWord("\u005c\u005cdeff", _defaultFont, _where);
    }
  
    final public void f() throws ParseException {Token val;
      jj_consume_token(F);
      val = jj_consume_token(CW_VAL);
  int font = null == val ? 0 : Integer.parseInt(val.image);
      if (IN_FONTTBL == _where) {
        _currentFontValue = font;
      } else if (IN_DOCUMENT == _where) {
        String encoding = (String)_fontEncodingMap.get(new Integer(font));
        setCurrentEncoding(null == encoding ? DEFAULT_ENCODING : encoding);
      }
      _delegate.controlWord("\u005c\u005cf", font, _where);
    }
  
    final public void cs() throws ParseException {Token val = null;
      jj_consume_token(CS);
      val = jj_consume_token(CW_VAL);
  int style = null == val ? 0 : Integer.parseInt(val.image);
      if (IN_STYLESHEET == _where) {
        _currentStyleValue = style;
      } else if (IN_DOCUMENT == _where) {
        setCurrentStyle((String)_styleMap.get(new Integer(style)));
      }
      _delegate.controlWord("\u005c\u005ccs", style, _where);
    }
  
    final public void plain() throws ParseException {
      jj_consume_token(PLAIN);
  setCurrentStyle(NO_STYLE);
      _delegate.controlWord("\u005c\u005cplain", VALUE_NOT_SPECIFIED, _where);
    }
  
  /* these productions identify the document encoding; note that they
   * are almost always clobbered by an \ansicpg or by unicode characters */
    final public void document_charset() throws ParseException {
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case PC:{
        jj_consume_token(PC);
  setDocumentEncoding(getJavaEncoding(437));
        break;
        }
      case PCA:{
        jj_consume_token(PCA);
  setDocumentEncoding(getJavaEncoding(850));
        break;
        }
      case MAC:{
        jj_consume_token(MAC);
  setDocumentEncoding("MacRoman");
        break;
        }
      case ANSI:{
        jj_consume_token(ANSI);
  setDocumentEncoding(getJavaEncoding(1252));
        break;
        }
      default:
        jj_la1[14] = jj_gen;
        jj_consume_token(-1);
        throw new ParseException();
      }
    }
  
  /* specifies the ANSI codepage to use as the document's encoding. Subject
   * to local overrides. */
    final public void ansicpg() throws ParseException {Token val = null;
      jj_consume_token(ANSICPG);
      val = jj_consume_token(CW_VAL);
  // must be a value in the map - we should throw if it isn't there.
      int cp = null == val ? 0 : Integer.parseInt(val.image);
      String encoding = getJavaEncoding(cp);
      if (encoding == null)
      {
        {if (true) throw new IllegalStateException("Failed to find a registered encoding for code page: " + cp);}
      }
      setDocumentEncoding(encoding);
    }
  
    final public void rtf_start() throws ParseException {Token word = null;
    Token val = null;
      word = jj_consume_token(RTF);
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case CW_VAL:{
        val = jj_consume_token(CW_VAL);
        break;
        }
      default:
        jj_la1[15] = jj_gen;
        ;
      }
  int depth = null == val ? 1 : Integer.parseInt(val.image);
      _rtfDepth = _braceDepth;
      _delegate.controlWord(word.image, depth, _where);
    }
  
    final public void from_html() throws ParseException {Token val = null;
      jj_consume_token(FROMHTML);
      switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
      case CW_VAL:{
        jj_consume_token(CW_VAL);
        break;
        }
      default:
        jj_la1[16] = jj_gen;
        ;
      }
  _delegate.controlWord("\u005c\u005cfromhtml", VALUE_NOT_SPECIFIED, _where);
    }
  
    final public void bin() throws ParseException, ParseException {Token val = null;
      jj_consume_token(BIN);
      val = jj_consume_token(CW_VAL);
  int nbytes = null == val ? 0 : Integer.parseInt(val.image);
      byte[] data = new byte[nbytes];
      OutputStream os = _delegate.getNextOutputStream(_where);
      try
      {
          try
          {
              // Skip leading space.
              jj_input_stream.readChar();
              for (int i = 0; i < nbytes; i++)
              {
                  // Will only return 8-bit characters.
                  byte b = (byte)jj_input_stream.readChar();
                  if (os != null)
                  {
                      os.write(b);
                  }
              }
          }
          finally
          {
              if (os != null)
              {
                  os.close();
              }
          }
      }
      catch (IOException e)
      {
          {if (true) throw new ParseException("Unable to process binary data");}
          e.printStackTrace();
      }
    }
  
  // TODO: consider collecting special characters in a buffer
    final public 
  void groupContents() throws ParseException, UnsupportedEncodingException {Token word = null, val = null;
      label_2:
      while (true) {
        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
        case LBRACE:
        case NON_BREAKING_SPACE:
        case OPTIONAL_HYPHEN:
        case NON_BREAKING_HYPHEN:
        case ESCAPED_NEWLINE:
        case ESCAPED_CARRIAGE_RETURN:
        case IGNORABLE_DESTINATION:
        case FORMULA_CHARACTER:
        case INDEX_SUBENTRY:
        case ESCAPED_LBRACE:
        case ESCAPED_RBRACE:
        case ESCAPED_BACKSLASH:
        case CONTROL_SYM:
        case TEXT:
        case HEX_CHAR:
        case PAR:
        case LINE:
        case U:
        case UC:
        case F:
        case CS:
        case FCHARSET:
        case PLAIN:
        case PC:
        case PCA:
        case MAC:
        case RTF:
        case ANSI:
        case ANSICPG:
        case DEFF:
        case FROMTEXT:
        case FROMHTML:
        case FBIDIS:
        case INFO:
        case REVTBL:
        case PNTEXT:
        case FONTTBL:
        case COLORTBL:
        case PNSECLVL:
        case LISTTABLE:
        case STYLESHEET:
        case TAB:
        case ZWJ:
        case ZWNJ:
        case EMDASH:
        case ENDASH:
        case EMSPACE:
        case ENSPACE:
        case QMSPACE:
        case BULLET:
        case LQUOTE:
        case RQUOTE:
        case LTRMARK:
        case RTLMARK:
        case LDBLQUOTE:
        case RDBLQUOTE:
        case BIN:
        case CONTROL_WORD:
        case TEXT_CONTROL_DELIMITER:{
          ;
          break;
          }
        default:
          jj_la1[17] = jj_gen;
          break label_2;
        }
        switch ((jj_ntk==-1)?jj_ntk_f():jj_ntk) {
        case RTF:{
          rtf_start();
          break;
          }
        case PC:
        case PCA:
        case MAC:
        case ANSI:{
          document_charset();
          break;
          }
        case FROMTEXT:{
          jj_consume_token(FROMTEXT);
          break;
          }
        case FROMHTML:{
          from_html();
          break;
          }
        case FBIDIS:{
          jj_consume_token(FBIDIS);
          break;
          }
        case ANSICPG:{
          ansicpg();
          break;
          }
        case DEFF:{
          deff();
          break;
          }
        case INFO:
        case REVTBL:
        case PNTEXT:
        case FONTTBL:
        case COLORTBL:
        case PNSECLVL:
        case LISTTABLE:
        case STYLESHEET:{
          table_declaration();
          break;
          }
        case UC:{
          uc();
          break;
          }
        case F:{
          f();
          break;
          }
        case FCHARSET:{
          fcharset();
          break;
          }
        case CS:{
          cs();
          break;
          }
        case PLAIN:{
          plain();
          break;
          }
        case BIN:{
          bin();
          break;
          }
        case ESCAPED_NEWLINE:
        case ESCAPED_CARRIAGE_RETURN:
        case PAR:
        case LINE:{
          line_breaks();
          break;
          }
        case IGNORABLE_DESTINATION:
        case CONTROL_WORD:{
          control_word();
          break;
          }
        case FORMULA_CHARACTER:
        case INDEX_SUBENTRY:
        case CONTROL_SYM:{
          control_symbol();
          break;
          }
        case LBRACE:{
          group();
          break;
          }
        case NON_BREAKING_SPACE:
        case OPTIONAL_HYPHEN:
        case NON_BREAKING_HYPHEN:
        case ESCAPED_LBRACE:
        case ESCAPED_RBRACE:
        case ESCAPED_BACKSLASH:
        case TEXT:
        case HEX_CHAR:
        case U:
        case TAB:
        case ZWJ:
        case ZWNJ:
        case EMDASH:
        case ENDASH:
        case EMSPACE:
        case ENSPACE:
        case QMSPACE:
        case BULLET:
        case LQUOTE:
        case RQUOTE:
        case LTRMARK:
        case RTLMARK:
        case LDBLQUOTE:
        case RDBLQUOTE:
        case TEXT_CONTROL_DELIMITER:{
          text();
          break;
          }
        default:
          jj_la1[18] = jj_gen;
          jj_consume_token(-1);
          throw new ParseException();
        }
      }
    }
  
    final public void group() throws ParseException, UnsupportedEncodingException {Token word = null, val = null;
      lbrace();
      groupContents();
      rbrace();
    }
  
    final public void document() throws ParseException, UnsupportedEncodingException {
  _delegate.startDocument();
      groupContents();
  _delegate.endDocument();
      jj_consume_token(0);
    }
  
    /** Generated Token Manager. */
    public RTFParserTokenManager token_source;
    SimpleCharStream jj_input_stream;
    /** Current token. */
    public Token token;
    /** Next token. */
    public Token jj_nt;
    private int jj_ntk;
    private int jj_gen;
    final private int[] jj_la1 = new int[19];
    static private int[] jj_la1_0;
    static private int[] jj_la1_1;
    static private int[] jj_la1_2;
    static {
        jj_la1_init_0();
        jj_la1_init_1();
        jj_la1_init_2();
     }
     private static void jj_la1_init_0() {
        jj_la1_0 = new int[] {0x800e0e00,0x80ae0e00,0x80ae0e00,0x200000,0xe0000,0xe00,0x0,0x60003000,0x0,0x0,0x0,0x118000,0x0,0x4000,0x0,0x0,0x0,0xe0bffe80,0xe0bffe80,};
     }
     private static void jj_la1_init_1() {
        jj_la1_1 = new int[] {0xff800000,0xff800000,0xff800000,0x0,0x0,0x0,0xff800000,0x0,0x0,0x0,0x7f8000,0x0,0x0,0x0,0x2e0,0x0,0x0,0xffffffff,0xffffffff,};
     }
     private static void jj_la1_init_2() {
        jj_la1_2 = new int[] {0x3f,0x43f,0x43f,0x400,0x0,0x0,0x3f,0x0,0x200,0x200,0x0,0x0,0x200,0x80,0x0,0x200,0x200,0x4ff,0x4ff,};
     }
  
    /** Constructor with InputStream. */
    public RTFParser(java.io.InputStream stream) {
       this(stream, null);
    }
    /** Constructor with InputStream and supplied encoding */
    public RTFParser(java.io.InputStream stream, String encoding) {
      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 < 19; i++) jj_la1[i] = -1;
    }
  
    /** Reinitialise. */
    public void ReInit(java.io.InputStream stream) {
       ReInit(stream, null);
    }
    /** Reinitialise. */
    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 < 19; i++) jj_la1[i] = -1;
    }
  
    /** Constructor. */
    public RTFParser(java.io.Reader stream) {
      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 < 19; i++) jj_la1[i] = -1;
    }
  
    /** Reinitialise. */
    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 < 19; i++) jj_la1[i] = -1;
    }
  
    /** Constructor with generated Token Manager. */
    public RTFParser(RTFParserTokenManager tm) {
      token_source = tm;
      token = new Token();
  