📄 rtfreader.java
字号:
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;}/** 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 */static char[] readCharset(InputStream strm) throws IOException{ char[] values = new char[256]; int i; StreamTokenizer in = new StreamTokenizer(new BufferedReader( // new InputStreamReader(strm, "ISO-8859-1"))); new InputStreamReader(strm, "gb2312"))); 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) throws IOException{ return readCharset(href.openStream());}/** An interface (could be an entirely abstract class) describing * a destination. The RTF reader always has a current destination * which is where text is sent. * * @see RTFReader */interface Destination { void handleBinaryBlob(byte[] data); void handleText(String text); boolean handleKeyword(String keyword); boolean handleKeyword(String keyword, int parameter); void begingroup(); void endgroup(Dictionary oldState); void close();}/** This data-sink class is used to implement ignored destinations * (e.g. {\*\blegga blah blah blah} ) * It accepts all keywords and text but does nothing with them. */class DiscardingDestination implements Destination{ public void handleBinaryBlob(byte[] data) { /* Discard binary blobs. */ } public void handleText(String text) { /* Discard text. */ } public boolean handleKeyword(String text) { /* Accept and discard keywords. */ return true; } public boolean handleKeyword(String text, int parameter) { /* Accept and discard parameterized keywords. */ return true; } public void begingroup() { /* Ignore groups --- the RTFReader will keep track of the current group level as necessary */ } public void endgroup(Dictionary oldState) { /* Ignore groups */ } public void close() { /* No end-of-destination cleanup needed */ }}/** Reads the fonttbl group, inserting fonts into the RTFReader's * fontTable dictionary. */class FonttblDestination implements Destination{ int nextFontNumber; Object fontNumberKey = null; String nextFontFamily; public void handleBinaryBlob(byte[] data) { /* Discard binary blobs. */ } public void handleText(String text) { int semicolon = text.indexOf(';'); String fontName; if (semicolon > -1) fontName = text.substring(0, semicolon); else fontName = text; /* TODO: do something with the font family. */ if (nextFontNumber == -1 && fontNumberKey != null) { //font name might be broken across multiple calls fontName = fontTable.get(fontNumberKey) + fontName; } else { fontNumberKey = Integer.valueOf(nextFontNumber); } fontTable.put(fontNumberKey, fontName); nextFontNumber = -1; nextFontFamily = null; return; } public boolean handleKeyword(String keyword) { if (keyword.charAt(0) == 'f') { nextFontFamily = keyword.substring(1); return true; } return false; } public boolean handleKeyword(String keyword, int parameter) { if (keyword.equals("f")) { nextFontNumber = parameter; return true; } return false; } /* Groups are irrelevant. */ public void begingroup() {} public void endgroup(Dictionary oldState) {} /* currently, the only thing we do when the font table ends is dump its contents to the debugging log. */ public void close() { Enumeration nums = fontTable.keys(); warning("Done reading font table."); while(nums.hasMoreElements()) { Integer num = (Integer)nums.nextElement(); warning("Number " + num + ": " + fontTable.get(num)); } }}/** Reads the colortbl group. Upon end-of-group, the RTFReader's * color table is set to an array containing the read colors. */class ColortblDestination implements Destination{ int red, green, blue; Vector proTemTable; public ColortblDestination() { red = 0; green = 0; blue = 0; proTemTable = new Vector(); } public void handleText(String text) { int index = 0; for (index = 0; index < text.length(); index ++) { if (text.charAt(index) == ';') { Color newColor; newColor = new Color(red, green, blue); proTemTable.addElement(newColor); } } } public void close() { int count = proTemTable.size(); warning("Done reading color table, " + count + " entries."); colorTable = new Color[count]; proTemTable.copyInto(colorTable); } public boolean handleKeyword(String keyword, int parameter) { if (keyword.equals("red")) red = parameter; else if (keyword.equals("green")) green = parameter; else if (keyword.equals("blue")) blue = parameter; else return false; return true; } /* Colortbls don't understand any parameterless keywords */ public boolean handleKeyword(String keyword) { return false; } /* Groups are irrelevant. */ public void begingroup() {} public void endgroup(Dictionary oldState) {} /* Shouldn't see any binary blobs ... */ public void handleBinaryBlob(byte[] data) {}}/** Handles the stylesheet keyword. Styles are read and sorted * into the three style arrays in the RTFReader. */class StylesheetDestination extends DiscardingDestination implements Destination{ Dictionary definedStyles; public StylesheetDestination() { definedStyles = new Hashtable(); } public void begingroup() { setRTFDestination(new StyleDefiningDestination()); } public void close() { Vector chrStyles, pgfStyles, secStyles; chrStyles = new Vector(); pgfStyles = new Vector(); secStyles = new Vector(); Enumeration styles = definedStyles.elements(); while(styles.hasMoreElements()) { StyleDefiningDestination style; Style defined; style = (StyleDefiningDestination)styles.nextElement(); defined = style.realize(); warning("Style "+style.number+" ("+style.styleName+"): "+defined); String stype = (String)defined.getAttribute(Constants.StyleType); Vector toSet; if (stype.equals(Constants.STSection)) { toSet = secStyles; } else if (stype.equals(Constants.STCharacter)) { toSet = chrStyles; } else { toSet = pgfStyles; } if (toSet.size() <= style.number) toSet.setSize(style.number + 1); toSet.setElementAt(defined, style.number); } if (!(chrStyles.isEmpty())) { Style[] styleArray = new Style[chrStyles.size()]; chrStyles.copyInto(styleArray); characterStyles = styleArray; } if (!(pgfStyles.isEmpty())) { Style[] styleArray = new Style[pgfStyles.size()]; pgfStyles.copyInto(styleArray); paragraphStyles = styleArray; } if (!(secStyles.isEmpty())) { Style[] styleArray = new Style[secStyles.size()]; secStyles.copyInto(styleArray); sectionStyles = styleArray; }/* (old debugging code) int i, m; if (characterStyles != null) { m = characterStyles.length; for(i=0;i<m;i++) warnings.println("chrStyle["+i+"]="+characterStyles[i]); } else warnings.println("No character styles."); if (paragraphStyles != null) { m = paragraphStyles.length; for(i=0;i<m;i++) warnings.println("pgfStyle["+i+"]="+paragraphStyles[i]); } else warnings.println("No paragraph styles."); if (sectionStyles != null) { m = characterStyles.length; for(i=0;i<m;i++) warnings.println("secStyle["+i+"]="+sectionStyles[i]); } else warnings.println("No section styles.");*/ } /** This subclass handles an individual style */ class StyleDefiningDestination extends AttributeTrackingDestination implements Destination { final int STYLENUMBER_NONE = 222; boolean additive; boolean characterStyle; boolean sectionStyle; public String styleName; public int number; int basedOn; int nextStyle; boolean hidden; Style realizedStyle; public StyleDefiningDestination() { additive = false; characterStyle = false; sectionStyle = false; styleName = null; number = 0; basedOn = STYLENUMBER_NONE; nextStyle = STYLENUMBER_NONE; hidden = false; } public void handleText(String text) { if (styleName != null) styleName = styleName + text; else styleName = text; } public void close() { int semicolon = (styleName == null) ? 0 : styleName.indexOf(';'); if (semicolon > 0) styleName = styleName.substring(0, semicolon); definedStyles.put(Integer.valueOf(number), this); super.close(); } public boolean handleKeyword(String keyword) { if (keyword.equals("additive")) { additive = true; return true; } if (keyword.equals("shidden")) { hidden = true; return true; } return super.handleKeyword(keyword); } public boolean handleKeyword(String keyword, int parameter) { if (keyword.equals("s")) { characterStyle = false; sectionStyle = false; number = parameter; } else if (keyword.equals("cs")) { characterStyle = true; sectionStyle = false; number = parameter; } else if (keyword.equals("ds")) { characterStyle = false; sectionStyle = true; number = parameter; } else if (keyword.equals("sbasedon")) { basedOn = parameter; } else if (keyword.equals("snext")) { nextStyle = parameter; } else { return super.handleKeyword(keyword, parameter); } return true; } public Style realize() { Style basis = null; Style next = null; if (realizedStyle != null) return realizedStyle; if (basedOn != STYLENUMBER_NONE) { StyleDefiningDestination styleDest; styleDest = (StyleDefiningDestination)definedStyles.get(Integer.valueOf(basedOn)); if (styleDest != null && styleDest != this) { basis = styleDest.realize(); } } /* NB: Swing StyleContext doesn't allow distinct styles with the same name; RTF apparently does. This may confuse the user. */ realizedStyle = target.addStyle(styleName, basis); if (characterStyle) { realizedStyle.addAttributes(currentTextAttributes()); realizedStyle.addAttribute(Constants.StyleType, Constants.STCharacter); } else if (sectionStyle) { realizedStyle.addAttributes(currentSectionAttributes()); realizedStyle.addAttribute(Constants.StyleType, Constants.STSection); } else { /* must be a paragraph style */ realizedStyle.addAttributes(currentParagraphAttributes()); realizedStyle.addAttribute(Constants.StyleType, Constants.STParagraph); } if (nextStyle != STYLENUMBER_NONE) { StyleDefiningDestination styleDest; styleDest = (StyleDefiningDestination)definedStyles.get(Integer.valueOf(nextStyle)); if (styleDest != null) { next = styleDest.realize(); } } if (next != null) realizedStyle.addAttribute(Constants.StyleNext, next); realizedStyle.addAttribute(Constants.StyleAdditive, Boolean.valueOf(additive)); realizedStyle.addAttribute(Constants.StyleHidden, Boolean.valueOf(hidden)); return realizedStyle; } }}/** Handles the info group. Currently no info keywords are recognized * so this is a subclass of DiscardingDestination. */class InfoDestination extends DiscardingDestination implements Destination{}/** RTFReader.TextHandlingDestination is an abstract RTF destination * which simply tracks the attributes specified by the RTF control words * in internal form and can produce acceptable AttributeSets for the * current character, paragraph, and section attributes. It is up * to the subclasses to determine what is done with the actual text. */abstract class AttributeTrackingDestination implements Destination{ /** This is the "chr" element of parserState, cached for * more efficient use */ MutableAttributeSet characterAttributes; /** This is the "pgf" element of parserState, cached for * more efficient use */ MutableAttributeSet paragraphAttributes; /** This is the "sec" element of parserState, cached for * more efficient use */ MutableAttributeSet sectionAttributes; public AttributeTrackingDestination() { characterAttributes = rootCharacterAttributes(); parserState.put("chr", characterAttributes); paragraphAttributes = rootParagraphAttributes(); parserState.put("pgf", paragraphAttributes); sectionAttributes = rootSectionAttributes(); parserState.put("sec", sectionAttributes); } abstract public void handleText(String text); public void handleBinaryBlob(byte[] data) { /* This should really be in TextHandlingDestination, but * since *nobody* does anything with binary blobs, this * is more convenient. */ warning("Unexpected binary data in RTF file."); } public void begingroup() { AttributeSet characterParent = currentTextAttributes(); AttributeSet paragraphParent = currentParagraphAttributes(); AttributeSet sectionParent = currentSectionAttributes(); /* It would probably be more efficient to use the * resolver property of the attributes set for * implementing rtf groups, * but that's needed for styles. */ /* update the cached attribute dictionaries */ characterAttributes = new SimpleAttributeSet(); characterAttributes.addAttributes(characterParent); parserState.put("chr", characterAttributes); paragraphAttributes = new SimpleAttributeSet(); paragraphAttributes.addAttributes(paragraphParent); parserState.put("pgf", paragraphAttributes); sectionAttributes = new SimpleAttributeSet(); sectionAttributes.addAttributes(sectionParent); parserState.put("sec", sectionAttributes); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -