FileDocCategorySizeDatePackage
RTFReader.javaAPI DocJava SE 5 API45298Fri Aug 26 14:58:20 BST 2005javax.swing.text.rtf

RTFReader

public class RTFReader extends RTFParser
Takes a sequence of RTF tokens and text and appends the text described by the RTF to a StyledDocument (the target). The RTF is lexed from the character stream by the RTFParser which is this class's superclass. This class is an indirect subclass of OutputStream. It must be closed in order to guarantee that all of the text has been sent to the text acceptor.
see
RTFParser
see
java.io.OutputStream

Fields Summary
StyledDocument
target
The object to which the parsed text is sent.
Dictionary
parserState
Miscellaneous information about the parser's state. This dictionary is saved and restored when an RTF group begins or ends.
Destination
rtfDestination
This is the "dst" item from parserState. rtfDestination is the current rtf destination. It is cached in an instance variable for speed.
MutableAttributeSet
documentAttributes
This holds the current document attributes.
Dictionary
fontTable
This Dictionary maps Integer font numbers to String font names.
Color[]
colorTable
This array maps color indices to Color objects.
Style[]
characterStyles
This array maps character style numbers to Style objects.
Style[]
paragraphStyles
This array maps paragraph style numbers to Style objects.
Style[]
sectionStyles
This array maps section style numbers to Style objects.
int
rtfversion
This is the RTF version number, extracted from the \rtf keyword. The version information is currently not used.
boolean
ignoreGroupIfUnknownKeyword
true to indicate that if the next keyword is unknown, the containing group should be ignored.
int
skippingCharacters
The parameter of the most recently parsed \\ucN keyword, used for skipping alternative representations after a Unicode character.
private static Dictionary
straightforwardAttributes
private MockAttributeSet
mockery
static Dictionary
textKeywords
textKeywords maps RTF keywords to single-character strings, for those keywords which simply insert some text.
static final String
TabAlignmentKey
static final String
TabLeaderKey
static Dictionary
characterSets
static boolean
useNeXTForAnsi
Constructors Summary
public RTFReader(StyledDocument destination)
Creates a new RTFReader instance. Text will be sent to the specified TextAcceptor.

param
destination The TextAcceptor which is to receive the text.

   
      characterSets = new Hashtable();
  
    int i;

    target = destination;
    parserState = new Hashtable();
    fontTable = new Hashtable();

    rtfversion = -1;

    mockery = new MockAttributeSet();
    documentAttributes = new SimpleAttributeSet();
Methods Summary
public voidbegingroup()
Called by the superclass when a new RTF group is begun. This implementation saves the current parserState, and gives the current destination a chance to save its own state.

see
RTFParser#begingroup

    if (skippingCharacters > 0) {
	/* TODO this indicates an error in the RTF. Log it? */
	skippingCharacters = 0;
    }

    /* we do this little dance to avoid cloning the entire state stack and
       immediately throwing it away. */
    Object oldSaveState = parserState.get("_savedState");
    if (oldSaveState != null)
	parserState.remove("_savedState");
    Dictionary saveState = (Dictionary)((Hashtable)parserState).clone();
    if (oldSaveState != null)
	saveState.put("_savedState", oldSaveState);
    parserState.put("_savedState", saveState);

    if (rtfDestination != null)
	rtfDestination.begingroup();
public voidclose()
Called by the user when there is no more input (i.e., at the end of the RTF file.)

see
OutputStream#close

    Enumeration docProps = documentAttributes.getAttributeNames();
    while(docProps.hasMoreElements()) {
        Object propName = docProps.nextElement();
	target.putProperty(propName,
			   documentAttributes.getAttribute((String)propName));
    }

    /* RTFParser should have ensured that all our groups are closed */

    warning("RTF filter done.");

    super.close();
java.awt.ColordefaultColor()
The default color for text which has no specified color.

    return Color.black;
public static voiddefineCharacterSet(java.lang.String name, char[] table)
Adds a character set to the RTFReader's list of known character sets

    if (table.length < 256)
	throw new IllegalArgumentException("Translation table must have 256 entries.");
    characterSets.put(name, table);
public voidendgroup()
Called by the superclass when the current RTF group is closed. This restores the parserState saved by begingroup() as well as invoking the endgroup method of the current destination.

see
RTFParser#endgroup

    if (skippingCharacters > 0) {
	/* NB this indicates an error in the RTF. Log it? */
	skippingCharacters = 0;
    }

    Dictionary restoredState = (Dictionary)parserState.get("_savedState");
    Destination restoredDestination = (Destination)restoredState.get("dst");
    if (restoredDestination != rtfDestination) {
	rtfDestination.close(); /* allow the destination to clean up */
	rtfDestination = restoredDestination;
    }
    Dictionary oldParserState = parserState;
    parserState = restoredState;
    if (rtfDestination != null)
	rtfDestination.endgroup(oldParserState);
