37 *
38 * @see AbstractFilter
39 * @see RTFFilter
40 */
41 abstract class RTFParser extends AbstractFilter
42 {
43 /** The current RTF group nesting level. */
44 public int level;
45
46 private int state;
47 private StringBuffer currentCharacters;
48 private String pendingKeyword; // where keywords go while we
49 // read their parameters
50 private int pendingCharacter; // for the \'xx construct
51
52 private long binaryBytesLeft; // in a \bin blob?
53 ByteArrayOutputStream binaryBuf;
54 private boolean[] savedSpecials;
55
56 /** A stream to which to write warnings and debugging information
57 * while parsing. This is set to <code>System.out</code> to log
58 * any anomalous information to stdout. */
59 protected PrintStream warnings;
60
61 // value for the 'state' variable
62 private final int S_text = 0; // reading random text
63 private final int S_backslashed = 1; // read a backslash, waiting for next
64 private final int S_token = 2; // reading a multicharacter token
65 private final int S_parameter = 3; // reading a token's parameter
66
67 private final int S_aftertick = 4; // after reading \'
68 private final int S_aftertickc = 5; // after reading \'x
69
70 private final int S_inblob = 6; // in a \bin blob
71
72 /** Implemented by subclasses to interpret a parameter-less RTF keyword.
73 * The keyword is passed without the leading '/' or any delimiting
74 * whitespace. */
75 public abstract boolean handleKeyword(String keyword);
76 /** Implemented by subclasses to interpret a keyword with a parameter.
77 * @param keyword The keyword, as with <code>handleKeyword(String)</code>.
78 * @param parameter The parameter following the keyword. */
79 public abstract boolean handleKeyword(String keyword, int parameter);
80 /** Implemented by subclasses to interpret text from the RTF stream. */
81 public abstract void handleText(String text);
82 public void handleText(char ch)
83 { handleText(String.valueOf(ch)); }
84 /** Implemented by subclasses to handle the contents of the \bin keyword. */
85 public abstract void handleBinaryBlob(byte[] data);
86 /** Implemented by subclasses to react to an increase
87 * in the nesting level. */
88 public abstract void begingroup();
89 /** Implemented by subclasses to react to the end of a group. */
90 public abstract void endgroup();
91
92 // table of non-text characters in rtf
93 static final boolean rtfSpecialsTable[];
94 static {
95 rtfSpecialsTable = noSpecialsTable.clone();
96 rtfSpecialsTable['\n'] = true;
97 rtfSpecialsTable['\r'] = true;
290 binaryBuf = null;
291 }
292 }
293 }
294
295 /** Flushes any buffered but not yet written characters.
296 * Subclasses which override this method should call this
297 * method <em>before</em> flushing
298 * any of their own buffers. */
299 public void flush()
300 throws IOException
301 {
302 super.flush();
303
304 if (state == S_text && currentCharacters.length() > 0) {
305 handleText(currentCharacters.toString());
306 currentCharacters = new StringBuffer();
307 }
308 }
309
310 /** Closes the parser. Currently, this simply does a <code>flush()</code>,
311 * followed by some minimal consistency checks. */
312 public void close()
313 throws IOException
314 {
315 flush();
316
317 if (state != S_text || level > 0) {
318 warning("Truncated RTF file.");
319
320 /* TODO: any sane way to handle termination in a non-S_text state? */
321 /* probably not */
322
323 /* this will cause subclasses to behave more reasonably
324 some of the time */
325 while (level > 0) {
326 endgroup();
327 level --;
328 }
329 }
330
|
37 *
38 * @see AbstractFilter
39 * @see RTFFilter
40 */
41 abstract class RTFParser extends AbstractFilter
42 {
43 /** The current RTF group nesting level. */
44 public int level;
45
46 private int state;
47 private StringBuffer currentCharacters;
48 private String pendingKeyword; // where keywords go while we
49 // read their parameters
50 private int pendingCharacter; // for the \'xx construct
51
52 private long binaryBytesLeft; // in a \bin blob?
53 ByteArrayOutputStream binaryBuf;
54 private boolean[] savedSpecials;
55
56 /** A stream to which to write warnings and debugging information
57 * while parsing. This is set to {@code System.out} to log
58 * any anomalous information to stdout. */
59 protected PrintStream warnings;
60
61 // value for the 'state' variable
62 private final int S_text = 0; // reading random text
63 private final int S_backslashed = 1; // read a backslash, waiting for next
64 private final int S_token = 2; // reading a multicharacter token
65 private final int S_parameter = 3; // reading a token's parameter
66
67 private final int S_aftertick = 4; // after reading \'
68 private final int S_aftertickc = 5; // after reading \'x
69
70 private final int S_inblob = 6; // in a \bin blob
71
72 /** Implemented by subclasses to interpret a parameter-less RTF keyword.
73 * The keyword is passed without the leading '/' or any delimiting
74 * whitespace. */
75 public abstract boolean handleKeyword(String keyword);
76 /** Implemented by subclasses to interpret a keyword with a parameter.
77 * @param keyword The keyword, as with {@code handleKeyword(String)}.
78 * @param parameter The parameter following the keyword. */
79 public abstract boolean handleKeyword(String keyword, int parameter);
80 /** Implemented by subclasses to interpret text from the RTF stream. */
81 public abstract void handleText(String text);
82 public void handleText(char ch)
83 { handleText(String.valueOf(ch)); }
84 /** Implemented by subclasses to handle the contents of the \bin keyword. */
85 public abstract void handleBinaryBlob(byte[] data);
86 /** Implemented by subclasses to react to an increase
87 * in the nesting level. */
88 public abstract void begingroup();
89 /** Implemented by subclasses to react to the end of a group. */
90 public abstract void endgroup();
91
92 // table of non-text characters in rtf
93 static final boolean rtfSpecialsTable[];
94 static {
95 rtfSpecialsTable = noSpecialsTable.clone();
96 rtfSpecialsTable['\n'] = true;
97 rtfSpecialsTable['\r'] = true;
290 binaryBuf = null;
291 }
292 }
293 }
294
295 /** Flushes any buffered but not yet written characters.
296 * Subclasses which override this method should call this
297 * method <em>before</em> flushing
298 * any of their own buffers. */
299 public void flush()
300 throws IOException
301 {
302 super.flush();
303
304 if (state == S_text && currentCharacters.length() > 0) {
305 handleText(currentCharacters.toString());
306 currentCharacters = new StringBuffer();
307 }
308 }
309
310 /** Closes the parser. Currently, this simply does a {@code flush()},
311 * followed by some minimal consistency checks. */
312 public void close()
313 throws IOException
314 {
315 flush();
316
317 if (state != S_text || level > 0) {
318 warning("Truncated RTF file.");
319
320 /* TODO: any sane way to handle termination in a non-S_text state? */
321 /* probably not */
322
323 /* this will cause subclasses to behave more reasonably
324 some of the time */
325 while (level > 0) {
326 endgroup();
327 level --;
328 }
329 }
330
|