001: /**
002: * $Id: RtfParser.java 2377 2006-09-15 07:51:05Z xlv $
003: * $Name$
004: *
005: * Copyright 2006 by Mark Hall
006: *
007: * The contents of this file are subject to the Mozilla Public License Version 1.1
008: * (the "License"); you may not use this file except in compliance with the License.
009: * You may obtain a copy of the License at http://www.mozilla.org/MPL/
010: *
011: * Software distributed under the License is distributed on an "AS IS" basis,
012: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
013: * for the specific language governing rights and limitations under the License.
014: *
015: * The Original Code is 'iText, a free JAVA-PDF library'.
016: *
017: * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
018: * the Initial Developer are Copyright (C) 1999-2006 by Bruno Lowagie.
019: * All Rights Reserved.
020: * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
021: * are Copyright (C) 2000-2006 by Paulo Soares. All Rights Reserved.
022: *
023: * Contributor(s): all the names of the contributors are added in the source code
024: * where applicable.
025: *
026: * Alternatively, the contents of this file may be used under the terms of the
027: * LGPL license (the ?GNU LIBRARY GENERAL PUBLIC LICENSE?), in which case the
028: * provisions of LGPL are applicable instead of those above. If you wish to
029: * allow use of your version of this file only under the terms of the LGPL
030: * License and not to allow others to use your version of this file under
031: * the MPL, indicate your decision by deleting the provisions above and
032: * replace them with the notice and other provisions required by the LGPL.
033: * If you do not delete the provisions above, a recipient may use your version
034: * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
035: *
036: * This library is free software; you can redistribute it and/or modify it
037: * under the terms of the MPL as stated above or under the terms of the GNU
038: * Library General Public License as published by the Free Software Foundation;
039: * either version 2 of the License, or any later version.
040: *
041: * This library is distributed in the hope that it will be useful, but WITHOUT
042: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
043: * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
044: * details.
045: *
046: * If you didn't download this code from the following link, you should check if
047: * you aren't using an obsolete version:
048: * http://www.lowagie.com/iText/
049: */package com.lowagie.text.rtf.direct;
050:
051: import java.awt.Color;
052: import java.io.IOException;
053: import java.io.Reader;
054: import java.util.Iterator;
055:
056: import com.lowagie.text.rtf.document.RtfDocument;
057:
058: /**
059: * The RtfParser allows the importing of RTF documents or
060: * RTF document fragments. The RTF document or fragment is tokenised,
061: * font and color definitions corrected and then added to
062: * the document being written.
063: *
064: * @version $Revision: 2377 $
065: * @author Mark Hall (mhall@edu.uni-klu.ac.at)
066: */
067: public class RtfParser {
068: /**
069: * Currently the RTF document header is being parsed.
070: */
071: private static final int PARSER_IN_HEADER = 0;
072: /**
073: * Currently the RTF font table is being parsed.
074: */
075: private static final int PARSER_IN_FONT_TABLE = 1;
076: /**
077: * Currently the RTF color table is being parsed.
078: */
079: private static final int PARSER_IN_COLOR_TABLE = 2;
080: /**
081: * Currently the RTF info group is being parsed.
082: */
083: private static final int PARSER_IN_INFO_GROUP = 4;
084: /**
085: * Currently the RTF document content is being parsed.
086: */
087: private static final int PARSER_IN_DOCUMENT = 8;
088:
089: /**
090: * The RtfDocument to add the RTF document or fragment to.
091: */
092: private RtfDocument rtfDoc = null;
093: /**
094: * The RtfTokeniser to use for tokenising the RTF document or fragment.
095: */
096: private RtfTokeniser tokeniser = null;
097: /**
098: * The RtfImportHeader to store imported font and color mappings in.
099: */
100: private RtfImportHeader importHeader = null;
101: /**
102: * The RtfFontTableParser to use for parsing the font table.
103: */
104: private RtfFontTableParser fontTableParser = null;
105: /**
106: * The RtfColorTableParser to use for parsing the color table.
107: */
108: private RtfColorTableParser colorTableParser = null;
109: /**
110: * The current parser state.
111: */
112: private int state = PARSER_IN_HEADER;
113:
114: /**
115: * Imports a complete RTF document.
116: *
117: * @param reader The Reader to read the RTF document from.
118: * @param rtfDoc The RtfDocument to add the imported document to.
119: * @throws IOException On I/O errors.
120: */
121: public void importRtfDocument(Reader reader, RtfDocument rtfDoc)
122: throws IOException {
123: this .rtfDoc = rtfDoc;
124: this .state = PARSER_IN_HEADER;
125: this .importHeader = new RtfImportHeader(this .rtfDoc);
126: this .fontTableParser = new RtfFontTableParser(this .importHeader);
127: this .colorTableParser = new RtfColorTableParser(
128: this .importHeader);
129: this .tokeniser = new RtfTokeniser(this , 0);
130: this .tokeniser.tokenise(reader);
131: }
132:
133: /**
134: * Imports an RTF fragment.
135: *
136: * @param reader The Reader to read the RTF fragment from.
137: * @param rtfDoc The RTF document to add the RTF fragment to.
138: * @param importMappings The RtfImportMappings defining font and color mappings for the fragment.
139: * @throws IOException On I/O errors.
140: */
141: public void importRtfFragment(Reader reader, RtfDocument rtfDoc,
142: RtfImportMappings importMappings) throws IOException {
143: this .rtfDoc = rtfDoc;
144: this .state = PARSER_IN_DOCUMENT;
145: this .importHeader = new RtfImportHeader(this .rtfDoc);
146: this .fontTableParser = new RtfFontTableParser(this .importHeader);
147: this .colorTableParser = new RtfColorTableParser(
148: this .importHeader);
149: handleImportMappings(importMappings);
150: this .tokeniser = new RtfTokeniser(this , 1);
151: this .tokeniser.tokenise(reader);
152: }
153:
154: /**
155: * Imports the mappings defined in the RtfImportMappings into the
156: * RtfImportHeader of this RtfParser.
157: *
158: * @param importMappings The RtfImportMappings to import.
159: */
160: private void handleImportMappings(RtfImportMappings importMappings) {
161: Iterator it = importMappings.getFontMappings().keySet()
162: .iterator();
163: while (it.hasNext()) {
164: String fontNr = (String) it.next();
165: this .importHeader.importFont(fontNr,
166: (String) importMappings.getFontMappings().get(
167: fontNr));
168: }
169: it = importMappings.getColorMappings().keySet().iterator();
170: while (it.hasNext()) {
171: String colorNr = (String) it.next();
172: this .importHeader.importColor(colorNr,
173: (Color) importMappings.getColorMappings().get(
174: colorNr));
175: }
176: }
177:
178: /**
179: * Handles open group tokens.
180: *
181: * @param groupLevel The current group nesting level.
182: */
183: public void handleOpenGroup(int groupLevel) {
184: if (this .state == PARSER_IN_DOCUMENT) {
185: this .rtfDoc.add(new RtfDirectContent("{"));
186: }
187: }
188:
189: /**
190: * Handles close group tokens. Depending on what is currently
191: * being parsed the parse state may change.
192: *
193: * @param groupLevel The current group nesting level.
194: */
195: public void handleCloseGroup(int groupLevel) {
196: if (this .state == PARSER_IN_DOCUMENT && groupLevel > 1) {
197: this .rtfDoc.add(new RtfDirectContent("}"));
198: } else if (this .state == PARSER_IN_INFO_GROUP
199: && groupLevel == 2) {
200: this .state = PARSER_IN_DOCUMENT;
201: } else if (this .state == PARSER_IN_FONT_TABLE) {
202: this .fontTableParser.handleCloseGroup(groupLevel);
203: if (groupLevel == 2) {
204: this .state = PARSER_IN_HEADER;
205: }
206: } else if (this .state == PARSER_IN_COLOR_TABLE) {
207: this .state = PARSER_IN_HEADER;
208: }
209: }
210:
211: /**
212: * Handles single control character tokens.
213: *
214: * @param ctrlCharacter The control character to handle.
215: * @param groupLevel The current group nesting level.
216: */
217: public void handleCtrlCharacter(String ctrlCharacter, int groupLevel) {
218: if (this .state == PARSER_IN_DOCUMENT) {
219: this .rtfDoc.add(new RtfDirectContent(ctrlCharacter));
220: }
221: }
222:
223: /**
224: * Handles control word tokens. Depending on the current
225: * state a control word can lead to a state change. When
226: * parsing the actual document contents, The font number,
227: * color number and background color number are remapped.
228: *
229: * @param ctrlWord The control word to handle.
230: * @param groupLevel The current group nesting level.
231: */
232: public void handleCtrlWord(String ctrlWord, int groupLevel) {
233: if (this .state == PARSER_IN_DOCUMENT) {
234: if (RtfColorTableParser.stringMatches(ctrlWord, "\\f")) {
235: ctrlWord = "\\f"
236: + this .importHeader.mapFontNr(ctrlWord
237: .substring(2));
238: } else if (RtfColorTableParser.stringMatches(ctrlWord,
239: "\\cf")) {
240: ctrlWord = "\\cf"
241: + this .importHeader.mapColorNr(ctrlWord
242: .substring(3));
243: } else if (RtfColorTableParser.stringMatches(ctrlWord,
244: "\\cb")) {
245: ctrlWord = "\\cb"
246: + this .importHeader.mapColorNr(ctrlWord
247: .substring(3));
248: }
249: this .rtfDoc.add(new RtfDirectContent(ctrlWord));
250: } else if (this .state == PARSER_IN_FONT_TABLE) {
251: this .fontTableParser.handleCtrlWord(ctrlWord, groupLevel);
252: } else if (this .state == PARSER_IN_COLOR_TABLE) {
253: this .colorTableParser.handleCtrlWord(ctrlWord, groupLevel);
254: } else if (this .state == PARSER_IN_HEADER) {
255: if (ctrlWord.equals("\\info")) {
256: this .state = PARSER_IN_INFO_GROUP;
257: } else if (ctrlWord.equals("\\fonttbl")) {
258: this .state = PARSER_IN_FONT_TABLE;
259: } else if (ctrlWord.equals("\\colortbl")) {
260: this .state = PARSER_IN_COLOR_TABLE;
261: }
262: }
263: }
264:
265: /**
266: * Handles text tokens. These are either handed on to the
267: * RtfColorTableParser or RtfFontTableParser or added directly
268: * to the document.
269: *
270: * @param text The text token to handle.
271: * @param groupLevel The current group nesting level.
272: */
273: public void handleText(String text, int groupLevel) {
274: if (this .state == PARSER_IN_DOCUMENT) {
275: this .rtfDoc.add(new RtfDirectContent(text));
276: } else if (this.state == PARSER_IN_FONT_TABLE) {
277: this.fontTableParser.handleText(text, groupLevel);
278: } else if (this.state == PARSER_IN_COLOR_TABLE) {
279: this.colorTableParser.handleText(text, groupLevel);
280: }
281: }
282: }
|