public static java.lang.ObjectgetCharacterSet(java.lang.String name)
Looks up a named character set. A character set is a 256-entry array of characters, mapping unsigned byte values to their Unicode equivalents. The character set is loaded if necessary.

returns
the character set

    char[] set;

    set = (char [])characterSets.get(name);
    if (set == null) {
      InputStream charsetStream;
      charsetStream = (InputStream)java.security.AccessController.
	              doPrivileged(new java.security.PrivilegedAction() {
	  public Object run() {
	      return RTFReader.class.getResourceAsStream
		                     ("charsets/" + name + ".txt");
	  }
      });
      set = readCharset(charsetStream);
      defineCharacterSet(name, set);
    }
    return set;
public voidhandleBinaryBlob(byte[] data)
Called when the RTFParser encounters a bin keyword in the RTF stream.

see
RTFParser

    if (skippingCharacters > 0) {
	/* a blob only counts as one character for skipping purposes */
	skippingCharacters --;
	return;
    }

    /* someday, someone will want to do something with blobs */
public booleanhandleKeyword(java.lang.String keyword, int parameter)
Handles an RTF keyword and its integer parameter. This is called by the superclass (RTFParser) when a keyword is found in the input stream.

returns
true if the keyword is recognized and handled; false otherwise
see
RTFParser#handleKeyword

    boolean ignoreGroupIfUnknownKeywordSave = ignoreGroupIfUnknownKeyword;

    if (skippingCharacters > 0) {
	skippingCharacters --;
	return true;
    }

    ignoreGroupIfUnknownKeyword = false;

    if (keyword.equals("uc")) {
	/* count of characters to skip after a unicode character */
	parserState.put("UnicodeSkip", Integer.valueOf(parameter));
	return true;
    }
    if (keyword.equals("u")) {
	if (parameter < 0)
	    parameter = parameter + 65536;
	handleText((char)parameter);
	Number skip = (Number)(parserState.get("UnicodeSkip"));
	if (skip != null) {
	    skippingCharacters = skip.intValue();
	} else {
	    skippingCharacters = 1;
	}
	return true;
    }

    if (keyword.equals("rtf")) {
        rtfversion = parameter;
	setRTFDestination(new DocumentDestination());
        return true;
    }

    if (keyword.startsWith("NeXT") ||
	keyword.equals("private"))
	ignoreGroupIfUnknownKeywordSave = true;

    if (rtfDestination != null) {
	if(rtfDestination.handleKeyword(keyword, parameter))
	    return true;
    }

    /* this point is reached only if the keyword is unrecognized */

    if (ignoreGroupIfUnknownKeywordSave) {
	setRTFDestination(new DiscardingDestination());
    }

    return false;
public booleanhandleKeyword(java.lang.String keyword)
Handles a parameterless RTF keyword. This is called by the superclass (RTFParser) when a keyword is found in the input stream.

returns
true if the keyword is recognized and handled; false otherwise
see
RTFParser#handleKeyword

    Object item;
    boolean ignoreGroupIfUnknownKeywordSave = ignoreGroupIfUnknownKeyword;

    if (skippingCharacters > 0) {
	skippingCharacters --;
	return true;
    }

    ignoreGroupIfUnknownKeyword = false;
    
    if ((item = textKeywords.get(keyword)) != null) {
	handleText((String)item);
	return true;
    }
    
    if (keyword.equals("fonttbl")) {
	setRTFDestination(new FonttblDestination());
        return true;
    }

    if (keyword.equals("colortbl")) {
	setRTFDestination(new ColortblDestination());
        return true;
    }

    if (keyword.equals("stylesheet")) {
	setRTFDestination(new StylesheetDestination());
        return true;
    }

    if (keyword.equals("info")) {
	setRTFDestination(new InfoDestination());
	return false; 
    }

    if (keyword.equals("mac")) {
	setCharacterSet("mac");
        return true;
    }

    if (keyword.equals("ansi")) {
	if (useNeXTForAnsi)
	    setCharacterSet("NeXT");
	else
	    setCharacterSet("ansi");
        return true;
    }

    if (keyword.equals("next")) {
	setCharacterSet("NeXT");
	return true;
    }

    if (keyword.equals("pc")) {
	setCharacterSet("cpg437"); /* IBM Code Page 437 */
        return true;
    }

    if (keyword.equals("pca")) {
	setCharacterSet("cpg850"); /* IBM Code Page 850 */
        return true;
    }

    if (keyword.equals("*")) {
        ignoreGroupIfUnknownKeyword = true;
        return true;
    }

    if (rtfDestination != null) {
	if(rtfDestination.handleKeyword(keyword))
	    return true;
    }

    /* this point is reached only if the keyword is unrecognized */

    /* other destinations we don't understand and therefore ignore */
    if (keyword.equals("aftncn") ||
	keyword.equals("aftnsep") ||
	keyword.equals("aftnsepc") ||
	keyword.equals("annotation") ||
	keyword.equals("atnauthor") ||
	keyword.equals("atnicn") ||
	keyword.equals("atnid") ||
	keyword.equals("atnref") ||
	keyword.equals("atntime") ||
	keyword.equals("atrfend") ||
	keyword.equals("atrfstart") ||
	keyword.equals("bkmkend") ||
	keyword.equals("bkmkstart") ||
	keyword.equals("datafield") ||
	keyword.equals("do") ||
	keyword.equals("dptxbxtext") ||
	keyword.equals("falt") ||
	keyword.equals("field") ||
	keyword.equals("file") ||
	keyword.equals("filetbl") ||
	keyword.equals("fname") ||
	keyword.equals("fontemb") ||
	keyword.equals("fontfile") ||
	keyword.equals("footer") ||
	keyword.equals("footerf") ||
	keyword.equals("footerl") ||
	keyword.equals("footerr") ||
	keyword.equals("footnote") ||
	keyword.equals("ftncn") ||
	keyword.equals("ftnsep") ||
	keyword.equals("ftnsepc") ||
	keyword.equals("header") ||
	keyword.equals("headerf") ||
	keyword.equals("headerl") ||
	keyword.equals("headerr") ||
	keyword.equals("keycode") ||
	keyword.equals("nextfile") ||
	keyword.equals("object") ||
	keyword.equals("pict") ||
	keyword.equals("pn") ||
	keyword.equals("pnseclvl") ||
	keyword.equals("pntxtb") ||
	keyword.equals("pntxta") ||
	keyword.equals("revtbl") ||
	keyword.equals("rxe") ||
	keyword.equals("tc") ||
	keyword.equals("template") ||
	keyword.equals("txe") ||
	keyword.equals("xe")) {
	ignoreGroupIfUnknownKeywordSave = true;
    }

    if (ignoreGroupIfUnknownKeywordSave) {
	setRTFDestination(new DiscardingDestination());
    }

    return false;
public voidhandleText(java.lang.String text)
Handles any pure text (containing no control characters) in the input stream. Called by the superclass.

    if (skippingCharacters > 0) {
	if (skippingCharacters >= text.length()) {
	    skippingCharacters -= text.length();
	    return;
	} else {
	    text = text.substring(skippingCharacters);
	    skippingCharacters = 0;
	}
    }

    if (rtfDestination != null) {
	rtfDestination.handleText(text);
	return;
    }

    warning("Text with no destination. oops.");
static char[]readCharset(java.io.InputStream strm)
Parses a character set from an InputStream. The character set must contain 256 decimal integers, separated by whitespace, with no punctuation. B- and C- style comments are allowed.

returns
the newly read character set

    char[] values = new char[256];
    int i;
    StreamTokenizer in = new StreamTokenizer(new BufferedReader(
            new InputStreamReader(strm, "ISO-8859-1")));

    in.eolIsSignificant(false);
    in.commentChar('#");
    in.slashSlashComments(true);
    in.slashStarComments(true);

    i = 0;
    while (i < 256) {
	int ttype;
	try {
	    ttype = in.nextToken();
	} catch (Exception e) {
	    throw new IOException("Unable to read from character set file (" + e + ")");
	}
	if (ttype != in.TT_NUMBER) {
//	    System.out.println("Bad token: type=" + ttype + " tok=" + in.sval);
	    throw new IOException("Unexpected token in character set file");
//	    continue;
	}
	values[i] = (char)(in.nval);
	i++;
    }

    return values;
static char[]readCharset(java.net.URL href)

    return readCharset(href.openStream());
public voidsetCharacterSet(java.lang.String name)
setCharacterSet sets the current translation table to correspond with the named character set. The character set is loaded if necessary.

see
AbstractFilter

    Object set;

    try {
        set = getCharacterSet(name);
    } catch (Exception e) {
	warning("Exception loading RTF character set \"" + name + "\": " + e);
	set = null;
    }

    if (set != null) {
	translationTable = (char[])set;
    } else {
	warning("Unknown RTF character set \"" + name + "\"");
	if (!name.equals("ansi")) {
	    try {
		translationTable = (char[])getCharacterSet("ansi");
	    } catch (IOException e) {
		throw new InternalError("RTFReader: Unable to find character set resources (" + e + ")");
	    }
	}
    }

    setTargetAttribute(Constants.RTFCharacterSet, name);
protected voidsetRTFDestination(javax.swing.text.rtf.RTFReader$Destination newDestination)

    /* Check that setting the destination won't close the
       current destination (should never happen) */
    Dictionary previousState = (Dictionary)parserState.get("_savedState");
    if (previousState != null) {
	if (rtfDestination != previousState.get("dst")) {
	    warning("Warning, RTF destination overridden, invalid RTF.");
	    rtfDestination.close();
	}
    }
    rtfDestination = newDestination;
    parserState.put("dst", rtfDestination);
private voidsetTargetAttribute(java.lang.String name, java.lang.Object value)

//    target.changeAttributes(new LFDictionary(LFArray.arrayWithObject(value), LFArray.arrayWithObject(name)));